ddr-models 3.0.0.beta.3 → 3.0.0.beta.4

Sign up to get free protection for your applications and to get access to all the features.
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