search_flip 3.0.0 → 4.0.0.beta1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa160794662cedbe89066113cb845c84daaee29451ba8c8ba4f9183689b42582
4
- data.tar.gz: b55133b0f4f90f61db0b76042c1223a17035f277ba221a00c0f665512e1cb170
3
+ metadata.gz: 3e231e9ac3434626705696aea544b0ab30a134de6c6773129e779e6ae7adfab4
4
+ data.tar.gz: 7fe5852eda4d9d73a1a6bfe14e1c6d807bffa08c47c15c137d624dd4050bbcd5
5
5
  SHA512:
6
- metadata.gz: eb2e1e1fd39d64639b9a1f542997e6a00c6238226144fbd32f45f0023f93aa827a1c54597fb71f993090c9d78bcb8b92bbac3a5185d584f26cbeb2e1c4b1a641
7
- data.tar.gz: caea53f0332131113662b24818268bfd5e3cf537ad04b07b853aba600fc4edd417d1783fd3a1d37fd6d848a75df21ec2e3d39c45a8dafab5fdc515d6f8ca43a9
6
+ metadata.gz: ec79c30df34f4cfdb9f8afcd25f4d982d1b03461a00af7a9055f4c48d0b5ffc346cccaed178a6e9137d6cd681f538beaf129d449070b44806966c27ea585d112
7
+ data.tar.gz: 23c9ea04e2d39447a0aaae56f215e3d6cce59c0c67187ba7a9ca18e509e1cbf22dd8dbd52007f4131880a1f97f9fea23e29892f491d5351f39f7b62019afe921
@@ -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
@@ -1,5 +1,15 @@
1
1
  AllCops:
2
2
  NewCops: enable
3
+ TargetRubyVersion: 2.4
4
+
5
+ Gemspec/RequiredRubyVersion:
6
+ Enabled: false
7
+
8
+ Style/CaseLikeIf:
9
+ Enabled: false
10
+
11
+ Style/ExplicitBlockArgument:
12
+ Enabled: false
3
13
 
4
14
  Style/HashTransformValues:
5
15
  Enabled: false
@@ -1,6 +1,28 @@
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
+
12
+ ## v3.1.2
13
+
14
+ * Fix ignored false value for source when merging criterias
15
+
16
+ ## v3.1.1
17
+
18
+ * Make `SearchFlip::Result.from_hit` work with the `_source` being disabled
19
+
20
+ ## v3.1.0
21
+
22
+ * Added plugin support in `SearchFlip::HTTPClient`
23
+ * Added `SearchFlip::AwsSigv4Plugin` to be able to use AWS Elasticsearch with
24
+ signed requests
25
+
4
26
  ## v3.0.0
5
27
 
6
28
  * Added `Criteria#to_query`, which returns a raw query including all queries
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  **Full-Featured Elasticsearch Ruby Client with a Chainable DSL**
5
5
 
