search_flip 3.1.1 → 4.0.0.beta3
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 +4 -4
- data/.github/workflows/test.yml +34 -0
- data/.rubocop.yml +11 -1
- data/CHANGELOG.md +19 -0
- data/README.md +13 -5
- data/UPDATING.md +40 -0
- data/lib/search_flip.rb +0 -1
- data/lib/search_flip/connection.rb +28 -1
- data/lib/search_flip/criteria.rb +20 -30
- data/lib/search_flip/filterable.rb +16 -0
- data/lib/search_flip/index.rb +9 -5
- data/lib/search_flip/json.rb +4 -9
- data/lib/search_flip/response.rb +6 -7
- data/lib/search_flip/result.rb +41 -19
- data/lib/search_flip/version.rb +1 -1
- data/search_flip.gemspec +1 -2
- data/spec/search_flip/aggregation_spec.rb +17 -17
- data/spec/search_flip/connection_spec.rb +29 -0
- data/spec/search_flip/criteria_spec.rb +23 -1
- data/spec/search_flip/index_spec.rb +17 -4
- data/spec/search_flip/json_spec.rb +31 -0
- data/spec/search_flip/null_instrumenter_spec.rb +2 -2
- data/spec/search_flip/result_spec.rb +23 -6
- metadata +9 -21
- data/.travis.yml +0 -20
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c93ffb5c3868ef14b27903734bfb2d77384acc4a52eb529070f8a17a82f323a3
|
|
4
|
+
data.tar.gz: 458f01664f5faf01006eddba2f59cdbcca7e10be22769aafca1084663c242a9b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 341783040e3c705d6ac1cb7875dbbb0088efd22439057ced5f9a21c5629eb6f9b4ea7e8e4a23a0368e5ef7c249ad0e6a578a5f0f8a57afb2cb3b649b2db0a22e
|
|
7
|
+
data.tar.gz: fa40baa33a6626af128fdb14713300f55690ee407bec989b1f2bfca3e55a169377e2a0c5f9cefd6107a97ed7aceba290b52a382dcf5bdbf8c6c9389253896df7
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
on: push
|
|
2
|
+
name: test
|
|
3
|
+
jobs:
|
|
4
|
+
test:
|
|
5
|
+
runs-on: ubuntu-latest
|
|
6
|
+
strategy:
|
|
7
|
+
fail-fast: false
|
|
8
|
+
matrix:
|
|
9
|
+
elasticsearch:
|
|
10
|
+
- plainpicture/elasticsearch:2.4.1_delete-by-query
|
|
11
|
+
- elasticsearch:5.4
|
|
12
|
+
- docker.elastic.co/elasticsearch/elasticsearch:6.7.0
|
|
13
|
+
- docker.elastic.co/elasticsearch/elasticsearch:7.0.0
|
|
14
|
+
- docker.elastic.co/elasticsearch/elasticsearch:7.9.0
|
|
15
|
+
ruby:
|
|
16
|
+
- 2.5
|
|
17
|
+
- 2.6
|
|
18
|
+
- 2.7
|
|
19
|
+
services:
|
|
20
|
+
elasticsearch:
|
|
21
|
+
image: ${{ matrix.elasticsearch }}
|
|
22
|
+
env:
|
|
23
|
+
discovery.type: single-node
|
|
24
|
+
ports:
|
|
25
|
+
- 9200:9200
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v1
|
|
28
|
+
- uses: actions/setup-ruby@v1
|
|
29
|
+
with:
|
|
30
|
+
ruby-version: ${{ matrix.ruby }}
|
|
31
|
+
- run: bundle
|
|
32
|
+
- run: sleep 10
|
|
33
|
+
- run: bundle exec rspec
|
|
34
|
+
- run: bundle exec rubocop
|
data/.rubocop.yml
CHANGED
|
@@ -2,12 +2,22 @@ AllCops:
|
|
|
2
2
|
NewCops: enable
|
|
3
3
|
TargetRubyVersion: 2.4
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Style/CaseLikeIf:
|
|
6
6
|
Enabled: false
|
|
7
7
|
|
|
8
|
+
Layout/EmptyLineBetweenDefs:
|
|
9
|
+
EmptyLineBetweenClassDefs: false
|
|
10
|
+
|
|
11
|
+
Lint/EmptyBlock:
|
|
12
|
+
Exclude:
|
|
13
|
+
- spec/**/*.rb
|
|
14
|
+
|
|
8
15
|
Style/ExplicitBlockArgument:
|
|
9
16
|
Enabled: false
|
|
10
17
|
|
|
18
|
+
Gemspec/RequiredRubyVersion:
|
|
19
|
+
Enabled: false
|
|
20
|
+
|
|
11
21
|
Style/HashTransformValues:
|
|
12
22
|
Enabled: false
|
|
13
23
|
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
|
|
2
2
|
# CHANGELOG
|
|
3
3
|
|
|
4
|
+
## v4.0.0
|
|
5
|
+
|
|
6
|
+
* [BREAKING] For performance reasons, `SearchFlip::Result` now no longer
|
|
7
|
+
inherits `Hashie::Mash`
|
|
8
|
+
* It no longer supports symbol based access like `result[:id]`
|
|
9
|
+
* It no longer supports question mark methods like `result.title?`
|
|
10
|
+
* It no longer supports method based assignment like `result.some_key = "value"`
|
|
11
|
+
* Added `SearchFlip::Connection#get_cluster_settings` and
|
|
12
|
+
`#update_cluster_settings`
|
|
13
|
+
|
|
14
|
+
## v3.2.0
|
|
15
|
+
|
|
16
|
+
* Fix `index_scope` not being passed in `each_record` without block
|
|
17
|
+
* Added `SearchFlip::Criteria#match_none`
|
|
18
|
+
|
|
19
|
+
## v3.1.2
|
|
20
|
+
|
|
21
|
+
* Fix ignored false value for source when merging criterias
|
|
22
|
+
|
|
4
23
|
## v3.1.1
|
|
5
24
|
|
|
6
25
|
* Make `SearchFlip::Result.from_hit` work with the `_source` being disabled
|
data/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
**Full-Featured Elasticsearch Ruby Client with a Chainable DSL**
|
|
5
5
|
|
|
6
|
-
[](https://github.com/mrkamel/search_flip/actions?query=workflow%3Atest+branch%3Amaster)
|
|
7
7
|
[](http://badge.fury.io/rb/search_flip)
|
|
8
8
|
|
|
9
9
|
Using SearchFlip it is dead-simple to create index classes that correspond to
|
|
@@ -51,8 +51,7 @@ CommentIndex.search("hello world").where(available: true).sort(id: "desc").aggre
|
|
|
51
51
|
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
Finally, SearchFlip comes with a minimal set of dependencies (http-rb
|
|
55
|
-
and oj only).
|
|
54
|
+
Finally, SearchFlip comes with a minimal set of dependencies (http-rb and oj only).
|
|
56
55
|
|
|
57
56
|
## Reference Docs
|
|
58
57
|
|
|
@@ -419,6 +418,14 @@ Simply matches all documents:
|
|
|
419
418
|
CommentIndex.match_all
|
|
420
419
|
```
|
|
421
420
|
|
|
421
|
+
* `match_none`
|
|
422
|
+
|
|
423
|
+
Simply matches none documents at all:
|
|
424
|
+
|
|
425
|
+
```ruby
|
|
426
|
+
CommentIndex.match_none
|
|
427
|
+
```
|
|
428
|
+
|
|
422
429
|
* `all`
|
|
423
430
|
|
|
424
431
|
Simply returns the criteria as is or an empty criteria when called on the index
|
|
@@ -475,8 +482,8 @@ end
|
|
|
475
482
|
```
|
|
476
483
|
|
|
477
484
|
Generally, aggregation results returned by Elasticsearch are returned as a
|
|
478
|
-
`SearchFlip::Result`, which basically is a
|
|
479
|
-
access them via:
|
|
485
|
+
`SearchFlip::Result`, which basically is a Hash with method-like access, such
|
|
486
|
+
that you can access them via:
|
|
480
487
|
|
|
481
488
|
```ruby
|
|
482
489
|
query.aggregations(:username)["mrkamel"].revenue.value
|
|
@@ -926,6 +933,7 @@ require "search_flip/to_json"
|
|
|
926
933
|
|
|
927
934
|
* for Elasticsearch 2.x, the delete-by-query plugin is required to delete
|
|
928
935
|
records via queries
|
|
936
|
+
* `#match_none` is only available with Elasticsearch >= 5
|
|
929
937
|
* `#track_total_hits` is only available with Elasticsearch >= 7
|
|
930
938
|
|
|
931
939
|
## Keeping your Models and Indices in Sync
|
data/UPDATING.md
CHANGED
|
@@ -1,6 +1,46 @@
|
|
|
1
1
|
|
|
2
2
|
# Updating from previous SearchFlip versions
|
|
3
3
|
|
|
4
|
+
## Update 3.x to 4.x
|
|
5
|
+
|
|
6
|
+
**[BREAKING]** For performance reasons, `SearchFlip::Result` no longer
|
|
7
|
+
inherits `Hashie::Mash`
|
|
8
|
+
|
|
9
|
+
* It no longer supports symbol based access like `result[:id]`
|
|
10
|
+
|
|
11
|
+
2.x:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
CommentIndex.match_all.results.first[:id]
|
|
15
|
+
CommentIndex.aggregate(:tags).aggregations(:tags).values.first[:doc_count]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
3.x
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
CommentIndex.match_all.results.first["id"] # or .id
|
|
22
|
+
CommentIndex.aggregate(:tags).aggregations(:tags).values.first["doc_count"] # or .doc_count
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
* It no longer supports question mark methods like `result.title?`
|
|
26
|
+
|
|
27
|
+
2.x:
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
CommentIndex.match_all.results.first.is_published?
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
3.x
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
CommentIndex.match_all.results.first.is_published == true
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
* It no longer supports method based assignment like `result.some_key = "value"`.
|
|
40
|
+
|
|
41
|
+
However, this should not have any practical implications, as changing the
|
|
42
|
+
results is not considered to be a common use case.
|
|
43
|
+
|
|
4
44
|
## Update 2.x to 3.x
|
|
5
45
|
|
|
6
46
|
* **[BREAKING]** No longer pass multiple arguments to `#must`, `#must_not`,
|
data/lib/search_flip.rb
CHANGED
|
@@ -19,6 +19,33 @@ module SearchFlip
|
|
|
19
19
|
@version_mutex = Mutex.new
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
# Queries the cluster settings from Elasticsearch
|
|
23
|
+
#
|
|
24
|
+
# @example
|
|
25
|
+
# connection.get_cluster_settings
|
|
26
|
+
# # => { "persistent" => { ... }, ... }
|
|
27
|
+
#
|
|
28
|
+
# @return [Hash] The cluster settings
|
|
29
|
+
|
|
30
|
+
def get_cluster_settings
|
|
31
|
+
http_client.get("#{base_url}/_cluster/settings").parse
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Updates the cluster settings according to the specified payload
|
|
35
|
+
#
|
|
36
|
+
# @example
|
|
37
|
+
# connection.update_cluster_settings(persistent: { action: { auto_create_index: false } })
|
|
38
|
+
#
|
|
39
|
+
# @param cluster_settings [Hash] The cluster settings
|
|
40
|
+
#
|
|
41
|
+
# @return [Boolean] Returns true or raises SearchFlip::ResponseError
|
|
42
|
+
|
|
43
|
+
def update_cluster_settings(cluster_settings)
|
|
44
|
+
http_client.put("#{base_url}/_cluster/settings", json: cluster_settings)
|
|
45
|
+
|
|
46
|
+
true
|
|
47
|
+
end
|
|
48
|
+
|
|
22
49
|
# Queries and returns the Elasticsearch version used.
|
|
23
50
|
#
|
|
24
51
|
# @example
|
|
@@ -71,7 +98,7 @@ module SearchFlip
|
|
|
71
98
|
.headers(accept: "application/json", content_type: "application/x-ndjson")
|
|
72
99
|
.post("#{base_url}/_msearch", body: payload)
|
|
73
100
|
|
|
74
|
-
raw_response.
|
|
101
|
+
SearchFlip::JSON.parse(raw_response.to_s)["responses"].map.with_index do |response, index|
|
|
75
102
|
SearchFlip::Response.new(criterias[index], response)
|
|
76
103
|
end
|
|
77
104
|
end
|
data/lib/search_flip/criteria.rb
CHANGED
|
@@ -44,35 +44,25 @@ module SearchFlip
|
|
|
44
44
|
other = other.criteria
|
|
45
45
|
|
|
46
46
|
fresh.tap do |criteria|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
criteria.must_not_values = (criteria.must_not_values || []) + other.must_not_values if other.must_not_values
|
|
67
|
-
criteria.filter_values = (criteria.filter_values || []) + other.filter_values if other.filter_values
|
|
68
|
-
criteria.post_must_values = (criteria.post_must_values || []) + other.post_must_values if other.post_must_values
|
|
69
|
-
criteria.post_must_not_values = (criteria.post_must_not_values || []) + other.post_must_not_values if other.post_must_not_values
|
|
70
|
-
criteria.post_filter_values = (criteria.post_filter_values || []) + other.post_filter_values if other.post_filter_values
|
|
71
|
-
|
|
72
|
-
criteria.highlight_values = (criteria.highlight_values || {}).merge(other.highlight_values) if other.highlight_values
|
|
73
|
-
criteria.suggest_values = (criteria.suggest_values || {}).merge(other.suggest_values) if other.suggest_values
|
|
74
|
-
criteria.custom_value = (criteria.custom_value || {}).merge(other.custom_value) if other.custom_value
|
|
75
|
-
criteria.aggregation_values = (criteria.aggregation_values || {}).merge(other.aggregation_values) if other.aggregation_values
|
|
47
|
+
[
|
|
48
|
+
:profile_value, :failsafe_value, :terminate_after_value, :timeout_value, :offset_value,
|
|
49
|
+
:limit_value, :scroll_args, :source_value, :preference_value, :search_type_value,
|
|
50
|
+
:routing_value, :track_total_hits_value, :explain_value
|
|
51
|
+
].each do |name|
|
|
52
|
+
criteria.send(:"#{name}=", other.send(name)) unless other.send(name).nil?
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
[
|
|
56
|
+
:sort_values, :includes_values, :preload_values, :eager_load_values, :must_values,
|
|
57
|
+
:must_not_values, :filter_values, :post_must_values, :post_must_not_values,
|
|
58
|
+
:post_filter_values
|
|
59
|
+
].each do |name|
|
|
60
|
+
criteria.send(:"#{name}=", (criteria.send(name) || []) + other.send(name)) if other.send(name)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
[:highlight_values, :suggest_values, :custom_value, :aggregation_values].each do |name|
|
|
64
|
+
criteria.send(:"#{name}=", (criteria.send(name) || {}).merge(other.send(name))) if other.send(name)
|
|
65
|
+
end
|
|
76
66
|
end
|
|
77
67
|
end
|
|
78
68
|
|
|
@@ -618,7 +608,7 @@ module SearchFlip
|
|
|
618
608
|
http_request.post("#{target.type_url}/_search", params: request_params, json: request)
|
|
619
609
|
end
|
|
620
610
|
|
|
621
|
-
SearchFlip::Response.new(self, http_response.
|
|
611
|
+
SearchFlip::Response.new(self, SearchFlip::JSON.parse(http_response.to_s))
|
|
622
612
|
rescue SearchFlip::ConnectionError, SearchFlip::ResponseError => e
|
|
623
613
|
raise e unless failsafe_value
|
|
624
614
|
|
|
@@ -235,6 +235,22 @@ module SearchFlip
|
|
|
235
235
|
filter(match_all: options)
|
|
236
236
|
end
|
|
237
237
|
|
|
238
|
+
# Adds a match none filter to the criteria, which simply matches none
|
|
239
|
+
# documents at all. Check out the Elasticsearch docs for further details.
|
|
240
|
+
#
|
|
241
|
+
# @example Basic usage
|
|
242
|
+
# CommentIndex.match_none
|
|
243
|
+
#
|
|
244
|
+
# @example Filter chaining
|
|
245
|
+
# query = CommentIndex.search("...")
|
|
246
|
+
# query = query.match_none unless current_user.admin?
|
|
247
|
+
#
|
|
248
|
+
# @return [SearchFlip::Criteria] A newly created extended criteria
|
|
249
|
+
|
|
250
|
+
def match_none
|
|
251
|
+
filter(match_none: {})
|
|
252
|
+
end
|
|
253
|
+
|
|
238
254
|
# Adds an exists filter to the criteria, which selects all documents for
|
|
239
255
|
# which the specified field has a non-null value.
|
|
240
256
|
#
|
data/lib/search_flip/index.rb
CHANGED
|
@@ -153,7 +153,7 @@ module SearchFlip
|
|
|
153
153
|
# scope to be applied to the scope
|
|
154
154
|
|
|
155
155
|
def each_record(scope, index_scope: false)
|
|
156
|
-
return enum_for(:each_record, scope) unless block_given?
|
|
156
|
+
return enum_for(:each_record, scope, index_scope: index_scope) unless block_given?
|
|
157
157
|
|
|
158
158
|
if scope.respond_to?(:find_each)
|
|
159
159
|
(index_scope ? self.index_scope(scope) : scope).find_each do |record|
|
|
@@ -247,8 +247,8 @@ module SearchFlip
|
|
|
247
247
|
SearchFlip::Criteria.new(target: self)
|
|
248
248
|
end
|
|
249
249
|
|
|
250
|
-
def_delegators :criteria, :all, :profile, :where, :where_not, :filter, :range, :match_all, :
|
|
251
|
-
:exists_not, :post_where, :post_where_not, :post_range, :post_exists, :post_exists_not,
|
|
250
|
+
def_delegators :criteria, :all, :profile, :where, :where_not, :filter, :range, :match_all, :match_none,
|
|
251
|
+
:exists, :exists_not, :post_where, :post_where_not, :post_range, :post_exists, :post_exists_not,
|
|
252
252
|
:post_filter, :post_must, :post_must_not, :post_should, :aggregate, :scroll, :source,
|
|
253
253
|
:includes, :eager_load, :preload, :sort, :resort, :order, :reorder, :offset, :limit, :paginate,
|
|
254
254
|
:page, :per, :search, :highlight, :suggest, :custom, :find_in_batches, :find_results_in_batches,
|
|
@@ -455,7 +455,9 @@ module SearchFlip
|
|
|
455
455
|
# @return [Hash] The specified document
|
|
456
456
|
|
|
457
457
|
def get(id, params = {})
|
|
458
|
-
connection.http_client.headers(accept: "application/json").get("#{type_url}/#{id}", params: params)
|
|
458
|
+
response = connection.http_client.headers(accept: "application/json").get("#{type_url}/#{id}", params: params)
|
|
459
|
+
|
|
460
|
+
SearchFlip::JSON.parse(response.to_s)
|
|
459
461
|
end
|
|
460
462
|
|
|
461
463
|
# Retrieves the documents specified by ids from elasticsearch.
|
|
@@ -471,7 +473,9 @@ module SearchFlip
|
|
|
471
473
|
# @return [Hash] The raw response
|
|
472
474
|
|
|
473
475
|
def mget(request, params = {})
|
|
474
|
-
connection.http_client.headers(accept: "application/json").post("#{type_url}/_mget", json: request, params: params)
|
|
476
|
+
response = connection.http_client.headers(accept: "application/json").post("#{type_url}/_mget", json: request, params: params)
|
|
477
|
+
|
|
478
|
+
SearchFlip::JSON.parse(response.to_s)
|
|
475
479
|
end
|
|
476
480
|
|
|
477
481
|
# Sends an analyze request to Elasticsearch. Raises
|
data/lib/search_flip/json.rb
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
module SearchFlip
|
|
2
2
|
class JSON
|
|
3
|
-
|
|
4
|
-
mode: :custom,
|
|
5
|
-
use_to_json: true
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
def self.default_options
|
|
9
|
-
@default_options
|
|
3
|
+
def self.generate(obj)
|
|
4
|
+
Oj.dump(obj, mode: :custom, use_to_json: true)
|
|
10
5
|
end
|
|
11
6
|
|
|
12
|
-
def self.
|
|
13
|
-
Oj.
|
|
7
|
+
def self.parse(str)
|
|
8
|
+
Oj.load(str, mode: :compat)
|
|
14
9
|
end
|
|
15
10
|
end
|
|
16
11
|
end
|
data/lib/search_flip/response.rb
CHANGED
|
@@ -156,8 +156,7 @@ module SearchFlip
|
|
|
156
156
|
end
|
|
157
157
|
|
|
158
158
|
# Returns the results, ie hits, wrapped in a SearchFlip::Result object
|
|
159
|
-
# which basically is a
|
|
160
|
-
# details.
|
|
159
|
+
# which basically is a Hash with method-like access.
|
|
161
160
|
#
|
|
162
161
|
# @example
|
|
163
162
|
# CommentIndex.search("hello world").results
|
|
@@ -166,7 +165,7 @@ module SearchFlip
|
|
|
166
165
|
# @return [Array] An array of results
|
|
167
166
|
|
|
168
167
|
def results
|
|
169
|
-
@results ||= hits["hits"].map { |hit| Result.from_hit(hit) }
|
|
168
|
+
@results ||= hits["hits"].map { |hit| SearchFlip::Result.from_hit(hit) }
|
|
170
169
|
end
|
|
171
170
|
|
|
172
171
|
# Returns the named sugggetion, if a name is specified or alle suggestions.
|
|
@@ -304,13 +303,13 @@ module SearchFlip
|
|
|
304
303
|
|
|
305
304
|
@aggregations[key] =
|
|
306
305
|
if response["aggregations"].nil? || response["aggregations"][key].nil?
|
|
307
|
-
Result.new
|
|
306
|
+
SearchFlip::Result.new
|
|
308
307
|
elsif response["aggregations"][key]["buckets"].is_a?(Array)
|
|
309
|
-
response["aggregations"][key]["buckets"].each_with_object({}) { |bucket, hash| hash[bucket["key"]] = Result.
|
|
308
|
+
response["aggregations"][key]["buckets"].each_with_object({}) { |bucket, hash| hash[bucket["key"]] = SearchFlip::Result.convert(bucket) }
|
|
310
309
|
elsif response["aggregations"][key]["buckets"].is_a?(Hash)
|
|
311
|
-
Result.
|
|
310
|
+
SearchFlip::Result.convert(response["aggregations"][key]["buckets"])
|
|
312
311
|
else
|
|
313
|
-
Result.
|
|
312
|
+
SearchFlip::Result.convert(response["aggregations"][key])
|
|
314
313
|
end
|
|
315
314
|
end
|
|
316
315
|
end
|
data/lib/search_flip/result.rb
CHANGED
|
@@ -1,29 +1,51 @@
|
|
|
1
1
|
module SearchFlip
|
|
2
|
-
# The SearchFlip::Result class
|
|
3
|
-
#
|
|
2
|
+
# The SearchFlip::Result class is a simple Hash, but extended with
|
|
3
|
+
# method-like access. Keys assigned via methods are stored as strings.
|
|
4
|
+
#
|
|
5
|
+
# @example method access
|
|
6
|
+
# result = SearchFlip::Result.new
|
|
7
|
+
# result["some_key"] = "value"
|
|
8
|
+
# result.some_key # => "value"
|
|
4
9
|
|
|
5
|
-
class Result <
|
|
6
|
-
def self.
|
|
7
|
-
|
|
8
|
-
end
|
|
10
|
+
class Result < Hash
|
|
11
|
+
def self.convert(hash)
|
|
12
|
+
res = self[hash]
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# SearchFlip::Result.from_hit(top_sales_hits.first)
|
|
14
|
+
res.each do |key, value|
|
|
15
|
+
if value.is_a?(Hash)
|
|
16
|
+
res[key] = convert(value)
|
|
17
|
+
elsif value.is_a?(Array)
|
|
18
|
+
res[key] = convert_array(value)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
res
|
|
23
|
+
end
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
def self.convert_array(arr)
|
|
26
|
+
arr.map do |obj|
|
|
27
|
+
if obj.is_a?(Hash)
|
|
28
|
+
convert(obj)
|
|
29
|
+
elsif obj.is_a?(Array)
|
|
30
|
+
convert_array(obj)
|
|
31
|
+
else
|
|
32
|
+
obj
|
|
33
|
+
end
|
|
24
34
|
end
|
|
35
|
+
end
|
|
25
36
|
|
|
26
|
-
|
|
37
|
+
def method_missing(name, *args, &block)
|
|
38
|
+
self[name.to_s]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def respond_to_missing?(name, include_private = false)
|
|
42
|
+
key?(name.to_s) || super
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.from_hit(hit)
|
|
46
|
+
res = convert(hit["_source"] || {})
|
|
47
|
+
res["_hit"] = convert(self[hit].tap { |hash| hash.delete("_source") })
|
|
48
|
+
res
|
|
27
49
|
end
|
|
28
50
|
end
|
|
29
51
|
end
|
data/lib/search_flip/version.rb
CHANGED
data/search_flip.gemspec
CHANGED
|
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
|
20
20
|
|
|
21
21
|
spec.post_install_message = <<~MESSAGE
|
|
22
22
|
Thanks for using search_flip!
|
|
23
|
-
When upgrading
|
|
23
|
+
When upgrading major versions, please check out
|
|
24
24
|
https://github.com/mrkamel/search_flip/blob/master/UPDATING.md
|
|
25
25
|
MESSAGE
|
|
26
26
|
|
|
@@ -35,7 +35,6 @@ Gem::Specification.new do |spec|
|
|
|
35
35
|
spec.add_development_dependency "timecop"
|
|
36
36
|
spec.add_development_dependency "webmock"
|
|
37
37
|
|
|
38
|
-
spec.add_dependency "hashie"
|
|
39
38
|
spec.add_dependency "http"
|
|
40
39
|
spec.add_dependency "oj"
|
|
41
40
|
spec.add_dependency "ruby2_keywords"
|
|
@@ -15,7 +15,7 @@ RSpec.describe SearchFlip::Aggregation do
|
|
|
15
15
|
aggregation.where(title: "title").where(description: "description").aggregate(:category)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[
|
|
18
|
+
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket["key"]] = bucket.doc_count }
|
|
19
19
|
|
|
20
20
|
expect(aggregations).to eq("category1" => 2, "category2" => 1)
|
|
21
21
|
end
|
|
@@ -36,7 +36,7 @@ RSpec.describe SearchFlip::Aggregation do
|
|
|
36
36
|
.aggregate(:category)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[
|
|
39
|
+
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket["key"]] = bucket.doc_count }
|
|
40
40
|
|
|
41
41
|
expect(aggregations).to eq("category1" => 2, "category2" => 1)
|
|
42
42
|
end
|
|
@@ -54,7 +54,7 @@ RSpec.describe SearchFlip::Aggregation do
|
|
|
54
54
|
aggregation.where(title: "title1".."title3").where(price: 100..200).aggregate(:category)
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[
|
|
57
|
+
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket["key"]] = bucket.doc_count }
|
|
58
58
|
|
|
59
59
|
expect(aggregations).to eq("category1" => 2, "category2" => 1)
|
|
60
60
|
end
|
|
@@ -74,7 +74,7 @@ RSpec.describe SearchFlip::Aggregation do
|
|
|
74
74
|
aggregation.where_not(title: "title4").where_not(title: "title5").aggregate(:category)
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[
|
|
77
|
+
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket["key"]] = bucket.doc_count }
|
|
78
78
|
|
|
79
79
|
expect(aggregations).to eq("category1" => 2, "category2" => 1)
|
|
80
80
|
end
|
|
@@ -94,7 +94,7 @@ RSpec.describe SearchFlip::Aggregation do
|
|
|
94
94
|
aggregation.where_not(title: ["title1", "title2"]).where_not(title: ["title6", "title7"]).aggregate(:category)
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
-
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[
|
|
97
|
+
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket["key"]] = bucket.doc_count }
|
|
98
98
|
|
|
99
99
|
expect(aggregations).to eq("category1" => 2, "category2" => 1)
|
|
100
100
|
end
|
|
@@ -114,7 +114,7 @@ RSpec.describe SearchFlip::Aggregation do
|
|
|
114
114
|
aggregation.where_not(price: 100..150).where_not(title: "title6".."title7").aggregate(:category)
|
|
115
115
|
end
|
|
116
116
|
|
|
117
|
-
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[
|
|
117
|
+
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket["key"]] = bucket.doc_count }
|
|
118
118
|
|
|
119
119
|
expect(aggregations).to eq("category1" => 2, "category2" => 1)
|
|
120
120
|
end
|
|
@@ -134,7 +134,7 @@ RSpec.describe SearchFlip::Aggregation do
|
|
|
134
134
|
aggregation.filter(range: { price: { gte: 100, lte: 200 } }).filter(term: { title: "title" }).aggregate(:category)
|
|
135
135
|
end
|
|
136
136
|
|
|
137
|
-
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[
|
|
137
|
+
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket["key"]] = bucket.doc_count }
|
|
138
138
|
|
|
139
139
|
expect(aggregations).to eq("category1" => 2, "category2" => 1)
|
|
140
140
|
end
|
|
@@ -156,7 +156,7 @@ RSpec.describe SearchFlip::Aggregation do
|
|
|
156
156
|
aggregation.range(:price, gte: 100, lte: 200).range(:title, gte: "title1", lte: "title3").aggregate(:category)
|
|
157
157
|
end
|
|
158
158
|
|
|
159
|
-
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[
|
|
159
|
+
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket["key"]] = bucket.doc_count }
|
|
160
160
|
|
|
161
161
|
expect(aggregations).to eq("category1" => 2, "category2" => 1)
|
|
162
162
|
end
|
|
@@ -174,7 +174,7 @@ RSpec.describe SearchFlip::Aggregation do
|
|
|
174
174
|
aggregation.match_all.aggregate(:category)
|
|
175
175
|
end
|
|
176
176
|
|
|
177
|
-
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[
|
|
177
|
+
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket["key"]] = bucket.doc_count }
|
|
178
178
|
|
|
179
179
|
expect(aggregations).to eq("category1" => 2, "category2" => 1)
|
|
180
180
|
end
|
|
@@ -194,7 +194,7 @@ RSpec.describe SearchFlip::Aggregation do
|
|
|
194
194
|
aggregation.exists(:title).exists(:price).aggregate(:category)
|
|
195
195
|
end
|
|
196
196
|
|
|
197
|
-
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[
|
|
197
|
+
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket["key"]] = bucket.doc_count }
|
|
198
198
|
|
|
199
199
|
expect(aggregations).to eq("category1" => 2, "category2" => 1)
|
|
200
200
|
end
|
|
@@ -214,7 +214,7 @@ RSpec.describe SearchFlip::Aggregation do
|
|
|
214
214
|
aggregation.exists_not(:title).exists_not(:price).aggregate(:category)
|
|
215
215
|
end
|
|
216
216
|
|
|
217
|
-
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket[
|
|
217
|
+
aggregations = query.aggregations(:category).category.buckets.each_with_object({}) { |bucket, hash| hash[bucket["key"]] = bucket.doc_count }
|
|
218
218
|
|
|
219
219
|
expect(aggregations).to eq("category1" => 2, "category2" => 1)
|
|
220
220
|
end
|
|
@@ -244,21 +244,21 @@ RSpec.describe SearchFlip::Aggregation do
|
|
|
244
244
|
expect(aggregations).to eq("category1" => 3, "category2" => 3)
|
|
245
245
|
|
|
246
246
|
aggregations = query.aggregations(:category)["category1"].title.buckets.each_with_object({}) do |bucket, hash|
|
|
247
|
-
hash[bucket[
|
|
247
|
+
hash[bucket["key"]] = bucket.doc_count
|
|
248
248
|
end
|
|
249
249
|
|
|
250
250
|
expect(aggregations).to eq("title1" => 2, "title2" => 1)
|
|
251
251
|
|
|
252
252
|
aggregations = query.aggregations(:category)["category2"].title.buckets.each_with_object({}) do |bucket, hash|
|
|
253
|
-
hash[bucket[
|
|
253
|
+
hash[bucket["key"]] = bucket.doc_count
|
|
254
254
|
end
|
|
255
255
|
|
|
256
256
|
expect(aggregations).to eq("title1" => 1, "title2" => 2)
|
|
257
257
|
|
|
258
|
-
expect(query.aggregations(:category)["category1"].title.buckets.detect { |bucket| bucket[
|
|
259
|
-
expect(query.aggregations(:category)["category1"].title.buckets.detect { |bucket| bucket[
|
|
260
|
-
expect(query.aggregations(:category)["category2"].title.buckets.detect { |bucket| bucket[
|
|
261
|
-
expect(query.aggregations(:category)["category2"].title.buckets.detect { |bucket| bucket[
|
|
258
|
+
expect(query.aggregations(:category)["category1"].title.buckets.detect { |bucket| bucket["key"] == "title1" }.price.value).to eq(30)
|
|
259
|
+
expect(query.aggregations(:category)["category1"].title.buckets.detect { |bucket| bucket["key"] == "title2" }.price.value).to eq(15)
|
|
260
|
+
expect(query.aggregations(:category)["category2"].title.buckets.detect { |bucket| bucket["key"] == "title1" }.price.value).to eq(30)
|
|
261
|
+
expect(query.aggregations(:category)["category2"].title.buckets.detect { |bucket| bucket["key"] == "title2" }.price.value).to eq(60)
|
|
262
262
|
end
|
|
263
263
|
end
|
|
264
264
|
|
|
@@ -19,6 +19,35 @@ RSpec.describe SearchFlip::Connection do
|
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
describe "#get_cluster_settings" do
|
|
23
|
+
it "returns the cluster settings" do
|
|
24
|
+
expect(SearchFlip::Connection.new.get_cluster_settings).to be_kind_of(Hash)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "#update_cluster_settings" do
|
|
29
|
+
let(:connection) { SearchFlip::Connection.new }
|
|
30
|
+
|
|
31
|
+
after do
|
|
32
|
+
connection.update_cluster_settings(persistent: { action: { auto_create_index: false } }) if connection.version.to_i > 2
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "updates the cluster settings" do
|
|
36
|
+
if connection.version.to_i > 2
|
|
37
|
+
connection.update_cluster_settings(persistent: { action: { auto_create_index: false } })
|
|
38
|
+
connection.update_cluster_settings(persistent: { action: { auto_create_index: true } })
|
|
39
|
+
|
|
40
|
+
expect(connection.get_cluster_settings["persistent"]["action"]["auto_create_index"]).to eq("true")
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "returns true" do
|
|
45
|
+
if connection.version.to_i > 2
|
|
46
|
+
expect(connection.update_cluster_settings(persistent: { action: { auto_create_index: false } })).to eq(true)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
22
51
|
describe "#msearch" do
|
|
23
52
|
it "sends multiple queries and returns all responses" do
|
|
24
53
|
ProductIndex.import create(:product)
|
|
@@ -110,6 +110,16 @@ RSpec.describe SearchFlip::Criteria do
|
|
|
110
110
|
|
|
111
111
|
expect(criteria1.merge(criteria2).send(method)).to eq("value2")
|
|
112
112
|
end
|
|
113
|
+
|
|
114
|
+
it "handles false values correctly" do
|
|
115
|
+
criteria1 = SearchFlip::Criteria.new(target: TestIndex)
|
|
116
|
+
criteria1.send("#{method}=", true)
|
|
117
|
+
|
|
118
|
+
criteria2 = SearchFlip::Criteria.new(target: TestIndex)
|
|
119
|
+
criteria2.send("#{method}=", false)
|
|
120
|
+
|
|
121
|
+
expect(criteria1.merge(criteria2).send(method)).to eq(false)
|
|
122
|
+
end
|
|
113
123
|
end
|
|
114
124
|
end
|
|
115
125
|
|
|
@@ -406,6 +416,18 @@ RSpec.describe SearchFlip::Criteria do
|
|
|
406
416
|
end
|
|
407
417
|
end
|
|
408
418
|
|
|
419
|
+
describe "#match_none" do
|
|
420
|
+
it "does not match any documents" do
|
|
421
|
+
if ProductIndex.connection.version.to_i >= 5
|
|
422
|
+
ProductIndex.import create(:product)
|
|
423
|
+
|
|
424
|
+
query = ProductIndex.match_none
|
|
425
|
+
|
|
426
|
+
expect(query.records).to eq([])
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
end
|
|
430
|
+
|
|
409
431
|
describe "#exists" do
|
|
410
432
|
it "sets up the constraints correctly and is chainable" do
|
|
411
433
|
product1 = create(:product, title: "title1", description: "description1")
|
|
@@ -1291,7 +1313,7 @@ RSpec.describe SearchFlip::Criteria do
|
|
|
1291
1313
|
ProductIndex.import create(:product)
|
|
1292
1314
|
|
|
1293
1315
|
query = ProductIndex.match_all.explain(true)
|
|
1294
|
-
expect(query.results.first._hit.key?(
|
|
1316
|
+
expect(query.results.first._hit.key?("_explanation")).to eq(true)
|
|
1295
1317
|
end
|
|
1296
1318
|
end
|
|
1297
1319
|
|
|
@@ -5,8 +5,8 @@ RSpec.describe SearchFlip::Index do
|
|
|
5
5
|
subject { ProductIndex }
|
|
6
6
|
|
|
7
7
|
methods = [
|
|
8
|
-
:all, :profile, :where, :where_not, :filter, :range, :match_all, :
|
|
9
|
-
:exists_not, :post_where, :post_where_not, :post_filter, :post_must,
|
|
8
|
+
:all, :profile, :where, :where_not, :filter, :range, :match_all, :match_none,
|
|
9
|
+
:exists, :exists_not, :post_where, :post_where_not, :post_filter, :post_must,
|
|
10
10
|
:post_must_not, :post_should, :post_range, :post_exists, :post_exists_not,
|
|
11
11
|
:aggregate, :scroll, :source, :includes, :eager_load, :preload, :sort, :resort,
|
|
12
12
|
:order, :reorder, :offset, :limit, :paginate, :page, :per, :search,
|
|
@@ -211,12 +211,18 @@ RSpec.describe SearchFlip::Index do
|
|
|
211
211
|
mapping = { properties: { id: { type: "long" } } }
|
|
212
212
|
|
|
213
213
|
allow(TestIndex).to receive(:mapping).and_return(mapping)
|
|
214
|
-
allow(TestIndex.connection).to receive(:update_mapping)
|
|
214
|
+
allow(TestIndex.connection).to receive(:update_mapping)
|
|
215
215
|
|
|
216
216
|
TestIndex.update_mapping
|
|
217
217
|
|
|
218
218
|
expect(TestIndex.connection).to have_received(:update_mapping).with("test", { "test" => mapping }, type_name: "test")
|
|
219
219
|
end
|
|
220
|
+
|
|
221
|
+
it "updates the mapping" do
|
|
222
|
+
TestIndex.create_index
|
|
223
|
+
|
|
224
|
+
expect(TestIndex.update_mapping).to eq(true)
|
|
225
|
+
end
|
|
220
226
|
end
|
|
221
227
|
end
|
|
222
228
|
|
|
@@ -258,12 +264,19 @@ RSpec.describe SearchFlip::Index do
|
|
|
258
264
|
TestIndex.create_index
|
|
259
265
|
TestIndex.update_mapping
|
|
260
266
|
|
|
261
|
-
allow(TestIndex.connection).to receive(:get_mapping)
|
|
267
|
+
allow(TestIndex.connection).to receive(:get_mapping)
|
|
262
268
|
|
|
263
269
|
TestIndex.get_mapping
|
|
264
270
|
|
|
265
271
|
expect(TestIndex.connection).to have_received(:get_mapping).with("test", type_name: "test")
|
|
266
272
|
end
|
|
273
|
+
|
|
274
|
+
it "returns the mapping" do
|
|
275
|
+
TestIndex.create_index
|
|
276
|
+
TestIndex.update_mapping
|
|
277
|
+
|
|
278
|
+
expect(TestIndex.get_mapping).to be_present
|
|
279
|
+
end
|
|
267
280
|
end
|
|
268
281
|
end
|
|
269
282
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require File.expand_path("../spec_helper", __dir__)
|
|
2
|
+
|
|
3
|
+
RSpec.describe SearchFlip::JSON do
|
|
4
|
+
describe ".generate" do
|
|
5
|
+
it "delegates to Oj" do
|
|
6
|
+
allow(Oj).to receive(:dump)
|
|
7
|
+
|
|
8
|
+
payload = { key: "value" }
|
|
9
|
+
|
|
10
|
+
described_class.generate(payload)
|
|
11
|
+
|
|
12
|
+
expect(Oj).to have_received(:dump).with(payload, mode: :custom, use_to_json: true)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "generates json" do
|
|
16
|
+
expect(described_class.generate(key: "value")).to eq('{"key":"value"}')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe ".parse" do
|
|
21
|
+
it "delegates to Oj" do
|
|
22
|
+
allow(Oj).to receive(:load)
|
|
23
|
+
|
|
24
|
+
payload = '{"key":"value"}'
|
|
25
|
+
|
|
26
|
+
described_class.parse(payload)
|
|
27
|
+
|
|
28
|
+
expect(Oj).to have_received(:load).with(payload, mode: :compat)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -7,7 +7,7 @@ RSpec.describe SearchFlip::NullInstrumenter do
|
|
|
7
7
|
it "calls start" do
|
|
8
8
|
allow(subject).to receive(:start)
|
|
9
9
|
|
|
10
|
-
subject.instrument("name", { key: "value" }) {}
|
|
10
|
+
subject.instrument("name", { key: "value" }) { true }
|
|
11
11
|
|
|
12
12
|
expect(subject).to have_received(:start)
|
|
13
13
|
end
|
|
@@ -15,7 +15,7 @@ RSpec.describe SearchFlip::NullInstrumenter do
|
|
|
15
15
|
it "calls finish" do
|
|
16
16
|
allow(subject).to receive(:finish)
|
|
17
17
|
|
|
18
|
-
subject.instrument("name", { key: "value" }) {}
|
|
18
|
+
subject.instrument("name", { key: "value" }) { true }
|
|
19
19
|
|
|
20
20
|
expect(subject).to have_received(:finish)
|
|
21
21
|
end
|
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
require File.expand_path("../spec_helper", __dir__)
|
|
2
2
|
|
|
3
3
|
RSpec.describe SearchFlip::Result do
|
|
4
|
+
describe ".convert" do
|
|
5
|
+
it "deeply converts hashes and arrays" do
|
|
6
|
+
result = described_class.convert("parent" => { "child" => [{ "key1" => "value" }, { "key2" => 3 }] })
|
|
7
|
+
|
|
8
|
+
expect(result.parent.child[0].key1).to eq("value")
|
|
9
|
+
expect(result.parent.child[1].key2).to eq(3)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe "#method_missing" do
|
|
14
|
+
it "returns the value of the key equal to the message name" do
|
|
15
|
+
expect(described_class.convert("some_key" => "value").some_key).to eq("value")
|
|
16
|
+
expect(described_class.new.some_key).to be_nil
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "#responds_to_missing?" do
|
|
21
|
+
it "returns true/false if the key equal to the message name is present or not" do
|
|
22
|
+
expect(described_class.convert("some_key" => nil).respond_to?(:some_key)).to eq(true)
|
|
23
|
+
expect(described_class.convert("some_key" => nil).respond_to?(:other_key)).to eq(false)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
4
27
|
describe ".from_hit" do
|
|
5
28
|
it "adds a _hit key into _source and merges the hit keys into it" do
|
|
6
29
|
result = SearchFlip::Result.from_hit("_score" => 1.0, "_source" => { "name" => "Some name" })
|
|
@@ -8,12 +31,6 @@ RSpec.describe SearchFlip::Result do
|
|
|
8
31
|
expect(result).to eq("name" => "Some name", "_hit" => { "_score" => 1.0 })
|
|
9
32
|
end
|
|
10
33
|
|
|
11
|
-
it "allows deep method access" do
|
|
12
|
-
result = SearchFlip::Result.from_hit("_source" => { "key1" => [{ "key2" => "value" }] })
|
|
13
|
-
|
|
14
|
-
expect(result.key1[0].key2).to eq("value")
|
|
15
|
-
end
|
|
16
|
-
|
|
17
34
|
it "works with the _source being disabled" do
|
|
18
35
|
result = SearchFlip::Result.from_hit("_id" => 1)
|
|
19
36
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: search_flip
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 4.0.0.beta3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Benjamin Vetter
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-03-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -150,20 +150,6 @@ dependencies:
|
|
|
150
150
|
- - ">="
|
|
151
151
|
- !ruby/object:Gem::Version
|
|
152
152
|
version: '0'
|
|
153
|
-
- !ruby/object:Gem::Dependency
|
|
154
|
-
name: hashie
|
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
|
156
|
-
requirements:
|
|
157
|
-
- - ">="
|
|
158
|
-
- !ruby/object:Gem::Version
|
|
159
|
-
version: '0'
|
|
160
|
-
type: :runtime
|
|
161
|
-
prerelease: false
|
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
-
requirements:
|
|
164
|
-
- - ">="
|
|
165
|
-
- !ruby/object:Gem::Version
|
|
166
|
-
version: '0'
|
|
167
153
|
- !ruby/object:Gem::Dependency
|
|
168
154
|
name: http
|
|
169
155
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -213,9 +199,9 @@ executables: []
|
|
|
213
199
|
extensions: []
|
|
214
200
|
extra_rdoc_files: []
|
|
215
201
|
files:
|
|
202
|
+
- ".github/workflows/test.yml"
|
|
216
203
|
- ".gitignore"
|
|
217
204
|
- ".rubocop.yml"
|
|
218
|
-
- ".travis.yml"
|
|
219
205
|
- CHANGELOG.md
|
|
220
206
|
- Gemfile
|
|
221
207
|
- LICENSE.txt
|
|
@@ -259,6 +245,7 @@ files:
|
|
|
259
245
|
- spec/search_flip/criteria_spec.rb
|
|
260
246
|
- spec/search_flip/http_client_spec.rb
|
|
261
247
|
- spec/search_flip/index_spec.rb
|
|
248
|
+
- spec/search_flip/json_spec.rb
|
|
262
249
|
- spec/search_flip/model_spec.rb
|
|
263
250
|
- spec/search_flip/null_instrumenter_spec.rb
|
|
264
251
|
- spec/search_flip/response_spec.rb
|
|
@@ -271,7 +258,7 @@ licenses:
|
|
|
271
258
|
metadata: {}
|
|
272
259
|
post_install_message: |
|
|
273
260
|
Thanks for using search_flip!
|
|
274
|
-
When upgrading
|
|
261
|
+
When upgrading major versions, please check out
|
|
275
262
|
https://github.com/mrkamel/search_flip/blob/master/UPDATING.md
|
|
276
263
|
rdoc_options: []
|
|
277
264
|
require_paths:
|
|
@@ -283,11 +270,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
283
270
|
version: '0'
|
|
284
271
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
285
272
|
requirements:
|
|
286
|
-
- - "
|
|
273
|
+
- - ">"
|
|
287
274
|
- !ruby/object:Gem::Version
|
|
288
|
-
version:
|
|
275
|
+
version: 1.3.1
|
|
289
276
|
requirements: []
|
|
290
|
-
rubygems_version: 3.
|
|
277
|
+
rubygems_version: 3.2.3
|
|
291
278
|
signing_key:
|
|
292
279
|
specification_version: 4
|
|
293
280
|
summary: Full-Featured Elasticsearch Ruby Client with a Chainable DSL
|
|
@@ -300,6 +287,7 @@ test_files:
|
|
|
300
287
|
- spec/search_flip/criteria_spec.rb
|
|
301
288
|
- spec/search_flip/http_client_spec.rb
|
|
302
289
|
- spec/search_flip/index_spec.rb
|
|
290
|
+
- spec/search_flip/json_spec.rb
|
|
303
291
|
- spec/search_flip/model_spec.rb
|
|
304
292
|
- spec/search_flip/null_instrumenter_spec.rb
|
|
305
293
|
- spec/search_flip/response_spec.rb
|
data/.travis.yml
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
sudo: false
|
|
2
|
-
language: ruby
|
|
3
|
-
env:
|
|
4
|
-
- ES_IMAGE=plainpicture/elasticsearch:2.4.1_delete-by-query
|
|
5
|
-
- ES_IMAGE=elasticsearch:5.4
|
|
6
|
-
- ES_IMAGE=docker.elastic.co/elasticsearch/elasticsearch:6.7.0
|
|
7
|
-
- ES_IMAGE=docker.elastic.co/elasticsearch/elasticsearch:7.0.0
|
|
8
|
-
- ES_IMAGE=docker.elastic.co/elasticsearch/elasticsearch:7.8.0
|
|
9
|
-
rvm:
|
|
10
|
-
- ruby-2.5.3
|
|
11
|
-
- ruby-2.6.2
|
|
12
|
-
- ruby-2.7.1
|
|
13
|
-
before_install:
|
|
14
|
-
- docker-compose up -d
|
|
15
|
-
- sleep 10
|
|
16
|
-
install:
|
|
17
|
-
- travis_retry bundle install
|
|
18
|
-
script:
|
|
19
|
-
- bundle exec rspec
|
|
20
|
-
- bundle exec rubocop
|