naranya_ecm-sdk 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/naranya_ecm/behaviors/localizable.rb +27 -31
  3. data/lib/naranya_ecm/behaviors/mediable.rb +25 -0
  4. data/lib/naranya_ecm/behaviors/timestampable.rb +18 -15
  5. data/lib/naranya_ecm/cache/key.rb +32 -56
  6. data/lib/naranya_ecm/cache/methods.rb +50 -63
  7. data/lib/naranya_ecm/lifecycles/content_lifecycle.rb +39 -16
  8. data/lib/naranya_ecm/models/category.rb +11 -30
  9. data/lib/naranya_ecm/models/content.rb +73 -73
  10. data/lib/naranya_ecm/models/content_version.rb +50 -29
  11. data/lib/naranya_ecm/models/download_authorization.rb +22 -26
  12. data/lib/naranya_ecm/models/media_resource.rb +49 -15
  13. data/lib/naranya_ecm/rest/associations.rb +156 -0
  14. data/lib/naranya_ecm/rest/client.rb +4 -0
  15. data/lib/naranya_ecm/rest/errors.rb +53 -0
  16. data/lib/naranya_ecm/rest/finder_methods.rb +50 -0
  17. data/lib/naranya_ecm/rest/model.rb +215 -0
  18. data/lib/naranya_ecm/rest/persistence.rb +122 -0
  19. data/lib/naranya_ecm/rest/relation.rb +54 -0
  20. data/lib/naranya_ecm/search/hit.rb +19 -14
  21. data/lib/naranya_ecm/search/methods.rb +18 -20
  22. data/lib/naranya_ecm/search/query.rb +229 -230
  23. data/lib/naranya_ecm/search/results.rb +136 -139
  24. data/lib/naranya_ecm-sdk/version.rb +1 -1
  25. data/lib/naranya_ecm-sdk.rb +54 -13
  26. data/naranya_ecm-sdk.gemspec +1 -1
  27. data/spec/models/category_spec.rb +7 -2
  28. data/spec/models/content_spec.rb +11 -2
  29. data/spec/models/media_spec.rb +1 -1
  30. data/spec/spec_helper.rb +1 -1
  31. data/spec/support/naranya_ecms_shared_specs.rb +0 -12
  32. metadata +15 -19
  33. data/lib/naranya_ecm/behaviors/resourceable.rb +0 -22
  34. data/lib/naranya_ecm/behaviors.rb +0 -10
  35. data/lib/naranya_ecm/cache.rb +0 -9
  36. data/lib/naranya_ecm/has_many_patch.rb +0 -105
  37. data/lib/naranya_ecm/lifecycles/lifecycleable.rb +0 -43
  38. data/lib/naranya_ecm/lifecycles/version_lifecycle.rb +0 -75
  39. data/lib/naranya_ecm/lifecycles.rb +0 -10
  40. data/lib/naranya_ecm/models/embedded_hash.rb +0 -10
  41. data/lib/naranya_ecm/models/embedded_localized_hash.rb +0 -38
  42. data/lib/naranya_ecm/models/lifecycle.rb +0 -34
  43. data/lib/naranya_ecm/models.rb +0 -15
  44. data/lib/naranya_ecm/search.rb +0 -14
@@ -1,296 +1,295 @@
1
- module NaranyaEcm
2
- module Search
3
- class Query < Hash
4
- class << self
5
- def build_searchkick_like(term, options = {})
6
- if term.is_a?(Hash)
7
- options = term
8
- term = nil
9
- else
10
- term = term.to_s
11
- end
12
1
 
13
- fields =
14
- if options[:fields]
15
- if options[:autocomplete]
16
- options[:fields].map{|f| "#{f}.autocomplete" }
17
- else
18
- options[:fields].map do |value|
19
- k, v = value.is_a?(Hash) ? value.to_a.first : [value, :word]
20
- "#{k}.#{v == :word ? "analyzed" : v}"
21
- end
22
- end
2
+ module NaranyaEcm::Search
3
+ class Query < Hash
4
+ class << self
5
+ def build_searchkick_like(term, options = {})
6
+ if term.is_a?(Hash)
7
+ options = term
8
+ term = nil
9
+ else
10
+ term = term.to_s
11
+ end
12
+
13
+ fields =
14
+ if options[:fields]
15
+ if options[:autocomplete]
16
+ options[:fields].map{|f| "#{f}.autocomplete" }
23
17
  else