6
- [![Build Status](https://secure.travis-ci.org/mrkamel/search_flip.svg?branch=master)](http://travis-ci.org/mrkamel/search_flip)
6
+ [![Build](https://github.com/mrkamel/search_flip/workflows/test/badge.svg)](https://github.com/mrkamel/search_flip/actions?query=workflow%3Atest+branch%3Amaster)
7
7
  [![Gem Version](https://badge.fury.io/rb/search_flip.svg)](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, hashie
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
 
@@ -475,8 +474,8 @@ end
475
474
  ```
476
475
 
477
476
  Generally, aggregation results returned by Elasticsearch are returned as a
478
- `SearchFlip::Result`, which basically is `Hashie::Mash`such that you can access
479
- them via:
477
+ `SearchFlip::Result`, which basically is a Hash with method-like access, such
478
+ that you can access them via:
480
479
 
481
480
  ```ruby
482
481
  query.aggregations(:username)["mrkamel"].revenue.value
@@ -769,6 +768,41 @@ http_client = http_client.headers(key: "value")
769
768
  SearchFlip::Connection.new(base_url: "...", http_client: http_client)
770
769
  ```
771
770
 
771
+ ## AWS Elasticsearch / Signed Requests
772
+
773
+ To use SearchFlip with AWS Elasticsearch and signed requests, you have to add
774
+ `aws-sdk-core` to your Gemfile and tell SearchFlip to use the
775
+ `SearchFlip::AwsSigv4Plugin`:
776
+
777
+ ```ruby
778
+ require "search_flip/aws_sigv4_plugin"
779
+
780
+ MyConnection = SearchFlip::Connection.new(
781
+ base_url: "https://your-elasticsearch-cluster.es.amazonaws.com",
782
+ http_client: SearchFlip::HTTPClient.new(
783
+ plugins: [
784
+ SearchFlip::AwsSigv4Plugin.new(
785
+ region: "...",
786
+ access_key_id: "...",
787
+ secret_access_key: "..."
788
+ )
789
+ ]
790
+ )
791
+ )
792
+ ```
793
+
794
+ Again, in your index you need to specify this connection:
795
+
796
+ ```ruby
797
+ class MyIndex
798
+ include SearchFlip::Index
799
+
800
+ def self.connection
801
+ MyConnection
802
+ end
803
+ end
804
+ ```
805
+
772
806
  ## Routing and other index-time options
773
807
 
774
808
  Override `index_options` in case you want to use routing or pass other
@@ -914,6 +948,10 @@ It uses `after_commit` (if applicable, `after_save`, `after_destroy` and
914
948
  `after_touch` otherwise) hooks to synchronously update the index when your
915
949
  model changes.
916
950
 
951
+ ## Semantic Versioning
952
+
953
+ SearchFlip is using Semantic Versioning: [SemVer](http://semver.org/)
954
+
917
955
  ## Links
918
956
 
919
957
  * Elasticsearch: [https://www.elastic.co/](https://www.elastic.co/)
@@ -945,5 +983,4 @@ $ rspec
945
983
 
946
984
  That's it.
947
985
 
948
-
949
986
  [Bulk API]: https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
@@ -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`,
@@ -1,7 +1,6 @@
1
1
  require "ruby2_keywords"
2
2
  require "forwardable"
3
3
  require "http"
4
- require "hashie"
5
4
  require "thread"
6
5
  require "oj"
7
6
  require "set"
@@ -39,6 +38,8 @@ module SearchFlip
39
38
  attr_reader :code, :body
40
39
 
41
40
  def initialize(code:, body:)
41
+ super
42
+
42
43
  @code = code
43
44
  @body = body
44
45
  end
@@ -40,7 +40,7 @@ module SearchFlip
40
40
  else
41
41
  filters = (filter_values || []) + (must_not_values || []).map { |must_not_value| { not: must_not_value } }
42
42
  queries = must_values ? { must: must_values } : {}
43
- filters_and_queries = filters + (queries.size > 0 ? [bool: queries] : [])
43
+ filters_and_queries = filters + (queries.size > 0 ? [{ bool: queries }] : [])
44
44
 
45
45
  res[:filter] = filters_and_queries.size > 1 ? { and: filters_and_queries } : filters_and_queries.first
46
46
  end
@@ -101,7 +101,7 @@ module SearchFlip
101
101
  end
102
102
 
103
103
  def respond_to_missing?(name, *args)
104
- target.respond_to?(name, *args)
104
+ target.respond_to?(name, *args) || super
105
105
  end
106
106
 
107
107
  def method_missing(name, *args, &block)
@@ -0,0 +1,47 @@
1
+ require "aws-sdk-core"
2
+ require "uri"
3
+
4
+ module SearchFlip
5
+ # The SearchFlip::AwsSigV4Plugin is a plugin for the SearchFlip::HTTPClient
6
+ # to be used with AWS Elasticsearch to sign requests, i.e. add signed
7
+ # headers, before sending the request to Elasticsearch.
8
+ #
9
+ # @example
10
+ # MyConnection = SearchFlip::Connection.new(
11
+ # base_url: "https://your-elasticsearch-cluster.es.amazonaws.com",
12
+ # http_client: SearchFlip::HTTPClient.new(
13
+ # plugins: [
14
+ # SearchFlip::AwsSigv4Plugin.new(
15
+ # region: "...",
16
+ # access_key_id: "...",
17
+ # secret_access_key: "..."
18
+ # )
19
+ # ]
20
+ # )
21
+ # )
22
+
23
+ class AwsSigv4Plugin
24
+ attr_accessor :signer
25
+
26
+ def initialize(options = {})
27
+ self.signer = Aws::Sigv4::Signer.new({ service: "es" }.merge(options))
28
+ end
29
+
30
+ def call(request, method, uri, options = {})
31
+ full_uri = URI.parse(uri)
32
+ full_uri.query = URI.encode_www_form(options[:params]) if options[:params]
33
+
34
+ signature_request = {
35
+ http_method: method.to_s.upcase,
36
+ url: full_uri.to_s
37
+ }
38
+
39
+ signature_request[:body] = options[:body] if options.key?(:body)
40
+ signature_request[:body] = options[:json].respond_to?(:to_str) ? options[:json] : JSON.generate(options[:json]) if options[:json]
41
+
42
+ signature = signer.sign_request(signature_request)
43
+
44
+ request.headers(signature.headers)
45
+ end
46
+ end
47
+ end
@@ -71,7 +71,7 @@ module SearchFlip
71
71
  .headers(accept: "application/json", content_type: "application/x-ndjson")
72
72
  .post("#{base_url}/_msearch", body: payload)
73
73
 
74
- raw_response.parse["responses"].map.with_index do |response, index|
74
+ SearchFlip::JSON.parse(raw_response.to_s)["responses"].map.with_index do |response, index|
75
75
  SearchFlip::Response.new(criterias[index], response)
76
76
  end
77
77
  end
@@ -44,35 +44,25 @@ module SearchFlip
44
44
  other = other.criteria
45
45
 
46
46
  fresh.tap do |criteria|
47
- criteria.profile_value = other.profile_value unless other.profile_value.nil?
48
- criteria.failsafe_value = other.failsafe_value unless other.failsafe_value.nil?
49
- criteria.terminate_after_value = other.terminate_after_value unless other.terminate_after_value.nil?
50
- criteria.timeout_value = other.timeout_value unless other.timeout_value.nil?
51
- criteria.offset_value = other.offset_value if other.offset_value
52
- criteria.limit_value = other.limit_value if other.limit_value
53
- criteria.scroll_args = other.scroll_args if other.scroll_args
54
- criteria.source_value = other.source_value if other.source_value
55
- criteria.preference_value = other.preference_value if other.preference_value
56
- criteria.search_type_value = other.search_type_value if other.search_type_value
57
- criteria.routing_value = other.routing_value if other.routing_value
58
- criteria.track_total_hits_value = other.track_total_hits_value unless other.track_total_hits_value.nil?
59
- criteria.explain_value = other.explain_value unless other.explain_value.nil?
60
-
61
- criteria.sort_values = (criteria.sort_values || []) + other.sort_values if other.sort_values
62
- criteria.includes_values = (criteria.includes_values || []) + other.includes_values if other.includes_values
63
- criteria.preload_values = (criteria.preload_values || []) + other.preload_values if other.preload_values
64
- criteria.eager_load_values = (criteria.eager_load_values || []) + other.eager_load_values if other.eager_load_values
65
- criteria.must_values = (criteria.must_values || []) + other.must_values if other.must_values
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
 
@@ -576,7 +566,7 @@ module SearchFlip
576
566
  end
577
567
 
578
568
  def respond_to_missing?(name, *args)
579
- target.respond_to?(name, *args)
569
+ target.respond_to?(name, *args) || super
580
570
  end
581
571
 
582
572
  def method_missing(name, *args, &block)
@@ -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.parse)
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
 
@@ -34,9 +34,10 @@ module SearchFlip
34
34
  criteria.highlight_values = (criteria.highlight_values || {}).merge(options)
35
35
 
36
36
  hash =
37
- if fields.is_a?(Hash)
37
+ case fields
38
+ when Hash
38
39
  fields
39
- elsif fields.is_a?(Array)
40
+ when Array
40
41
  fields.each_with_object({}) { |field, h| h[field] = {} }
41
42
  else
42
43
  { fields => {} }
@@ -1,15 +1,14 @@
1
1
  module SearchFlip
2
- # @api private
3
- #
4
2
  # The SearchFlip::HTTPClient class wraps the http gem, is for internal use
5
3
  # and responsible for the http request/response handling, ie communicating
6
4
  # with Elasticsearch.
7
5
 
8
6
  class HTTPClient
9
- attr_accessor :request
7
+ attr_accessor :request, :plugins
10
8
 
11
- def initialize
9
+ def initialize(plugins: [])
12
10
  self.request = HTTP
11
+ self.plugins = plugins
13
12
  end
14
13
 
15
14
  class << self
@@ -30,17 +29,16 @@ module SearchFlip
30
29
  end
31
30
 
32
31
  [:get, :post, :put, :delete, :head].each do |method|
33
- define_method(method) do |*args|
34
- execute(method, *args)
32
+ define_method(method) do |uri, options = {}|
33
+ execute(method, uri, options)
35
34
  end
36
-
37
- ruby2_keywords method
38
35
  end
39
36
 
40
37
  private
41
38
 
42
- ruby2_keywords def execute(method, *args)
43
- response = request.send(method, *args)
39
+ def execute(method, uri, options = {})
40
+ final_request = plugins.inject(self) { |res, cur| cur.call(res, method, uri, options) }
41
+ response = final_request.request.send(method, uri, options)
44
42
 
45
43
  raise SearchFlip::ResponseError.new(code: response.code, body: response.body.to_s) unless response.status.success?
46
44
 
@@ -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).parse
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).parse
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
@@ -1,16 +1,11 @@
1
1
  module SearchFlip
2
2
  class JSON
3
- @default_options = {
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.generate(obj)
13
- Oj.dump(obj, default_options)
7
+ def self.parse(str)
8
+ Oj.load(str, mode: :compat)
14
9
  end
15
10
  end
16
11
  end
@@ -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 Hashie::Mash. Check out the Hashie docs for further
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.new(bucket) }
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.new response["aggregations"][key]["buckets"]
310
+ SearchFlip::Result.convert(response["aggregations"][key]["buckets"])
312
311
  else
313
- Result.new response["aggregations"][key]
312
+ SearchFlip::Result.convert(response["aggregations"][key])
314
313
  end
315
314
  end
316
315
  end
@@ -1,29 +1,55 @@
1
1
  module SearchFlip
2
- # The SearchFlip::Result class basically is a hash wrapper that uses
3
- # Hashie::Mash to provide convenient method access to the hash attributes.
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 < Hashie::Mash
6
- def self.disable_warnings?(*args)
7
- true
8
- end
10
+ class Result < Hash
11
+ def self.convert(hash)
12
+ res = self[hash]
9
13
 
10
- # Creates a SearchFlip::Result object from a raw hit. Useful for e.g.
11
- # top hits aggregations.
12
- #
13
- # @example
14
- # query = ProductIndex.aggregate(top_sales: { top_hits: "..." })
15
- # top_sales_hits = query.aggregations(:top_sales).top_hits.hits.hits
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
- def self.from_hit(hit)
20
- raw_result = hit["_source"].dup
22
+ res
23
+ end
21
24
 
22
- raw_result["_hit"] = hit.each_with_object({}) do |(key, value), hash|
23
- hash[key] = value if key != "_source"
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
36
+
37
+ # rubocop:disable Lint/MissingSuper
25
38
 
26
- new(raw_result)
39
+ def method_missing(name, *args, &block)
40
+ self[name.to_s]
41
+ end
42
+
43
+ # rubocop:enable Lint/MissingSuper
44
+
45
+ def respond_to_missing?(name, include_private = false)
46
+ key?(name.to_s) || super
47
+ end
48
+
49
+ def self.from_hit(hit)
50
+ res = convert(hit["_source"] || {})
51
+ res["_hit"] = convert(self[hit].tap { |hash| hash.delete("_source") })
52
+ res
27
53
  end
28
54
  end
29
55
  end
@@ -1,3 +1,3 @@
1
1
  module SearchFlip
2
- VERSION = "3.0.0"
2
+ VERSION = "4.0.0.beta1"
3
3
  end
@@ -20,11 +20,12 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.post_install_message = <<~MESSAGE
22
22
  Thanks for using search_flip!
23
- When upgrading to 3.x, please check out
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
 
27
27
  spec.add_development_dependency "activerecord", ">= 3.0"
28
+ spec.add_development_dependency "aws-sdk-core"
28
29
  spec.add_development_dependency "bundler"
29
30
  spec.add_development_dependency "factory_bot"
30
31
  spec.add_development_dependency "rake"
@@ -34,7 +35,6 @@ Gem::Specification.new do |spec|
34
35
  spec.add_development_dependency "timecop"
35
36
  spec.add_development_dependency "webmock"
36
37
 
37
- spec.add_dependency "hashie"
38
38
  spec.add_dependency "http"
39
39
  spec.add_dependency "oj"
40
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[:key]] = bucket.doc_count }
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[:key]] = bucket.doc_count }
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[:key]] = bucket.doc_count }
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[:key]] = bucket.doc_count }
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[:key]] = bucket.doc_count }
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[:key]] = bucket.doc_count }
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[:key]] = bucket.doc_count }
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[:key]] = bucket.doc_count }
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[:key]] = bucket.doc_count }
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[:key]] = bucket.doc_count }
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[:key]] = bucket.doc_count }
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[:key]] = bucket.doc_count
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[:key]] = bucket.doc_count
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[: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)
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
 
