elasticquery 0.1.2 → 0.1.3

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 (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