24
- ["_all"]
18
+ options[:fields].map do |value|
19
+ k, v = value.is_a?(Hash) ? value.to_a.first : [value, :word]
20
+ "#{k}.#{v == :word ? "analyzed" : v}"
21
+ end
25
22
  end
23
+ else
24
+ ["_all"]
25
+ end
26
26
 
27
- operator = options[:partial] ? "or" : "and"
27
+ operator = options[:partial] ? "or" : "and"
28
28
 
29
- # model and eagar loading
30
- load = options[:load].nil? ? true : options[:load]
31
- load = (options[:include] ? {include: options[:include]} : true) if load
29
+ # model and eagar loading
30
+ load = options[:load].nil? ? true : options[:load]
31
+ load = (options[:include] ? {include: options[:include]} : true) if load
32
32
 
33
- # pagination
34
- page = [options[:page].to_i, 1].max
35
- per_page = (options[:limit] || options[:per_page] || 10).to_i
36
- offset = options[:offset] || (page - 1) * per_page
33
+ # pagination
34
+ page = [options[:page].to_i, 1].max
35
+ per_page = (options[:limit] || options[:per_page] || 10).to_i
36
+ offset = options[:offset] || (page - 1) * per_page
37
37
 
38
- all = term == "*"
38
+ all = term == "*"
39
39
 