@@ -0,0 +1,41 @@
1
+ require File.expand_path("../spec_helper", __dir__)
2
+ require "search_flip/aws_sigv4_plugin"
3
+
4
+ RSpec.describe SearchFlip::AwsSigv4Plugin do
5
+ describe "#call" do
6
+ subject(:plugin) do
7
+ SearchFlip::AwsSigv4Plugin.new(
8
+ region: "us-east-1",
9
+ access_key_id: "access key",
10
+ secret_access_key: "secret access key"
11
+ )
12
+ end
13
+
14
+ let(:client) { SearchFlip::HTTPClient.new }
15
+
16
+ it "adds the signed headers to the request" do
17
+ Timecop.freeze Time.parse("2020-01-01 12:00:00 UTC") do
18
+ expect(client).to receive(:headers).with(
19
+ "host" => "localhost",
20
+ "authorization" => /.*/,
21
+ "x-amz-content-sha256" => /.*/,
22
+ "x-amz-date" => /20200101T120000Z/
23
+ )
24
+
25
+ plugin.call(client, :get, "http://localhost/index")
26
+ end
27
+ end
28
+
29
+ it "feeds the http method, full url and body to the signer" do
30
+ signing_request = {
31
+ http_method: "GET",
32
+ url: "http://localhost/index?param=value",
33
+ body: JSON.generate(key: "value")
34
+ }
35
+
36
+ expect(plugin.signer).to receive(:sign_request).with(signing_request).and_call_original
37
+
38
+ plugin.call(client, :get, "http://localhost/index", params: { param: "value" }, json: { key: "value" })
39
+ end
40
+ end
41
+ end
@@ -36,10 +36,10 @@ RSpec.describe SearchFlip::Connection do
36
36
  it "changes the aliases" do
