elasticated 2.4.0 → 2.5.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0c21bce40f279a26bfc18215caed1f0e2869584d
4
- data.tar.gz: b6b33eabf8cb3ea40a848b4ba012201c630c6b2b
3
+ metadata.gz: 6637480a40d6c018f1edc45efa103df9c836f81f
4
+ data.tar.gz: a65c27a00654dd7616e9f8086441f4365f616d24
5
5
  SHA512:
6
- metadata.gz: 1f6b73bf87e1c6da918a9dcbe88ddec3f7cc2a0fa1dbe49133c3170908f58ecf095a197082846506b5dc8e23ef3be5cfd5be7f4a86bbf48f9196f98d6f3d2fd6
7
- data.tar.gz: 51fdff057ce01cce2113d448c7426ec89fb0304e76b7fe646f28071730118b17b5805e1779b0843f153200bcf24d9e0a54e0fc68973a3c8aeba548a2580e765e
6
+ metadata.gz: 1cda536b17d2dddb5d62be83cb2f2ae15555569df1fe7086574f1605c379897f12f9952e0047be486d4fc5b59f35f891544d7d466975b87ab4068a57b1b4b553
7
+ data.tar.gz: 904e56da96d375422ac0951ffababf82f262e7afb68dd6a2cde125f1f9b2954bcc6d4eabb41bf4b3448132e352fcd451c462db4975cb597a5d9050acb07f396b
data/lib/elasticated.rb CHANGED
@@ -30,6 +30,10 @@ require_relative 'elasticated/conditions/custom_condition'
30
30
  require_relative 'elasticated/delimiters/standard_field_delimiter'
31
31
  require_relative 'elasticated/delimiters/term_field_delimiter'
32
32
  require_relative 'elasticated/delimiters/date_field_delimiter'
33
+ require_relative 'elasticated/term_delimiter_factory'
34
+ require_relative 'elasticated/date_delimiter_factory'
35
+ require_relative 'elasticated/delimiter_visitor'
36
+ require_relative 'elasticated/strategy_params_for_query_service'
33
37
 
34
38
  # query components
35
39
 
@@ -112,4 +116,20 @@ module Elasticated
112
116
  block.call Configuration
113
117
  end
114
118
 
119
+ def self.date_delimiter_factory
120
+ @date_delimiter_factory ||= DateDelimiterFactory.new
121
+ end
122
+
123
+ def self.term_delimiter_factory
124
+ @term_delimiter_factory ||= TermDelimiterFactory.new
125
+ end
126
+
127
+ def self.delimiter_visitor
128
+ @delimiter_visitor ||= DelimiterVisitor.new
129
+ end
130
+
131
+ def self.strategy_params_for_query_service
132
+ @strategy_params_for_query_service ||= StrategyParamsForQueryService.new
133
+ end
134
+
115
135
  end
@@ -32,5 +32,9 @@ module Elasticated
32
32
  end
33
33
  end
34
34
 
35
+ def accept_visitor(visitor)
36
+ visitor.visit_aggregation(self)
37
+ end
38
+
35
39
  end
36
40
  end
@@ -36,5 +36,9 @@ module Elasticated
36
36
  end
37
37
  end
38
38
 
39
+ def accept_visitor(visitor)
40
+ visitor.visit_filter_aggregation(self)
41
+ end
42
+
39
43
  end
40
44
  end
@@ -11,10 +11,18 @@ module Elasticated
11
11
 
12
12
  # delimiters
13
13
 
14
+ def accept_visitor(visitor)
15
+ visitor.visit_boolean_clause(self)
16
+ end
17
+
14
18
  def fill_delimiter(field_delimiter)
15
19
  conditions.each{ |condition| condition.fill_delimiter field_delimiter }
16
20
  end
17
21
 
22
+ def delimiters
23
+ conditions.map(&:delimiter)
24
+ end
25
+
18
26
  # conditions
19
27
 
20
28
  def add(condition)
