jay_api 29.4.0 → 29.5.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: 03ef39a19b2ff79bf0aea18958f4c0ea7d2b77f87f502c85fbaa793dc191af29
4
- data.tar.gz: 5abb8d21871415133f2d95cab6090b2ee8d224d7056349dbf2b667873d3ea257
3
+ metadata.gz: f997e23215ab5ee73c077534d19889c9b91ae5c877a77859b75f454e555bb105
4
+ data.tar.gz: f0250fc57649d863fde276f3e753b9d8aecff90c0bd286a1a97fb12b447b1c33
5
5
  SHA512:
6
- metadata.gz: aceb3ee3bc16cee43009c8c48e079f31eed730be5ae560c1974d660dd5ac4a385648cb329a9ef9d191f0ae2358915fd311fe0d81a1ddcd5ecac8ac806ae7a17d
7
- data.tar.gz: cf762fbc558af858e560a83b4bcbc57574ac9ab0ffecb7fdbebb51254008550079a4f36beec32e19ea7b58e4187ae69f06e4e1c48e8ff1aae5835691e12b6072
6
+ metadata.gz: bf6ba31a0f5960479de755757d6479b0c9373cc4b4e9e99ee55d853ba90417d1161b02d88d2103d8c86cd13a028f725293c3f13422c0422c51e0d64b6a906a40
7
+ data.tar.gz: ad81742c20b6a93b973972ee49b814ea61b3ecaac8ce0945aceac05dbd8020ec2c9d4dca701c261dadc7eeffbb3e40658ba6476ba015662217e0a8509785235f
data/CHANGELOG.md CHANGED
@@ -8,6 +8,34 @@ Please mark backwards incompatible changes with an exclamation mark at the start
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [29.5.0] - 2026-02-23
12
+
13
+ ### Fixed
14
+ - A `NameError` that was being raised when `jay_api/elasticsearch/client` was
15
+ required without requiring `elasticsearch`.
16
+ - A `NoMethodError` that was being raised by `Elasticsearch::Stats::Indices`
17
+ when `active_support/core_ext/string` hadn't been loaded.
18
+
19
+ ### Added
20
+ - The `#force_merge` method to the `Elasticsearch::Index` class. This method
21
+ starts a Forced Segment Merge on the index.
22
+ - The `#totals` method to `Elasticsearch::Stats::Index`, this gives the caller
23
+ access to the index's total metrics.
24
+ - The `Elasticsearch::Stats::Index::Totals` class. The class contains information
25
+ about an index's total metrics, for example, total number of documents, total
26
+ size, etc.
27
+ - The `#settings` method to the `Elasticsearch::Index` class. This gives the
28
+ caller access to the index's settings.
29
+ - The `Elasticsearch::Indices::Settings::Blocks` class. The class encapsulates
30
+ an index's blocks settings (for example, whether the index is read-only).
31
+ - The `Elasticsearch::Indices::Settings` class. The class encapsulates an
32
+ index's settings.
33
+ - It is now possible to configure the type used by the `RSpec::TestDataCollector`
34
+ class when pushing documents to Elasticsearch. If no type is specified in the
35
+ configuration the default type will be used.
36
+ - Allow the `Elasticsearch::Index` and `Elasticsearch::Indexes`'s `#push` method
37
+ to receive a `type` parameter, just like `#index` does.
38
+
11
39
  ## [29.4.0] - 2026-01-28
12
40
 
13
41
  ### Added
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'elasticsearch/api/namespace/tasks'
3
+ require 'timeout'
4
4
  require 'elasticsearch/transport/transport/errors'
5
5
  require 'faraday/error'
6
6
  require 'forwardable'
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../errors/error'
4
+
5
+ module JayAPI
6
+ module Elasticsearch
7
+ module Errors
8
+ # An error to be raised when an attempt is made to perform force_merge
9
+ # over an index which hasn't been set to be read-only.
10
+ class WritableIndexError < ::JayAPI::Errors::Error; end
11
+ end
12
+ end
13
+ end
@@ -6,6 +6,7 @@ require_relative 'errors/query_execution_error'
6
6
  require_relative 'errors/query_execution_failure'
7
7
  require_relative 'errors/query_execution_timeout'
8
8
  require_relative 'errors/search_after_error'
9
+ require_relative 'errors/writable_index_error'
9
10
 
10
11
  module JayAPI
11
12
  module Elasticsearch
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'indexable'
4
+ require_relative 'indices/settings'
5
+ require_relative 'errors/writable_index_error'
4
6
 
5
7
  module JayAPI
6
8
  module Elasticsearch
@@ -49,6 +51,36 @@ module JayAPI
49
51
  def index(data, type: DEFAULT_DOC_TYPE)