37
37
  connection = SearchFlip::Connection.new
38
38
 
39
- connection.update_aliases(actions: [add: { index: "products", alias: "alias1" }])
39
+ connection.update_aliases(actions: [{ add: { index: "products", alias: "alias1" } }])
40
40
  expect(connection.get_aliases(alias_name: "alias1").keys).to eq(["products"])
41
41
 
42
- connection.update_aliases(actions: [remove: { index: "products", alias: "alias1" }])
42
+ connection.update_aliases(actions: [{ remove: { index: "products", alias: "alias1" } }])
43
43
  expect(connection.alias_exists?("alias1")).to eq(false)
44
44
  end
45
45
  end
@@ -79,11 +79,11 @@ RSpec.describe SearchFlip::Connection do
79
79
 
80
80
  expect(connection.alias_exists?(:some_alias)).to eq(false)
81
81
 
82
- connection.update_aliases(actions: [add: { index: "products", alias: "some_alias" }])
82
+ connection.update_aliases(actions: [{ add: { index: "products", alias: "some_alias" } }])
83
83
 
84
84
  expect(connection.alias_exists?(:some_alias)).to eq(true)
85
85
  ensure
86
- connection.update_aliases(actions: [remove: { index: "products", alias: "some_alias" }])
86
+ connection.update_aliases(actions: [{ remove: { index: "products", alias: "some_alias" } }])
87
87
  end