@@ -14,8 +14,8 @@ module Elasticated
14
14
  body
15
15
  end
16
16
 
17
- def fill_delimiter(field_delimiter)
18
- # nothing to do
17
+ def accept_visitor(visitor)
18
+ visitor.visit_condition(self)
19
19
  end
20
20
 
21
21
  end
@@ -15,11 +15,8 @@ module Elasticated
15
15
  { range: { field => body }.merge(opts) }
16
16
  end
17
17
 
18
- def fill_delimiter(field_delimiter)
19
- minimum_value = body[:gt] || body[:gte]
20
- field_delimiter.set_minimum field, minimum_value
21
- maximum_value = body[:lt] || body[:lte]
22
- field_delimiter.set_maximum field, maximum_value
18
+ def accept_visitor(visitor)
19
+ visitor.visit_range(self)
23
20
  end
24
21
 
25
22
  end
@@ -17,8 +17,8 @@ module Elasticated
17
17
  { script: body }
18
18
  end
19
19
 
20
- def fill_delimiter(field_delimiter)
21
- # nothing to do
20
+ def accept_visitor(visitor)
21
+ visitor.visit_condition(self)
22
22
  end
23
23
 
24
24
  end
@@ -13,8 +13,8 @@ module Elasticated
13
13
  self.opts = opts
14
14
  end
15
15
 
16
- def fill_delimiter(field_delimiter)
17
- # nothing to do, by default
16
+ def accept_visitor(visitor)
17
+ visitor.visit_condition(self)
18
18
  end
19
19
 
20
20
  end
@@ -13,8 +13,8 @@ module Elasticated
13
13
  { terms: { field => values }.merge(opts) }
14
14
  end
15
15
 
16
- def fill_delimiter(field_delimiter)
17
- values.each{ |value| field_delimiter.add_term field, value }
16
+ def accept_visitor(visitor)
17
+ visitor.visit_terms(self)
18
18
  end
19
19
 
20
20
  end