40
- if options[:query]
41
- payload = options[:query]
42
- elsif options[:similar]
40
+ if options[:query]
41
+ payload = options[:query]
42
+ elsif options[:similar]
43
+ payload = {
44
+ more_like_this: {
45
+ fields: fields,
46
+ like_text: term,
47
+ min_doc_freq: 1,
48
+ min_term_freq: 1,
49
+ analyzer: "searchkick_search2"
50
+ }
51
+ }
52
+ elsif all
53
+ payload = {
54
+ match_all: {}
55
+ }
56
+ else
57
+ if options[:autocomplete]
43
58
  payload = {
44
- more_like_this: {
59
+ multi_match: {
45
60
  fields: fields,
46
- like_text: term,
47
- min_doc_freq: 1,
48
- min_term_freq: 1,
49
- analyzer: "searchkick_search2"
61
+ query: term,
62
+ analyzer: "searchkick_autocomplete_search"
50
63
  }
51
64
  }
52
- elsif all
53
- payload = {
54
- match_all: {}
55
- }
56
65
  else
57
- if options[:autocomplete]
58
- payload = {
59
- multi_match: {
60
- fields: fields,
66
+ queries = []
67
+ fields.each do |field|
68
+ if field == "_all" or field.end_with?(".analyzed")
69
+ shared_options = {
70
+ fields: [field],
61
71
  query: term,
62
- analyzer: "searchkick_autocomplete_search"
72
+ use_dis_max: false,
73
+ operator: operator,
74
+ cutoff_frequency: 0.001
63
75
  }
64
- }
65
- else
66
- queries = []
67
- fields.each do |field|
68
- if field == "_all" or field.end_with?(".analyzed")
69
- shared_options = {
70
- fields: [field],
71
- query: term,
72
- use_dis_max: false,
73
- operator: operator,
74
- cutoff_frequency: 0.001
75
- }
76
+ queries.concat [
77
+ {multi_match: shared_options.merge(boost: 10, analyzer: "searchkick_search")},
78
+ {multi_match: shared_options.merge(boost: 10, analyzer: "searchkick_search2")}
79
+ ]
80
+ if options[:misspellings] != false
81
+ distance = (options[:misspellings].is_a?(Hash) && options[:misspellings][:distance]) || 1
76
82
  queries.concat [
77
- {multi_match: shared_options.merge(boost: 10, analyzer: "searchkick_search")},
78
- {multi_match: shared_options.merge(boost: 10, analyzer: "searchkick_search2")}
83
+ {multi_match: shared_options.merge(fuzziness: distance, max_expansions: 3, analyzer: "searchkick_search")},
84
+ {multi_match: shared_options.merge(fuzziness: distance, max_expansions: 3, analyzer: "searchkick_search2")}
79
85
  ]
80
- if options[:misspellings] != false
81
- distance = (options[:misspellings].is_a?(Hash) && options[:misspellings][:distance]) || 1
82
- queries.concat [
83
- {multi_match: shared_options.merge(fuzziness: distance, max_expansions: 3, analyzer: "searchkick_search")},
84
- {multi_match: shared_options.merge(fuzziness: distance, max_expansions: 3, analyzer: "searchkick_search2")}
85
- ]
86
- end
87
- else
88
- queries << {
89
- multi_match: {
90
- fields: [field],
91
- query: term,
92
- analyzer: "searchkick_autocomplete_search"
93
- }
94
- }
95
86
  end
96
- end
97
-
98
- payload = {
99
- dis_max: {
100
- queries: queries
87
+ else
88
+ queries << {
89
+ multi_match: {
90
+ fields: [field],
91
+ query: term,
92
+ analyzer: "searchkick_autocomplete_search"
93
+ }
101
94
  }
102
- }
95
+ end
103
96
  end
104
97
 
98
+ payload = {
99
+ dis_max: {
100
+ queries: queries
101
+ }
102
+ }
105
103
  end
106
104
 
107
- custom_filters = []
105
+ end
108
106
 
109
- if options[:boost]
110
- custom_filters << {
111
- filter: {
112
- exists: {
113
- field: options[:boost]
114
- }
115
- },
116
- script: "log(doc['#{options[:boost]}'].value + 2.718281828)"
117
- }
118
- end
107
+ custom_filters = []
119
108
 
120
- if custom_filters.any?
121
- payload = {
122
- custom_filters_score: {
123
- query: payload,
124
- filters: custom_filters,
125
- score_mode: "total"
109
+ if options[:boost]
110
+ custom_filters << {
111
+ filter: {
112
+ exists: {
113
+ field: options[:boost]
126
114
  }
127
- }
128
- end
115
+ },
116
+ script: "log(doc['#{options[:boost]}'].value + 2.718281828)"
117
+ }
118
+ end
129
119
 
120
+ if custom_filters.any?
130
121
  payload = {
131
- query: payload,
132
- size: per_page,
133
- from: offset
122
+ custom_filters_score: {
123
+ query: payload,
124
+ filters: custom_filters,
125
+ score_mode: "total"
126
+ }
134
127
  }
135
- payload[:explain] = options[:explain] if options[:explain]
128
+ end
136
129
 
137
- # order
138
- if options[:order]
139
- order = options[:order].is_a?(Enumerable) ? options[:order] : {options[:order] => :asc}
140
- payload[:sort] = Hash[ order.map{|k, v| [k.to_s == "id" ? :_id : k, v] } ]
141
- end
130
+ payload = {
131
+ query: payload,
132
+ size: per_page,
133
+ from: offset
134
+ }
135
+ payload[:explain] = options[:explain] if options[:explain]
142
136
 
143
- term_filters =
144
- proc do |field, value|
145
- if value.is_a?(Array) # in query
146
- if value.any?
147
- {or: value.map{|v| term_filters.call(field, v) }}
148
- else
149
- {terms: {field => value}} # match nothing
150
- end
151
- elsif value.nil?
152
- {missing: {"field" => field, existence: true, null_value: true}}
137
+ # order
138
+ if options[:order]
139
+ order = options[:order].is_a?(Enumerable) ? options[:order] : {options[:order] => :asc}
140
+ payload[:sort] = Hash[ order.map{|k, v| [k.to_s == "id" ? :_id : k, v] } ]
141
+ end
142
+
143
+ term_filters =
144
+ proc do |field, value|
145
+ if value.is_a?(Array) # in query
146
+ if value.any?
147
+ {or: value.map{|v| term_filters.call(field, v) }}
153
148
  else
154
- {term: {field => value}}
149
+ {terms: {field => value}} # match nothing
155
150
  end
151
+ elsif value.nil?
152
+ {missing: {"field" => field, existence: true, null_value: true}}
153
+ else
154
+ {term: {field => value}}
156
155
  end
156
+ end
157
157
 
158
- # where
159
- where_filters =
160
- proc do |where|
161
- filters = []
162
- (where || {}).each do |field, value|
163
- field = :_id if field.to_s == "id"
158
+ # where
159
+ where_filters =
160
+ proc do |where|
161
+ filters = []
162
+ (where || {}).each do |field, value|
163
+ field = :_id if field.to_s == "id"
164
164
 
165
- if field == :or
166
- value.each do |or_clause|
167
- filters << {or: or_clause.map{|or_statement| {and: where_filters.call(or_statement)} }}
168
- end
169
- else
170
- # expand ranges
171
- if value.is_a?(Range)
172
- value = {gte: value.first, (value.exclude_end? ? :lt : :lte) => value.last}
173
- end
165
+ if field == :or
166
+ value.each do |or_clause|
167
+ filters << {or: or_clause.map{|or_statement| {and: where_filters.call(or_statement)} }}
168
+ end
169
+ else
170
+ # expand ranges
171
+ if value.is_a?(Range)
172
+ value = {gte: value.first, (value.exclude_end? ? :lt : :lte) => value.last}
173
+ end
174
174
 
175
- if value.is_a?(Hash)
176
- if value[:near]
177
- filters << {
178
- geo_distance: {
179
- field => value.delete(:near).map(&:to_f).reverse,
180
- distance: value.delete(:within) || "50mi"
181
- }
175
+ if value.is_a?(Hash)
176
+ if value[:near]
177
+ filters << {
178
+ geo_distance: {
179
+ field => value.delete(:near).map(&:to_f).reverse,
180
+ distance: value.delete(:within) || "50mi"
182
181
  }
183
- end
182
+ }
183
+ end
184
184
 
185
- if value[:top_left]
186
- filters << {
187
- geo_bounding_box: {
188
- field => {
189
- top_left: value.delete(:top_left).map(&:to_f).reverse,
190
- bottom_right: value.delete(:bottom_right).map(&:to_f).reverse
191
- }
185
+ if value[:top_left]
186
+ filters << {
187
+ geo_bounding_box: {
188
+ field => {
189
+ top_left: value.delete(:top_left).map(&:to_f).reverse,
190
+ bottom_right: value.delete(:bottom_right).map(&:to_f).reverse
192
191
  }
193
192
  }
194
- end
193
+ }
194
+ end
195
195
 
196
- value.each do |op, op_value|
197
- if op == :not # not equal
198
- filters << {not: term_filters.call(field, op_value)}
199
- elsif op == :all
200
- filters << {terms: {field => op_value, execution: "and"}}
201
- else
202
- range_query =
203
- case op
204
- when :gt
205
- {from: op_value, include_lower: false}
206
- when :gte
207
- {from: op_value, include_lower: true}
208
- when :lt
209
- {to: op_value, include_upper: false}
210
- when :lte
211
- {to: op_value, include_upper: true}
212
- else
213
- raise "Unknown where operator"
214
- end
215
- filters << {range: {field => range_query}}
216
- end
196
+ value.each do |op, op_value|
197
+ if op == :not # not equal
198
+ filters << {not: term_filters.call(field, op_value)}
199
+ elsif op == :all
200
+ filters << {terms: {field => op_value, execution: "and"}}
201
+ else
202
+ range_query =
203
+ case op
204
+ when :gt
205
+ {from: op_value, include_lower: false}
206
+ when :gte
207
+ {from: op_value, include_lower: true}
208
+ when :lt
209
+ {to: op_value, include_upper: false}
210
+ when :lte
211
+ {to: op_value, include_upper: true}
212
+ else
213
+ raise "Unknown where operator"
214
+ end
215
+ filters << {range: {field => range_query}}
217
216
  end
218
- else
219
- filters << term_filters.call(field, value)
220
217
  end
218
+ else
219
+ filters << term_filters.call(field, value)
221
220
  end
222
221
  end
223
- filters
224
222
  end
225
-
226
- # filters
227
- filters = where_filters.call(options[:where])
228
- if filters.any?
229
- payload[:filter] = {
230
- and: filters
231
- }
223
+ filters
232
224
  end
233
225
 
234
- # facets
235
- facet_limits = {}
236
- if options[:facets]
237
- facets = options[:facets] || {}
238
- if facets.is_a?(Array) # convert to more advanced syntax
239
- facets = Hash[ facets.map{|f| [f, {}] } ]
240
- end
226
+ # filters
227
+ filters = where_filters.call(options[:where])
228
+ if filters.any?
229
+ payload[:filter] = {
230
+ and: filters
231
+ }
232
+ end
241
233
 
242
- payload[:facets] = {}
243
- facets.each do |field, facet_options|
244
- # ask for extra facets due to
245
- # https://github.com/elasticsearch/elasticsearch/issues/1305
234
+ # facets
235
+ facet_limits = {}
236
+ if options[:facets]
237
+ facets = options[:facets] || {}
238
+ if facets.is_a?(Array) # convert to more advanced syntax
239
+ facets = Hash[ facets.map{|f| [f, {}] } ]
240
+ end
246
241
 
247
- if facet_options[:ranges]
248
- payload[:facets][field] = {
249
- range: {
250
- field.to_sym => facet_options[:ranges]
251
- }
242
+ payload[:facets] = {}
243
+ facets.each do |field, facet_options|
244
+ # ask for extra facets due to
245
+ # https://github.com/elasticsearch/elasticsearch/issues/1305
246
+
247
+ if facet_options[:ranges]
248
+ payload[:facets][field] = {
249
+ range: {
250
+ field.to_sym => facet_options[:ranges]
252
251
  }
253
- else
254
- payload[:facets][field] = {
255
- terms: {
256
- field: field,
257
- size: facet_options[:limit] ? facet_options[:limit] + 150 : 100000
258
- }
252
+ }
253
+ else
254
+ payload[:facets][field] = {
255
+ terms: {
256
+ field: field,
257
+ size: facet_options[:limit] ? facet_options[:limit] + 150 : 100000
259
258
  }
260
- end
259
+ }
260
+ end
261
261
 
262
- facet_limits[field] = facet_options[:limit] if facet_options[:limit]
262
+ facet_limits[field] = facet_options[:limit] if facet_options[:limit]
263
263
 
264
- # offset is not possible
265
- # http://elasticsearch-users.115913.n3.nabble.com/Is-pagination-possible-in-termsStatsFacet-td3422943.html
264
+ # offset is not possible
265
+ # http://elasticsearch-users.115913.n3.nabble.com/Is-pagination-possible-in-termsStatsFacet-td3422943.html
266
266
 
267
- facet_filters = where_filters.call(facet_options[:where])
268
- if facet_filters.any?
269
- payload[:facets][field][:facet_filter] = {
270
- and: {
271
- filters: facet_filters
272
- }
267
+ facet_filters = where_filters.call(facet_options[:where])
268
+ if facet_filters.any?
269
+ payload[:facets][field][:facet_filter] = {
270
+ and: {
271
+ filters: facet_filters
273
272
  }
274
- end
273
+ }
275
274
  end
276
275
  end
276
+ end
277
277
 
278
- # highlight
279
- if options[:highlight]
280
- payload[:highlight] = {
281
- fields: Hash[ fields.map{|f| [f, {}] } ]
282
- }
283
- if options[:highlight].is_a?(Hash) and tag = options[:highlight][:tag]
284
- payload[:highlight][:pre_tags] = [tag]
285
- payload[:highlight][:post_tags] = [tag.to_s.gsub(/\A</, "</")]
286
- end
278
+ # highlight
279
+ if options[:highlight]
280
+ payload[:highlight] = {
281
+ fields: Hash[ fields.map{|f| [f, {}] } ]
282
+ }
283
+ if options[:highlight].is_a?(Hash) and tag = options[:highlight][:tag]
284
+ payload[:highlight][:pre_tags] = [tag]
285
+ payload[:highlight][:post_tags] = [tag.to_s.gsub(/\A</, "</")]
287
286
  end
287
+ end
288
288
 
289
- payload[:_source] = 'updated_at'
289
+ payload[:_source] = 'updated_at'
290
290
 
291
- self.new.merge payload
292
- end
291
+ self.new.merge payload
293
292
  end
294
293
  end
295
294
  end
296
- end
295
+ end