chewy_query 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +37 -0
  7. data/Rakefile +2 -0
  8. data/chewy_query.gemspec +27 -0
  9. data/lib/chewy_query.rb +12 -0
  10. data/lib/chewy_query/builder.rb +865 -0
  11. data/lib/chewy_query/builder/compose.rb +64 -0
  12. data/lib/chewy_query/builder/criteria.rb +182 -0
  13. data/lib/chewy_query/builder/filters.rb +227 -0
  14. data/lib/chewy_query/builder/nodes/and.rb +26 -0
  15. data/lib/chewy_query/builder/nodes/base.rb +17 -0
  16. data/lib/chewy_query/builder/nodes/bool.rb +33 -0
  17. data/lib/chewy_query/builder/nodes/equal.rb +34 -0
  18. data/lib/chewy_query/builder/nodes/exists.rb +20 -0
  19. data/lib/chewy_query/builder/nodes/expr.rb +28 -0
  20. data/lib/chewy_query/builder/nodes/field.rb +106 -0
  21. data/lib/chewy_query/builder/nodes/has_child.rb +14 -0
  22. data/lib/chewy_query/builder/nodes/has_parent.rb +14 -0
  23. data/lib/chewy_query/builder/nodes/has_relation.rb +61 -0
  24. data/lib/chewy_query/builder/nodes/match_all.rb +11 -0
  25. data/lib/chewy_query/builder/nodes/missing.rb +20 -0
  26. data/lib/chewy_query/builder/nodes/not.rb +26 -0
  27. data/lib/chewy_query/builder/nodes/or.rb +26 -0
  28. data/lib/chewy_query/builder/nodes/prefix.rb +18 -0
  29. data/lib/chewy_query/builder/nodes/query.rb +20 -0
  30. data/lib/chewy_query/builder/nodes/range.rb +63 -0
  31. data/lib/chewy_query/builder/nodes/raw.rb +15 -0
  32. data/lib/chewy_query/builder/nodes/regexp.rb +33 -0
  33. data/lib/chewy_query/builder/nodes/script.rb +20 -0
  34. data/lib/chewy_query/version.rb +3 -0
  35. data/spec/chewy_query/builder/context_spec.rb +529 -0
  36. data/spec/chewy_query/builder/filters_spec.rb +181 -0
  37. data/spec/chewy_query/builder/nodes/and_spec.rb +16 -0
  38. data/spec/chewy_query/builder/nodes/bool_spec.rb +22 -0
  39. data/spec/chewy_query/builder/nodes/equal_spec.rb +58 -0
  40. data/spec/chewy_query/builder/nodes/exists_spec.rb +16 -0
  41. data/spec/chewy_query/builder/nodes/has_child_spec.rb +79 -0
  42. data/spec/chewy_query/builder/nodes/has_parent_spec.rb +84 -0
  43. data/spec/chewy_query/builder/nodes/match_all_spec.rb +11 -0
  44. data/spec/chewy_query/builder/nodes/missing_spec.rb +14 -0
  45. data/spec/chewy_query/builder/nodes/not_spec.rb +14 -0
  46. data/spec/chewy_query/builder/nodes/or_spec.rb +16 -0
  47. data/spec/chewy_query/builder/nodes/prefix_spec.rb +15 -0
  48. data/spec/chewy_query/builder/nodes/query_spec.rb +17 -0
  49. data/spec/chewy_query/builder/nodes/range_spec.rb +36 -0
  50. data/spec/chewy_query/builder/nodes/raw_spec.rb +11 -0
  51. data/spec/chewy_query/builder/nodes/regexp_spec.rb +45 -0
  52. data/spec/chewy_query/builder/nodes/script_spec.rb +16 -0
  53. data/spec/chewy_query/builder_spec.rb +196 -0
  54. data/spec/chewy_query_spec.rb +0 -0
  55. data/spec/spec_helper.rb +8 -0
  56. metadata +191 -0
