elasticsearch 8.8.0 → 8.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c72b5eb32153d9598565613a720c140bef43a1794cebcd5f9f75f977a96700ef
4
- data.tar.gz: 07b1eb4c84634993423f26519d87115c84e70f8a67f952469149209169a4701a
3
+ metadata.gz: 01703b098a99215d5b9b9591ed0e978843b55314b9dfa2d8fcf4abeebbd7dd1e
4
+ data.tar.gz: 907bf243f4dbc446d962b4055e80a08688b2a28c0fe3a087c8c4e8b648600380
5
5
  SHA512:
6
- metadata.gz: 3e0ff385f6834e5a5c8f07db48caaf65e9eb08797f307dc8b9e6869b2202006bbdcb6cd64c9d9d3d4dd4c735340e18aaa019a44f2511ae8b34d07dba74106f41
7
- data.tar.gz: 7b2bed8e82f2c1e421951910143b7455567d6c78dc74775c8502233422c2d20bd6c8249a03d543f82be379dfaab498085f6ae7fab27745788456f68eb0940158
6
+ metadata.gz: 0c1f8db8b41885f95e07b12e28f7d402c2695cb2497d0e1de348918c0f0ca7740731dfad4770bd3319e9df2c216b23e00e73ba4ca51e5be2686ee86f4b3b4889
7
+ data.tar.gz: 4e770597919914ff503d30c3a81bfa38d0361d626eb04e75a7168728baf402ea479bc7a84febde17abf1e7ca85f0a6efdafde429f2d28755966e2ddb06383334
@@ -2,9 +2,11 @@
2
2
 
3
3
  $LOAD_PATH.unshift(File.expand_path('../../elasticsearch/lib', __dir__))
4
4
  $LOAD_PATH.unshift(File.expand_path('../../elasticsearch-api/lib', __dir__))
5
+ $LOAD_PATH.unshift(File.expand_path('../../elasticsearch/lib/elasticsearch/helpers', __dir__))
5
6
 
6
7
  require 'elasticsearch'
7
8
  require 'elasticsearch-api'
9
+ require 'elasticsearch/helpers/bulk_helper'
8
10
 
9
11
  include Elasticsearch
10
12
 
@@ -22,8 +22,8 @@ require 'elasticsearch/version'
22
22
  Gem::Specification.new do |s|
23
23
  s.name = 'elasticsearch'
24
24
  s.version = Elasticsearch::VERSION
25
- s.authors = ['Karel Minarik']
26
- s.email = ['support@elastic.co']
25
+ s.authors = ['Karel Minarik', 'Emily Stolfo', 'Fernando Briano']
26
+ s.email = ['clients-team@elastic.co']
27
27
  s.summary = 'Ruby integrations for Elasticsearch'
28
28
  s.homepage = 'https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/current/index.html'
29
29
  s.license = 'Apache-2.0'
@@ -46,7 +46,7 @@ Gem::Specification.new do |s|
46
46
  s.required_ruby_version = '>= 2.5'
47
47
 
48
48
  s.add_dependency 'elastic-transport', '~> 8'
49
- s.add_dependency 'elasticsearch-api', '8.8.0'
49
+ s.add_dependency 'elasticsearch-api', '8.10.0'
50
50
 
51
51
  s.add_development_dependency 'bundler'
52
52
  s.add_development_dependency 'byebug' unless defined?(JRUBY_VERSION) || defined?(Rubinius)