@@ -0,0 +1,123 @@
1
+ module Elasticated
2
+ class DateDelimiterFactory
3
+
4
+ def create(empty_delimiter, query_delimiters, opts={})
5
+ klass = Delimiters::DateFieldDelimiter
6
+ field = empty_delimiter.field_name
7
+ filter_name = empty_delimiter.filter_name
8
+ field_since = "#{field}_since".to_sym
9
+ field_until = "#{field}_until".to_sym
10
+ filter_since = "#{filter_name}_since".to_sym
11
+ filter_until = "#{filter_name}_until".to_sym
12
+ field_term = field.to_sym
13
+ delimit_by = opts.fetch(:delimit_by, [:conditions])
14
+
15
+ case delimit_by
16
+ when []
17
+ _since = nil
18
+ _until = nil
19
+ when [:conditions]
20
+ if has_terms?(query_delimiters, :conditions, field_term)
21
+ _since = since_condition_delimiters(query_delimiters.fetch(:conditions, []), field_term)
22
+ _until = until_condition_delimiters(query_delimiters.fetch(:conditions, []), field_term)
23
+ else
24
+ _since = since_condition_delimiters(query_delimiters.fetch(:conditions, []), field_since)
25
+ _until = until_condition_delimiters(query_delimiters.fetch(:conditions, []), field_until)
26
+ end
27
+ when [:aggregations]
28
+ if has_terms?(query_delimiters, :aggregations, field_term)
29
+ _since = since_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_term)
30
+ _until = until_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_term)
31
+ else
32
+ _since = since_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_since)
33
+ _until = until_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_until)
34
+ end
35
+ when [:conditions, :aggregations]
36
+ if has_terms?(query_delimiters, :conditions, field_term)
37
+ _since = since_condition_delimiters(query_delimiters.fetch(:conditions, []), field_term)
38
+ _until = until_condition_delimiters(query_delimiters.fetch(:conditions, []), field_term)
39
+ _since = since_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_term) if _since.empty?
40
+ _until = until_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_term) if _until.empty?
41
+ else
42
+ condition_since = since_condition_delimiters(query_delimiters.fetch(:conditions, []), field_since)
43
+ condition_until = until_condition_delimiters(query_delimiters.fetch(:conditions, []), field_until)
44
+ aggregation_since = since_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_since)
45
+ aggregation_until = until_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_until)
46
+ _since = condition_since || aggregation_since
47
+ _until = condition_until || aggregation_until
48
+ end
49
+ end
50
+
51
+ filtered_empty_delimiter = {
52
+ filter_since => _since,
53
+ filter_until => _until
54
+ }.select { |_, v| not v.nil? }
55
+
56
+ klass.new(filtered_empty_delimiter.merge(field: field, as: filter_name))
57
+ end
58
+
59
+ private
60
+
61
+ def since_aggregation_delimiters(all_aggregation_delimiters, field_since)
62
+ return nil if missing_field?(all_aggregation_delimiters, field_since)
63
+ return min_since_delimiter(all_aggregation_delimiters, field_since) if all_aggregation_delimiters.any? { |delimiter| delimiter[field_since].is_a? Array }
64
+ since_delimiters = all_aggregation_delimiters.min_by { |delimiter| delimiter[field_since] }
65
+ since_delimiters.nil? ? nil : since_delimiters[field_since]
66
+ end
67
+
68
+ def since_condition_delimiters(all_condition_delimiters, field_since)
69
+ condition_delimiterts_with_field = all_condition_delimiters.select { |delimiter| delimiter[field_since] }
70
+ return min_since_delimiter(condition_delimiterts_with_field, field_since) if condition_delimiterts_with_field.any? { |delimiter| delimiter[field_since].is_a? Array }
71
+ since_delimiters = condition_delimiterts_with_field.min_by { |delimiter| delimiter[field_since] }
72
+ since_delimiters.nil? ? nil : since_delimiters[field_since]
73
+ end
74
+
75
+ def min_since_delimiter(delimiters, field)
76
+ array_delimiters = delimiters.select { |delimiter| delimiter[field].is_a? Array }
77
+ min_array_delimiter = array_delimiters.min_by { |delimiter| delimiter[field].min }
78
+ individual_delimiters = delimiters.select { |delimiter| not delimiter[field].is_a? Array }
79
+ min_individual_delimiter = individual_delimiters.min_by { |delimiter| delimiter[field] }
80
+ if not (min_array_delimiter.nil? or min_individual_delimiter.nil?)
81
+ min_array_delimiter > min_individual_delimiter ? min_individual_delimiter : min_array_delimiter
82
+ else
83
+ return min_array_delimiter[field].min if min_array_delimiter and min_array_delimiter[field].min
84
+ min_individual_delimiter
85
+ end
86
+ end
87
+
88
+ def until_aggregation_delimiters(all_aggregation_delimiters, field_until)
89
+ return nil if missing_field?(all_aggregation_delimiters, field_until)
90
+ return max_until_delimiter(all_aggregation_delimiters, field_until) if all_aggregation_delimiters.any? { |delimiter| delimiter[field_until].is_a? Array }
91
+ until_delimiters = all_aggregation_delimiters.max_by { |delimiter| delimiter[field_until] }
92
+ until_delimiters.nil? ? nil : until_delimiters[field_until]
93
+ end
94
+
95
+ def until_condition_delimiters(all_condition_delimiters, field_until)
96
+ condition_delimiterts_with_field = all_condition_delimiters.select { |delimiter| delimiter[field_until] }
97
+ return max_until_delimiter(condition_delimiterts_with_field, field_until) if condition_delimiterts_with_field.any? { |delimiter| delimiter[field_until].is_a? Array }
98
+ until_delimiters = condition_delimiterts_with_field.max_by { |delimiter| delimiter[field_until] }
99
+ until_delimiters.nil? ? nil : until_delimiters[field_until]
100
+ end
101
+
102
+ def max_until_delimiter(delimiters, field)
103
+ array_delimiters = delimiters.select { |delimiter| delimiter[field].is_a? Array }
104
+ max_array_delimiter = array_delimiters.max_by { |delimiter| delimiter[field].max }
105
+ individual_delimiters = delimiters.select { |delimiter| not delimiter[field].is_a? Array }
106
+ max_individual_delimiter = individual_delimiters.max_by { |delimiter| delimiter[field] }
107
+ if not (max_array_delimiter.nil? or max_individual_delimiter.nil?)
108
+ max_array_delimiter > max_individual_delimiter ? max_individual_delimiter : max_array_delimiter
109
+ else
110
+ return max_array_delimiter[field].max if max_array_delimiter and max_array_delimiter[field].max
111
+ max_individual_delimiter
112
+ end
113
+ end
114
+
115
+ def missing_field?(delimiters, field)
116
+ delimiters.any? { |delimiter| not delimiter.has_key?(field) }
117
+ end
118
+
119
+ def has_terms?(delimiters, condition_or_agg, field)
120
+ delimiters.fetch(condition_or_agg, []).any? { |delimiter| delimiter[field] }
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,51 @@
1
+ module Elasticated
2
+ class DelimiterVisitor
3
+
4
+ def visit_query(query)
5
+ {
6
+ conditions: query._conditions.accept_visitor(self) + query._filter_conditions.accept_visitor(self),
7
+ aggregations: query._aggregations.accept_visitor(self)
8
+ }
9
+ end
10
+
11
+ def visit_query_conditions(query_conditions)
12
+ query_conditions._must.accept_visitor(self)
13
+ end
14
+
15
+ def visit_boolean_clause(boolean_clause)
16
+ boolean_clause.conditions.map { |c| c.accept_visitor(self) }
17
+ end
18
+
19
+ def visit_condition(condition)
20
+ {}
21
+ end
22
+
23
+ def visit_terms(terms_condition)
24
+ { terms_condition.field => terms_condition.values }
25
+ end
26
+
27
+ def visit_range(range_condition)
28
+ field = range_condition.field
29
+ minimum_value = range_condition.body[:gt] || range_condition.body[:gte]
30
+ maximum_value = range_condition.body[:lt] || range_condition.body[:lte]
31
+
32
+ {}.tap do |h|
33
+ h["#{field}_since".to_sym] = minimum_value if minimum_value
34
+ h["#{field}_until".to_sym] = maximum_value if maximum_value
35
+ end
36
+ end
37
+
38
+ def visit_query_aggregations(query_aggregations)
39
+ query_aggregations._aggregations.flat_map { |agg| agg.accept_visitor(self) }
40
+ end
41
+
42
+ def visit_aggregation(aggregation)
43
+ []
44
+ end
45
+
46
+ def visit_filter_aggregation(filter_aggregation)
47
+ filter_aggregation._subaggregations._conditions.accept_visitor(self)
48
+ end
49
+
50
+ end
51
+ end
@@ -1,37 +1,32 @@
1
1
  module Elasticated