@@ -0,0 +1,26 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class And < Expr
5
+ def initialize(*nodes)
6
+ @options = nodes.extract_options!
7
+ @nodes = nodes.flatten.map{|node| node.is_a?(self.class) ? node.__nodes__ : node }.flatten
8
+ end
9
+
10
+ def __nodes__
11
+ @nodes
12
+ end
13
+
14
+ def __render__
15
+ nodes = @nodes.map(&:__render__)
16
+
17
+ if @options.key?(:cache)
18
+ { and: { filters: nodes, _cache: !!@options[:cache] } }
19
+ else
20
+ { and: nodes }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Base
5
+ def render
6
+ raise NotImplementedError
7
+ end
8
+
9
+ def eql?(other)
10
+ other.is_a?(self.class) && instance_variables.all? do |ivar|
11
+ instance_variable_get(ivar).eql? other.instance_variable_get(ivar)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Bool < Expr
5
+ METHODS = %w(must must_not should)
6
+
7
+ def initialize(options = {})
8
+ @options = options
9
+ @must, @must_not, @should = [], [], []
10
+ end
11
+
12
+ METHODS.each do |method|
13
+ define_method method do |*exprs|
14
+ instance_variable_get("@#{method}").push(*exprs)
15
+ self
16
+ end
17
+ end
18
+
19
+ def __render__
20
+ bool = METHODS.map do |method|
21
+ value = instance_variable_get("@#{method}")
22
+ [method.to_sym, value.map(&:__render__)] if value.any?
23
+ end.compact
24
+
25
+ bool = { bool: Hash[bool] }
26
+
27
+ bool[:bool][:_cache] = !!@options[:cache] if @options.key?(:cache)
28
+ bool
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,34 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Equal < Expr
5
+ EXECUTION = {
6
+ :| => :or,
7
+ :or => :or,
8
+ :& => :and,
9
+ :and => :and,
10
+ :b => :bool,
11
+ :bool => :bool,
12
+ :f => :fielddata,
13
+ :fielddata => :fielddata,
14
+ }
15
+
16
+ def initialize(name, value, *args)
17
+ @name = name.to_s
18
+ @value = value
19
+ @options = args.extract_options!
20
+ execution = EXECUTION[args.first.to_sym] if args.first
21
+ @options[:execution] = execution if execution
22
+ end
23
+
24
+ def __render__
25
+ filter = (@value.is_a?(Array) ? :terms : :term)
26
+ body = { @name => @value }
27
+ body.merge!(@options.slice(:execution)) if filter == :terms
28
+ body.merge!(_cache: !!@options[:cache]) if @options.key?(:cache)
29
+ { filter => body }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Exists < Expr
5
+ def initialize(name, options = {})
6
+ @name = name.to_s
7
+ @options = options
8
+ end
9
+
10
+ def !
11
+ Nodes::Missing.new(@name, null_value: true)
12
+ end
13
+
14
+ def __render__
15
+ { exists: { field: @name } }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Expr < Base
5
+ def &(other)
6
+ Nodes::And.new(self, other)
7
+ end
8
+
9
+ def |(other)
10
+ Nodes::Or.new(self, other)
11
+ end
12
+
13
+ def !
14
+ Nodes::Not.new(self)
15
+ end
16
+
17
+ def ~
18
+ @options[:cache] = true
19
+ self
20
+ end
21
+
22
+ def __render__
23
+ raise NotImplementedError
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,106 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Field < Base
5
+ def initialize(name, *args)
6
+ @name = name.to_s
7
+ @args = args
8
+ end
9
+
10
+ def !
11
+ Nodes::Missing.new(@name)
12
+ end
13
+
14
+ def ~
15
+ __options_merge__!(cache: true)
16
+ self
17
+ end
18
+
19
+ def >(value)
20
+ Nodes::Range.new(@name, *__options_merge__(gt: value))
21
+ end
22
+
23
+ def <(value)
24
+ Nodes::Range.new(@name, *__options_merge__(lt: value))
25
+ end
26
+
27
+ def >=(value)
28
+ Nodes::Range.new(@name, *__options_merge__(gt: value, left_closed: true))
29
+ end
30
+
31
+ def <=(value)
32
+ Nodes::Range.new(@name, *__options_merge__(lt: value, right_closed: true))
33
+ end
34
+
35
+ def ==(value)
36
+ case value
37
+ when nil
38
+ Nodes::Missing.new(@name, existence: false, null_value: true)
39
+ when ::Regexp
40
+ Nodes::Regexp.new(@name, value, *@args)
41
+ when ::Range
42
+ Nodes::Range.new(@name, *__options_merge__(gt: value.first, lt: value.last))
43
+ else
44
+ if value.is_a?(Array) && value.first.is_a?(::Range)
45
+ Nodes::Range.new(@name, *__options_merge__(
46
+ gt: value.first.first, lt: value.first.last,
47
+ left_closed: true, right_closed: true
48
+ ))
49
+ else
50
+ Nodes::Equal.new(@name, value, *@args)
51
+ end
52
+ end
53
+ end
54
+
55
+ def !=(value)
56
+ case value
57
+ when nil
58
+ Nodes::Exists.new(@name)
59
+ else
60
+ Nodes::Not.new(self == value)
61
+ end
62
+ end
63
+
64
+ def =~(value)
65
+ case value
66
+ when ::Regexp
67
+ Nodes::Regexp.new(@name, value, *@args)
68
+ else
69
+ Nodes::Prefix.new(@name, value, @args.extract_options!)
70
+ end
71
+ end
72
+
73
+ def !~(value)
74
+ Not.new(self =~ value)
75
+ end
76
+
77
+ def method_missing(method, *args, &block)
78
+ method = method.to_s
79
+ if method =~ /\?\Z/
80
+ Nodes::Exists.new([@name, method.gsub(/\?\Z/, '')].join(?.))
81
+ else
82
+ self.class.new([@name, method].join(?.), *args)
83
+ end
84
+ end
85
+
86
+ def to_ary
87
+ nil
88
+ end
89
+
90
+ private
91
+
92
+ def __options_merge__!(additional = {})
93
+ options = @args.extract_options!
94
+ options = options.merge(additional)
95
+ @args.push(options)
96
+ end
97
+
98
+ def __options_merge__(additional = {})
99
+ options = @args.extract_options!
100
+ options = options.merge(additional)
101
+ @args + [options]
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,14 @@
1
+ require 'chewy_query/builder/nodes/has_relation'
2
+
3
+ module ChewyQuery
4
+ class Builder
5
+ module Nodes
6
+ class HasChild < HasRelation
7
+ private
8
+ def _relation
9
+ :has_child
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require 'chewy_query/builder/nodes/has_relation'
2
+
3
+ module ChewyQuery
4
+ class Builder
5
+ module Nodes
6
+ class HasParent < HasRelation
7
+ private
8
+ def _relation
9
+ :has_parent
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,61 @@
1
+ require 'chewy_query/builder/compose'
2
+
3
+ module ChewyQuery
4
+ class Builder
5
+ module Nodes
6
+ class HasRelation < Expr
7
+ include Compose
8
+
9
+ def initialize(type, outer = nil)
10
+ @type = type.to_s
11
+ @outer = outer
12
+ @query_mode = :must
13
+ @filter_mode = :and
14
+ @queries = []
15
+ @filters = []
16
+ end
17
+
18
+ def query_mode(mode)
19
+ @query_mode = mode
20
+ self
21
+ end
22
+
23
+ def filter_mode(mode)
24
+ @filter_mode = mode
25
+ self
26
+ end
27
+
28
+ def query(params = nil, &block)
29
+ if block
30
+ raise 'Query DLS is not supported yet'
31
+ else
32
+ @queries.push(params)
33
+ end
34
+ self
35
+ end
36
+
37
+ def filter(params = nil, &block)
38
+ if block
39
+ @filters.push(ChewyQuery::Builder::Filters.new(@outer, &block).__render__)
40
+ else
41
+ @filters.push(params)
42
+ end
43
+ self
44
+ end
45
+
46
+ def __render__
47
+ queries = _queries_join(@queries, @query_mode)
48
+ filters = _filters_join(@filters, @filter_mode)
49
+
50
+ body = if filters && !queries
51
+ { filter: filters }
52
+ else
53
+ _filtered_query(queries, filters)
54
+ end || {}
55
+
56
+ { _relation => body.merge(type: @type) } if body
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,11 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class MatchAll < Expr
5
+ def __render__
6
+ { match_all: {} }
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Missing < Expr
5
+ def initialize(name, options = {})
6
+ @name = name.to_s
7
+ @options = options.reverse_merge(existence: true, null_value: false)
8
+ end
9
+
10
+ def !
11
+ Nodes::Exists.new(@name)
12
+ end
13
+
14
+ def __render__
15
+ { missing: { field: @name }.merge(@options.slice(:existence, :null_value)) }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Not < Expr
5
+ def initialize(expr, options = {})
6
+ @expr = expr
7
+ @options = options
8
+ end
9
+
10
+ def !
11
+ @expr
12
+ end
13
+
14
+ def __render__
15
+ expr = @expr.__render__
16
+
17
+ if @options.key?(:cache)
18
+ { not: { filter: expr, _cache: !!@options[:cache] } }
19
+ else
20
+ { not: expr }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ module ChewyQuery
2
+ class Builder
3
+ module Nodes
4
+ class Or < Expr
5
+ def initialize(*nodes)
6
+ @options = nodes.extract_options!
7
+ @nodes = nodes.flatten.map{|node| node.is_a?(self.class) ? node.__nodes__ : node }.flatten
8
+ end
9
+
10
+ def __nodes__
11
+ @nodes
12
+ end
13
+
14
+ def __render__
15
+ nodes = @nodes.map(&:__render__)
16
+
17
+ if @options.key?(:cache)
18
+ { or: { filters: nodes, _cache: !!@options[:cache] } }
19
+ else
20
+ { or: nodes }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end