88
88
  end
89
89
  end
@@ -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
 
@@ -1291,7 +1301,7 @@ RSpec.describe SearchFlip::Criteria do
1291
1301
  ProductIndex.import create(:product)
1292
1302
 
1293
1303
  query = ProductIndex.match_all.explain(true)
1294
- expect(query.results.first._hit.key?(:_explanation)).to eq(true)
1304
+ expect(query.results.first._hit.key?("_explanation")).to eq(true)
1295
1305
  end
1296
1306
  end
1297
1307
 
@@ -39,6 +39,23 @@ RSpec.describe SearchFlip::HTTPClient do
39
39
  end
40
40
  end
41
41
 
42
+ describe "plugins" do
43
+ subject do
44
+ SearchFlip::HTTPClient.new(
45
+ plugins: [
46
+ ->(request, _method, _uri, _options = {}) { request.headers("First-Header" => "Value") },
47
+ ->(request, _method, _uri, _options = {}) { request.headers("Second-Header" => "Value") }
48
+ ]
49
+ )
50
+ end
51
+
52
+ it "injects the plugins and uses their result in the request" do
53
+ stub_request(:get, "http://localhost/path").with(query: { key: "value" }, headers: { "First-Header" => "Value", "Second-Header" => "Value" }).and_return(body: "success")
54
+
55
+ expect(subject.get("http://localhost/path", params: { key: "value" }).body.to_s).to eq("success")
56
+ end
57
+ end
58
+
42
59
  [:via, :basic_auth, :auth].each do |method|
