-
Notifications
You must be signed in to change notification settings - Fork 7
/
filter.go
180 lines (163 loc) · 4.31 KB
/
filter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package sift
import (
"encoding/json"
"fmt"
)
// SourceIdentifierer returns a source identifier.
type SourceIdentifierer interface {
SourceIdentifier() string
}
// Packager returns package names.
type Packager interface {
Packages() []string
}
// Collectioner returns a number of collections.
type Collectioner interface {
Collections() []string
}
// SerialNumberer returns a list of ISSN as strings.
type SerialNumberer interface {
SerialNumbers() []string
}
// DocumentObjectIdentifier returns a single document object identifier as string.
type DocumentObjectIdentifier interface {
DOI() string
}
// Subjecter returns a number of subjects.
type Subjecter interface {
Subjects() []string
}
// PublicationDater returns a publication date string in ISO format: 2017-07-15.
type PublicationDater interface {
PublicationDate() string
}
// Volumer returns a volume number, preferably without decoration.
type Volumer interface {
Volume() string
}
// Issuer returns a issue, preferably without decoration.
type Issuer interface {
Issue() string
}
// Filter returns a boolean, given a value. This abstracts away the process of
// the actual decision making. The implementations will need to type assert
// certain interfaces to access values from the interfaces.
type Filter interface {
Apply(interface{}) bool
}
// firstKey returns the top level key of an object, given as a raw JSON message.
// It peeks into the fragment. An empty document will cause an error, as
// multiple top level keys.
func firstKey(raw json.RawMessage) (string, error) {
var peeker = make(map[string]interface{})
if err := json.Unmarshal(raw, &peeker); err != nil {
return "", err
}
var keys []string
for k := range peeker {
keys = append(keys, k)
}
if len(keys) == 0 {
return "", fmt.Errorf("no key found")
}
if len(keys) > 1 {
return "", fmt.Errorf("cannot decide which top-level key to use: %s", keys)
}
return keys[0], nil
}
// unmarshalFilterList returns a list of filters from a list of JSON fragments. Unknown
// filter names will cause errors.
func unmarshalFilterList(raw []json.RawMessage) (filters []Filter, err error) {
var name string
var f Filter
for _, r := range raw {
if name, err = firstKey(r); err != nil {
return
}
if f, err = unmarshalFilter(name, r); err != nil {
return
}
filters = append(filters, f)
}
return
}
// unmarshalFilter takes the name of a filter and a raw JSON message and
// unmarshals the appropriate filter. All filters must be registered here.
// Unknown filters cause an error.
func unmarshalFilter(name string, raw json.RawMessage) (Filter, error) {
switch name {
// Add more filters here.
case "any":
return &AnyFilter{}, nil
case "none":
return &NoneFilter{}, nil
case "collection":
var filter CollectionsFilter
if err := json.Unmarshal(raw, &filter); err != nil {
return nil, err
}
return &filter, nil
case "doi":
var filter DocumentObjectIdentifiersFilter
if err := json.Unmarshal(raw, &filter); err != nil {
return nil, err
}
return &filter, nil
case "holdings":
var filter HoldingsFilter
if err := json.Unmarshal(raw, &filter); err != nil {
return nil, err
}
return &filter, nil
case "issn":
var filter SerialNumbersFilter
if err := json.Unmarshal(raw, &filter); err != nil {
return nil, err
}
return &filter, nil
case "package":
var filter PackagesFilter
if err := json.Unmarshal(raw, &filter); err != nil {
return nil, err
}
return &filter, nil
case "source":
var filter SourceIdentifierFilter
if err := json.Unmarshal(raw, &filter); err != nil {
return nil, err
}
return &filter, nil
case "subject":
var filter SubjectsFilter
if err := json.Unmarshal(raw, &filter); err != nil {
return nil, err
}
return &filter, nil
case "and":
var filter AndFilter
if err := json.Unmarshal(raw, &filter); err != nil {
return nil, err
}
return &filter, nil
case "or":
var filter OrFilter
if err := json.Unmarshal(raw, &filter); err != nil {
return nil, err
}
return &filter, nil
case "not":
var filter NotFilter
if err := json.Unmarshal(raw, &filter); err != nil {
return nil, err
}
return &filter, nil
case "id":
var filter IdentifierFilter
if err := json.Unmarshal(raw, &filter); err != nil {
return nil, err
}
return &filter, nil
default:
return nil, fmt.Errorf("unknown filter: %s", name)
}
}