50
52
  super.first
51
53
  end
54
+
55
+ # @return [JayAPI::Elasticsearch::Indices::Settings] The settings for the
56
+ # index.
57
+ def settings
58
+ # DO NOT MEMOIZE! Leave it to the caller.
59
+ ::JayAPI::Elasticsearch::Indices::Settings.new(client.transport_client, index_name)
60
+ end
61
+
62
+ # Starts a Forced Segment Merge process on the index.
63
+ #
64
+ # ⚠️ For big indexes this process can take a very long time, make sure to
65
+ # adjust the timeout when creating the client.
66
+ # @param [Boolean] only_expunge_deletes Specifies whether the operation
67
+ # should only remove deleted documents.
68
+ # @raise [JayAPI::Elasticsearch::Errors::WritableIndexError] If the index
69
+ # is writable (hasn't been set to read-only).
70
+ # @return [Hash] A +Hash+ with the result of the index merging process,
71
+ # it looks like this:
72
+ #
73
+ # { "_shards" => { "total" => 10, "successful" => 10, "failed" => 0 } }
74
+ def force_merge(only_expunge_deletes: nil)
75
+ unless settings.blocks.write_blocked?
76
+ raise ::JayAPI::Elasticsearch::Errors::WritableIndexError,
77
+ "Write block for '#{index_name}' has not been enabled. " \
78
+ "Please enable the index's write block before performing a segment merge"
79
+ end
80
+
81
+ params = { index: index_name, only_expunge_deletes: }.compact
82
+ client.transport_client.indices.forcemerge(**params)
83
+ end
52
84
  end
53
85
  end
54
86
  end
@@ -48,9 +48,13 @@ module JayAPI
48
48
  # Pushes a record into the index. (This does not send the record to the
49
49
  # Elasticsearch instance, only puts it into the send queue).
50
50
  # @param [Hash] data The data to be pushed to the index.
51
- def push(data)
51
+ # @param [String, nil] type The type of the document. When set to +nil+
52
+ # the decision is left to Elasticsearch's API. Which will normally
53
+ # default to +_doc+.
54
+ def push(data, type: DEFAULT_DOC_TYPE)
55
+ validate_type(type)
52
56
  index_names.each do |index_name|
53
- batch << { index: { _index: index_name, _type: 'nested', data: data } }
57
+ batch << { index: { _index: index_name, _type: type, data: data }.compact }
54
58
  end
55
59
 
56
60
  flush! if batch.size >= batch_size
@@ -78,8 +82,7 @@ module JayAPI
78
82
  # For information on the contents of this Hash please see:
79
83
  # https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html#docs-index-api-response-body
80
84
  def index(data, type: DEFAULT_DOC_TYPE)
81
- raise ArgumentError, "Unsupported type: '#{type}'" unless SUPPORTED_TYPES.include?(type)
82
-
85
+ validate_type(type)
83
86
  index_names.map { |index_name| client.index index: index_name, type: type, body: data }
84
87
  end
85
88
 
@@ -220,6 +223,15 @@ module JayAPI
220
223
  def async
221
224
  @async ||= JayAPI::Elasticsearch::Async.new(self)
222
225
  end
226
+
227
+ # @param [String, nil] type The type of the document. When set to +nil+
228
+ # the decision is left to Elasticsearch's API. Which will normally
229
+ # default to +_doc+.
230
+ # @raise [ArgumentError] When the given +type+ is not one of the
231
+ # +SUPPORTED_TYPES+
232
+ def validate_type(type)
233
+ raise ArgumentError, "Unsupported type: '#{type}'" unless SUPPORTED_TYPES.include?(type)
234
+ end
223
235
  end
224
236
  end