@@ -0,0 +1,127 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ module Elasticsearch
19
+ module Helpers
20
+ # Elasticsearch Client Helper for the Bulk API
21
+ #
22
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/master/docs-bulk.html
23
+ #
24
+ class BulkHelper
25
+ attr_accessor :index
26
+
27
+ # Create a BulkHelper
28
+ #
29
+ # @param [Elasticsearch::Client] client Instance of Elasticsearch client to use.
30
+ # @param [String] index Index on which to perform the Bulk actions.
31
+ # @param [Hash] params Parameters to re-use in every bulk call
32
+ #
33
+ def initialize(client, index, params = {})
34
+ @client = client
35
+ @index = index
36
+ @params = params
37
+ end
38
+
39
+ # Index documents using the Bulk API.
40
+ #
41
+ # @param [Array<Hash>] docs The documents to be indexed.
42
+ # @param [Hash] params Parameters to use in the bulk ingestion. See the official Elastic documentation for Bulk API for parameters to send to the Bulk API.
43
+ # @option params [Integer] slice number of documents to send to the Bulk API for eatch batch of ingestion.
44
+ # @param block [Block] Optional block to run after ingesting a batch of documents.
45
+ # @yieldparam response [Elasticsearch::Transport::Response] The response object from calling the Bulk API.
46
+ # @yieldparam ingest_docs [Array<Hash>] The collection of documents sent in the bulk request.
47
+ #
48
+ def ingest(docs, params = {}, body = {}, &block)
49
+ ingest_docs = docs.map { |doc| { index: { _index: @index, data: doc} } }
50
+ if (slice = params.delete(:slice))
51
+ ingest_docs.each_slice(slice) { |items| ingest(items, params, &block) }
52
+ else
53
+ bulk_request(ingest_docs, params, &block)
54
+ end
55
+ end
56
+
57
+ # Delete documents using the Bulk API
58
+ #
59
+ # @param [Array] ids Array of id's for documents to delete.
60
+ # @param [Hash] params Parameters to send to bulk delete.
61
+ #
62
+ def delete(ids, params = {}, body = {})
63
+ delete_docs = ids.map { |id| { delete: { _index: @index, _id: id} } }
64
+ @client.bulk({ body: delete_docs }.merge(params.merge(@params)))
65
+ end
66
+
67
+ # Update documents using the Bulk API
68
+ #
69
+ # @param [Array<Hash>] docs (Required) The documents to be updated.
70
+ # @option params [Integer] slice number of documents to send to the Bulk API for eatch batch of updates.
71
+ # @param block [Block] Optional block to run after ingesting a batch of documents.
72
+ #
73
+ # @yieldparam response [Elasticsearch::Transport::Response] The response object from calling the Bulk API.
74
+ # @yieldparam ingest_docs [Array<Hash>] The collection of documents sent in the bulk request.
75
+ #
76
+ def update(docs, params = {}, body = {}, &block)
77
+ ingest_docs = docs.map do |doc|
78
+ { update: { _index: @index, _id: doc.delete('id'), data: { doc: doc } } }
79
+ end
80
+ if (slice = params.delete(:slice))
81
+ ingest_docs.each_slice(slice) { |items| update(items, params, &block) }
82
+ else
83
+ bulk_request(ingest_docs, params, &block)
84
+ end
85
+ end
86
+
87
+ # Ingest data directly from a JSON file
88
+ #
89
+ # @param [String] file (Required) The file path.
90
+ # @param [Hash] params Parameters to use in the bulk ingestion.
91
+ # @option params [Integer] slice number of documents to send to the Bulk API for eatch batch of updates.
92
+ # @option params [Array|String] keys If the data needs to be digged from the JSON file, the
93
+ # keys can be passed in with this parameter to find it.
94
+ #
95
+ # E.g.: If the data in the parsed JSON Hash is found in
96
+ # +json_parsed['data']['items']+, keys would be passed
97
+ # like this (as an Array):
98
+ #
99
+ # +bulk_helper.ingest_json(file, { keys: ['data', 'items'] })+
100
+ #
101
+ # or as a String:
102
+ #
103
+ # +bulk_helper.ingest_json(file, { keys: 'data, items' })+
104
+ #
105
+ # @yieldparam response [Elasticsearch::Transport::Response] The response object from calling the Bulk API.
106
+ # @yieldparam ingest_docs [Array<Hash>] The collection of documents sent in the bulk request.
107
+ #
108
+ def ingest_json(file, params = {}, &block)
109
+ data = JSON.parse(File.read(file))
110
+ if (keys = params.delete(:keys))
111
+ keys = keys.split(',') if keys.is_a?(String)
112
+ data = data.dig(*keys)
113
+ end
114
+
115
+ ingest(data, params, &block)
116
+ end
117
+
118
+ private
119
+
120
+ def bulk_request(ingest_docs, params, &block)
121
+ response = @client.bulk({ body: ingest_docs }.merge(params.merge(@params)))
122
+ yield response, ingest_docs if block_given?
123
+ response
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,95 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ module Elasticsearch
19
+ module Helpers
20
+ # Elasticsearch Client Helper for the Scroll API
21
+ #
22
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/scroll-api.html
23
+ #
24
+ class ScrollHelper
25
+ include Enumerable
26
+
27
+ # Create a ScrollHelper
28
+ #
29
+ # @param [Elasticsearch::Client] client (Required) Instance of Elasticsearch client to use.
30
+ # @param [String] index (Required) Index on which to perform the Bulk actions.
31
+ # @param [Hash] body Body parameters to re-use in every scroll request
32
+ # @param [Time] scroll Specify how long a consistent view of the index should be maintained for scrolled search
33
+ #
34
+ def initialize(client, index, body, scroll = '1m')
35
+ @index = index
36
+ @client = client
37
+ @scroll = scroll
38
+ @body = body
39
+ end
40
+
41
+ # Implementation of +each+ for Enumerable module inclusion
42
+ #
43
+ # @yieldparam document [Hash] yields a document found in the search hits.
44
+ #
45
+ def each(&block)
46
+ @docs = []
47
+ @scroll_id = nil
48
+ refresh_docs
49
+ for doc in @docs do
50
+ refresh_docs
51
+ yield doc
52
+ end
53
+ clear
54
+ end
55
+
56
+ # Results from a scroll.
57
+ # Can be called repeatedly (e.g. in a loop) to get the scroll pages.
58
+ #
59
+ def results
60
+ if @scroll_id
61
+ scroll_request
62
+ else
63
+ initial_search
64
+ end
65
+ rescue StandardError => e
66
+ raise e
67
+ end
68
+
69
+ # Clear Scroll and resets inner documents collection
70
+ #
71
+ def clear
72
+ @client.clear_scroll(body: { scroll_id: @scroll_id }) if @scroll_id
73
+ @docs = []
74
+ end
75
+
76
+ private
77
+
78
+ def refresh_docs
79
+ @docs ||= []
80
+ @docs << results
81
+ @docs.flatten!
82
+ end
83
+
84
+ def initial_search
85
+ response = @client.search(index: @index, scroll: @scroll, body: @body)
86
+ @scroll_id = response['_scroll_id']
87
+ response['hits']['hits']
88
+ end
89
+
90
+ def scroll_request
91
+ @client.scroll(body: {scroll: @scroll, scroll_id: @scroll_id})['hits']['hits']
92
+ end
93
+ end
94
+ end
95
+ end
@@ -16,5 +16,5 @@
16
16
  # under the License.
17
17
 
18
18
  module Elasticsearch
19
- VERSION = '8.8.0'.freeze
19
+ VERSION = '8.10.0'.freeze
20
20
  end
data/lib/elasticsearch.rb CHANGED
@@ -35,24 +35,22 @@ module Elasticsearch
35
35
 
36
36
  # Create a client connected to an Elasticsearch cluster.
37
37
  #
38
+ # @param [Hash] arguments - initializer arguments
38
39
  # @option arguments [String] :cloud_id - The Cloud ID to connect to Elastic Cloud
39
- # @option api_key [String, Hash] :api_key Use API Key Authentication, either the base64 encoding of `id` and `api_key`
40
- # joined by a colon as a String, or a hash with the `id` and `api_key` values.
41
- # @option opaque_id_prefix [String] :opaque_id_prefix set a prefix for X-Opaque-Id when initializing the client.
42
- # This will be prepended to the id you set before each request
43
- # if you're using X-Opaque-Id
40
+ # @option arguments [String, Hash] :api_key Use API Key Authentication, either the base64 encoding of `id` and `api_key`
41
+ # joined by a colon as a String, or a hash with the `id` and `api_key` values.
42
+ # @option arguments [String] :opaque_id_prefix set a prefix for X-Opaque-Id when initializing the client.
43
+ # This will be prepended to the id you set before each request
44
+ # if you're using X-Opaque-Id
45
+ # @option arguments [Hash] :headers Custom HTTP Request Headers
46
+ #
44
47
  def initialize(arguments = {}, &block)
