ddr-models 3.0.0.beta.3 → 3.0.0.beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/config/locales/ddr-models.en.yml +74 -0
- data/ddr-models.gemspec +3 -2
- data/lib/ddr/auth.rb +5 -2
- data/lib/ddr/auth/roles.rb +0 -2
- data/lib/ddr/auth/roles/role_set.rb +1 -0
- data/lib/ddr/derivatives/generators/png_generator.rb +1 -1
- data/lib/ddr/index.rb +6 -2
- data/lib/ddr/index/abstract_query_result.rb +1 -1
- data/lib/ddr/index/csv_options.rb +14 -0
- data/lib/ddr/index/csv_query_result.rb +39 -32
- data/lib/ddr/index/field.rb +11 -1
- data/lib/ddr/index/field_attribute.rb +22 -0
- data/lib/ddr/index/fields.rb +29 -20
- data/lib/ddr/index/filter.rb +81 -30
- data/lib/ddr/index/filters.rb +15 -10
- data/lib/ddr/index/query.rb +34 -13
- data/lib/ddr/index/query_builder.rb +150 -30
- data/lib/ddr/index/query_clause.rb +64 -19
- data/lib/ddr/index/query_params.rb +40 -0
- data/lib/ddr/index/solr_csv_options.rb +18 -0
- data/lib/ddr/index/sort_order.rb +28 -0
- data/lib/ddr/jobs.rb +5 -1
- data/lib/ddr/jobs/fits_file_characterization.rb +3 -41
- data/lib/ddr/jobs/fixity_check.rb +13 -0
- data/lib/ddr/jobs/job.rb +36 -0
- data/lib/ddr/jobs/queue.rb +27 -0
- data/lib/ddr/jobs/update_index.rb +13 -0
- data/lib/ddr/models.rb +20 -3
- data/lib/ddr/models/admin_set.rb +7 -3
- data/lib/ddr/models/contact.rb +19 -0
- data/lib/ddr/models/error.rb +3 -0
- data/lib/ddr/models/file_characterization.rb +37 -0
- data/lib/ddr/models/finding_aid.rb +35 -2
- data/lib/ddr/models/has_admin_metadata.rb +5 -1
- data/lib/ddr/models/has_content.rb +4 -2
- data/lib/ddr/models/indexing.rb +7 -0
- data/lib/ddr/models/licenses/license.rb +7 -3
- data/lib/ddr/models/solr_document.rb +2 -2
- data/lib/ddr/models/version.rb +1 -1
- data/lib/ddr/models/with_content_file.rb +37 -0
- data/lib/ddr/vocab/asset.rb +3 -0
- data/spec/derivatives/png_generator_spec.rb +8 -1
- data/spec/fixtures/arrow1rightred_e0.gif +0 -0
- data/spec/index/fields_spec.rb +197 -0
- data/spec/index/filter_spec.rb +155 -30
- data/spec/index/query_builder_spec.rb +116 -0
- data/spec/index/query_clause_spec.rb +58 -0
- data/spec/index/query_spec.rb +39 -10
- data/spec/jobs/fits_file_characterization_spec.rb +7 -43
- data/spec/jobs/fixity_check_spec.rb +22 -0
- data/spec/jobs/job_spec.rb +40 -0
- data/spec/jobs/update_index_spec.rb +22 -0
- data/spec/managers/derivatives_manager_spec.rb +15 -11
- data/spec/models/admin_set_spec.rb +28 -10
- data/spec/models/contact_spec.rb +42 -0
- data/spec/models/effective_license_spec.rb +17 -7
- data/spec/models/file_characterization_spec.rb +38 -0
- data/spec/models/finding_aid_spec.rb +31 -8
- data/spec/models/has_admin_metadata_spec.rb +8 -5
- data/spec/models/indexing_spec.rb +2 -0
- data/spec/models/license_spec.rb +31 -10
- data/spec/models/solr_document_spec.rb +23 -3
- data/spec/models/with_content_file_spec.rb +32 -0
- data/spec/spec_helper.rb +2 -0
- metadata +66 -28
- data/lib/ddr/contacts.rb +0 -25
- data/lib/ddr/index/query_value.rb +0 -18
- data/lib/ddr/models/access_controllable.rb +0 -12
- data/spec/auth/ldap_gateway_spec.rb +0 -9
- data/spec/contacts/contacts_spec.rb +0 -26
- data/spec/index/filters_spec.rb +0 -17
data/lib/ddr/index/filter.rb
CHANGED
@@ -1,48 +1,99 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "virtus"
|
3
|
+
|
1
4
|
module Ddr::Index
|
2
5
|
class Filter
|
6
|
+
include Virtus.model
|
7
|
+
|
8
|
+
attribute :clauses, Array, default: [ ]
|
3
9
|
|
4
|
-
|
5
|
-
|
10
|
+
def ==(other)
|
11
|
+
other.instance_of?(self.class) && (other.clauses == self.clauses)
|
6
12
|
end
|
7
13
|
|
8
|
-
|
14
|
+
module Api
|
15
|
+
def raw(*clauses)
|
16
|
+
self.clauses += clauses
|
17
|
+
self
|
18
|
+
end
|
9
19
|
|
10
|
-
|
11
|
-
|
12
|
-
|
20
|
+
def term(conditions)
|
21
|
+
self.clauses += conditions.map { |f, v| QueryClause.term(f, v) }
|
22
|
+
self
|
23
|
+
end
|
13
24
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
QueryClause.or_values(field, *value)
|
18
|
-
else
|
19
|
-
QueryClause.term(field, value)
|
20
|
-
end
|
25
|
+
def where(conditions)
|
26
|
+
self.clauses += conditions.map { |f, v| QueryClause.where(f, v) }
|
27
|
+
self
|
21
28
|
end
|
22
|
-
raw *clauses
|
23
|
-
end
|
24
29
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
+
def where_not(conditions)
|
31
|
+
self.clauses += conditions.map do |field, v|
|
32
|
+
Array(v).map { |value| QueryClause.negative(field, value) }
|
33
|
+
end.flatten
|
34
|
+
end
|
30
35
|
|
31
|
-
|
32
|
-
|
33
|
-
|
36
|
+
def absent(field)
|
37
|
+
self.clauses << QueryClause.absent(field)
|
38
|
+
self
|
39
|
+
end
|
34
40
|
|
35
|
-
|
36
|
-
|
37
|
-
|
41
|
+
def present(field)
|
42
|
+
self.clauses << QueryClause.present(field)
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def negative(field, value)
|
47
|
+
self.clauses << QueryClause.negative(field, value)
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
def before(field, value)
|
52
|
+
self.clauses << QueryClause.before(field, value)
|
53
|
+
self
|
54
|
+
end
|
38
55
|
|
39
|
-
|
40
|
-
|
56
|
+
def before_days(field, value)
|
57
|
+
self.clauses << QueryClause.before_days(field, value)
|
58
|
+
self
|
59
|
+
end
|
41
60
|
end
|
42
61
|
|
43
|
-
|
44
|
-
|
62
|
+
module ClassMethods
|
63
|
+
extend Forwardable
|
64
|
+
|
65
|
+
delegate Api.public_instance_methods => :new_filter
|
66
|
+
|
67
|
+
def has_content
|
68
|
+
model "Component", "Attachment", "Target"
|
69
|
+
end
|
70
|
+
|
71
|
+
def is_governed_by(object_or_id)
|
72
|
+
term is_governed_by: get_id(object_or_id)
|
73
|
+
end
|
74
|
+
|
75
|
+
def is_member_of_collection(object_or_id)
|
76
|
+
term is_member_of_collection: get_id(object_or_id)
|
77
|
+
end
|
78
|
+
|
79
|
+
def model(*models)
|
80
|
+
where active_fedora_model: models
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def get_id(object_or_id)
|
86
|
+
object_or_id.respond_to?(:id) ? object_or_id.id : object_or_id
|
87
|
+
end
|
88
|
+
|
89
|
+
def new_filter
|
90
|
+
Filter.new
|
91
|
+
end
|
92
|
+
|
45
93
|
end
|
46
94
|
|
95
|
+
include Api
|
96
|
+
extend ClassMethods
|
97
|
+
|
47
98
|
end
|
48
99
|
end
|
data/lib/ddr/index/filters.rb
CHANGED
@@ -1,19 +1,24 @@
|
|
1
1
|
module Ddr::Index
|
2
2
|
module Filters
|
3
|
+
extend Deprecation
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
def self.is_governed_by(pid)
|
6
|
+
Deprecation.warn(self,
|
7
|
+
"`Ddr::Index:Filters.is_governed_by` is deprecated and will be removed in ddr-models 3.0." \
|
8
|
+
" Use `Ddr::Index::Filter.is_governed_by` instead.")
|
9
|
+
Filter.is_governed_by(pid)
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
12
|
+
def self.const_missing(name)
|
13
|
+
if name == :HAS_CONTENT
|
14
|
+
Deprecation.warn(self,
|
15
|
+
"`Ddr::Index::Filters::#{name}` is deprecated and will be removed in ddr-models 3.0." \
|
16
|
+
" Use `Ddr::Index::Filter.has_content` instead.")
|
17
|
+
Filter.has_content
|
18
|
+
else
|
19
|
+
super
|
13
20
|
end
|
14
21
|
end
|
15
22
|
|
16
|
-
private_class_method :internal_uri
|
17
|
-
|
18
23
|
end
|
19
24
|
end
|
data/lib/ddr/index/query.rb
CHANGED
@@ -1,9 +1,26 @@
|
|
1
|
+
require "virtus"
|
2
|
+
require "forwardable"
|
3
|
+
|
1
4
|
module Ddr::Index
|
2
5
|
class Query
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
6
|
+
include Virtus.model
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
attribute :q, String
|
10
|
+
attribute :fields, Array[FieldAttribute], default: [ ]
|
11
|
+
attribute :filters, Array[Filter], default: [ ]
|
12
|
+
attribute :sort, Array[String], default: [ ]
|
13
|
+
attribute :rows, Integer
|
14
|
+
|
15
|
+
delegate [:count, :docs, :pids, :each_pid, :all] => :result
|
16
|
+
delegate :params => :query_params
|
17
|
+
|
18
|
+
def initialize(**args, &block)
|
19
|
+
super(**args)
|
20
|
+
if block_given?
|
21
|
+
build(&block)
|
22
|
+
end
|
23
|
+
end
|
7
24
|
|
8
25
|
def inspect
|
9
26
|
"#<#{self.class.name} q=#{q.inspect}, filters=#{filters.inspect}," \
|
@@ -14,15 +31,6 @@ module Ddr::Index
|
|
14
31
|
URI.encode_www_form(params)
|
15
32
|
end
|
16
33
|
|
17
|
-
def params
|
18
|
-
{ q: q,
|
19
|
-
fq: filters.map(&:clauses).flatten,
|
20
|
-
fl: fields.join(","),
|
21
|
-
sort: sort.join(","),
|
22
|
-
rows: rows,
|
23
|
-
}.select { |k, v| v.present? }
|
24
|
-
end
|
25
|
-
|
26
34
|
def result
|
27
35
|
QueryResult.new(self)
|
28
36
|
end
|
@@ -31,5 +39,18 @@ module Ddr::Index
|
|
31
39
|
CSVQueryResult.new(self, **opts)
|
32
40
|
end
|
33
41
|
|
42
|
+
def filter_clauses
|
43
|
+
filters.map(&:clauses).flatten
|
44
|
+
end
|
45
|
+
|
46
|
+
def query_params
|
47
|
+
QueryParams.new(self)
|
48
|
+
end
|
49
|
+
|
50
|
+
def build(&block)
|
51
|
+
QueryBuilder.new(self, &block)
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
34
55
|
end
|
35
56
|
end
|
@@ -1,73 +1,193 @@
|
|
1
1
|
module Ddr::Index
|
2
|
+
#
|
3
|
+
# QueryBuilder - Provides a DSL for building a Query.
|
4
|
+
#
|
5
|
+
# Note: Where a method receives a [field] parameter, the parameter value is
|
6
|
+
# coerced to a Field instance. See FieldAttribute#coerce for details.
|
7
|
+
#
|
8
|
+
# *** DSL METHODS ***
|
9
|
+
#
|
10
|
+
# absent [field]
|
11
|
+
# Adds a filter selecting documents where the field is not present (no values).
|
12
|
+
#
|
13
|
+
# asc [field], ...
|
14
|
+
# Adds ascending orderings by the fields specified.
|
15
|
+
#
|
16
|
+
# See also: desc, order_by
|
17
|
+
#
|
18
|
+
# before [field], [date_time]
|
19
|
+
# Adds a filter selecting documents where the field has a date/time before
|
20
|
+
# (earlier than) the value.
|
21
|
+
#
|
22
|
+
# before_days [field], [int]
|
23
|
+
# Adds a filter selecting documents where the field has a date/time the
|
24
|
+
# specified number of days before today (now) or earlier.
|
25
|
+
#
|
26
|
+
# desc [field], ...
|
27
|
+
# Adds descending orderings by the fields specified.
|
28
|
+
#
|
29
|
+
# See also: asc, order_by
|
30
|
+
#
|
31
|
+
# id [doc_id]
|
32
|
+
# For selecting a single document by ID.
|
33
|
+
#
|
34
|
+
# filter [filter1], ...
|
35
|
+
# Adds filters to the query.
|
36
|
+
#
|
37
|
+
# Aliased as: filters
|
38
|
+
#
|
39
|
+
# filters [filter], ...
|
40
|
+
# Alias for: filter
|
41
|
+
#
|
42
|
+
# field [field1], ...
|
43
|
+
# Adds fields to result documents.
|
44
|
+
# Note that all fields are returned when none is specified.
|
45
|
+
#
|
46
|
+
# Aliased as: fields
|
47
|
+
#
|
48
|
+
# fields [field], ...
|
49
|
+
# Alias for: field
|
50
|
+
#
|
51
|
+
# limit [int]
|
52
|
+
# Limits the number of documents returned by the query.
|
53
|
+
#
|
54
|
+
# Aliased as: rows
|
55
|
+
#
|
56
|
+
# model [model_name], ...
|
57
|
+
# Adds a filter selecting document where ActiveFedora model equals value
|
58
|
+
# or one of the values.
|
59
|
+
#
|
60
|
+
# negative [field], [value]
|
61
|
+
# Adds a filter selecting document where field does not have the value.
|
62
|
+
#
|
63
|
+
# order_by [{field => order, ...}], ...
|
64
|
+
# Adds ordering(s) to the query.
|
65
|
+
#
|
66
|
+
# Aliased as: sort
|
67
|
+
#
|
68
|
+
# present [field]
|
69
|
+
# Adds a filter selecting document where the field has any value.
|
70
|
+
#
|
71
|
+
# q [query_clause]
|
72
|
+
# Sets a query clause for the `q` parameter.
|
73
|
+
#
|
74
|
+
# raw [clause1], ...
|
75
|
+
# Adds a filter of "raw" query clauses (i.e., pre-constructed).
|
76
|
+
#
|
77
|
+
# rows [int]
|
78
|
+
# Alias for: limit
|
79
|
+
#
|
80
|
+
# sort [{field => order, ...}]
|
81
|
+
# Alias for: order_by
|
82
|
+
#
|
83
|
+
# term [{field => value, ...}]
|
84
|
+
# Adds a filter of "term" query clauses for the fields and values.
|
85
|
+
#
|
86
|
+
# where [{field => value, ...}]
|
87
|
+
# Adds a filter of "standard" query clauses.
|
88
|
+
# Values will be escaped when the filter is serialized.
|
89
|
+
# If a hash value is an array, that query clause will select documents
|
90
|
+
# where the field matches any array entry.
|
91
|
+
#
|
2
92
|
class QueryBuilder
|
3
93
|
|
94
|
+
# Builds a Query object
|
95
|
+
# @yield [builder] a new QueryBuilder instance.
|
96
|
+
# @return [Query]
|
4
97
|
def self.build
|
98
|
+
Deprecation.warn(self,
|
99
|
+
"`Ddr::Index::QueryBuilder.build` is deprecated and will be removed in ddr-models 3.0." \
|
100
|
+
" Use `Ddr::Index::QueryBuilder.new` instead.")
|
5
101
|
builder = new
|
6
102
|
yield builder
|
7
103
|
builder.query
|
8
104
|
end
|
9
105
|
|
10
|
-
|
11
|
-
@q = nil
|
12
|
-
@fields = [ ]
|
13
|
-
@filters = [ ]
|
14
|
-
@sort = [ ]
|
15
|
-
@rows = nil
|
16
|
-
end
|
106
|
+
attr_reader :query
|
17
107
|
|
18
|
-
def query
|
19
|
-
Query.new
|
20
|
-
|
21
|
-
|
22
|
-
end
|
108
|
+
def initialize(query = nil, &block)
|
109
|
+
@query = query || Query.new
|
110
|
+
if block_given?
|
111
|
+
instance_eval &block
|
23
112
|
end
|
24
113
|
end
|
25
114
|
|
115
|
+
# @param pid [String]
|
116
|
+
# @return [QueryBuilder]
|
26
117
|
def id(pid)
|
27
118
|
q QueryClause.id(pid)
|
28
119
|
limit 1
|
29
120
|
end
|
30
121
|
|
31
|
-
|
32
|
-
|
122
|
+
# @param filters [Array<Filter>]
|
123
|
+
# @return [QueryBuilder]
|
124
|
+
def filter(*filters)
|
125
|
+
query.filters += filters
|
33
126
|
self
|
34
127
|
end
|
128
|
+
alias_method :filters, :filter
|
35
129
|
|
36
|
-
|
37
|
-
|
130
|
+
# @param fields [Array<Field>]
|
131
|
+
# @return [QueryBuilder] self
|
132
|
+
def field(*fields)
|
133
|
+
query.fields += fields.flatten.map { |f| FieldAttribute.coerce(f) }
|
38
134
|
self
|
39
135
|
end
|
136
|
+
alias_method :fields, :field
|
40
137
|
|
138
|
+
# @param num [Integer]
|
139
|
+
# @return [QueryBuilder] self
|
41
140
|
def limit(num)
|
42
|
-
|
141
|
+
query.rows = num.to_i
|
43
142
|
self
|
44
143
|
end
|
144
|
+
alias_method :rows, :limit
|
45
145
|
|
46
|
-
|
47
|
-
|
146
|
+
# @param orderings [Hash<Field, String>]
|
147
|
+
# @return [QueryBuilder] self
|
148
|
+
def order_by(*orderings)
|
149
|
+
unless orderings.first.is_a? Hash
|
150
|
+
Deprecation.warn(QueryBuilder, "`order_by` will require a hash of orderings in ddr-models 3.0.")
|
151
|
+
field, order = orderings
|
152
|
+
return order_by(field => order)
|
153
|
+
end
|
154
|
+
query.sort += orderings.first.map { |field, order| SortOrder.new(field: field, order: order) }
|
48
155
|
self
|
49
156
|
end
|
157
|
+
alias_method :sort, :order_by
|
50
158
|
|
51
|
-
|
52
|
-
|
159
|
+
# @param fields [Array<Field, Symbol, String>]
|
160
|
+
# @return [QueryBuilder] self
|
161
|
+
def asc(*fields)
|
162
|
+
query.sort += fields.map { |field| SortOrder.asc(field) }
|
163
|
+
self
|
53
164
|
end
|
54
|
-
|
55
|
-
|
56
|
-
|
165
|
+
# @param fields [Array<Field, Symbol, String>]
|
166
|
+
# @return [QueryBuilder] self
|
167
|
+
def desc(*fields)
|
168
|
+
query.sort += fields.map { |field| SortOrder.desc(field) }
|
169
|
+
self
|
57
170
|
end
|
58
171
|
|
59
|
-
|
60
|
-
|
172
|
+
# @param query_clause [QueryClause, String]
|
173
|
+
# @return [QueryBuilder] self
|
174
|
+
def q(query_clause)
|
175
|
+
query.q = query_clause
|
61
176
|
self
|
62
177
|
end
|
63
178
|
|
64
|
-
|
179
|
+
private
|
180
|
+
|
181
|
+
def respond_to_missing?(name, include_all)
|
182
|
+
Filter::ClassMethods.public_instance_methods.include?(name)
|
183
|
+
end
|
65
184
|
|
66
185
|
def method_missing(name, *args, &block)
|
67
|
-
if
|
68
|
-
|
186
|
+
if respond_to?(name)
|
187
|
+
filter Filter.send(name, *args)
|
188
|
+
else
|
189
|
+
super
|
69
190
|
end
|
70
|
-
super
|
71
191
|
end
|
72
192
|
|
73
193
|
end
|