From ff272e48f461122d23a3786b8beaf8d5c62ad432 Mon Sep 17 00:00:00 2001 From: Sergio Bobillier Date: Wed, 19 Aug 2026 14:39:41 +0200 Subject: [PATCH] [JAY-787] Add the Prefix query to QueryBuilder Adds the QueryClauses::Prefix class and the corresponding #prefix method to the MatchClauses module. This allows users to use Elasticsearch's prefix query, which allows matching documents that contain a field that starts with a specified prefix. --- CHANGELOG.md | 7 ++++ .../elasticsearch/query_builder.rst | 13 +++++++ .../query_clauses/match_clauses.rb | 11 ++++++ .../query_builder/query_clauses/prefix.rb | 39 +++++++++++++++++++ .../query_clauses/match_clauses_spec.rb | 10 +++++ .../query_clauses/prefix_spec.rb | 30 ++++++++++++++ 6 files changed, 110 insertions(+) create mode 100644 lib/jay_api/elasticsearch/query_builder/query_clauses/prefix.rb create mode 100644 spec/jay_api/elasticsearch/query_builder/query_clauses/prefix_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index c8e06ea..11b58b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,13 @@ Please mark backwards incompatible changes with an exclamation mark at the start ## [Unreleased] +### Added +- The `JayAPI::Elasticsearch::QueryBuilder::QueryClauses::Prefix` class and the + corresponding `#prefix` method to the `MatchClauses` module. This allows the + use of Elasticsearch's + [prefix](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html) + query with the Query Builder. + ## [29.9.0] - 2026-08-04 ### Added diff --git a/documentation/source/user_guidelines/elasticsearch/query_builder.rst b/documentation/source/user_guidelines/elasticsearch/query_builder.rst index 3b85c32..ec9085c 100644 --- a/documentation/source/user_guidelines/elasticsearch/query_builder.rst +++ b/documentation/source/user_guidelines/elasticsearch/query_builder.rst @@ -334,6 +334,18 @@ Example: query_builder.query.match_none +prefix +++++++ + +A `Prefix Query`_ allows you to find documents in which one of the fields +starts with the given prefix. + +Example: + +.. code-block:: ruby + + query_builder.query.prefix(field: 'user.id', value: "ki") + query_string ++++++++++++ @@ -539,6 +551,7 @@ Example: .. _`Match Phrase Query`: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query-phrase.html#query-dsl-match-query-phrase .. _`Match All`: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html .. _`Match None`: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html#query-dsl-match-none-query +.. _`Prefix Query`: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html .. _`Query String Query`: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html .. _`Wildcard Query`: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html .. _`Exists Query`: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html diff --git a/lib/jay_api/elasticsearch/query_builder/query_clauses/match_clauses.rb b/lib/jay_api/elasticsearch/query_builder/query_clauses/match_clauses.rb index 06f0a82..73fb43e 100644 --- a/lib/jay_api/elasticsearch/query_builder/query_clauses/match_clauses.rb +++ b/lib/jay_api/elasticsearch/query_builder/query_clauses/match_clauses.rb @@ -5,6 +5,7 @@ require_relative 'match_all' require_relative 'match_none' require_relative 'match_phrase' +require_relative 'prefix' require_relative 'query_string' require_relative 'range' require_relative 'regexp' @@ -31,6 +32,16 @@ def match_phrase(**params) self << ::JayAPI::Elasticsearch::QueryBuilder::QueryClauses::MatchPhrase.new(**params) end + # Adds a +JayAPI::Elasticsearch::QueryBuilder::QueryClauses::Prefix+ + # clause to the Query Clauses set. + # @param [Hash] params The parameters for the +Prefix+ class. + # @return [self] Returns itself so that other methods can be chained. + # @raise [JayAPI::Elasticsearch::QueryBuilder::Errors::QueryBuilderError] + # If an error occurs when trying to add the query clause to the set. + def prefix(**params) + self << ::JayAPI::Elasticsearch::QueryBuilder::QueryClauses::Prefix.new(**params) + end + # Adds a +JayAPI::Elasticsearch::QueryBuilder::QueryClauses::QueryString+ # clause to the Query Clauses set. # @param [Hash] params The parameters for the +QueryString+ class diff --git a/lib/jay_api/elasticsearch/query_builder/query_clauses/prefix.rb b/lib/jay_api/elasticsearch/query_builder/query_clauses/prefix.rb new file mode 100644 index 0000000..9bb9233 --- /dev/null +++ b/lib/jay_api/elasticsearch/query_builder/query_clauses/prefix.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require_relative 'query_clause' + +module JayAPI + module Elasticsearch + class QueryBuilder + class QueryClauses + # Represents a +Prefix+ query in Elasticsearch + # More information about this type of query can be found here: + # https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html + class Prefix < ::JayAPI::Elasticsearch::QueryBuilder::QueryClauses::QueryClause + attr_reader :field, :value + + # @param [String, Symbol] field The field where the prefix query + # should be applied. + # @param [String] value The prefix to be found in +field+ + def initialize(field:, value:) + super() + @field = field + @value = value + end + + # @return [Hash] The Hash that represents this query (in + # Elasticsearch's format) + def to_h + { + prefix: { + field => { + value: value + } + } + } + end + end + end + end + end +end diff --git a/spec/jay_api/elasticsearch/query_builder/query_clauses/match_clauses_spec.rb b/spec/jay_api/elasticsearch/query_builder/query_clauses/match_clauses_spec.rb index d2f9dda..59b865c 100644 --- a/spec/jay_api/elasticsearch/query_builder/query_clauses/match_clauses_spec.rb +++ b/spec/jay_api/elasticsearch/query_builder/query_clauses/match_clauses_spec.rb @@ -59,6 +59,16 @@ def <<(_clause) it_behaves_like '#match_phrase' end + describe '#prefix' do + subject(:method_call) { test_instance.prefix(**params) } + + let(:params) { { field: 'test_case.name', value: 'Networking/CAN0' } } + + let(:clause_class) { JayAPI::Elasticsearch::QueryBuilder::QueryClauses::Prefix } + + it_behaves_like '#match_phrase' + end + describe '#query_string' do subject(:method_call) { test_instance.query_string(**params) } diff --git a/spec/jay_api/elasticsearch/query_builder/query_clauses/prefix_spec.rb b/spec/jay_api/elasticsearch/query_builder/query_clauses/prefix_spec.rb new file mode 100644 index 0000000..aaaf74f --- /dev/null +++ b/spec/jay_api/elasticsearch/query_builder/query_clauses/prefix_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'jay_api/elasticsearch/query_builder/query_clauses/prefix' + +RSpec.describe JayAPI::Elasticsearch::QueryBuilder::QueryClauses::Prefix do + let(:prefix) do + described_class.new( + field: 'user.id', + value: 'ki' + ) + end + + describe '#to_h' do + subject(:method_call) { prefix.to_h } + + let(:expected_hash) do + { + prefix: { + 'user.id' => { + value: 'ki' + } + } + } + end + + it 'returns the expected hash' do + expect(method_call).to eq(expected_hash) + end + end +end