chewy 0.0.1 → 0.1.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.
Files changed (80) hide show
  1. checksums.yaml +13 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +5 -3
  4. data/CHANGELOG.md +75 -0
  5. data/README.md +487 -92
  6. data/Rakefile +3 -2
  7. data/chewy.gemspec +2 -2
  8. data/filters +76 -0
  9. data/lib/chewy.rb +5 -3
  10. data/lib/chewy/config.rb +36 -19
  11. data/lib/chewy/fields/base.rb +5 -1
  12. data/lib/chewy/index.rb +22 -10
  13. data/lib/chewy/index/actions.rb +13 -13
  14. data/lib/chewy/index/search.rb +7 -2
  15. data/lib/chewy/query.rb +382 -64
  16. data/lib/chewy/query/context.rb +174 -0
  17. data/lib/chewy/query/criteria.rb +127 -34
  18. data/lib/chewy/query/loading.rb +9 -9
  19. data/lib/chewy/query/nodes/and.rb +25 -0
  20. data/lib/chewy/query/nodes/base.rb +17 -0
  21. data/lib/chewy/query/nodes/bool.rb +32 -0
  22. data/lib/chewy/query/nodes/equal.rb +34 -0
  23. data/lib/chewy/query/nodes/exists.rb +20 -0
  24. data/lib/chewy/query/nodes/expr.rb +28 -0
  25. data/lib/chewy/query/nodes/field.rb +106 -0
  26. data/lib/chewy/query/nodes/missing.rb +20 -0
  27. data/lib/chewy/query/nodes/not.rb +25 -0
  28. data/lib/chewy/query/nodes/or.rb +25 -0
  29. data/lib/chewy/query/nodes/prefix.rb +18 -0
  30. data/lib/chewy/query/nodes/query.rb +20 -0
  31. data/lib/chewy/query/nodes/range.rb +63 -0
  32. data/lib/chewy/query/nodes/raw.rb +15 -0
  33. data/lib/chewy/query/nodes/regexp.rb +31 -0
  34. data/lib/chewy/query/nodes/script.rb +20 -0
  35. data/lib/chewy/query/pagination.rb +28 -22
  36. data/lib/chewy/railtie.rb +23 -0
  37. data/lib/chewy/rspec/update_index.rb +20 -3
  38. data/lib/chewy/type/adapter/active_record.rb +78 -5
  39. data/lib/chewy/type/adapter/base.rb +46 -0
  40. data/lib/chewy/type/adapter/object.rb +40 -8
  41. data/lib/chewy/type/base.rb +1 -1
  42. data/lib/chewy/type/import.rb +18 -44
  43. data/lib/chewy/type/observe.rb +24 -14
  44. data/lib/chewy/version.rb +1 -1
  45. data/lib/tasks/chewy.rake +27 -0
  46. data/spec/chewy/config_spec.rb +30 -12
  47. data/spec/chewy/fields/base_spec.rb +11 -5
  48. data/spec/chewy/index/actions_spec.rb +20 -20
  49. data/spec/chewy/index/search_spec.rb +5 -5
  50. data/spec/chewy/index_spec.rb +28 -8
  51. data/spec/chewy/query/context_spec.rb +173 -0
  52. data/spec/chewy/query/criteria_spec.rb +219 -12
  53. data/spec/chewy/query/loading_spec.rb +6 -4
  54. data/spec/chewy/query/nodes/and_spec.rb +16 -0
  55. data/spec/chewy/query/nodes/bool_spec.rb +22 -0
  56. data/spec/chewy/query/nodes/equal_spec.rb +32 -0
  57. data/spec/chewy/query/nodes/exists_spec.rb +18 -0
  58. data/spec/chewy/query/nodes/missing_spec.rb +15 -0
  59. data/spec/chewy/query/nodes/not_spec.rb +16 -0
  60. data/spec/chewy/query/nodes/or_spec.rb +16 -0
  61. data/spec/chewy/query/nodes/prefix_spec.rb +16 -0
  62. data/spec/chewy/query/nodes/query_spec.rb +12 -0
  63. data/spec/chewy/query/nodes/range_spec.rb +32 -0
  64. data/spec/chewy/query/nodes/raw_spec.rb +11 -0
  65. data/spec/chewy/query/nodes/regexp_spec.rb +31 -0
  66. data/spec/chewy/query/nodes/script_spec.rb +15 -0
  67. data/spec/chewy/query/pagination_spec.rb +3 -2
  68. data/spec/chewy/query_spec.rb +83 -26
  69. data/spec/chewy/rspec/update_index_spec.rb +20 -0
  70. data/spec/chewy/type/adapter/active_record_spec.rb +102 -0
  71. data/spec/chewy/type/adapter/object_spec.rb +82 -0
  72. data/spec/chewy/type/import_spec.rb +30 -1
  73. data/spec/chewy/type/mapping_spec.rb +1 -1
  74. data/spec/chewy/type/observe_spec.rb +46 -12
  75. data/spec/spec_helper.rb +7 -6
  76. data/spec/support/class_helpers.rb +2 -2
  77. metadata +98 -48
  78. data/.rvmrc +0 -1
  79. data/lib/chewy/index/client.rb +0 -13
  80. data/spec/chewy/index/client_spec.rb +0 -18
