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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -3
  3. data/config/locales/ddr-models.en.yml +74 -0
  4. data/ddr-models.gemspec +3 -2
  5. data/lib/ddr/auth.rb +5 -2
  6. data/lib/ddr/auth/roles.rb +0 -2
  7. data/lib/ddr/auth/roles/role_set.rb +1 -0
  8. data/lib/ddr/derivatives/generators/png_generator.rb +1 -1
  9. data/lib/ddr/index.rb +6 -2
  10. data/lib/ddr/index/abstract_query_result.rb +1 -1
  11. data/lib/ddr/index/csv_options.rb +14 -0
  12. data/lib/ddr/index/csv_query_result.rb +39 -32
  13. data/lib/ddr/index/field.rb +11 -1
  14. data/lib/ddr/index/field_attribute.rb +22 -0
  15. data/lib/ddr/index/fields.rb +29 -20
  16. data/lib/ddr/index/filter.rb +81 -30
  17. data/lib/ddr/index/filters.rb +15 -10
  18. data/lib/ddr/index/query.rb +34 -13
  19. data/lib/ddr/index/query_builder.rb +150 -30
  20. data/lib/ddr/index/query_clause.rb +64 -19
  21. data/lib/ddr/index/query_params.rb +40 -0
  22. data/lib/ddr/index/solr_csv_options.rb +18 -0
  23. data/lib/ddr/index/sort_order.rb +28 -0
  24. data/lib/ddr/jobs.rb +5 -1
  25. data/lib/ddr/jobs/fits_file_characterization.rb +3 -41
  26. data/lib/ddr/jobs/fixity_check.rb +13 -0
  27. data/lib/ddr/jobs/job.rb +36 -0
  28. data/lib/ddr/jobs/queue.rb +27 -0
  29. data/lib/ddr/jobs/update_index.rb +13 -0
  30. data/lib/ddr/models.rb +20 -3
  31. data/lib/ddr/models/admin_set.rb +7 -3
  32. data/lib/ddr/models/contact.rb +19 -0
  33. data/lib/ddr/models/error.rb +3 -0
  34. data/lib/ddr/models/file_characterization.rb +37 -0
  35. data/lib/ddr/models/finding_aid.rb +35 -2
  36. data/lib/ddr/models/has_admin_metadata.rb +5 -1
  37. data/lib/ddr/models/has_content.rb +4 -2
  38. data/lib/ddr/models/indexing.rb +7 -0
  39. data/lib/ddr/models/licenses/license.rb +7 -3
  40. data/lib/ddr/models/solr_document.rb +2 -2
  41. data/lib/ddr/models/version.rb +1 -1
  42. data/lib/ddr/models/with_content_file.rb +37 -0
  43. data/lib/ddr/vocab/asset.rb +3 -0
  44. data/spec/derivatives/png_generator_spec.rb +8 -1
  45. data/spec/fixtures/arrow1rightred_e0.gif +0 -0
  46. data/spec/index/fields_spec.rb +197 -0
  47. data/spec/index/filter_spec.rb +155 -30
  48. data/spec/index/query_builder_spec.rb +116 -0
  49. data/spec/index/query_clause_spec.rb +58 -0
  50. data/spec/index/query_spec.rb +39 -10
  51. data/spec/jobs/fits_file_characterization_spec.rb +7 -43
  52. data/spec/jobs/fixity_check_spec.rb +22 -0
  53. data/spec/jobs/job_spec.rb +40 -0
  54. data/spec/jobs/update_index_spec.rb +22 -0
  55. data/spec/managers/derivatives_manager_spec.rb +15 -11
  56. data/spec/models/admin_set_spec.rb +28 -10
  57. data/spec/models/contact_spec.rb +42 -0
  58. data/spec/models/effective_license_spec.rb +17 -7
  59. data/spec/models/file_characterization_spec.rb +38 -0
  60. data/spec/models/finding_aid_spec.rb +31 -8
  61. data/spec/models/has_admin_metadata_spec.rb +8 -5
  62. data/spec/models/indexing_spec.rb +2 -0
  63. data/spec/models/license_spec.rb +31 -10
  64. data/spec/models/solr_document_spec.rb +23 -3
  65. data/spec/models/with_content_file_spec.rb +32 -0
  66. data/spec/spec_helper.rb +2 -0
  67. metadata +66 -28
  68. data/lib/ddr/contacts.rb +0 -25
  69. data/lib/ddr/index/query_value.rb +0 -18
  70. data/lib/ddr/models/access_controllable.rb +0 -12
  71. data/spec/auth/ldap_gateway_spec.rb +0 -9
  72. data/spec/contacts/contacts_spec.rb +0 -26
  73. data/spec/index/filters_spec.rb +0 -17
