elasticquery 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +12 -0
  3. data/README.md +151 -70
  4. data/Rakefile +1 -9
  5. data/elasticquery.gemspec +2 -2
  6. data/lib/elasticquery.rb +1 -0
  7. data/lib/elasticquery/base.rb +6 -48
  8. data/lib/elasticquery/builder.rb +74 -17
  9. data/lib/elasticquery/es.rb +32 -0
  10. data/lib/elasticquery/filters/base.rb +4 -0
  11. data/lib/elasticquery/filters/exists.rb +24 -0
  12. data/lib/elasticquery/filters/not.rb +7 -11
  13. data/lib/elasticquery/filters/range.rb +3 -7
  14. data/lib/elasticquery/filters/term.rb +4 -28
  15. data/lib/elasticquery/filters/terms.rb +23 -0
  16. data/lib/elasticquery/queries/base.rb +16 -0
  17. data/lib/elasticquery/queries/multi_match.rb +34 -0
  18. data/lib/elasticquery/query.rb +25 -36
  19. data/lib/elasticquery/version.rb +1 -1
  20. data/test/base_test.rb +4 -4
  21. data/test/builder_test.rb +24 -8
  22. data/test/es_test.rb +23 -0
  23. data/test/filters/exists_test.rb +30 -0
  24. data/test/filters/not_test.rb +23 -10
  25. data/test/filters/range_test.rb +10 -11
  26. data/test/filters/term_test.rb +6 -7
  27. data/test/filters/terms_test.rb +50 -0
  28. data/test/integration/chainable_call_test.rb +6 -6
  29. data/test/integration/exists_case_test.rb +56 -0
  30. data/test/integration/not_case_test.rb +11 -5
  31. data/test/integration/queries_inheritence_test.rb +12 -4
  32. data/test/integration/range_case_test.rb +4 -2
  33. data/test/integration/search_case_test.rb +20 -11
  34. data/test/integration/term_case_test.rb +4 -2
  35. data/test/integration/terms_case_test.rb +49 -0
  36. data/test/queries/multi_match_test.rb +49 -0
  37. data/test/query_test.rb +40 -40
  38. metadata +26 -27
  39. data/lib/elasticquery/filters/search.rb +0 -54
  40. data/test/filters/search_test.rb +0 -62
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 62b85e40bdf7bc8321ee105e4c67ee408b732117
4
- data.tar.gz: 4c329fec2adc7718269d89313623183e92fd6f1c
3
+ metadata.gz: f2b9c2cc27bc50734cdc0d3b33140ddf3d4d9ef9
4
+ data.tar.gz: e59c4f8544a438c6d7ea3761223498a46e6aa3f3
5
5
  SHA512:
6
- metadata.gz: 849847e5c48fb2bfb4c60f096fc7654ae25b8bff9619e006f61014065cfe9d204d6b439db2e9e94ac95bfe0d1b6d3ed683d84969ca0c7ce88d016f6cd387aba4
7
- data.tar.gz: 6f5312d494e156c13d9dc662d771322860a34d3ee2f567d484126eede664cd4b97c632c5253073ff99397e708e78fe2d6e49373f9c2b902c58bf2bd8b2aa96f2
6
+ metadata.gz: 7f1ca3adbaa442c18253c14c75ba9c07a1f5f697261008fc506292149a587c12679b465f239c399ffe165dcc96aad914d904042af73df753899c9b8afaeb5253
7
+ data.tar.gz: 2852864ee870296ccbba95835083f1b11c28a42a09f4e20f39fe0109bb89cfed1d4de8e87486902b27d78a932334b2e3a5a6c01f2a90234d462b6ea8eee77a09
data/History.md CHANGED
@@ -1,5 +1,17 @@
1
1
  ## Elasticquery (master)
2
2
 