43
60
  describe "##{method}" do
44
61
  it "creates a dupped instance" do
@@ -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
@@ -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,10 +31,10 @@ 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" }] })
34
+ it "works with the _source being disabled" do
35
+ result = SearchFlip::Result.from_hit("_id" => 1)
13
36
 
14
- expect(result.key1[0].key2).to eq("value")
37
+ expect(result._hit._id).to eq(1)
15
38
  end
16
39
  end
17
40
  end
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: 3.0.0
4
+ version: 4.0.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Vetter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-29 00:00:00.000000000 Z
11
+ date: 2020-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '3.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: bundler
28
+ name: aws-sdk-core
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: factory_bot
42
+ name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rake
56
+ name: factory_bot
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rspec
70
+ name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rubocop
84
+ name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: sqlite3
98
+ name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -109,7 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: timecop
112
+ name: sqlite3
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
@@ -123,7 +123,7 @@ dependencies:
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
- name: webmock
126
+ name: timecop
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - ">="
@@ -137,13 +137,13 @@ dependencies:
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
- name: hashie
140
+ name: webmock
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - ">="
144
144
  - !ruby/object:Gem::Version
145
145
  version: '0'
146
- type: :runtime
146
+ type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
@@ -199,9 +199,9 @@ executables: []
199
199
  extensions: []