2
2
  module Delimiters
3
- class DateFieldDelimiter < TermFieldDelimiter
3
+ class DateFieldDelimiter < StandardFieldDelimiter
4
4
 
5
5
  attr_accessor :date_since, :date_until
6
6
 
7
- def set_minimum(field, date)
8
- return unless applies_to? field
9
- self.date_since = date unless date_since && date < date_since
10
- end
11
-
12
- def set_maximum(field, date)
13
- return unless applies_to? field
14
- self.date_until = date unless date_until && date > date_until
7
+ def initialize(opts={})
8
+ super
9
+ self.date_since = opts[:date_since]
10
+ self.date_until = opts[:date_until]
15
11
  end
16
12
 
17
13
  def build_strategy_params
18
14
  params = Hash.new
19
- if values.empty?
20
- raise "date_since is higher than date_until (#{date_since} - #{date_until})" \
21
- if date_since && date_until && date_since > date_until
15
+ raise "date_since is higher than date_until (#{date_since} - #{date_until})" \
16
+ if date_since && date_until && date_since > date_until
17
+ if date_since == date_until and not date_since.nil?
18
+ params.merge! date: date_since
19
+ else
22
20
  params.merge! date_since: date_since if date_since
23
21
  params.merge! date_until: date_until if date_until
24
- else
25
- if values.count > 1
26
- params.merge! date_since: values.min
27
- params.merge! date_until: values.max
28
- else
29
- params.merge! date: values.first
30
- end
31
22
  end