@@ -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
- class << self
5
- delegate :where, :raw, :before_days, :before, :present, :absent, to: :new
10
+ def ==(other)
11
+ other.instance_of?(self.class) && (other.clauses == self.clauses)
6
12
  end
7
13
 
8
- attr_accessor :clauses
14
+ module Api
15
+ def raw(*clauses)
16
+ self.clauses += clauses
17
+ self
18
+ end
9
19
 
10
- def initialize
11
- @clauses = [ ]
12
- end
20
+ def term(conditions)
21
+ self.clauses += conditions.map { |f, v| QueryClause.term(f, v) }
22
+ self
23
+ end
13
24
 
14
- def where(conditions)
15
- clauses = conditions.map do |field, value|
16
- if value.respond_to?(:each)
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
- # Adds clause (String) w/o escaping
26
- def raw(*clauses)
27
- self.clauses += clauses
28
- self
29
- end
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
- def present(field)
32
- raw QueryClause.present(field)
33
- end
36
+ def absent(field)
37
+ self.clauses << QueryClause.absent(field)
38
+ self
39
+ end
34
40
 
35
- def absent(field)
36
- raw QueryClause.absent(field)
37
- end
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
- def before(field, date_time)
40
- raw QueryClause.before(field, date_time)
56
+ def before_days(field, value)
57
+ self.clauses << QueryClause.before_days(field, value)
58
+ self
59
+ end
41
60
  end
42
61
 
43
- def before_days(field, days)
44
- raw QueryClause.before_days(field, days)
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
@@ -1,19 +1,24 @@
1
1
  module Ddr::Index
2
2
  module Filters
3
+ extend Deprecation
3
4
 
4
- HAS_CONTENT = Filter.where(Fields::ACTIVE_FEDORA_MODEL => ["Component", "Attachment", "Target"])
5
-
6
- class << self
7
- def is_governed_by(pid)
8
- Filter.where(Fields::IS_GOVERNED_BY => pid)
9
- end
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
- def internal_uri(pid)
12
- ActiveFedora::Base.internal_uri(pid)
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
@@ -1,9 +1,26 @@
1
+ require "virtus"
2
+ require "forwardable"
3
+
1
4
  module Ddr::Index
2
5
  class Query
3
-
4
- attr_reader :q, :fields, :filters, :sort, :rows
5
-
6
- delegate :count, :docs, :pids, :each_pid, :all, to: :result
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
- def initialize
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.tap do |qry|
20
- instance_variables.each do |var|
21
- qry.instance_variable_set(var, instance_variable_get(var))
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
- def filter(*fltrs)
32
- @filters.push *fltrs
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
- def fields(*flds)
37
- @fields.push *flds
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
- @rows = num
141
+ query.rows = num.to_i
43
142
  self
44
143
  end
144
+ alias_method :rows, :limit
45
145
 
46
- def order_by(field, order)
47
- @sort << [field, order].join(" ")
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
- def asc(field)
52
- order_by field, "asc"
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
- def desc(field)
56
- order_by field, "desc"
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
- def q(q)
60
- @q = q
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
- protected
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 Filter.respond_to? name
68
- return filter Filter.send(name, *args, &block)
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