Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def initialize(elasticgraph_graphql:, config:)

def resolve(field:, object:, args:, context:)
query = @datastore_query_builder.new_query(
search_index_definitions: [@product_index_def],
initial_search_index_definitions: [@product_index_def],
monotonic_clock_deadline: context[:monotonic_clock_deadline],
client_filters: [{"id" => {"equalToAnyOf" => [args.fetch("id")]}}],
individual_docs_needed: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def build_query(adapter, representations, query_attributes)
return nil unless adapter.root_document_type?

type = adapter.type
query = @datastore_query_builder.new_query(search_index_definitions: type.search_index_definitions, **query_attributes)
query = @datastore_query_builder.new_query(initial_search_index_definitions: type.search_index_definitions, **query_attributes)
adapter.customize_query(query, representations)
end

Expand Down
25 changes: 14 additions & 11 deletions elasticgraph-graphql/lib/elastic_graph/graphql/datastore_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class GraphQL
# with minimal effort.
class DatastoreQuery < Support::MemoizableData.define(
:total_document_count_needed, :aggregations, :logger, :filter_interpreter, :routing_picker,
:index_expression_builder, :default_page_size, :search_index_definitions, :max_page_size,
:index_expression_builder, :default_page_size, :initial_search_index_definitions, :max_page_size,
:client_filters, :internal_filters, :sort, :document_pagination,
:requested_fields, :request_all_fields, :requested_highlights, :request_all_highlights,
:individual_docs_needed, :size_multiplier, :monotonic_clock_deadline, :schema_element_names
Expand Down Expand Up @@ -138,13 +138,16 @@ def to_datastore_msearch_header_and_body
@to_datastore_msearch_header_and_body ||= [to_datastore_msearch_header, to_datastore_body]
end

# @!attribute [r] initial_search_index_definitions
# The index definitions as provided at construction, before any subsequent adjustments.

# Returns an index_definition expression string to use for searches. This string can specify
# multiple indices, use wildcards, etc. For info about what is supported, see:
# https://www.elastic.co/guide/en/elasticsearch/reference/current/multi-index.html
def search_index_expression
@search_index_expression ||= index_expression_builder.determine_search_index_expression(
all_filters,
search_index_definitions,
initial_search_index_definitions,
# When we have aggregations, we must require indices to search. When we search no indices, the datastore does not return
# the standard aggregations response structure, which causes problems.
require_indices: !aggregations_datastore_body.empty?
Expand All @@ -158,10 +161,10 @@ def excluding_indices?
# Returns the name of the datastore cluster as a String where this query should be setn.
# Unless exactly 1 cluster name is found, this method raises a Errors::ConfigError.
def cluster_name
cluster_name = search_index_definitions.map(&:cluster_to_query).uniq
cluster_name = initial_search_index_definitions.map(&:cluster_to_query).uniq
return cluster_name.first if cluster_name.size == 1
raise Errors::ConfigError, "Found different datastore clusters (#{cluster_name}) to query " \
"for query targeting indices: #{search_index_definitions}"
"for query targeting indices: #{initial_search_index_definitions}"
end

# Returns a list of unique field paths that should be used for shard routing during searches.
Expand All @@ -173,7 +176,7 @@ def cluster_name
# can be composed of subtypes that have use different shard routing; this will return
# the set union of them all.
def route_with_field_paths
search_index_definitions.map(&:route_with).uniq
initial_search_index_definitions.map(&:route_with).uniq
end

# The shard routing values used for this search. Can be `nil` if the query will hit all shards.
Expand Down Expand Up @@ -236,7 +239,7 @@ def document_paginator
decoded_cursor_factory: decoded_cursor_factory,
schema_element_names: schema_element_names,
size_multiplier: size_multiplier,
max_effective_size: search_index_definitions.map { |i| i.max_result_window }.min,
max_effective_size: initial_search_index_definitions.map { |i| i.max_result_window }.min,
paginator: Paginator.new(
default_page_size: default_page_size,
max_page_size: max_page_size,
Expand Down Expand Up @@ -297,7 +300,7 @@ def contains_ignored_values_for_routing?(routing_values)
end

def ignored_values_for_routing
@ignored_values_for_routing ||= search_index_definitions.flat_map { |i| i.ignored_values_for_routing.to_a }.to_set
@ignored_values_for_routing ||= initial_search_index_definitions.flat_map { |i| i.ignored_values_for_routing.to_a }.to_set
end

def to_datastore_body
Expand Down Expand Up @@ -361,7 +364,7 @@ def index_expression_builder
end

def new_query(
search_index_definitions:,
initial_search_index_definitions:,
client_filters: [],
internal_filters: [],
sort: [],
Expand All @@ -376,8 +379,8 @@ def new_query(
total_document_count_needed: false,
monotonic_clock_deadline: nil
)
if search_index_definitions.empty?
raise Errors::SearchFailedError, "Query is invalid, since it contains no `search_index_definitions`."
if initial_search_index_definitions.empty?
raise Errors::SearchFailedError, "Query is invalid, since it contains no `initial_search_index_definitions`."
end

individual_docs_needed ||= !requested_fields.empty? || request_all_fields ||
Expand All @@ -390,7 +393,7 @@ def new_query(
index_expression_builder: index_expression_builder,
logger: logger,
schema_element_names: runtime_metadata.schema_element_names,
search_index_definitions: search_index_definitions,
initial_search_index_definitions: initial_search_index_definitions,
client_filters: client_filters.to_set,
internal_filters: internal_filters.to_set,
sort: sort,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def build_automatic_filter(client_filter:, query:)
# If an incomplete document could be hit by a search with our filters against any of the
# index definitions, we must add a filter that will exclude incomplete documents.
exclude_incomplete_docs_filter if query
.search_index_definitions
.initial_search_index_definitions
.any? { |index_def| search_could_hit_incomplete_docs?(index_def, client_filter || {}) }
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def call(query:, args:, field:, lookahead:, context:)
# really cared, they would have provided an `order_by` argument...) but we want our
# logic to be consistent and deterministic, so we just use the alphabetically first
# index here.
sort_clauses = (_ = query.search_index_definitions.min_by(&:name)).default_sort_clauses
sort_clauses = (_ = query.initial_search_index_definitions.min_by(&:name)).default_sort_clauses
end

query.merge_with(sort: sort_clauses)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def build_new_query_from(field, args, lookahead, context, monotonic_clock_deadli
unwrapped_type = field.type.unwrap_fully

initial_query = @datastore_query_builder.new_query(
search_index_definitions: unwrapped_type.search_index_definitions,
initial_search_index_definitions: unwrapped_type.search_index_definitions,
monotonic_clock_deadline: monotonic_clock_deadline
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module ElasticGraph
class GraphQL
class DatastoreQuerySupertype
attr_reader search_index_definitions: ::Array[DatastoreCore::_IndexDefinition]
attr_reader initial_search_index_definitions: ::Array[DatastoreCore::_IndexDefinition]
attr_reader aggregations: ::Hash[::String, Aggregation::Query]
attr_reader document_paginator: DatastoreQuery::DocumentPaginator
attr_reader total_document_count_needed: bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def search_datastore(index_def_name: "widgets", aggregations: [], graphql: self.
index_def = graphql.datastore_core.index_definitions_by_name.fetch(index_def_name)

query = graphql.datastore_query_builder.new_query(
search_index_definitions: [index_def],
initial_search_index_definitions: [index_def],
requested_fields: ["id"],
sort: index_def.default_sort_clauses,
aggregations: aggregations.to_h { |agg| [agg.name, agg] },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def msearch(body:, **args, &block)
widgets_def = graphql.datastore_core.index_definitions_by_name.fetch(unique_index_name)

query = graphql.datastore_query_builder.new_query(
search_index_definitions: [widgets_def],
initial_search_index_definitions: [widgets_def],
requested_fields: ["id"]
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def resolve_field(field, *value_sets, **query_args)
join = graphql_field.relation_join
monotonic_clock = graphql.monotonic_clock
query = graphql.datastore_query_builder.new_query(
search_index_definitions: graphql_field.type.unwrap_fully.search_index_definitions,
initial_search_index_definitions: graphql_field.type.unwrap_fully.search_index_definitions,
# We need to request at least one field, or individual documents won't be requested.
requested_fields: ["name"],
**query_args
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ module Resolvers
components_def = graphql.datastore_core.index_definitions_by_name.fetch("components")

widget_query = graphql.datastore_query_builder.new_query(
search_index_definitions: [widgets_def],
initial_search_index_definitions: [widgets_def],
requested_fields: ["id"]
)

component_query = graphql.datastore_query_builder.new_query(
search_index_definitions: [components_def],
initial_search_index_definitions: [components_def],
requested_fields: ["id"]
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ module Aggregation
alt_individual_docs_needed = base_query.with(individual_docs_needed: !base_query.individual_docs_needed),
alt_sort = base_query.with(sort: [{"age" => {"order" => "desc"}}]),
alt_requested_fields = base_query.with(requested_fields: ["name"]),
alt_index = base_query.with(search_index_definitions: [components_def])
alt_index = base_query.with(initial_search_index_definitions: [components_def])
)

expect(executed_queries).to contain_exactly(
Expand Down Expand Up @@ -193,7 +193,7 @@ def optimize_queries(*queries)
end

def new_query(**options)
graphql.datastore_query_builder.new_query(search_index_definitions: [widgets_def], **options)
graphql.datastore_query_builder.new_query(initial_search_index_definitions: [widgets_def], **options)
end

def build_response_for(query)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ class GraphQL
end

it "returns the name of the datastore cluster from the search index definitions" do
main_query = new_query(search_index_definitions: [widgets_def, addresses_def])
main_query = new_query(initial_search_index_definitions: [widgets_def, addresses_def])
expect(main_query.cluster_name).to eq "main"

other_query = new_query(search_index_definitions: [components_def])
other_query = new_query(initial_search_index_definitions: [components_def])
expect(other_query.cluster_name).to eq "other1"
end

it "raises an error if the index definitions do not agree about the cluster" do
query = new_query(search_index_definitions: [widgets_def, components_def])
query = new_query(initial_search_index_definitions: [widgets_def, components_def])

expect {
query.cluster_name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def new_query(aggregations: {}, types: ["Widget"], **options)

builder.new_query(
aggregations: aggregations,
search_index_definitions: types.flat_map { |t| graphql.datastore_core.index_definitions_by_graphql_type.fetch(t) },
initial_search_index_definitions: types.flat_map { |t| graphql.datastore_core.index_definitions_by_graphql_type.fetch(t) },
**options
)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ class GraphQL
"but the following do not appear to have coverage: #{@attributes_needing_merge_test_coverage}"
end

it "does not allow `search_index_definitions` to be overridden", covers: :search_index_definitions do
it "does not allow `initial_search_index_definitions` to be overridden", covers: :initial_search_index_definitions do
widgets_def = graphql.datastore_core.index_definitions_by_name.fetch("widgets")
components_def = graphql.datastore_core.index_definitions_by_name.fetch("components")

query = new_query(search_index_definitions: [widgets_def])
query = new_query(initial_search_index_definitions: [widgets_def])

expect {
query.merge_with(search_index_definitions: [components_def])
}.to raise_error ArgumentError, a_string_including("search_index_definitions")
query.merge_with(initial_search_index_definitions: [components_def])
}.to raise_error ArgumentError, a_string_including("initial_search_index_definitions")
end

%i[client_filters internal_filters].each do |filter_attr|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ class GraphQL
let(:default_page_size) { 73 }
let(:graphql) { build_graphql(default_page_size: default_page_size) }

it "raises an error if instantiated with an empty collection of `search_index_definitions`" do
it "raises an error if instantiated with an empty collection of `initial_search_index_definitions`" do
expect {
new_query(search_index_definitions: [])
}.to raise_error Errors::SearchFailedError, a_string_including("search_index_definitions")
new_query(initial_search_index_definitions: [])
}.to raise_error Errors::SearchFailedError, a_string_including("initial_search_index_definitions")
end

it "inspects nicely, but redacts filters since they could contain PII" do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ class GraphQL
expect(widgets_def.cluster_to_query).to eq "main"
expect(components_def.cluster_to_query).to eq "other1"

query0 = new_query(search_index_definitions: [widgets_def], client_filters: [{"age" => {"equal_to_any_of" => [0]}}], requested_fields: ["name"])
query1 = new_query(search_index_definitions: [widgets_def], client_filters: [{"age" => {"equal_to_any_of" => [10]}}], requested_fields: ["name"])
query2 = new_query(search_index_definitions: [components_def], client_filters: [{"age" => {"equal_to_any_of" => [20]}}], requested_fields: ["name"])
query0 = new_query(initial_search_index_definitions: [widgets_def], client_filters: [{"age" => {"equal_to_any_of" => [0]}}], requested_fields: ["name"])
query1 = new_query(initial_search_index_definitions: [widgets_def], client_filters: [{"age" => {"equal_to_any_of" => [10]}}], requested_fields: ["name"])
query2 = new_query(initial_search_index_definitions: [components_def], client_filters: [{"age" => {"equal_to_any_of" => [20]}}], requested_fields: ["name"])

yielded_header_body_tuples_by_query = nil

Expand Down Expand Up @@ -120,9 +120,9 @@ class GraphQL
expect(widgets_def.cluster_to_query).to eq "main"
expect(components_def.cluster_to_query).to eq "other1"

query0 = new_query(search_index_definitions: [widgets_def], client_filters: [{"age" => {"equal_to_any_of" => [0]}}], requested_fields: ["name"])
query1 = new_query(search_index_definitions: [widgets_def], client_filters: [{"age" => {"equal_to_any_of" => [10]}}], requested_fields: ["name"])
query2 = new_query(search_index_definitions: [components_def], client_filters: [{"age" => {"equal_to_any_of" => [20]}}], requested_fields: ["name"])
query0 = new_query(initial_search_index_definitions: [widgets_def], client_filters: [{"age" => {"equal_to_any_of" => [0]}}], requested_fields: ["name"])
query1 = new_query(initial_search_index_definitions: [widgets_def], client_filters: [{"age" => {"equal_to_any_of" => [10]}}], requested_fields: ["name"])
query2 = new_query(initial_search_index_definitions: [components_def], client_filters: [{"age" => {"equal_to_any_of" => [20]}}], requested_fields: ["name"])

expect {
DatastoreQuery.perform([query0, query1, query2]) do |header_body_tuples_by_query|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ class GraphQL
expect(manufacturers_def.route_with).to eq "id"
end

it "returns a list of `route_with` values from the `search_index_definitions`" do
query = new_query(search_index_definitions: [widgets_def, addresses_def])
it "returns a list of `route_with` values from the `initial_search_index_definitions`" do
query = new_query(initial_search_index_definitions: [widgets_def, addresses_def])

expect(query.route_with_field_paths).to contain_exactly("workspace_id2", "id")
end

it "deduplicates values when multiple search index definitions have the same `route_with` value" do
query = new_query(search_index_definitions: [manufacturers_def, addresses_def])
query = new_query(initial_search_index_definitions: [manufacturers_def, addresses_def])

expect(query.route_with_field_paths).to contain_exactly("id")
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class GraphQL
expect(widgets_def.index_expression_for_search).to eq "widgets_rollover__*"
expect(components_def.index_expression_for_search).to eq "components"

query = new_query(search_index_definitions: [components_def, widgets_def])
query = new_query(initial_search_index_definitions: [components_def, widgets_def])

expect(query.search_index_expression).to eq "components,widgets_rollover__*"
end
Expand Down Expand Up @@ -548,7 +548,7 @@ def search_index_expression_parts_for(filter_or_filters, aggregations: {})
end

index_def = graphql.datastore_core.index_definitions_by_name.fetch("widgets")
builder.new_query(search_index_definitions: [index_def], aggregations: aggregations, **options).search_index_expression.split(",")
builder.new_query(initial_search_index_definitions: [index_def], aggregations: aggregations, **options).search_index_expression.split(",")
end

# The search index expression parts should be the same regardless of whether a client or internal filter is used.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ def shard_routing_for(route_with_field_paths, filter_or_filters, ignored_routing

search_index_definitions = search_index_definitions_for(route_with_field_paths, ignored_routing_values)

query = new_query(search_index_definitions: search_index_definitions, aggregations: aggregations, **options)
query = new_query(initial_search_index_definitions: search_index_definitions, aggregations: aggregations, **options)

datastore_msearch_header_of(query)[:routing]&.split(",").tap do |used_routing_values|
expect(used_routing_values).to eq(query.shard_routing_values)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ class GraphQL

def new_widgets_query(default_page_size: 50, **args)
options = {
search_index_definitions: [graphql.datastore_core.index_definitions_by_name.fetch("widgets")],
initial_search_index_definitions: [graphql.datastore_core.index_definitions_by_name.fetch("widgets")],
sort: sort_list
}.merge(args)

Expand Down
Loading