32
23
  params
33
24
  end
34
25
 
26
+ def completed_with(delimiters, opts={})
27
+ Elasticated.date_delimiter_factory.create(self, delimiters, opts)
28
+ end
29
+
35
30
  end
36
31
  end
37
32
  end
@@ -8,24 +8,8 @@ module Elasticated
8
8
  attr_accessor :field_name, :filter_name
9
9
 
10
10
  def initialize(opts={})
11
- self.field_name = opts.fetch :field
12
- self.filter_name = opts.fetch :as, field_name
13
- end
14
-
15
- def applies_to?(condition_field)
16
- field_name.to_s == condition_field.to_s
17
- end
18
-
19
- def add_term(field, value)
20
- # nothing to do, by default
21
- end
22
-
23
- def set_minimum(field, value)
24
- # nothing to do, by default
25
- end
26
-
27
- def set_maximum(field, value)
28
- # nothing to do, by default
11
+ self.field_name = opts.fetch(:field)
12
+ self.filter_name = opts.fetch(:as, field_name)
29
13
  end
30
14
 
31
15
  end
@@ -6,12 +6,7 @@ module Elasticated
6
6
 
7
7
  def initialize(opts={})
8
8
  super
9
- self.values = Array.new
10
- end
11
-
12
- def add_term(field, value)
13
- return unless applies_to? field
14
- values << value
9
+ self.values = opts[:values] || []
15
10
  end
16
11
 
17
12
  def build_strategy_params
@@ -19,6 +14,10 @@ module Elasticated
19
14
  { filter_name => values.uniq }
20
15
  end
21
16
 
17
+ def completed_with(delimiters, opts={})
18
+ Elasticated.term_delimiter_factory.create(self, delimiters, opts)
19
+ end
20
+
22
21
  end
23
22
  end
24
23
  end
@@ -1,15 +1,20 @@
1
1
  module Elasticated
2
2
  class IndexSelector
3
3
 
4
- # abstract class
5
- # child must implement 'delimiters()'
6
- # child must implement 'strategy()'
7
4
  # child can override 'strategy_params_for(document)'
8
5
 
9
6
  include BlockEvaluation
10
7
 
11
- def indices_for_query(query)
12
- strategy_params = strategy_params_for_query query
8
+ attr_reader :strategy, :delimiters
9
+
10
+ # params will not be optionals in the next version
11
+ def initialize(strategy=nil, delimiters=nil)
12
+ @strategy = strategy
13
+ @delimiters = delimiters
14
+ end
15
+
16
+ def indices_for_query(query, opts={})
17
+ strategy_params = Elasticated.strategy_params_for_query_service.strategy_params_for_query delimiters, query, opts
13
18
  indices = strategy.call strategy_params
14
19
  raise "At least one index should be affected for a search" if indices.count < 1
15
20
  indices
@@ -41,13 +46,6 @@ module Elasticated
41
46
  end
42
47
  end
43
48
 
44
- def strategy_params_for_query(query)
45
- delimiters.inject Hash.new do |params, delimiter|
46
- query.fill_delimiter delimiter
47
- params.merge delimiter.build_strategy_params
48
- end
49
- end
50
-
51
49
  def strategy_params_for_percolator(query)
52
50
  { date: DateTime.now.iso8601 }
53
51
  end