3
+ * Separate all filters to filters and queries. Rename search to multi_match. Change dsl for using explisit rule type.
4
+
5
+ * Add `terms` filter
6
+
7
+ * Add `exists` filter. `exists.not` works as `missing`.
8
+
9
+ * Add `where` alias to `terms`
10
+
11
+ * Add `without`/`missing` filter
12
+
13
+ * Add `es` shortcut from `Elasticquery::Es` to model chain calls
14
+
3
15
  ## Elasticquery 0.1.2 (16 June 2015)
4
16
 
5
17
  * Fix `range.not`. Exception was raised
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![Code Climate](https://codeclimate.com/github/caulfield/elasticquery/badges/gpa.svg)](https://codeclimate.com/github/caulfield/elasticquery)
6
6
  [![Test Coverage](https://codeclimate.com/github/caulfield/elasticquery/badges/coverage.svg)](https://codeclimate.com/github/caulfield/elasticquery)
7
7
 
8
- A module for elasticquery ruby [libraries][elasticsearch_rails] for using user-friendly query generator. [Click here to view demo with code examples.][demo]
8
+ A module for elasticsearch-rails [libraries][elasticsearch_rails] like as user-friendly query generator.
9
9
 
10
10
  ## Instalation
11
11
 
@@ -23,43 +23,148 @@ gem install elasticquery
23
23
  ## Getting Started
24
24
  ### First instruction
25
25
 
26
- Elasticquery was designed to be customized as you need to. Providing simple methods it allows you to build power and flexible form objects. Simplicity - is the main goal. For example:
26
+ Elasticquery was designed to be customized as you need to. Providing simple methods it allows you to build flexible queries using [Elastic Query DSL][elastic_query_dsl]
27
27
 
28
28
  ```ruby
29
29
  class MyQuery < Elasticquery::Base
30
30
  filtered do |params|
31
- search params[:query]
32
- term user_id: params[:user_id] if params[:user_id].present?
33
- range.not :age, gte: 18
31
+ filters do
32
+ term "user.id" => params[:user_id]
33
+ range.not :age, gte: 18
34
+ end
35
+ queries do
36
+ multi_match params[:query]
37
+ end
34
38
  end
35
39
  end
36
40
  ```
37
41
 
38
- Then use it
39
-
40
42
  ```ruby
41
43
  query = MyQuery.new query: 'i typed', user_id: 5
42
- query.build # => query for elasticsearch
43
- Article.search query.build # => be happy
44
+ query.build # => query for elastic
45
+ Article.search query.build # => returns result
44
46
  ```
45
- ### Currently you have
46
47
 
47
- 1. [Term][es_term] filter. [Usage][term_examples]
48
- 2. [MultiMatch][es_search] filter. [Usage][search_examples]
49
- 3. [Range][es_range] filter. [Usage][range_examples]
48
+ ## Currently you have
49
+ ### Filters
50
+ [Term][es_term]
51
+
52
+
53
+ ```ruby
54
+ # Simple one term filter
55
+ term category: 'Rock'
56
+
57
+ # _cache option support
58
+ term category: 'Soul', _cache: false
59
+
60
+ # Blank values are skipped. This query returns all records
61
+ term name: " "
62
+ ```
63
+ [Terms][es_terms]
64
+
65
+
66
+ ```ruby
67
+ # Standard terms options
68
+ terms a: 1, b: 2
69
+
70
+ # Skip empty values
71
+ terms a: 1, b: "" # => {a: 1} wil be passed
72
+
73
+ # Blank terms are skipped
74
+ terms a: "", b: nil # => match_all will be executed
75
+
76
+ # _cache and execution support
77
+ terms a: 1, b: 2, _cache: false, execution: "or"
78
+
79
+ # where alias. Usable in chain calls
80
+ where a: 1, b: 2, c: 3
81
+ ```
82
+ [Range][es_range]
83
+
84
+
85
+ ```ruby
86
+ # One side range
87
+ range :age, gte: 18
88
+
89
+ # Double sides range
90
+ range :volume, gte: 1, lte: 100
91
+
92
+ # _cache and execution options support
93
+ range :volume, gte: 1, lte: 100, _cache: true, execution: "fielddata"
94
+ ```
95
+ [Exists][es_exists]
96
+ [Missing][es_missing]
97
+
98
+
99
+ ```ruby
100
+ # Field existence check
101
+ exists "last_name"
102
+ missing "last_name"
103
+
104
+ # Blank value skipped
105
+ exists ""
106
+ missing ""
107
+
108
+ # Has with alias
109
+ with 'first_name'
110
+ without 'first_name'
111
+ ```
112
+ [Not][es_not]
113
+
114
+
115
+ ```ruby
116
+ # Blank values are skipped. This query returns all records
117
+ range.not :age, lte: ' ', gte: nil
118
+
119
+ # Term exclusion
120
+ term.not category: 'Rap'
121
+
122
+ # Terms exclusion
123
+ terms.not category: 'Rap', name: "Guf"
124
+
125
+ # 'Exists not' uses missing
126
+ with.not #=> returns missing filter
127
+ ```
128
+
129
+ All filters are joined by **AND** filter.
130
+ ## Queries
131
+ [MultiMatch][es_search]
132
+
133
+
134
+ ```ruby
135
+ # Simple all fields search in your index
136
+ multi_match 'developers'
137
+
138
+ # The same as above
139
+ multi_match 'developers', fields: "_all", operator: "and", type: "best_fields"
140
+
141
+ # Configure fields
142
+ multi_match 'Jordan', fields: ['first_name', 'last_name'], operator: "or"
143
+
144
+ # Blank values are skipped. This query returns all records
145
+ multi_match ''
146
+
147
+ # Alias as search
148
+ search 'Hello!'
149
+ ```
50
150
 
51
151
  ### Extended instruction
52
- There are multiple ways to organize your query, using chaining calls, or custom filters. Better custom filters support in progress now.
152
+ There are multiple ways to organize your query, using chaining calls, or custom filters.
53
153
 
54
154
  - Chain calls
55
155
  ```ruby
56
- PeopleQuery.new.search('hi', operator: :or).term(age: 21).build # => es-ready query
156
+ PeopleQuery.new.queries.multi_match('hi', operator: :or).filters.term(age: 21).build # => returns hash
157
+ Query.new.queries./queries-chain/.filters./filters-chain/
57
158
  ```
159
+
58
160
  - Class methods
161
+
59
162
  ```ruby
60
163
  class PeopleQuery < Elasticquery::Base
61
164
  filtered do |params|
62
- range :age, lte: prepare_age(params[:max_age])
165
+ filters do
166
+ range :age, lte: prepare_age(params[:max_age])
167
+ end
63
168
  end
64
169
 
65
170
  protected
@@ -68,95 +173,71 @@ class PeopleQuery < Elasticquery::Base
68
173
  param.to_i
69
174
  end
70
175
  end
71
- PeopleQuery.build(max_age: '42') # => es-ready
176
+ PeopleQuery.build(max_age: '42') # => result
72
177
  ```
178
+
73
179
  - Multiple `filtered` blocks
180
+
74
181
  ```ruby
75
182
  class ChildQuery < Elasticquery::Base
76
183
  filtered do |params|
77
- term :'category.id' => params[:category_id]
184
+ filters do
185
+ term :'category.id' => params[:category_id]
186
+ end
78
187
  end
79
188
 
80
189
  filtered do |params|
81
- term :'author.name' => User.find(params[:user_id]).name
190
+ filters do
191
+ term :'author.id' => User.find(params[:user_id]).name
192
+ end
82
193
  end
83
194
  end
84
- ChildQuery.build({user_id: 1, category_id: 14}) => # ;)
85
-
195
+ ChildQuery.build({user_id: 1, category_id: 14}) => returns both user and category filters
86
196
  ```
197
+
87
198
  - Query inheritance
199
+
88
200
  ```ruby
89
201
  class ParentQuery < Elasticquery::Base
90
202
  filtered do |params|
91
- term :'category.id' => params[:category_id]
203
+ filters do
204
+ term :'category.id' => params[:category_id]
205
+ end
92
206
  end
93
207
  end
94
208
 
95
209
  class ChildQuery < ParentQuery
96
210
  filtered do |params|
97
- term :'author.name' => User.find(params[:user_id]).name
211
+ filters do
212
+ term :'author.id' => User.find(params[:user_id]).name
213
+ end
98
214
  end
99
215
  end
100
216
 
101
217
  ChildQuery.build({user_id: 1, category_id: 14}) => # the same as in previous example
102
218
  ```
103
219
 
104
- ### Usage
105
- #### term
106
-
107
- ```ruby
108
- # Simple one term filter
109
- term category: 'Rock'
110
-
111
- # Multiple filters joined by AND condition
112
- term category: 'Soul', user: 'Aaron'
113
-
114
- # Term exclusion
115
- term.not category: 'Rap'
116
-
117
- # Blank values are skipped. This query returns all records
118
- term name: " "
119
- ```
220
+ - Elasticsearch::Model support with `es` shortcut
120
221
 
121
- #### search (multimatch)
122
222
  ```ruby
123
- # Simple all fields search in your index
124
- search 'developers'
125
-
126
- # The same as above
127
- search 'developers', fields: "_all", operator: "and", type: "best_fields"
128
-
129
- # Configure fields
130
- search 'Jordan', fields: ['first_name', 'last_name'], operator: "or"
223
+ class Article
224
+ include Elasticsearch::Model
225
+ extend Elasticquery::Es
226
+ end
131
227
 
132
- # Blank values are skipped. This query returns all records
133
- search ''
228
+ Article.es.filters.term(user_id: 12).with("published_at").queries.search("Verge").results # => collection of "hits"
229
+ Article.es.filters.term(user_id: 12).with("published_at").queries.search("Verge").records # => collection of records from db
134
230
  ```
135
231
 
136
- #### range
137
- ```ruby
138
- # One side range
139
- range :age, gte: 18
140
-
141
- # Double sides range
142
- range :volume, gte: 1, lte: 100
143
-
144
- # Range exclusion
145
- range.not :size, gte: 32, lte: 128
146
-
147
- # Blank values are skipped. This query returns all records
148
- range.not :age, lte: ' ', gte: nil
149
-
150
- # _cache and execution options support
151
- range :volume, gte: 1, lte: 100, _cache: true, execution: "fielddata"
152
- ```
153
232
  [elasticsearch_rails]: https://github.com/elasticsearch/elasticsearch-rails
154
233
  [demo]: http://elasticquery-demo.herokuapp.com
155
234
  [bundler]: http://bundler.io/
156
235
  [rubygems]: https://rubygems.org/
157
236
  [es_term]: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-term-filter.html
237
+ [es_terms]: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-terms-filter.html
238
+ [es_not]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-not-filter.html
239
+ [es_exists]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-filter.html
240
+ [es_missing]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-missing-filter.html
158
241
  [es_search]: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html
159
242
  [es_range]: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-range-query.html
160
- [term_examples]: #
161
- [search_examples]: #
162
- [range_examples]: #
243
+ [elastic_query_dsl]: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html
data/Rakefile CHANGED
@@ -1,21 +1,13 @@
1
1
  require "bundler/gem_tasks"
2
2
  require 'rake/testtask'
3
- require 'yard'
4
3
 
5
4
  desc "Run unit tests"
6
5
  Rake::TestTask.new do |t|
7
6
  t.libs << 'lib'
8
7
  t.libs << 'test'
9
- t.pattern = "test/**/*_test.rb"
8
+ t.pattern = "test/**/**_test.rb"
10
9
  # t.verbose = true
11
10
  # t.warning = false
12
11
  end
13
12
 
14
- desc "Generate docs"
15
- YARD::Rake::YardocTask.new do |t|
16
- t.files = ['lib/**/*.rb']
17
- t.options = ['--any', '--extra', '--opts']
18
- t.stats_options = ['--list-undoc']
19
- end
20
-
21
13
  task default: :test
@@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = %q{Powerful and flexible elasticsearch query factory for you ruby application}
13
13
  spec.homepage = "https://github.com/caulfield/elasticquery"
14
14
  spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 2.0.0"
15
16
 
16
17
  spec.files = `git ls-files -z`.split("\x0")
17
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
@@ -19,12 +20,11 @@ Gem::Specification.new do |spec|
19
20
  spec.require_paths = ["lib"]
20
21
 
21
22
  spec.add_dependency "activesupport"
22
- spec.add_dependency "deep_merge"
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 1.6"
25
- spec.add_development_dependency "yard"
26
25
  spec.add_development_dependency "rake"
27
26
  spec.add_development_dependency "minitest"
28
27
  spec.add_development_dependency "minitest-reporters"
29
28
  spec.add_development_dependency "codeclimate-test-reporter"
29
+ spec.add_development_dependency "elasticsearch-model"
30
30
  end
@@ -3,4 +3,5 @@ require "elasticquery/version"
3
3
  # Base gem module
4
4
  module Elasticquery
5
5
  autoload :Base, "elasticquery/base"
6
+ autoload :Es, "elasticquery/es"
6
7
  end
@@ -7,72 +7,30 @@ module Elasticquery
7
7
  class Base
8
8
  include Elasticquery::Builder
9
9
 
10
- class_attribute :filters
10
+ class_attribute :rules
11
11
  attr_reader :params, :query
12
12
 
13
- self.filters = []
13
+ self.rules = []
14
14
 
15
- # Define params processor for es query.
16
- #
17
- # @note Multiple filtered blocks can be defined.
18
- #
19
- # @yield [params] Block with defined filters for passed yield param processing
20
- #
21
- # @yieldparam [Hash] passed params to processing
22
- #
23
- # @example query builder for id
24
- # class PostQuery < Elasticquery::Base
25
- # filtered do |params|
26
- # term "id" => params[:id]
27
- # end
28
- # end
29
15
  def self.filtered(&block)
30
- self.filters += [block]
16
+ self.rules += [block]
31
17
  end
32
18
 
33
- # Is your object can process params to elasticqueriable.
34
- #
35
- # @return [Boolean]
36
- #
37
- # @example
38
- # class EmptyQuery < Elasticquery::Base
39
- # end
40
- # EmptyQuery.new.filterable? #=> false
41
- #
42
- # @example
43
- # class PostQuery < Elasticquery::Base
44
- # filtered { |params| true }
45
- # end
46
- # PostQuery.new.filterable? #=> true
47
19
  def filterable?
48
- filters.any?
20
+ rules.any?
49
21
  end
50
22
 
51
- # Create new query objects with built empty query.
52
23
  def initialize(params = {})
53
24
  @params = params
54
25
  @query = Query.new
55
26
  end
56
27
 
57
- # Build elasticquery query using defined filters.
58
- #
59
- # @example
60
- # query.build # => { query: { match_all: {} }
61
- #
62
- # @return [Hash] elasticqueriable hash
63
28
  def build
64
- filters.each { |filter| instance_exec @params, &filter }
29
+ @namespace = nil
30
+ rules.each { |rule| instance_exec @params, &rule }
65
31
  query.to_hash
66
32
  end
67
33
 
68
- # Build elasticquery query using defined filters.
69
- #
70
- # @example
71
- # query.build # => { query: { match_all: {} }
72
- #
73
- # @see Elasticquery::Base#build
74
- #
75
- # @return [Hash] elasticqueriable hash
76
34
  def self.build(params = {})
77
35
  new(params).build
78
36
  end