45
48
  @verified = false
49
+ @warned = false
46
50
  @opaque_id_prefix = arguments[:opaque_id_prefix] || nil
47
51
  api_key(arguments) if arguments[:api_key]
48
- if arguments[:cloud_id]
49
- arguments[:hosts] = setup_cloud_host(
50
- arguments[:cloud_id],
51
- arguments[:user],
52
- arguments[:password],
53
- arguments[:port]
54
- )
55
- end
52
+ setup_cloud(arguments) if arguments[:cloud_id]
53
+ set_user_agent!(arguments) unless sent_user_agent?(arguments)
56
54
  @transport = Elastic::Transport::Client.new(arguments, &block)
57
55
  end
58
56
 
@@ -67,8 +65,11 @@ module Elasticsearch
67
65
  opaque_id = @opaque_id_prefix ? "#{@opaque_id_prefix}#{opaque_id}" : opaque_id
68
66
  args[4] = headers.merge('X-Opaque-Id' => opaque_id)
69
67
  end
70
- verify_elasticsearch unless @verified
71
- @transport.perform_request(*args, &block)
68
+ unless @verified
69
+ verify_elasticsearch(*args, &block)
70
+ else
71
+ @transport.perform_request(*args, &block)
72
+ end
72
73
  else
73
74
  @transport.send(name, *args, &block)
74
75
  end
@@ -80,42 +81,28 @@ module Elasticsearch
80
81
 
81
82
  private
82
83
 
83
- def verify_elasticsearch
84
+ def verify_elasticsearch(*args, &block)
84
85
  begin
85
- response = elasticsearch_validation_request
86
+ response = @transport.perform_request(*args, &block)
86
87
  rescue Elastic::Transport::Transport::Errors::Unauthorized,
87
88
  Elastic::Transport::Transport::Errors::Forbidden,
88
- Elastic::Transport::Transport::Errors::RequestEntityTooLarge
89
- @verified = true
89
+ Elastic::Transport::Transport::Errors::RequestEntityTooLarge => e
90
90
  warn(SECURITY_PRIVILEGES_VALIDATION_WARNING)
91
- return
92
- rescue Elastic::Transport::Transport::Error
91
+ @verified = true
92
+ raise e
93
+ rescue Elastic::Transport::Transport::Error => e
94
+ unless @warned
95
+ warn(VALIDATION_WARNING)
96
+ @warned = true
97
+ end
98
+ raise e
99
+ rescue StandardError => e
93
100
  warn(VALIDATION_WARNING)
94
- return
101
+ raise e
95
102
  end
96
-
97
- body = if response.headers['content-type'] == 'application/yaml'
98
- require 'yaml'
99
- YAML.safe_load(response.body)
100
- else
101
- response.body
102
- end
103
- version = body.dig('version', 'number')
104
- verify_with_version_or_header(version, response.headers)
105
- rescue StandardError => e
106
- warn(VALIDATION_WARNING)
107
- raise e
108
- end
109
-
110
- def verify_with_version_or_header(version, headers)
111
- if version.nil? ||
112
- Gem::Version.new(version) < Gem::Version.new('8.0.0.pre') && version != '8.0.0-SNAPSHOT' ||
113
- headers['x-elastic-product'] != 'Elasticsearch'
114
-
115
- raise Elasticsearch::UnsupportedProductError
116
- end
117
-
103
+ raise Elasticsearch::UnsupportedProductError unless response.headers['x-elastic-product'] == 'Elasticsearch'
118
104
  @verified = true
105
+ response
119
106
  end
120
107
 
121
108
  def setup_cloud_host(cloud_id, user, password, port)
@@ -149,6 +136,15 @@ module Elasticsearch
149
136
  end
150
137
  end
151
138
 
139
+ def setup_cloud(arguments)
140
+ arguments[:hosts] = setup_cloud_host(
141
+ arguments[:cloud_id],
142
+ arguments[:user],
143
+ arguments[:password],
144
+ arguments[:port]
145
+ )
146
+ end
147
+
152
148
  # Encode credentials for the Authorization Header
153
149
  # Credentials is the base64 encoding of id and api_key joined by a colon
154
150
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html
@@ -159,6 +155,25 @@ module Elasticsearch
159
155
  def elasticsearch_validation_request
160
156
  @transport.perform_request('GET', '/')
161
157
  end
158
+
159
+ def sent_user_agent?(arguments)
160
+ return unless (headers = arguments&.[](:transport_options)&.[](:headers))
161
+ !!headers.keys.detect { |h| h =~ /user-?_?agent/ }
162
+ end
163
+
164
+ def set_user_agent!(arguments)
165
+ user_agent = [
166
+ "elasticsearch-ruby/#{Elasticsearch::VERSION}",
167
+ "elastic-transport-ruby/#{Elastic::Transport::VERSION}",
168
+ "RUBY_VERSION: #{RUBY_VERSION}"
169
+ ]
170
+ if RbConfig::CONFIG && RbConfig::CONFIG['host_os']
171
+ user_agent << "#{RbConfig::CONFIG['host_os'].split('_').first[/[a-z]+/i].downcase} #{RbConfig::CONFIG['target_cpu']}"
172
+ end
173
+ arguments[:transport_options] ||= {}
174
+ arguments[:transport_options][:headers] ||= {}
175
+ arguments[:transport_options][:headers].merge!({ user_agent: user_agent.join('; ')})
176
+ end
162
177
  end
163
178
 
164
179
  # Error class for when we detect an unsupported version of Elasticsearch