225
237
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JayAPI
4
+ module Elasticsearch
5
+ module Indices
6
+ class Settings
7
+ # Represents the block settings of an Elasticsearch index.
8
+ class Blocks
9
+ attr_reader :settings
10
+
11
+ # @param [JayAPI::Elasticsearch::Indices::Settings] settings The
12
+ # parent +Settings+ object.
13
+ def initialize(settings)
14
+ @settings = settings
15
+ end
16
+
17
+ # @return [Boolean] True if the Index's write block has been set to
18
+ # true, false otherwise.
19
+ def write_blocked?
20
+ blocks_settings.fetch('write') == 'true'
21
+ end
22
+
23
+ # Sets the index's +write+ block to the given value. When the +write+
24
+ # block is set to +true+ the index's data is read-only, but the
25
+ # index's settings can still be changed. This allows maintenance tasks
26
+ # to still be performed on the index.
27
+ # @param [Boolean] value The new value for the +write+ block of the
28
+ # index.
29
+ # @raise [Elasticsearch::Transport::Transport::Errors::ServerError] If
30
+ # an error occurs when trying to set the value of the block.
31
+ def write=(value)
32
+ unless [true, false].include?(value)
33
+ raise ArgumentError, "Expected 'value' to be true or false, #{value.class} given"
34
+ end
35
+
36
+ return if write_blocked? == value
37
+
38
+ settings.transport_client.indices.put_settings(
39
+ index: settings.index_name,
40
+ body: { 'blocks.write' => value }
41
+ )
42
+ end
43
+
44
+ private
45
+
46
+ # @return [Hash] The block settings of the index. Something like this:
47
+ #
48
+ # { 'read_only_allow_delete' => 'false', 'write' => 'false' }
49
+ #
50
+ # @raise [KeyError] If the index's settings do not contain a "blocks"
51
+ # section.
52
+ def blocks_settings
53
+ settings.all.fetch('blocks')
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'settings/blocks'
4
+
5
+ module JayAPI
6
+ module Elasticsearch
7
+ module Indices
8
+ # Represents the settings of an Elasticsearch Index.
9
+ class Settings
10
+ attr_reader :transport_client, :index_name
11
+
12
+ # @param [Elasticsearch::Transport::Client] transport_client Elasticsearch's
13
+ # transport client.
14
+ # @param [String] index_name The name of the index this class will be
15
+ # handling settings for.
16
+ def initialize(transport_client, index_name)
17
+ @transport_client = transport_client
18
+ @index_name = index_name
19
+ end
20
+
21
+ # @return [Hash] A Hash with all the settings for the index. It looks
22
+ # like this:
23
+ #
24
+ # {
25
+ # "number_of_shards" => "5",
26
+ # "blocks" => { "read_only_allow_delete" => "false", "write" => "false" },
27
+ # "provided_name" => "xyz01_tests",
28
+ # "creation_date" => "1588701800423",
29
+ # "number_of_replicas" => "1",
30
+ # "uuid" => "VFx2e5t0Qgi-1zc2PUkYEg",
31
+ # "version" => { "created" => "7010199", "upgraded" => "7100299"}
32
+ # }
33
+ #
34
+ # @raise [Elasticsearch::Transport::Transport::Errors::ServerError] If
35
+ # an error occurs when trying to get the index's settings.
36
+ # @raise [KeyError] If any of the expected hierarchical elements in the
37
+ # response are missing.
38
+ def all
39
+ transport_client.indices.get_settings(index: index_name)
40
+ .fetch(index_name).fetch('settings').fetch('index')
41
+ end
42
+
43
+ # @return [JayAPI::Elasticsearch::Indices::Settings::Blocks] The blocks
44
+ # settings for the given index.
45
+ def blocks
46
+ @blocks ||= ::JayAPI::Elasticsearch::Indices::Settings::Blocks.new(self)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'indices/settings'
4
+
5
+ module JayAPI
6
+ module Elasticsearch
7
+ # Namespace for sub-elements of Elasticsearch's indices
8
+ module Indices; end
9
+ end
10
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JayAPI
4
+ module Elasticsearch
5
+ class Stats
6
+ class Index
7
+ # Contains information about an index's totals (docs, used space, etc).
8
+ class Totals
9
+ # @param [Hash] data The data under the index's +total+ key.
10
+ def initialize(data)
11
+ @data = data
12
+ end
13
+
14
+ # @return [Integer] The total number of documents in the index.
15
+ def docs_count
16
+ @docs_count ||= docs.fetch('count')
17
+ end
18
+
19
+ # @return [Integer] The total number of deleted documents in the index.
20
+ def deleted_docs
21
+ @deleted_docs ||= docs.fetch('deleted')
22
+ end
23
+
24
+ # @return [Float] A number between 0 and 1 that represents the ratio
25
+ # of between deleted documents and total documents in the index.
26
+ def deleted_ratio
27
+ @deleted_ratio ||= calculate_deleted_ratio
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :data
33
+
34
+ # @return [Hash] The information about the documents in the index.
35
+ # Looks something like this:
36
+ #
37
+ # { "count" => 530626, "deleted" => 11 }
38
+ #
39
+ # @raise [KeyError] If the given data doesn't have a +docs+ key.
40
+ def docs
41
+ @docs ||= data.fetch('docs')
42
+ end
43
+
44
+ # @return [Float] A number between 0 and 1 that represents the ratio
45
+ # of between deleted documents and total documents in the index.
46
+ def calculate_deleted_ratio
47
+ if docs_count.zero?
48
+ return deleted_docs.zero? ? 0.0 : 1.0
49
+ end
50
+
51
+ deleted_docs / docs_count.to_f
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'index/totals'
4
+
3
5
  module JayAPI
4
6
  module Elasticsearch