200
200
  extra_rdoc_files: []
201
201
  files:
202
+ - ".github/workflows/test.yml"
202
203
  - ".gitignore"
203
204
  - ".rubocop.yml"
204
- - ".travis.yml"
205
205
  - CHANGELOG.md
206
206
  - Gemfile
207
207
  - LICENSE.txt
@@ -212,6 +212,7 @@ files:
212
212
  - lib/search_flip.rb
213
213
  - lib/search_flip/aggregatable.rb
214
214
  - lib/search_flip/aggregation.rb
215
+ - lib/search_flip/aws_sigv4_plugin.rb
215
216
  - lib/search_flip/bulk.rb
216
217
  - lib/search_flip/config.rb
217
218
  - lib/search_flip/connection.rb
@@ -238,11 +239,13 @@ files:
238
239
  - search_flip.gemspec
239
240
  - spec/delegate_matcher.rb
240
241
  - spec/search_flip/aggregation_spec.rb
242
+ - spec/search_flip/aws_sigv4_plugin_spec.rb
241
243
  - spec/search_flip/bulk_spec.rb
242
244
  - spec/search_flip/connection_spec.rb
243
245
  - spec/search_flip/criteria_spec.rb
244
246
  - spec/search_flip/http_client_spec.rb
245
247
  - spec/search_flip/index_spec.rb
248
+ - spec/search_flip/json_spec.rb
246
249
  - spec/search_flip/model_spec.rb
247
250
  - spec/search_flip/null_instrumenter_spec.rb
248
251
  - spec/search_flip/response_spec.rb
@@ -255,7 +258,7 @@ licenses:
255
258
  metadata: {}
256
259
  post_install_message: |
257
260
  Thanks for using search_flip!
258
- When upgrading to 3.x, please check out
261
+ When upgrading major versions, please check out
259
262
  https://github.com/mrkamel/search_flip/blob/master/UPDATING.md
260
263
  rdoc_options: []
261
264
  require_paths:
@@ -267,9 +270,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
267
270
  version: '0'
268
271
  required_rubygems_version: !ruby/object:Gem::Requirement
269
272
  requirements:
270
- - - ">="
273
+ - - ">"
271
274
  - !ruby/object:Gem::Version
272
- version: '0'
275
+ version: 1.3.1
273
276
  requirements: []
274
277
  rubygems_version: 3.0.3
275
278
  signing_key:
@@ -278,11 +281,13 @@ summary: Full-Featured Elasticsearch Ruby Client with a Chainable DSL
278
281
  test_files:
279
282
  - spec/delegate_matcher.rb
280
283
  - spec/search_flip/aggregation_spec.rb
284
+ - spec/search_flip/aws_sigv4_plugin_spec.rb
281
285
  - spec/search_flip/bulk_spec.rb
282
286
  - spec/search_flip/connection_spec.rb
283
287
  - spec/search_flip/criteria_spec.rb
284
288
  - spec/search_flip/http_client_spec.rb
285
289
  - spec/search_flip/index_spec.rb
290
+ - spec/search_flip/json_spec.rb
286
291
  - spec/search_flip/model_spec.rb
287
292
  - spec/search_flip/null_instrumenter_spec.rb
288
293
  - spec/search_flip/response_spec.rb
@@ -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.6.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