@@ -0,0 +1,32 @@
1
+ module Chewy
2
+ class Query
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 = {
21
+ bool: Hash[METHODS.map do |method|
22
+ value = instance_variable_get("@#{method}")
23
+ [method.to_sym, value.map(&:__render__)] if value.any?
24
+ end.compact]
25
+ }
26
+ bool[:bool][:_cache] = !!@options[:cache] if @options.key?(:cache)
27
+ bool
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,34 @@
1
+ module Chewy
2
+ class Query
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 Chewy
2
+ class Query
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: {term: @name}}
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ module Chewy
2
+ class Query
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 Chewy
2
+ class Query
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,20 @@
1
+ module Chewy
2
+ class Query
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: {term: @name}.merge(@options.slice(:existence, :null_value))}
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ module Chewy
2
+ class Query
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
+ if @options.key?(:cache)
17
+ {not: {filter: expr, _cache: !!@options[:cache]}}
18
+ else
19
+ {not: expr}
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ module Chewy
2
+ class Query
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
+ if @options.key?(:cache)
17
+ {or: {filters: nodes, _cache: !!@options[:cache]}}
18
+ else
19
+ {or: nodes}
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ module Chewy
2
+ class Query
3
+ module Nodes
4
+ class Prefix < Expr
5
+ def initialize name, value, options = {}
6
+ @name = name.to_s
7
+ @value, @options = value, options
8
+ end
9
+
10
+ def __render__
11
+ filter = {prefix: {@name => @value}}
12
+ filter[:prefix][:_cache] = !!@options[:cache] if @options.key?(:cache)
13
+ filter
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ module Chewy
2
+ class Query
3
+ module Nodes
4
+ class Query < Expr
5
+ def initialize query, options = {}
6
+ @query = query
7
+ @options = options
8
+ end
9
+
10
+ def __render__
11
+ if @options.key?(:cache)
12
+ {fquery: {query: @query, _cache: !!@options[:cache]}}
13
+ else
14
+ {query: @query}
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,63 @@
1
+ module Chewy
2
+ class Query
3
+ module Nodes
4
+ class Range < Expr
5
+ EXECUTION = {
6
+ :i => :index,
7
+ :index => :index,
8
+ :f => :fielddata,
9
+ :fielddata => :fielddata,
10
+ }
11
+
12
+ def initialize name, *args
13
+ @name = name.to_s
14
+ @options = args.extract_options!
15
+ @range = @options.extract!(:gt, :lt)
16
+ @bounds = @options.extract!(:left_closed, :right_closed)
17
+ execution = EXECUTION[args.first.to_sym] if args.first
18
+ @options[:execution] = execution if execution
19
+ end
20
+
21
+ def & other
22
+ if other.is_a?(self.class) && other.__name__ == @name
23
+ state = __state__.merge(other.__state__)
24
+
25
+ cache = other.__options__[:cache] || @options[:cache]
26
+ state[:cache] = cache unless cache.nil?
27
+
28
+ execution = other.__options__[:execution] || @options[:execution]
29
+ state[:execution] = execution unless execution.nil?
30
+
31
+ self.class.new(@name, state)
32
+ else
33
+ super
34
+ end
35
+ end
36
+
37
+ def __name__
38
+ @name
39
+ end
40
+
41
+ def __state__
42
+ @range.merge(@bounds)
43
+ end
44
+
45
+ def __options__
46
+ @options
47
+ end
48
+
49
+ def __render__
50
+ body = {}
51
+ body[@bounds[:left_closed] ? :gte : :gt] = @range[:gt] if @range.key?(:gt)
52
+ body[@bounds[:right_closed] ? :lte : :lt] = @range[:lt] if @range.key?(:lt)
53
+
54
+ filter = {@name => body}
55
+ filter[:_cache] = !!@options[:cache] if @options.key?(:cache)
56
+ filter.merge!(@options.slice(:execution))
57
+
58
+ {range: filter}
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,15 @@
1
+ module Chewy
2
+ class Query
3
+ module Nodes
4
+ class Raw < Expr
5
+ def initialize raw
6
+ @raw = raw
7
+ end
8
+
9
+ def __render__
10
+ @raw
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ module Chewy
2
+ class Query
3
+ module Nodes
4
+ class Regexp < Expr
5
+ FLAGS = %w(all anystring automaton complement empty intersection interval none)
6
+
7
+ def initialize name, regexp, *args
8
+ @name = name.to_s
9
+ @regexp = regexp.respond_to?(:source) ? regexp.source : regexp.to_s
10
+ @options = args.extract_options!
11
+ if args.any? || @options[:flags].present?
12
+ @options[:flags] = FLAGS & (args.any? ? args.flatten : @options[:flags]).map(&:to_s).map(&:downcase)
13
+ end
14
+ end
15
+
16
+ def __render__
17
+ body = @options[:flags] ?
18
+ {value: @regexp, flags: @options[:flags].map(&:to_s).map(&:upcase).uniq.join('|')} :
19
+ @regexp
20
+ filter = {@name => body}
21
+ if @options.key?(:cache)
22
+ filter[:_cache] = !!@options[:cache]
23
+ filter[:_cache_key] = @options[:cache].is_a?(TrueClass) || @options[:cache].is_a?(FalseClass) ?
24
+ @regexp.underscore : @options[:cache]
25
+ end
26
+ {regexp: filter}
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end