@@ -0,0 +1,211 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+ ELASTICSEARCH_URL = ENV['TEST_ES_SERVER'] || "http://localhost:#{(ENV['PORT'] || 9200)}"
18
+ raise URI::InvalidURIError unless ELASTICSEARCH_URL =~ /\A#{URI::DEFAULT_PARSER.make_regexp}\z/
19
+
20
+ require 'elasticsearch/helpers/bulk_helper'
21
+ require 'spec_helper'
22
+ require 'tempfile'
23
+
24
+ context 'Elasticsearch client helpers' do
25
+ context 'Bulk helper' do
26
+ let(:client) do
27
+ Elasticsearch::Client.new(
28
+ host: ELASTICSEARCH_URL,
29
+ user: 'elastic',
30
+ password: 'changeme'
31
+ )
32
+ end
33
+ let(:index) { 'bulk_animals' }
34
+ let(:params) { { refresh: 'wait_for' } }
35
+ let(:bulk_helper) { Elasticsearch::Helpers::BulkHelper.new(client, index, params) }
36
+ let(:docs) do
37
+ [
38
+ { scientific_name: 'Lama guanicoe', name:'Guanaco' },
39
+ { scientific_name: 'Tayassu pecari', name:'White-lipped peccary' },
40
+ { scientific_name: 'Snycerus caffer', name:'Buffalo, african' },
41
+ { scientific_name: 'Coluber constrictor', name:'Snake, racer' },
42
+ { scientific_name: 'Thalasseus maximus', name:'Royal tern' },
43
+ { scientific_name: 'Centrocercus urophasianus', name:'Hen, sage' },
44
+ { scientific_name: 'Sitta canadensis', name:'Nuthatch, red-breasted' },
45
+ { scientific_name: 'Aegypius tracheliotus', name:'Vulture, lappet-faced' },
46
+ { scientific_name: 'Bucephala clangula', name:'Common goldeneye' },
47
+ { scientific_name: 'Felis pardalis', name:'Ocelot' }
48
+ ]
49
+ end
50
+
51
+ after do
52
+ client.indices.delete(index: index, ignore: 404)
53
+ end
54
+
55
+ it 'Ingests documents' do
56
+ response = bulk_helper.ingest(docs)
57
+ expect(response).to be_an_instance_of Elasticsearch::API::Response
58
+ expect(response.status).to eq(200)
59
+ expect(response['items'].map { |a| a['index']['status'] }.uniq.first).to eq 201
60
+ end
61
+
62
+ it 'Updates documents' do
63
+ docs = [
64
+ { scientific_name: 'Otocyon megalotos', name: 'Bat-eared fox' },
65
+ { scientific_name: 'Herpestes javanicus', name: 'Small Indian mongoose' }
66
+ ]
67
+ bulk_helper.ingest(docs)
68
+ # Get the ingested documents, add id and modify them to update them:
69
+ animals = client.search(index: index)['hits']['hits']
70
+ # Add id to each doc
71
+ docs = animals.map { |animal| animal['_source'].merge({'id' => animal['_id'] }) }
72
+ docs.map { |doc| doc['scientific_name'].upcase! }
73
+ response = bulk_helper.update(docs)
74
+ expect(response.status).to eq(200)
75
+ expect(response['items'].map { |i| i['update']['result'] }.uniq.first).to eq('updated')
76
+ end
77
+
78
+ it 'Deletes documents' do
79
+ response = bulk_helper.ingest(docs)
80
+ ids = response.body['items'].map { |a| a['index']['_id'] }
81
+ response = bulk_helper.delete(ids)
82
+ expect(response.status).to eq 200
83
+ expect(response['items'].map { |item| item['delete']['result'] }.uniq.first).to eq('deleted')
84
+ expect(client.count(index: index)['count']).to eq(0)
85
+ end
86
+
87
+ it 'Ingests documents and yields response and docs' do
88
+ slice = 2
89
+ response = bulk_helper.ingest(docs, {slice: slice}) do |response, docs|
90
+ expect(response).to be_an_instance_of Elasticsearch::API::Response
91
+ expect(docs.count).to eq slice
92
+ end
93
+ end
94
+
95
+ context 'JSON File helper' do
96
+ let(:file) { Tempfile.new('test-data.json') }
97
+ let(:json) do
98
+ json = <<~JSON
99
+ [
100
+ {
101
+ "character_name": "Anallese Lonie",
102
+ "species": "mouse",
103
+ "catchphrase": "Seamless regional definition",
104
+ "favorite_food": "pizza"
105
+ },
106
+ {
107
+ "character_name": "Janey Davidovsky",
108
+ "species": "cat",
109
+ "catchphrase": "Down-sized responsive pricing structure",
110
+ "favorite_food": "pizza"
111
+ },
112
+ {
113
+ "character_name": "Morse Mountford",
114
+ "species": "cat",
115
+ "catchphrase": "Ameliorated modular data-warehouse",
116
+ "favorite_food": "carrots"
117
+ },
118
+ {
119
+ "character_name": "Saundra Kauble",
120
+ "species": "dog",
121
+ "catchphrase": "Synchronised 24/7 support",
122
+ "favorite_food": "carrots"
123
+ },
124
+ {
125
+ "character_name": "Kain Viggars",
126
+ "species": "cat",
127
+ "catchphrase": "Open-architected asymmetric circuit",
128
+ "favorite_food": "carrots"
129
+ }
130
+ ]
131
+ JSON
132
+ end
133
+
134
+ before do
135
+ file.write(json)
136
+ file.rewind
137
+ end
138
+
139
+ after do
140
+ file.close
141
+ file.unlink
142
+ end
143
+
144
+ it 'Ingests a JSON file' do
145
+ response = bulk_helper.ingest_json(file)
146
+
147
+ expect(response).to be_an_instance_of Elasticsearch::API::Response
148
+ expect(response.status).to eq(200)
149
+ end
150
+
151
+ context 'with data not in root of JSON file' do
152
+ let(:json) do
153
+ json = <<~JSON
154
+ {
155
+ "field": "value",
156
+ "status": 200,
157
+ "data": {
158
+ "items": [
159
+ {
160
+ "character_name": "Anallese Lonie",
161
+ "species": "mouse",
162
+ "catchphrase": "Seamless regional definition",
163
+ "favorite_food": "pizza"
164
+ },
165
+ {
166
+ "character_name": "Janey Davidovsky",
167
+ "species": "cat",
168
+ "catchphrase": "Down-sized responsive pricing structure",
169
+ "favorite_food": "pizza"
170
+ },
171
+ {
172
+ "character_name": "Morse Mountford",
173
+ "species": "cat",
174
+ "catchphrase": "Ameliorated modular data-warehouse",
175
+ "favorite_food": "carrots"
176
+ },
177
+ {
178
+ "character_name": "Saundra Kauble",
179
+ "species": "dog",
180
+ "catchphrase": "Synchronised 24/7 support",
181
+ "favorite_food": "carrots"
182
+ },
183
+ {
184
+ "character_name": "Kain Viggars",
185
+ "species": "cat",
186
+ "catchphrase": "Open-architected asymmetric circuit",
187
+ "favorite_food": "carrots"
188
+ }
189
+ ]
190
+ }
191
+ }
192
+ JSON
193
+ end
194
+
195
+ it 'Ingests a JSON file passing keys as Array' do
196
+ response = bulk_helper.ingest_json(file, { keys: ['data', 'items'] })
197
+ expect(response).to be_an_instance_of Elasticsearch::API::Response
198
+ expect(response.status).to eq(200)
199
+ expect(response['items'].map { |a| a['index']['status'] }.uniq.first).to eq 201
200
+ end
201
+
202
+ it 'Ingests a JSON file passing keys as String' do
203
+ response = bulk_helper.ingest_json(file, { keys: 'data,items' })
204
+ expect(response).to be_an_instance_of Elasticsearch::API::Response
205
+ expect(response.status).to eq(200)
206
+ expect(response['items'].map { |a| a['index']['status'] }.uniq.first).to eq 201
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,91 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+ ELASTICSEARCH_URL = ENV['TEST_ES_SERVER'] || "http://localhost:#{(ENV['PORT'] || 9200)}"
18
+ raise URI::InvalidURIError unless ELASTICSEARCH_URL =~ /\A#{URI::DEFAULT_PARSER.make_regexp}\z/
19
+
20
+ require 'spec_helper'
21
+ require 'elasticsearch/helpers/scroll_helper'
22
+
23
+ context 'Elasticsearch client helpers' do
24
+ let(:client) do
25
+ Elasticsearch::Client.new(
26
+ host: ELASTICSEARCH_URL,
27
+ user: 'elastic',
28
+ password: 'changeme'
29
+ )
30
+ end
31
+ let(:index) { 'books' }
32
+ let(:body) { { size: 12, query: { match_all: {} } } }
33
+ let(:scroll_helper) { Elasticsearch::Helpers::ScrollHelper.new(client, index, body) }
34
+
35
+ before do
36
+ documents = [
37
+ { index: { _index: index, data: {name: "Leviathan Wakes", "author": "James S.A. Corey", "release_date": "2011-06-02", "page_count": 561} } },
38
+ { index: { _index: index, data: {name: "Hyperion", "author": "Dan Simmons", "release_date": "1989-05-26", "page_count": 482} } },
39
+ { index: { _index: index, data: {name: "Dune", "author": "Frank Herbert", "release_date": "1965-06-01", "page_count": 604} } },
40
+ { index: { _index: index, data: {name: "Dune Messiah", "author": "Frank Herbert", "release_date": "1969-10-15", "page_count": 331} } },
41
+ { index: { _index: index, data: {name: "Children of Dune", "author": "Frank Herbert", "release_date": "1976-04-21", "page_count": 408} } },
42
+ { index: { _index: index, data: {name: "God Emperor of Dune", "author": "Frank Herbert", "release_date": "1981-05-28", "page_count": 454} } },
43
+ { index: { _index: index, data: {name: "Consider Phlebas", "author": "Iain M. Banks", "release_date": "1987-04-23", "page_count": 471} } },
44
+ { index: { _index: index, data: {name: "Pandora's Star", "author": "Peter F. Hamilton", "release_date": "2004-03-02", "page_count": 768} } },
45
+ { index: { _index: index, data: {name: "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585} } },
46
+ { index: { _index: index, data: {name: "A Fire Upon the Deep", "author": "Vernor Vinge", "release_date": "1992-06-01", "page_count": 613} } },
47
+ { index: { _index: index, data: {name: "Ender's Game", "author": "Orson Scott Card", "release_date": "1985-06-01", "page_count": 324} } },
48
+ { index: { _index: index, data: {name: "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328} } },
49
+ { index: { _index: index, data: {name: "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227} } },
50
+ { index: { _index: index, data: {name: "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268} } },
51
+ { index: { _index: index, data: {name: "Foundation", "author": "Isaac Asimov", "release_date": "1951-06-01", "page_count": 224} } },
52
+ { index: { _index: index, data: {name: "The Giver", "author": "Lois Lowry", "release_date": "1993-04-26", "page_count": 208} } },
53
+ { index: { _index: index, data: {name: "Slaughterhouse-Five", "author": "Kurt Vonnegut", "release_date": "1969-06-01", "page_count": 275} } },
54
+ { index: { _index: index, data: {name: "The Hitchhiker's Guide to the Galaxy", "author": "Douglas Adams", "release_date": "1979-10-12", "page_count": 180} } },
55
+ { index: { _index: index, data: {name: "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470} } },
56
+ { index: { _index: index, data: {name: "Neuromancer", "author": "William Gibson", "release_date": "1984-07-01", "page_count": 271} } },
57
+ { index: { _index: index, data: {name: "The Handmaid's Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311} } },
58
+ { index: { _index: index, data: {name: "Starship Troopers", "author": "Robert A. Heinlein", "release_date": "1959-12-01", "page_count": 335} } },
59
+ { index: { _index: index, data: {name: "The Left Hand of Darkness", "author": "Ursula K. Le Guin", "release_date": "1969-06-01", "page_count": 304} } },
60
+ { index: { _index: index, data: {name: "The Moon is a Harsh Mistress", "author": "Robert A. Heinlein", "release_date": "1966-04-01", "page_count": 288 } } }
61
+ ]
62
+ client.bulk(body: documents, refresh: 'wait_for')
63
+ end
64
+
65
+ after do
66
+ client.indices.delete(index: index)
67
+ end
68
+
69
+ it 'instantiates a scroll helper' do
70
+ expect(scroll_helper).to be_an_instance_of Elasticsearch::Helpers::ScrollHelper
71
+ end
72
+
73
+ it 'searches an index' do
74
+ my_documents = []
75
+ while !(documents = scroll_helper.results).empty?
76
+ my_documents << documents
77
+ end
78
+
79
+ expect(my_documents.flatten.size).to eq 24
80
+ end
81
+
82
+ it 'uses enumerable' do
83
+ count = 0
84
+ scroll_helper.each { |a| count += 1 }
85
+ expect(count).to eq 24
86
+ expect(scroll_helper).to respond_to(:count)
87
+ expect(scroll_helper).to respond_to(:reject)
88
+ expect(scroll_helper).to respond_to(:uniq)
89
+ expect(scroll_helper.map { |a| a['_id'] }.uniq.count).to eq 24
90
+ end
91
+ end
@@ -20,52 +20,28 @@ require 'webmock/rspec'
20
20
 
21
21
  describe 'Elasticsearch: Validation' do
22
22
  let(:host) { 'http://localhost:9200' }
23
- let(:verify_request_stub) do
24
- stub_request(:get, host)
25
- .to_return(status: status, body: body, headers: headers)
26
- end
27
23
  let(:count_request_stub) do
28
24
  stub_request(:get, "#{host}/_count")
29
- .to_return(status: 200, body: nil, headers: {})
25
+ .to_return(status: status, body: nil, headers: headers)
30
26
  end
31
27
  let(:status) { 200 }
32
- let(:body) { {}.to_json }
28
+ let(:body) { nil }
29
+ let(:headers) { {} }
33
30
  let(:client) { Elasticsearch::Client.new }
34
- let(:headers) do
35
- { 'content-type' => 'application/json' }
36
- end
37
-
38
- def error_requests_and_expectations(message = Elasticsearch::NOT_ELASTICSEARCH_WARNING)
39
- expect { client.count }.to raise_error Elasticsearch::UnsupportedProductError, message
40
- assert_requested :get, host
41
- assert_not_requested :post, "#{host}/_count"
42
- expect { client.cluster.health }.to raise_error Elasticsearch::UnsupportedProductError, message
43
- expect(client.instance_variable_get('@verified')).to be false
44
- expect { client.cluster.health }.to raise_error Elasticsearch::UnsupportedProductError, message
45
- end
46
-
47
- def valid_requests_and_expectations
48
- expect(client.instance_variable_get('@verified')).to be false
49
- assert_not_requested :get, host
50
-
51
- client.count
52
- expect(client.instance_variable_get('@verified'))
53
- assert_requested :get, host
54
- assert_requested :get, "#{host}/_count"
55
- end
56
31
 
57
32
  context 'When Elasticsearch replies with status 401' do
58
33
  let(:status) { 401 }
59
- let(:body) { {}.to_json }
60
34
 
61
35
  it 'Verifies the request but shows a warning' do
62
36
  stderr = $stderr
63
37
  fake_stderr = StringIO.new
64
38
  $stderr = fake_stderr
65
-
66
- verify_request_stub
39
+ expect(client.instance_variable_get('@verified')).to be false
67
40
  count_request_stub
68
- valid_requests_and_expectations
41
+ expect do
42
+ client.count
43
+ end.to raise_error Elastic::Transport::Transport::Errors::Unauthorized
44
+ expect(client.instance_variable_get('@verified')).to be true
69
45
 
70
46
  fake_stderr.rewind
71
47
  expect(fake_stderr.string).to eq("#{Elasticsearch::SECURITY_PRIVILEGES_VALIDATION_WARNING}\n")
@@ -76,16 +52,18 @@ describe 'Elasticsearch: Validation' do
76
52
 
77
53
  context 'When Elasticsearch replies with status 403' do
78
54
  let(:status) { 403 }
79
- let(:body) { {}.to_json }
80
55
 
81
56
  it 'Verifies the request but shows a warning' do
82
57
  stderr = $stderr
83
58
  fake_stderr = StringIO.new
84
59
  $stderr = fake_stderr
85
60
 
86
- verify_request_stub
61
+ expect(client.instance_variable_get('@verified')).to be false
87
62
  count_request_stub
88
- valid_requests_and_expectations
63
+ expect do
64
+ client.count
65
+ end.to raise_error Elastic::Transport::Transport::Errors::Forbidden
66
+ expect(client.instance_variable_get('@verified')).to be true
89
67
 
90
68
  fake_stderr.rewind
91
69
  expect(fake_stderr.string).to eq("#{Elasticsearch::SECURITY_PRIVILEGES_VALIDATION_WARNING}\n")
@@ -96,7 +74,6 @@ describe 'Elasticsearch: Validation' do
96
74
 
97
75
  context 'When Elasticsearch replies with status 413' do
98
76
  let(:status) { 413 }
99
- let(:body) { {}.to_json }
100
77
 
101
78
  it 'Verifies the request and shows a warning' do
102
79
  stderr = $stderr
@@ -104,9 +81,10 @@ describe 'Elasticsearch: Validation' do
104
81
  $stderr = fake_stderr
105
82
 
106
83
  expect(client.instance_variable_get('@verified')).to be false
107
- assert_not_requested :get, host
108
- verify_request_stub
109
- expect { client.info }.to raise_error Elastic::Transport::Transport::Errors::RequestEntityTooLarge
84
+ count_request_stub
85
+ expect do
86
+ client.count
87
+ end.to raise_error Elastic::Transport::Transport::Errors::RequestEntityTooLarge
110
88
  expect(client.instance_variable_get('@verified')).to be true
111
89
 
112
90
  fake_stderr.rewind
@@ -127,10 +105,10 @@ describe 'Elasticsearch: Validation' do
127
105
  $stderr = fake_stderr
128
106
 
129
107
  expect(client.instance_variable_get('@verified')).to be false
130
- assert_not_requested :get, host
131
- verify_request_stub
132
- expect { client.info }.to raise_error Elastic::Transport::Transport::Errors::ServiceUnavailable
133
- assert_not_requested :post, "#{host}/_count"
108
+ count_request_stub
109
+ expect do
110
+ client.count
111
+ end.to raise_error Elastic::Transport::Transport::Errors::ServiceUnavailable
134
112
  expect(client.instance_variable_get('@verified')).to be false
135
113
 
136
114
  fake_stderr.rewind
@@ -147,156 +125,24 @@ describe 'Elasticsearch: Validation' do
147
125
  end
148
126
  end
149
127
 
128
+ context 'When the header is present' do
129
+ let(:headers) { { 'X-Elastic-Product' => 'Elasticsearch' } }
150
130
 
151
- context 'When the Elasticsearch version is >= 8.0.0' do
152
- context 'With a valid Elasticsearch response' do
153
- let(:body) { { 'version' => { 'number' => '8.0.0' } }.to_json }
154
- let(:headers) do
155
- {
156
- 'X-Elastic-Product' => 'Elasticsearch',
157
- 'content-type' => 'json'
158
- }
159
- end
160
-
161
- it 'Makes requests and passes validation' do
162
- verify_request_stub
163
- count_request_stub
164
-
165
- valid_requests_and_expectations
166
- end
167
- end
168
-
169
- context 'When the header is not present' do
170
- it 'Fails validation' do
171
- verify_request_stub
172
-
173
- expect(client.instance_variable_get('@verified')).to be false
174
- assert_not_requested :get, host
175
-
176
- error_requests_and_expectations
177
- end
178
- end
179
- end
180
-
181
- context 'When the Elasticsearch version is >= 8.1.0' do
182
- context 'With a valid Elasticsearch response' do
183
- let(:body) { { 'version' => { 'number' => '8.1.0' } }.to_json }
184
- let(:headers) do
185
- {
186
- 'X-Elastic-Product' => 'Elasticsearch',
187
- 'content-type' => 'json'
188
- }
189
- end
190
-
191
- it 'Makes requests and passes validation' do
192
- verify_request_stub
193
- count_request_stub
194
-
195
- valid_requests_and_expectations
196
- end
197
- end
198
-
199
- context 'When the header is not present' do
200
- it 'Fails validation' do
201
- verify_request_stub
202
-
203
- expect(client.instance_variable_get('@verified')).to be false
204
- assert_not_requested :get, host
205
-
206
- error_requests_and_expectations
207
- end
208
- end
209
- end
210
-
211
-
212
- context 'When the Elasticsearch version is 8.0.0.pre' do
213
- context 'With a valid Elasticsearch response' do
214
- let(:body) { { 'version' => { 'number' => '8.0.0.pre' } }.to_json }
215
- let(:headers) do
216
- {
217
- 'X-Elastic-Product' => 'Elasticsearch',
218
- 'content-type' => 'json'
219
- }
220
- end
221
-
222
- it 'Makes requests and passes validation' do
223
- verify_request_stub
224
- count_request_stub
225
-
226
- valid_requests_and_expectations
227
- end
228
- end
229
-
230
- context 'When the header is not present' do
231
- it 'Fails validation' do
232
- verify_request_stub
233
-
234
- expect(client.instance_variable_get('@verified')).to be false
235
- assert_not_requested :get, host
236
-
237
- error_requests_and_expectations
238
- end
239
- end
240
- end
241
-
242
- context 'When the version is 8.0.0-SNAPSHOT' do
243
- let(:body) { { 'version' => { 'number' => '8.0.0-SNAPSHOT' } }.to_json }
244
-
245
- context 'When the header is not present' do
246
- it 'Fails validation' do
247
- verify_request_stub
248
- count_request_stub
249
-
250
- error_requests_and_expectations
251
- end
252
- end
253
-
254
- context 'With a valid Elasticsearch response' do
255
- let(:headers) do
256
- {
257
- 'X-Elastic-Product' => 'Elasticsearch',
258
- 'content-type' => 'json'
259
- }
260
- end
261
-
262
- it 'Makes requests and passes validation' do
263
- verify_request_stub
264
- count_request_stub
265
-
266
- valid_requests_and_expectations
267
- end
268
- end
269
- end
270
-
271
- context 'When Elasticsearch version is < 8.0.0' do
272
- let(:body) { { 'version' => { 'number' => '7.16.0' } }.to_json }
273
-
274
- it 'Raises an exception and client doesnae work' do
275
- verify_request_stub
276
- error_requests_and_expectations
277
- end
278
- end
279
-
280
- context 'When there is no version data' do
281
- let(:body) { {}.to_json }
282
- it 'Raises an exception and client doesnae work' do
283
- verify_request_stub
284
- error_requests_and_expectations
131
+ it 'Makes requests and passes validation' do
132
+ expect(client.instance_variable_get('@verified')).to be false
133
+ count_request_stub
134
+ client.count
135
+ expect(client.instance_variable_get('@verified')).to be true
285
136
  end
286
137
  end
287
138
 
288
- context 'When doing a yaml content-type request' do
289
- let(:client) do
290
- Elasticsearch::Client.new(transport_options: {headers: { accept: 'application/yaml', content_type: 'application/yaml' }})
291
- end
292
-
293
- let(:headers) { { 'content-type' => 'application/yaml', 'X-Elastic-Product' => 'Elasticsearch' } }
294
- let(:body) { "---\nversion:\n number: \"8.0.0-SNAPSHOT\"\n" }
295
-
296
- it 'validates' do
297
- verify_request_stub
298
- count_request_stub
299
- valid_requests_and_expectations
139
+ context 'When the header is not present' do
140
+ it 'Fails validation' do
141
+ expect(client.instance_variable_get('@verified')).to be false
142
+ stub_request(:get, "#{host}/_cluster/health")
143
+ .to_return(status: status, body: nil, headers: {})
144
+ expect { client.cluster.health }.to raise_error Elasticsearch::UnsupportedProductError, Elasticsearch::NOT_ELASTICSEARCH_WARNING
145
+ expect(client.instance_variable_get('@verified')).to be false
300
146
  end
301
147
  end
302
148
  end
@@ -0,0 +1,69 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+ require 'spec_helper'
18
+
19
+ describe Elasticsearch::Client do
20
+ let(:user_agent) {
21
+ "elasticsearch-ruby/#{Elasticsearch::VERSION}; elastic-transport-ruby/#{Elastic::Transport::VERSION}; RUBY_VERSION: #{RUBY_VERSION}; #{RbConfig::CONFIG['host_os'].split('_').first[/[a-z]+/i].downcase} #{RbConfig::CONFIG['target_cpu']}"
22
+ }
23
+
24
+ context 'when no user-agent is set on initialization' do
25
+ let(:client) { described_class.new }
26
+
27
+ it 'has the expected header' do
28
+ expect(client.transport.options[:transport_options][:headers][:user_agent]).to eq user_agent
29
+ end
30
+ end
31
+
32
+ context 'when a header is specified on initialization' do
33
+ let(:client) do
34
+ described_class.new(
35
+ transport_options: { headers: { 'X-Test-Header' => 'Test' } }
36
+ )
37
+ end
38
+
39
+ it 'has the expected header' do
40
+ expect(client.transport.options[:transport_options][:headers][:user_agent]).to eq user_agent
41
+ expect(client.transport.options[:transport_options][:headers]['X-Test-Header']).to eq 'Test'
42
+ end
43
+ end
44
+
45
+ context 'when other transport_options are specified on initialization' do
46
+ let(:client) do
47
+ described_class.new(
48
+ transport_options: { params: { format: 'yaml' } }
49
+ )
50
+ end
51
+
52
+ it 'has the expected header' do
53
+ expect(client.transport.options[:transport_options][:headers][:user_agent]).to eq user_agent
54
+ expect(client.transport.options[:transport_options][:params][:format]).to eq 'yaml'
55
+ end
56
+ end
57
+
58
+ context 'when :user_agent is specified on initialization' do
59
+ let(:client) do
60
+ described_class.new(
61
+ transport_options: { headers: { user_agent: 'TestApp' } }
62
+ )
63
+ end
64
+
65
+ it 'has the expected header' do
66
+ expect(client.transport.options[:transport_options][:headers][:user_agent]).to eq 'TestApp'
67
+ end
68
+ end
69
+ end
metadata CHANGED
@@ -1,14 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.8.0
4
+ version: 8.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Karel Minarik
8
+ - Emily Stolfo
9
+ - Fernando Briano
8
10
  autorequire:
9
11
  bindir: bin
10
12
  cert_chain: []
11
- date: 2023-05-25 00:00:00.000000000 Z
13
+ date: 2023-09-12 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: elastic-transport
@@ -30,14 +32,14 @@ dependencies:
30
32
  requirements:
31
33
  - - '='
32
34
  - !ruby/object:Gem::Version
33
- version: 8.8.0
35
+ version: 8.10.0
34
36
  type: :runtime
35
37
  prerelease: false
36
38
  version_requirements: !ruby/object:Gem::Requirement
37
39
  requirements:
38
40
  - - '='
39
41
  - !ruby/object:Gem::Version
40
- version: 8.8.0
42
+ version: 8.10.0
41
43
  - !ruby/object:Gem::Dependency
42
44
  name: bundler
43
45
  requirement: !ruby/object:Gem::Requirement
@@ -182,7 +184,7 @@ description: 'Ruby integrations for Elasticsearch (client, API, etc.)
182
184
 
183
185
  '
184
186
  email:
185
- - support@elastic.co
187
+ - clients-team@elastic.co
186
188
  executables:
187
189
  - elastic_ruby_console
188
190
  extensions: []
@@ -199,9 +201,13 @@ files:
199
201
  - elasticsearch.gemspec
200
202
  - lib/elasticsearch-ruby.rb
201
203
  - lib/elasticsearch.rb
204
+ - lib/elasticsearch/helpers/bulk_helper.rb
205
+ - lib/elasticsearch/helpers/scroll_helper.rb
202
206
  - lib/elasticsearch/version.rb
203
207
  - spec/integration/characters_escaping_spec.rb
204
208
  - spec/integration/client_integration_spec.rb
209
+ - spec/integration/helpers/bulk_helper_spec.rb
210
+ - spec/integration/helpers/scroll_helper_spec.rb
205
211
  - spec/spec_helper.rb
206
212
  - spec/unit/api_key_spec.rb
207
213
  - spec/unit/cloud_credentials_spec.rb
@@ -209,6 +215,7 @@ files:
209
215
  - spec/unit/elasticsearch_product_validation_spec.rb
210
216
  - spec/unit/headers_spec.rb
211
217
  - spec/unit/opaque_id_spec.rb
218
+ - spec/unit/user_agent_spec.rb
212
219
  - spec/unit/wrapper_gem_spec.rb
213
220
  homepage: https://www.elastic.co/guide/en/elasticsearch/client/ruby-api/current/index.html
214
221
  licenses:
@@ -234,13 +241,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
234
241
  - !ruby/object:Gem::Version
235
242
  version: '0'
236
243
  requirements: []
237
- rubygems_version: 3.4.13
244
+ rubygems_version: 3.4.19
238
245
  signing_key:
239
246
  specification_version: 4
240
247
  summary: Ruby integrations for Elasticsearch
241
248
  test_files:
242
249
  - spec/integration/characters_escaping_spec.rb
243
250
  - spec/integration/client_integration_spec.rb
251
+ - spec/integration/helpers/bulk_helper_spec.rb
252
+ - spec/integration/helpers/scroll_helper_spec.rb
244
253
  - spec/spec_helper.rb
245
254
  - spec/unit/api_key_spec.rb
246
255
  - spec/unit/cloud_credentials_spec.rb
@@ -248,4 +257,5 @@ test_files:
248
257
  - spec/unit/elasticsearch_product_validation_spec.rb
249
258
  - spec/unit/headers_spec.rb
250
259
  - spec/unit/opaque_id_spec.rb
260
+ - spec/unit/user_agent_spec.rb
251
261
  - spec/unit/wrapper_gem_spec.rb