From c8fa2569e17cc7cb4f1e564bc4f17f1e51ee7f55 Mon Sep 17 00:00:00 2001 From: Sergio Bobillier Date: Fri, 13 Feb 2026 15:41:40 +0100 Subject: [PATCH 1/2] [JAY-737] Add the Stats::Index::Totals class The class contains information about an index's total metrics, for example, total number of documents, total size, etc. At the time of writing it only returns two metrics, total number of documents and total number of deleted documents. --- CHANGELOG.md | 3 + .../elasticsearch/stats/index/totals.rb | 41 +++++++++++ .../elasticsearch/stats/index/totals_spec.rb | 73 +++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 lib/jay_api/elasticsearch/stats/index/totals.rb create mode 100644 spec/jay_api/elasticsearch/stats/index/totals_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index ed4b727..1d41f79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ Please mark backwards incompatible changes with an exclamation mark at the start ## [Unreleased] ### Added +- The `Elasticsearch::Stats::Index::Totals` class. The class contains information + about an index's total metrics, for example, total number of documents, total + size, etc. - It is now possible to configure the type used by the `RSpec::TestDataCollector` class when pushing documents to Elasticsearch. If no type is specified in the configuration the default type will be used. diff --git a/lib/jay_api/elasticsearch/stats/index/totals.rb b/lib/jay_api/elasticsearch/stats/index/totals.rb new file mode 100644 index 0000000..62dca94 --- /dev/null +++ b/lib/jay_api/elasticsearch/stats/index/totals.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module JayAPI + module Elasticsearch + class Stats + class Index + # Contains information about an index's totals (docs, used space, etc). + class Totals + # @param [Hash] data The data under the index's +total+ key. + def initialize(data) + @data = data + end + + # @return [Integer] The total number of documents in the index. + def docs_count + @docs_count ||= docs.fetch('count') + end + + # @return [Integer] The total number of deleted documents in the index. + def deleted_docs + @deleted_docs ||= docs.fetch('deleted') + end + + private + + attr_reader :data + + # @return [Hash] The information about the documents in the index. + # Looks something like this: + # + # { "count" => 530626, "deleted" => 11 } + # + # @raise [KeyError] If the given data doesn't have a +docs+ key. + def docs + @docs ||= data.fetch('docs') + end + end + end + end + end +end diff --git a/spec/jay_api/elasticsearch/stats/index/totals_spec.rb b/spec/jay_api/elasticsearch/stats/index/totals_spec.rb new file mode 100644 index 0000000..18e64a0 --- /dev/null +++ b/spec/jay_api/elasticsearch/stats/index/totals_spec.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require 'jay_api/elasticsearch/stats/index/totals' + +RSpec.describe JayAPI::Elasticsearch::Stats::Index::Totals do + subject(:totals) { described_class.new(data) } + + let(:docs) do + { 'count' => 530_626, 'deleted' => 11 } + end + + let(:data) do + { + 'docs' => docs, + 'store' => { 'size_in_bytes' => 1_001_425_875, 'reserved_in_bytes' => 0 }, + 'flush' => { 'total' => 25, 'periodic' => 0, 'total_time_in_millis' => 1924 }, + 'warmer' => { 'current' => 0, 'total' => 30, 'total_time_in_millis' => 0 }, + 'completion' => { 'size_in_bytes' => 0 } + } + end + + shared_examples_for '#docs' do + context "when the data doesn't have a 'docs' key" do + let(:data) { super().except('docs') } + + it 'raises a KeyError' do + expect { method_call }.to raise_error( + KeyError, 'key not found: "docs"' + ) + end + end + end + + describe '#docs_count' do + subject(:method_call) { totals.docs_count } + + it_behaves_like '#docs' + + context "when the data doesn't contain the total number of documents" do + let(:docs) { super().except('count') } + + it 'raises a KeyError' do + expect { method_call }.to raise_error( + KeyError, 'key not found: "count"' + ) + end + end + + it 'returns the expected number of documents' do + expect(method_call).to eq(530_626) + end + end + + describe '#deleted_docs' do + subject(:method_call) { totals.deleted_docs } + + it_behaves_like '#docs' + + context "when the data doesn't contain the number of deleted documents" do + let(:docs) { super().except('deleted') } + + it 'raises a KeyError' do + expect { method_call }.to raise_error( + KeyError, 'key not found: "deleted"' + ) + end + end + + it 'returns the expected number of deleted documents' do + expect(method_call).to eq(11) + end + end +end From 8b2c238428419c73aeaf5677d1fd540e38634eaf Mon Sep 17 00:00:00 2001 From: Sergio Bobillier Date: Fri, 13 Feb 2026 16:01:09 +0100 Subject: [PATCH 2/2] [JAY-737] Add the Stats::Index#totals method The method returns the index's total metrics like the number of documents, total size, etc. --- CHANGELOG.md | 2 + lib/jay_api/elasticsearch/stats/index.rb | 13 +++++ .../jay_api/elasticsearch/stats/index_spec.rb | 56 ++++++++++++++++++- 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d41f79..eaf095b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ Please mark backwards incompatible changes with an exclamation mark at the start ## [Unreleased] ### Added +- The `#totals` method to `Elasticsearch::Stats::Index`, this gives the caller + access to the index's total metrics. - The `Elasticsearch::Stats::Index::Totals` class. The class contains information about an index's total metrics, for example, total number of documents, total size, etc. diff --git a/lib/jay_api/elasticsearch/stats/index.rb b/lib/jay_api/elasticsearch/stats/index.rb index 7c0eb2b..2915805 100644 --- a/lib/jay_api/elasticsearch/stats/index.rb +++ b/lib/jay_api/elasticsearch/stats/index.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require_relative 'index/totals' + module JayAPI module Elasticsearch class Stats @@ -13,6 +15,17 @@ def initialize(name, data) @name = name @data = data end + + # @return [JayAPI::Elasticsearch::Stats::Index::Totals] Information + # about the index's total metrics. + # @raise [KeyError] If the given data doesn't have a +total+ key. + def totals + @totals ||= ::JayAPI::Elasticsearch::Stats::Index::Totals.new(data.fetch('total')) + end + + private + + attr_reader :data end end end diff --git a/spec/jay_api/elasticsearch/stats/index_spec.rb b/spec/jay_api/elasticsearch/stats/index_spec.rb index 252d14a..823aa0a 100644 --- a/spec/jay_api/elasticsearch/stats/index_spec.rb +++ b/spec/jay_api/elasticsearch/stats/index_spec.rb @@ -6,7 +6,20 @@ subject(:index) { described_class.new(name, data) } let(:name) { 'xyz01_integration_tests' } - let(:data) { {} } + + let(:data) do + { + 'uuid' => 'rouPqkZMSrKHY5bzL7OhTA', + 'primaries' => { + 'docs' => { 'count' => 265_313, 'deleted' => 0 }, + 'store' => { 'size_in_bytes' => 497_335_237, 'reserved_in_bytes' => 0 } + }, + 'total' => { + 'docs' => { 'count' => 530_626, 'deleted' => 11 }, + 'store' => { 'size_in_bytes' => 1_001_425_875, 'reserved_in_bytes' => 0 } + } + } + end describe '#initialize' do subject(:method_call) { index } @@ -16,4 +29,45 @@ expect(index.name).to be(name) end end + + describe '#totals' do + subject(:method_call) { index.totals } + + let(:totals_hash) do + { + 'docs' => { 'count' => 530_626, 'deleted' => 11 }, + 'store' => { 'size_in_bytes' => 1_001_425_875, 'reserved_in_bytes' => 0 } + } + end + + let(:totals) do + instance_double( + JayAPI::Elasticsearch::Stats::Index::Totals + ) + end + + before do + allow(JayAPI::Elasticsearch::Stats::Index::Totals) + .to receive(:new).and_return(totals) + end + + context "when the index's data doesn't contain the totals information" do + let(:data) { super().except('total') } + + it 'raises a KeyError' do + expect { method_call }.to raise_error( + KeyError, 'key not found: "total"' + ) + end + end + + it 'creates a new instance of the Totals class with the expected Hash' do + expect(JayAPI::Elasticsearch::Stats::Index::Totals).to receive(:new).with(totals_hash) + method_call + end + + it 'returns the instance of the Totals class' do + expect(method_call).to be(totals) + end + end end