5
7
  class Stats
@@ -13,6 +15,17 @@ module JayAPI
13
15
  @name = name
14
16
  @data = data
15
17
  end
18
+
19
+ # @return [JayAPI::Elasticsearch::Stats::Index::Totals] Information
20
+ # about the index's total metrics.
21
+ # @raise [KeyError] If the given data doesn't have a +total+ key.
22
+ def totals
23
+ @totals ||= ::JayAPI::Elasticsearch::Stats::Index::Totals.new(data.fetch('total'))
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :data
16
29
  end
17
30
  end
18
31
  end
@@ -10,7 +10,7 @@ module JayAPI
10
10
  class Indices
11
11
  # A lambda used to select / reject system indices (indices whose name
12
12
  # starts with dot).
13
- SYSTEM_SELECTOR = ->(name, _data) { name.starts_with?('.') }
13
+ SYSTEM_SELECTOR = ->(name, _data) { name.start_with?('.') }
14
14
 
15
15
  # @param [Hash{String=>Hash}] indices A +Hash+ with the information
16
16
  # about the indices. Its keys are the names of the indices, its values
@@ -7,6 +7,7 @@ require_relative 'elasticsearch/client_factory'
7
7
  require_relative 'elasticsearch/errors'
8
8
  require_relative 'elasticsearch/index'
9
9
  require_relative 'elasticsearch/indexes'
10
+ require_relative 'elasticsearch/indices'
10
11
  require_relative 'elasticsearch/query_builder'
11
12
  require_relative 'elasticsearch/query_results'
12
13
  require_relative 'elasticsearch/response'
@@ -79,7 +79,7 @@ module JayAPI
79
79
  }
80
80
  }
81
81
 
82
- elasticsearch_index.push(data)
82
+ elasticsearch_index.push(data, **push_params)
83
83
  end
84
84
 
85
85
  # Executed by RSpec at the end of the test run. If the push is enabled,
@@ -94,6 +94,14 @@ module JayAPI
94
94
 
95
95
  attr_reader :push_enabled
96
96
 
97
+ # @return [Hash] Additional parameters for the Elasticsearch::Index#push.
98
+ def push_params
99
+ # The extraction of the parameters is done with a #slice to be able to
100
+ # differentiate between when the parameter is not specified (completely
101
+ # absent) or when the parameter has been specified as +nil+.
102
+ @push_params ||= configuration.to_h.slice(:type)
103
+ end
104
+
97
105
  # @return [Hash] The configuration set for Elasticsearch as a hash. If no
98
106
  # value has been set for the batch size a reasonable default is set.
99
107
  # @raise [JayAPI::Errors::ConfigurationError] If no configuration for
@@ -2,5 +2,5 @@
2
2
 
3
3
  module JayAPI
4
4
  # JayAPI gem's semantic version
5
- VERSION = '29.4.0'
5
+ VERSION = '29.5.0'
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jay_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 29.4.0
4
+ version: 29.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Accenture-Industry X
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2026-01-28 00:00:00.000000000 Z
12
+ date: 2026-02-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -128,9 +128,13 @@ files:
128
128
  - lib/jay_api/elasticsearch/errors/query_execution_failure.rb
129
129
  - lib/jay_api/elasticsearch/errors/query_execution_timeout.rb
130
130
  - lib/jay_api/elasticsearch/errors/search_after_error.rb
131
+ - lib/jay_api/elasticsearch/errors/writable_index_error.rb
131
132
  - lib/jay_api/elasticsearch/index.rb
132
133
  - lib/jay_api/elasticsearch/indexable.rb
133
134
  - lib/jay_api/elasticsearch/indexes.rb
135
+ - lib/jay_api/elasticsearch/indices.rb
136
+ - lib/jay_api/elasticsearch/indices/settings.rb
137
+ - lib/jay_api/elasticsearch/indices/settings/blocks.rb
134
138
  - lib/jay_api/elasticsearch/query_builder.rb
135
139
  - lib/jay_api/elasticsearch/query_builder/aggregations.rb
136
140
  - lib/jay_api/elasticsearch/query_builder/aggregations/aggregation.rb
@@ -174,6 +178,7 @@ files:
174
178
  - lib/jay_api/elasticsearch/stats.rb
175
179
  - lib/jay_api/elasticsearch/stats/errors/stats_data_not_available.rb
176
180
  - lib/jay_api/elasticsearch/stats/index.rb
181
+ - lib/jay_api/elasticsearch/stats/index/totals.rb
177
182
  - lib/jay_api/elasticsearch/stats/indices.rb
178
183
  - lib/jay_api/elasticsearch/stats/node.rb
179
184
  - lib/jay_api/elasticsearch/stats/node/storage.rb