elasticgraph-elasticsearch 0.18.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ac2e4def50b32a87f206ef9a89ae3347904fdf25a279020eafda8ae83ce0f4d8
4
+ data.tar.gz: 5cdd0b1dffabe213c5ed9cf2e69aa32de23a5a2082ebeed21dee26c88ed9bfea
5
+ SHA512:
6
+ metadata.gz: b65082d7b887e707b41eb04a169d444a19ac44461b7e0d086200ff122b196fdef0ef24bda3add37c07e1b65ea7ba382b4dd7ea11208d8341ba0d5f4696b7ad91
7
+ data.tar.gz: 19a28e1f078ec420b27bb8d1c339614579fdbacf9415b3321f9a6b1c6843eda6c5d2ef71762b7f486db00be1abadc4ec2bcd2101822047b1e7879cd79adedc39
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Block, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # ElasticGraph::Elasticsearch
2
+
3
+ Wraps the official Elasticsearch client for use by ElasticGraph.
@@ -0,0 +1,20 @@
1
+ # Copyright 2024 Block, Inc.
2
+ #
3
+ # Use of this source code is governed by an MIT-style
4
+ # license that can be found in the LICENSE file or at
5
+ # https://opensource.org/licenses/MIT.
6
+ #
7
+ # frozen_string_literal: true
8
+
9
+ require_relative "../gemspec_helper"
10
+
11
+ ElasticGraphGemspecHelper.define_elasticgraph_gem(gemspec_file: __FILE__, category: :datastore_adapter) do |spec, eg_version|
12
+ spec.summary = "Wraps the Elasticsearch client for use by ElasticGraph."
13
+
14
+ spec.add_dependency "elasticgraph-support", eg_version
15
+ spec.add_dependency "elasticsearch", "~> 8.14"
16
+ spec.add_dependency "faraday", "~> 2.10"
17
+ spec.add_dependency "faraday-retry", "~> 2.2"
18
+
19
+ spec.add_development_dependency "httpx", ">= 1.2.6", "< 2.0"
20
+ end
@@ -0,0 +1,203 @@
1
+ # Copyright 2024 Block, Inc.
2
+ #
3
+ # Use of this source code is governed by an MIT-style
4
+ # license that can be found in the LICENSE file or at
5
+ # https://opensource.org/licenses/MIT.
6
+ #
7
+ # frozen_string_literal: true
8
+
9
+ require "elastic_graph/constants"
10
+ require "elastic_graph/error"
11
+ require "elastic_graph/support/faraday_middleware/msearch_using_get_instead_of_post"
12
+ require "elastic_graph/support/faraday_middleware/support_timeouts"
13
+ require "elasticsearch"
14
+ require "faraday/retry"
15
+
16
+ module ElasticGraph
17
+ module Elasticsearch
18
+ class Client
19
+ # @dynamic cluster_name
20
+ attr_reader :cluster_name
21
+
22
+ def initialize(cluster_name, url:, faraday_adapter: nil, retry_on_failure: 3, logger: nil)
23
+ @cluster_name = cluster_name
24
+
25
+ @raw_client = ::Elasticsearch::Client.new(
26
+ adapter: faraday_adapter,
27
+ url: url,
28
+ retry_on_failure: retry_on_failure,
29
+ # We use `logger` for both the tracer and logger to log everything we can. While the trace and log output do overlap, one is
30
+ # not a strict superset of the other (for example, warnings go to `logger`, while full request bodies go to `tracer`).
31
+ logger: logger,
32
+ tracer: logger
33
+ ) do |faraday|
34
+ faraday.use Support::FaradayMiddleware::MSearchUsingGetInsteadOfPost
35
+ faraday.use Support::FaradayMiddleware::SupportTimeouts
36
+
37
+ # Note: this overrides the default retry exceptions, which includes `Faraday::TimeoutError`.
38
+ # That's important because we do NOT want a retry on timeout -- a timeout indicates a slow,
39
+ # expensive query, and is transformed to a `RequestExceededDeadlineError` by `SupportTimeouts`,
40
+ # anyway.
41
+ #
42
+ # In addition, it's worth noting that the retry middleware ONLY retries known idempotent HTTP
43
+ # methods (e.g. get/put/delete/head/options). POST requests will not be retried. We could
44
+ # configure it to make it retry POSTs but we'd need to do an analysis of all ElasticGraph requests to
45
+ # make sure all POST requests are truly idempotent, and at least for now, it's sufficient to skip
46
+ # any POST requests we make.
47
+ faraday.request :retry,
48
+ exceptions: [::Faraday::ConnectionFailed, ::Faraday::RetriableResponse],
49
+ max: retry_on_failure,
50
+ retry_statuses: [500, 502, 503] # Internal Server Error, Bad Gateway, Service Unavailable
51
+
52
+ yield faraday if block_given?
53
+ end
54
+
55
+ # Here we call `app` on each Faraday connection as a way to force it to resolve
56
+ # all configured middlewares and adapters. If it cannot load a required dependency
57
+ # (e.g. `httpx`), it'll fail fast with a clear error.
58
+ #
59
+ # Without this, we would instead get an error when the client was used to make
60
+ # a request for the first time, which isn't as ideal.
61
+ @raw_client.transport.connections.each { |c| c.connection.app }
62
+ end
63
+
64
+ # Cluster APIs
65
+
66
+ def get_cluster_health
67
+ transform_errors { |c| c.cluster.health.body }
68
+ end
69
+
70
+ def get_node_os_stats
71
+ transform_errors { |c| c.nodes.stats(metric: "os").body }
72
+ end
73
+
74
+ def get_flat_cluster_settings
75
+ transform_errors { |c| c.cluster.get_settings(flat_settings: true).body }
76
+ end
77
+
78
+ # We only support persistent settings here because Elasticsearch docs recommend against using transient settings:
79
+ # https://www.elastic.co/guide/en/elasticsearch/reference/8.13/cluster-update-settings.html
80
+ #
81
+ # > We no longer recommend using transient cluster settings. Use persistent cluster settings instead. If a cluster becomes unstable,
82
+ # > transient settings can clear unexpectedly, resulting in a potentially undesired cluster configuration.
83
+ def put_persistent_cluster_settings(settings)
84
+ transform_errors { |c| c.cluster.put_settings(body: {persistent: settings}).body }
85
+ end
86
+
87
+ # Script APIs
88
+
89
+ # Gets the script with the given ID. Returns `nil` if the script does not exist.
90
+ def get_script(id:)
91
+ transform_errors { |c| c.get_script(id: id).body }
92
+ rescue ::Elastic::Transport::Transport::Errors::NotFound
93
+ nil
94
+ end
95
+
96
+ def put_script(id:, body:, context:)
97
+ transform_errors { |c| c.put_script(id: id, body: body, context: context).body }
98
+ end
99
+
100
+ def delete_script(id:)
101
+ transform_errors { |c| c.delete_script(id: id).body }
102
+ rescue ::Elastic::Transport::Transport::Errors::NotFound
103
+ # it's ok if it's already not there.
104
+ end
105
+
106
+ # Index Template APIs
107
+
108
+ def get_index_template(index_template_name)
109
+ transform_errors do |client|
110
+ client.indices.get_index_template(name: index_template_name, flat_settings: true).fetch("index_templates").to_h do |entry|
111
+ [entry.fetch("name"), entry.fetch("index_template")]
112
+ end.dig(index_template_name) || {}
113
+ end
114
+ rescue ::Elastic::Transport::Transport::Errors::NotFound
115
+ {}
116
+ end
117
+
118
+ def put_index_template(name:, body:)
119
+ transform_errors { |c| c.indices.put_index_template(name: name, body: body).body }
120
+ end
121
+
122
+ def delete_index_template(index_template_name)
123
+ transform_errors { |c| c.indices.delete_index_template(name: [index_template_name], ignore: [404]).body }
124
+ end
125
+
126
+ # Index APIs
127
+
128
+ def get_index(index_name)
129
+ transform_errors do |client|
130
+ client.indices.get(
131
+ index: index_name,
132
+ ignore_unavailable: true,
133
+ flat_settings: true
134
+ )[index_name] || {}
135
+ end
136
+ end
137
+
138
+ def list_indices_matching(index_expression)
139
+ transform_errors do |client|
140
+ client
141
+ .cat
142
+ .indices(index: index_expression, format: "json", h: ["index"])
143
+ .map { |index_hash| index_hash.fetch("index") }
144
+ end
145
+ end
146
+
147
+ def create_index(index:, body:)
148
+ transform_errors { |c| c.indices.create(index: index, body: body).body }
149
+ end
150
+
151
+ def put_index_mapping(index:, body:)
152
+ transform_errors { |c| c.indices.put_mapping(index: index, body: body).body }
153
+ end
154
+
155
+ def put_index_settings(index:, body:)
156
+ transform_errors { |c| c.indices.put_settings(index: index, body: body).body }
157
+ end
158
+
159
+ def delete_indices(*index_names)
160
+ # `allow_no_indices: true` is needed when we attempt to delete a non-existing index to avoid errors. For rollover indices,
161
+ # when we delete the actual indices, we will always perform a wildcard deletion, and `allow_no_indices: true` is needed.
162
+ #
163
+ # Note that the Elasticsearch API documentation[^1] says that `allow_no_indices` defaults to `true` but a Elasticsearch Ruby
164
+ # client code comment[^2] says it defaults to `false`. Regardless, we don't want to rely on the default behavior that could change.
165
+ #
166
+ # [^1]: https://www.elastic.co/guide/en/elasticsearch/reference/8.12/indices-delete-index.html#delete-index-api-query-params
167
+ # [^2]: https://github.com/elastic/elasticsearch-ruby/blob/8.12/elasticsearch-api/lib/elasticsearch/api/actions/indices/delete.rb#L31
168
+ transform_errors do |client|
169
+ client.indices.delete(index: index_names, ignore_unavailable: true, allow_no_indices: true).body
170
+ end
171
+ end
172
+
173
+ # Document APIs
174
+
175
+ def msearch(body:, headers: nil)
176
+ transform_errors { |c| c.msearch(body: body, headers: headers).body }
177
+ end
178
+
179
+ def bulk(body:, refresh: false)
180
+ transform_errors { |c| c.bulk(body: body, filter_path: DATASTORE_BULK_FILTER_PATH, refresh: refresh).body }
181
+ end
182
+
183
+ # Synchronously deletes all documents in the cluster. Intended for tests to give ourselves a clean slate.
184
+ # Supports an `index` argument so the caller can limit the deletion to a specific "scope" (e.g. a set of indices with a common prefix).
185
+ #
186
+ # Overrides `scroll` to `10s` to avoid getting a "Trying to create too many scroll contexts" error, as discussed here:
187
+ # https://discuss.elastic.co/t/too-many-scroll-contexts-with-update-by-query-and-or-delete-by-query/282325/1
188
+ def delete_all_documents(index: "_all")
189
+ transform_errors do |client|
190
+ client.delete_by_query(index: index, body: {query: {match_all: _ = {}}}, refresh: true, scroll: "10s").body
191
+ end
192
+ end
193
+
194
+ private
195
+
196
+ def transform_errors
197
+ yield @raw_client
198
+ rescue ::Elastic::Transport::Transport::Errors::BadRequest => ex
199
+ raise BadDatastoreRequest, ex.message
200
+ end
201
+ end
202
+ end
203
+ end
metadata ADDED
@@ -0,0 +1,290 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elasticgraph-elasticsearch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.18.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Myron Marston
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-08-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubocop-factory_bot
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.26'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.26'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop-rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop-rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: standard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 1.39.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.39.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: steep
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.7'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.7'
83
+ - !ruby/object:Gem::Dependency
84
+ name: coderay
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.1'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.1'
97
+ - !ruby/object:Gem::Dependency
98
+ name: flatware-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 2.3.2
104
+ - - "<"
105
+ - !ruby/object:Gem::Version
106
+ version: '3.0'
107
+ type: :development
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: 2.3.2
114
+ - - "<"
115
+ - !ruby/object:Gem::Version
116
+ version: '3.0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: rspec
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '3.13'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '3.13'
131
+ - !ruby/object:Gem::Dependency
132
+ name: super_diff
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: 0.12.1
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 0.12.1
145
+ - !ruby/object:Gem::Dependency
146
+ name: simplecov
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '0.22'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: '0.22'
159
+ - !ruby/object:Gem::Dependency
160
+ name: simplecov-console
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: 0.9.1
166
+ - - "<"
167
+ - !ruby/object:Gem::Version
168
+ version: '1.0'
169
+ type: :development
170
+ prerelease: false
171
+ version_requirements: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - ">="
174
+ - !ruby/object:Gem::Version
175
+ version: 0.9.1
176
+ - - "<"
177
+ - !ruby/object:Gem::Version
178
+ version: '1.0'
179
+ - !ruby/object:Gem::Dependency
180
+ name: elasticgraph-support
181
+ requirement: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - '='
184
+ - !ruby/object:Gem::Version
185
+ version: 0.18.0.0
186
+ type: :runtime
187
+ prerelease: false
188
+ version_requirements: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - '='
191
+ - !ruby/object:Gem::Version
192
+ version: 0.18.0.0
193
+ - !ruby/object:Gem::Dependency
194
+ name: elasticsearch
195
+ requirement: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - "~>"
198
+ - !ruby/object:Gem::Version
199
+ version: '8.14'
200
+ type: :runtime
201
+ prerelease: false
202
+ version_requirements: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - "~>"
205
+ - !ruby/object:Gem::Version
206
+ version: '8.14'
207
+ - !ruby/object:Gem::Dependency
208
+ name: faraday
209
+ requirement: !ruby/object:Gem::Requirement
210
+ requirements:
211
+ - - "~>"
212
+ - !ruby/object:Gem::Version
213
+ version: '2.10'
214
+ type: :runtime
215
+ prerelease: false
216
+ version_requirements: !ruby/object:Gem::Requirement
217
+ requirements:
218
+ - - "~>"
219
+ - !ruby/object:Gem::Version
220
+ version: '2.10'
221
+ - !ruby/object:Gem::Dependency
222
+ name: faraday-retry
223
+ requirement: !ruby/object:Gem::Requirement
224
+ requirements:
225
+ - - "~>"
226
+ - !ruby/object:Gem::Version
227
+ version: '2.2'
228
+ type: :runtime
229
+ prerelease: false
230
+ version_requirements: !ruby/object:Gem::Requirement
231
+ requirements:
232
+ - - "~>"
233
+ - !ruby/object:Gem::Version
234
+ version: '2.2'
235
+ - !ruby/object:Gem::Dependency
236
+ name: httpx
237
+ requirement: !ruby/object:Gem::Requirement
238
+ requirements:
239
+ - - ">="
240
+ - !ruby/object:Gem::Version
241
+ version: 1.2.6
242
+ - - "<"
243
+ - !ruby/object:Gem::Version
244
+ version: '2.0'
245
+ type: :development
246
+ prerelease: false
247
+ version_requirements: !ruby/object:Gem::Requirement
248
+ requirements:
249
+ - - ">="
250
+ - !ruby/object:Gem::Version
251
+ version: 1.2.6
252
+ - - "<"
253
+ - !ruby/object:Gem::Version
254
+ version: '2.0'
255
+ description:
256
+ email:
257
+ - myron@squareup.com
258
+ executables: []
259
+ extensions: []
260
+ extra_rdoc_files: []
261
+ files:
262
+ - LICENSE.txt
263
+ - README.md
264
+ - elasticgraph-elasticsearch.gemspec
265
+ - lib/elastic_graph/elasticsearch/client.rb
266
+ homepage:
267
+ licenses:
268
+ - MIT
269
+ metadata:
270
+ gem_category: datastore_adapter
271
+ post_install_message:
272
+ rdoc_options: []
273
+ require_paths:
274
+ - lib
275
+ required_ruby_version: !ruby/object:Gem::Requirement
276
+ requirements:
277
+ - - "~>"
278
+ - !ruby/object:Gem::Version
279
+ version: '3.2'
280
+ required_rubygems_version: !ruby/object:Gem::Requirement
281
+ requirements:
282
+ - - ">="
283
+ - !ruby/object:Gem::Version
284
+ version: '0'
285
+ requirements: []
286
+ rubygems_version: 3.5.9
287
+ signing_key:
288
+ specification_version: 4
289
+ summary: Wraps the Elasticsearch client for use by ElasticGraph.
290
+ test_files: []