elasticgraph-graphql 1.1.0 → 1.2.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: 8acfd27b78b920f78cdd6f27781890bc49b77f430f45d785e5f1b8fa66f74dae
4
- data.tar.gz: ed33c16391844f8b3321ec5849dba8a7acbe502ace6286aaabc401122d085aee
3
+ metadata.gz: aff2847d08949b4bdcd6b6d5ad8d4bdd093998f5e0117545b061336c68c79b2c
4
+ data.tar.gz: 26bad3e27afa0239ac27540a2a1783b51ed6790dfe60db1b6ca8f750dc0f45bf
5
5
  SHA512:
6
- metadata.gz: cad2e9df85cc80e064599f15d1492496b24a8007ddbdf633ae3862ea55f81725e9fae5d266b3e435ee49787c97558955465ad71305ea57e14719031499812ff1
7
- data.tar.gz: 9c3e3ea42f82d421c5319c373f60f23666bee9237ed7df0e84ea2a51f0d7228af49bbc8e3cce9856eaac532b5ea0b0110e7afb9204abd9e737e055743425bb9e
6
+ metadata.gz: b2e1e76a48dea32a3b3f7e0fd7b8b4f71c94f4a9a0595f9c4890c126d1de05666334095715f0fc680b238f465068918af06844a4bd7f18f0912abbba3406b51f
7
+ data.tar.gz: a66d894a2098b9109eeeb71faf42290fc349a90af3116b3a1baa7f2fdedaf64baa6c1e4572179b7ea6c4bfb77f2c13b5c1c71f660732f4b3f9ecc714d30fea33
data/README.md CHANGED
@@ -23,9 +23,6 @@ graph LR;
23
23
  graphql["graphql"];
24
24
  elasticgraph-graphql --> graphql;
25
25
  class graphql externalGemStyle;
26
- graphql-c_parser["graphql-c_parser"];
27
- elasticgraph-graphql --> graphql-c_parser;
28
- class graphql-c_parser externalGemStyle;
29
26
  elasticgraph-apollo["elasticgraph-apollo"];
30
27
  elasticgraph-apollo --> elasticgraph-graphql;
31
28
  class elasticgraph-apollo otherEgGemStyle;
@@ -52,7 +49,6 @@ graph LR;
52
49
  class elasticgraph-schema_definition otherEgGemStyle;
53
50
  click base64 href "https://rubygems.org/gems/base64" "Open on RubyGems.org" _blank;
54
51
  click graphql href "https://rubygems.org/gems/graphql" "Open on RubyGems.org" _blank;
55
- click graphql-c_parser href "https://rubygems.org/gems/graphql-c_parser" "Open on RubyGems.org" _blank;
56
52
  ```
57
53
 
58
54
  ## Usage
@@ -13,12 +13,13 @@ module ElasticGraph
13
13
  # meant to be a friendly/human readable string (such as a service name)
14
14
  # where as `source_description` is meant to be an opaque string describing
15
15
  # where `name` came from.
16
- class Client < Data.define(:source_description, :name)
16
+ class Client < Data.define(:source_description, :name, :extra_opaque_id_parts)
17
17
  # `Data.define` provides the following methods:
18
- # @dynamic initialize, name, source_description, with
18
+ # @dynamic name, source_description, extra_opaque_id_parts, with
19
19
 
20
- ANONYMOUS = new("(anonymous)", "(anonymous)")
21
- ELASTICGRAPH_INTERNAL = new("(ElasticGraphInternal)", "(ElasticGraphInternal)")
20
+ def initialize(source_description:, name:, extra_opaque_id_parts: [])
21
+ super
22
+ end
22
23
 
23
24
  def description
24
25
  if source_description == name
@@ -38,6 +39,9 @@ module ElasticGraph
38
39
  Client::ANONYMOUS
39
40
  end
40
41
  end
42
+
43
+ ANONYMOUS = new("(anonymous)", "(anonymous)")
44
+ ELASTICGRAPH_INTERNAL = new("(ElasticGraphInternal)", "(ElasticGraphInternal)")
41
45
  end
42
46
  end
43
47
  end
@@ -10,6 +10,7 @@ require "elastic_graph/constants"
10
10
  require "elastic_graph/errors"
11
11
  require "elastic_graph/graphql/datastore_response/search_response"
12
12
  require "elastic_graph/graphql/query_details_tracker"
13
+ require "elastic_graph/support/opaque_id"
13
14
  require "elastic_graph/support/threading"
14
15
 
15
16
  module ElasticGraph
@@ -32,7 +33,7 @@ module ElasticGraph
32
33
 
33
34
  # Sends the datastore a multi-search request based on the given queries.
34
35
  # Returns a hash of responses keyed by the query.
35
- def msearch(queries, query_tracker: QueryDetailsTracker.empty)
36
+ def msearch(queries, query_tracker: QueryDetailsTracker.empty, opaque_id_parts: ["elasticgraph-graphql"])
36
37
  DatastoreQuery.perform(queries) do |header_body_tuples_by_query|
37
38
  # Here we set a client-side timeout, which causes the client to give up and close the connection.
38
39
  # According to [1]--"We have a new way to cancel search requests efficiently from the client
@@ -64,6 +65,9 @@ module ElasticGraph
64
65
  # even though Faraday (the underlying HTTP client) does. To work around this, we pass our desired
65
66
  # timeout in a specific header that the `SupportTimeouts` Faraday middleware will use.
66
67
  headers = {TIMEOUT_MS_HEADER => msearch_request_timeout_from(queries)&.to_s}.compact
68
+ if (opaque_id = Support::OpaqueID.build_header(opaque_id_parts))
69
+ headers[OPAQUE_ID_HEADER] = opaque_id
70
+ end
67
71
 
68
72
  queries_and_header_body_tuples_by_datastore_client = header_body_tuples_by_query.group_by do |(query, header_body_tuples)|
69
73
  @datastore_clients_by_name.fetch(query.cluster_name)
@@ -0,0 +1,59 @@
1
+ # Copyright 2024 - 2026 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
+ module ElasticGraph
10
+ class GraphQL
11
+ class QueryAdapter
12
+ # Query adapter that injects a `__typename` filter when querying an abstract type (interface
13
+ # or union) that shares an index with types that fall outside the set of its subtypes. Without
14
+ # this filter, documents belonging to those other types would incorrectly appear in results.
15
+ #
16
+ # For example, given this hierarchy:
17
+ #
18
+ # DistributionChannel (abstract interface, index: distribution_channels)
19
+ # ├── Wholesale (abstract interface, distribution_channels index)
20
+ # │ ├── DirectWholesaler (concrete, distribution_channels index)
21
+ # │ └── BrokerWholesaler (concrete, distribution_channels index)
22
+ # └── Retail (abstract interface, distribution_channels index)
23
+ # └── Store (abstract interface, distribution_channels index)
24
+ # ├── OnlineStore (concrete, distribution_channels index)
25
+ # └── PhysicalStore (concrete, physical_stores index — dedicated)
26
+ #
27
+ # A query for `retailers` (i.e. the `Retail` interface) searches both `distribution_channels`
28
+ # and `physical_stores`. Without a `__typename` filter, `DirectWholesaler` and
29
+ # `BrokerWholesaler` documents from `distribution_channels` would appear in results.
30
+ # So we inject:
31
+ #
32
+ # __typename: { equal_to_any_of: ["OnlineStore", "PhysicalStore"] }
33
+ #
34
+ # `PhysicalStore` has a dedicated index with `__typename` stored as a `constant_keyword`,
35
+ # so it matches the `equal_to_any_of` filter just like documents in the shared index.
36
+ class AbstractTypeFilter
37
+ def initialize(schema_element_names)
38
+ @equal_to_any_of = schema_element_names.equal_to_any_of
39
+ end
40
+
41
+ def call(field:, query:, args:, lookahead:, context:)
42
+ type = field.type.unwrap_fully
43
+
44
+ # For derived types (e.g. indexed aggregations), resolve the underlying document type so we can
45
+ # apply the same __typename scoping as we do for document queries.
46
+ doc_type = type.source_type || type
47
+
48
+ return query unless doc_type.shares_index_with_non_subtypes?
49
+
50
+ subtypes = doc_type.subtypes # Note: subtypes returns all concrete subtypes at any depth
51
+ typename_values = subtypes.map(&:name)
52
+ query.merge_with(internal_filters: [{
53
+ "__typename" => {@equal_to_any_of => typename_values}
54
+ }])
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -55,7 +55,7 @@ module ElasticGraph
55
55
  .selection(@schema.element_names.highlights)
56
56
 
57
57
  {
58
- individual_docs_needed: pagination_fields_need_individual_docs?(lookahead),
58
+ individual_docs_needed: pagination_fields_need_individual_docs?(lookahead) || relay_connection_node_from(lookahead).selected?,
59
59
  requested_fields: requested_fields_under(relay_connection_node_from(lookahead), index_field_paths),
60
60
  request_all_highlights: requesting_all_highlights?(lookahead),
61
61
  requested_highlights: requested_fields_under(highlights, index_field_paths)
@@ -86,7 +86,10 @@ module ElasticGraph
86
86
  requested_fields_for(child, index_field_paths, path_prefix: path_prefix)
87
87
  end
88
88
 
89
- fields << "#{path_prefix}__typename" if field_for(node.field)&.type&.abstract?
89
+ # For abstract types (unions/interfaces), we need __typename to resolve the concrete type.
90
+ # We must fully unwrap the type to check the innermost type, since the field type could be
91
+ # wrapped in non-null or list wrappers (e.g., `[NamedInventor!]!` on a `nodes` relay connection field).
92
+ fields << "#{path_prefix}__typename" if field_for(node.field)&.type&.unwrap_fully&.abstract?
90
93
  fields
91
94
  end
92
95
 
@@ -59,7 +59,8 @@ module ElasticGraph
59
59
  client: client,
60
60
  context: context.merge({
61
61
  monotonic_clock_deadline: timeout_in_ms&.+(start_time_in_ms),
62
- elastic_graph_query_tracker: query_tracker
62
+ elastic_graph_query_tracker: query_tracker,
63
+ elastic_graph_client: client
63
64
  }.compact)
64
65
  )
65
66
 
@@ -89,7 +90,7 @@ module ElasticGraph
89
90
  @logger.info({
90
91
  "message_type" => "ElasticGraphQueryExecutorQueryDuration",
91
92
  "client" => client.name,
92
- "query_fingerprint" => fingerprint_for(query),
93
+ "query_fingerprint" => query.fingerprint,
93
94
  "query_name" => query.selected_operation_name,
94
95
  "duration_ms" => duration,
95
96
  # How long the datastore queries took according to what the datastore itself reported.
@@ -142,7 +143,7 @@ module ElasticGraph
142
143
  def execute_query(query, client:)
143
144
  # Log the query before starting to execute it, in case there's a lambda timeout, in which case
144
145
  # we won't get any other logged messages for the query.
145
- @logger.info "Starting to execute query #{fingerprint_for(query)} for client #{client.description}."
146
+ @logger.info "Starting to execute query #{query.fingerprint} for client #{client.description}."
146
147
 
147
148
  query.result
148
149
  rescue => ex
@@ -163,11 +164,7 @@ module ElasticGraph
163
164
  # the fingerprint to make sure that we at least have some identification information
164
165
  # about the query.
165
166
  def full_description_of(query)
166
- "#{fingerprint_for(query)} #{query.sanitized_query_string}"
167
- end
168
-
169
- def fingerprint_for(query)
170
- query.query_string ? query.fingerprint : "(no query string)"
167
+ "#{query.fingerprint} #{query.sanitized_query_string}"
171
168
  end
172
169
 
173
170
  def slo_result_for(query, duration)
@@ -110,8 +110,9 @@ module ElasticGraph
110
110
  # In order to support unions and interfaces, we must implement `resolve_type`.
111
111
  def resolve_type(supertype, object, context)
112
112
  schema = context.fetch(:elastic_graph_schema)
113
- # If `__typename` is available, use that to resolve. It should be available on any embedded abstract types...
114
- # (See `Inventor` in `config/schema.graphql` for an example of this kind of type union.)
113
+ # If `__typename` is available, use that to resolve. It will be present on embedded abstract
114
+ # types, and also on root documents indexed in a shared interface/union index.
115
+ # (See `Inventor` in `config/schema/widgets.rb` for an example of an embedded abstract type.)
115
116
  if (typename = object["__typename"])
116
117
  schema
117
118
  .graphql_schema
@@ -121,7 +122,9 @@ module ElasticGraph
121
122
  # ...otherwise infer the type based on what index the object came from. This is the case
122
123
  # with unions/interfaces of individually indexed types.
123
124
  # (See `Part` in `config/schema/widgets.rb` for an example of this kind of type union.)
124
- schema.document_type_stored_in(object.index_definition_name).graphql_type
125
+ # This branch is only reached for individually-indexed types (no `__typename`
126
+ # in the document), so the set always contains exactly one type.
127
+ schema.document_types_stored_in(object.index_definition_name).first.graphql_type
125
128
  end
126
129
  end
127
130
  end
@@ -12,8 +12,8 @@ require "elastic_graph/graphql/resolvers/relay_connection"
12
12
  module ElasticGraph
13
13
  class GraphQL
14
14
  module Resolvers
15
- # Responsible for fetching a a list of records of a particular type
16
- class ListRecords
15
+ # Responsible for resolving the list and aggregation root fields generated for each indexed type.
16
+ class IndexedTypeRootFieldsResolver
17
17
  def initialize(elasticgraph_graphql:, config:)
18
18
  # Nothing to initialize, but needs to be defined to satisfy the resolver interface.
19
19
  end
@@ -20,28 +20,48 @@ module ElasticGraph
20
20
  # Note: `NestedRelationshipsSource` implements further optimizations on top of this, and should
21
21
  # be used rather than this class when applicable.
22
22
  class QuerySource < ::GraphQL::Dataloader::Source
23
- def initialize(datastore_router, query_tracker)
23
+ def initialize(datastore_router, query_tracker, opaque_id_parts = [])
24
24
  @datastore_router = datastore_router
25
25
  @query_tracker = query_tracker
26
+ @opaque_id_parts = opaque_id_parts
26
27
  end
27
28
 
28
29
  def fetch(queries)
29
- responses_by_query = @datastore_router.msearch(queries, query_tracker: @query_tracker)
30
+ responses_by_query = @datastore_router.msearch(
31
+ queries,
32
+ query_tracker: @query_tracker,
33
+ opaque_id_parts: @opaque_id_parts
34
+ )
30
35
  queries.map { |q| responses_by_query.fetch(q) }
31
36
  end
32
37
 
33
38
  def self.execute_many(queries, for_context:)
34
39
  datastore_router = for_context.fetch(:datastore_search_router)
35
40
  query_tracker = for_context.fetch(:elastic_graph_query_tracker)
41
+ opaque_id_parts = datastore_opaque_id_parts_for(for_context)
36
42
  dataloader = for_context.dataloader
37
43
 
38
- responses = dataloader.with(self, datastore_router, query_tracker).load_all(queries)
44
+ responses = dataloader.with(self, datastore_router, query_tracker, opaque_id_parts).load_all(queries)
39
45
  queries.zip(responses).to_h
40
46
  end
41
47
 
42
48
  def self.execute_one(query, for_context:)
43
49
  execute_many([query], for_context: for_context).fetch(query)
44
50
  end
51
+
52
+ # `QueryExecutor` adds `:elastic_graph_client` to the GraphQL context before
53
+ # resolver execution begins, so resolver-side datastore queries can reuse the
54
+ # same client identity in their datastore `X-Opaque-Id` headers.
55
+ private_class_method def self.datastore_opaque_id_parts_for(for_context)
56
+ client = for_context.fetch(:elastic_graph_client)
57
+ graphql_query = for_context.query
58
+ [
59
+ "elasticgraph-graphql",
60
+ "client=#{client.name}",
61
+ *client.extra_opaque_id_parts,
62
+ "query=#{graphql_query.fingerprint}"
63
+ ]
64
+ end
45
65
  end
46
66
  end
47
67
  end
@@ -47,7 +47,16 @@ module ElasticGraph
47
47
 
48
48
  def all_highlights
49
49
  @all_highlights ||= begin
50
- document_type = schema.document_type_stored_in(node.index_definition_name)
50
+ document_type =
51
+ if (typename = node["__typename"])
52
+ # When multiple types share an index, documents carry a `__typename` field
53
+ # that identifies the concrete type; use it to resolve the concrete type directly.
54
+ schema.type_named(typename)
55
+ else
56
+ # Index inheritance always injects `__typename` into any shared index mapping,
57
+ # so a missing `__typename` means no sharing — the set contains exactly one type.
58
+ schema.document_types_stored_in(node.index_definition_name).first # : Schema::Type
59
+ end
51
60
 
52
61
  node.highlights.filter_map do |path_string, snippets|
53
62
  if (path = path_from(path_string, document_type))
@@ -61,12 +61,12 @@ module ElasticGraph
61
61
  # List of index definitions that should be searched for this type.
62
62
  def search_index_definitions
63
63
  @search_index_definitions ||=
64
- if indexed_aggregation?
65
- # For an indexed aggregation, we just delegate to its source type. This works better than
66
- # dumping index definitions in the runtime metadata of the indexed aggregation type itself
67
- # because of abstract (interface/union) types. The source document type handles that (since
68
- # there is a supertype/subtype relationship on the document types) but that relationship
69
- # does not exist on the indexed aggregation.
64
+ if (st = source_type)
65
+ # When a type has a source type (a prime example being indexed aggregations), we delegate
66
+ # to the source type. This works better than dumping index definitions in the runtime metadata
67
+ # of the derived type itself because of abstract (interface/union) types. The source document
68
+ # type handles that (since there is a supertype/subtype relationship on the document types)
69
+ # but that relationship does not exist on derived types.
70
70
  #
71
71
  # For example, assume we have these indexed document types:
72
72
  # - type Person {}
@@ -76,9 +76,15 @@ module ElasticGraph
76
76
  # We can go from `Inventor` to its subtypes to find the search indexes. However, `InventorAggregation`
77
77
  # is NOT a union of `PersonAggregation` and `CompanyAggregation`, so we can't do the same thing on the
78
78
  # indexed aggregation types. Delegating to the source type solves this case.
79
- @schema.type_named(@object_runtime_metadata.source_type).search_index_definitions
79
+ st.search_index_definitions
80
+ elsif abstract?
81
+ # For abstract types, derive search indexes purely from concrete subtypes. This correctly
82
+ # handles cases where subtypes override the abstract type's declared index with a dedicated
83
+ # one — only indexes that actually contain documents for this type are searched.
84
+ # Note: subtypes returns all concrete subtypes at any depth, so no explicit recursion is needed.
85
+ subtypes.flat_map(&:search_index_definitions).to_set
80
86
  else
81
- @index_definitions.union(subtypes.flat_map(&:search_index_definitions))
87
+ @index_definitions
82
88
  end
83
89
  end
84
90
 
@@ -117,13 +123,35 @@ module ElasticGraph
117
123
  end
118
124
  end
119
125
 
120
- # Returns the subtypes of this type, if it has any. This is like `#possible_types` provided by the
126
+ # Returns all concrete subtypes, at any depth. This is like `#possible_types` provided by the
121
127
  # GraphQL gem, but that includes a type itself when you ask for the possible types of a non-abstract type.
122
128
  def subtypes
123
129
  @subtypes ||= @schema
124
130
  .graphql_schema
125
131
  .possible_types(graphql_type, visibility_profile: :boot)
126
- .map { |t| @schema.type_from(t) } - [self]
132
+ .map { |t| @schema.type_from(t) }
133
+ .reject { |t| t == self }
134
+ .to_set
135
+ end
136
+
137
+ # For derived types (e.g. indexed aggregations), returns the underlying source document type.
138
+ # Returns `nil` for non-derived types.
139
+ def source_type
140
+ return @source_type if defined?(@source_type)
141
+ @source_type = @object_runtime_metadata&.source_type&.then { |st| @schema.type_named(st) }
142
+ end
143
+
144
+ # Returns true if any of this type's search indexes contain any concrete document types
145
+ # that are not subtypes of this type. Used to determine whether a `__typename` filter is
146
+ # needed when querying an abstract type.
147
+ def shares_index_with_non_subtypes?
148
+ return @shares_index_with_non_subtypes if defined?(@shares_index_with_non_subtypes)
149
+ @shares_index_with_non_subtypes =
150
+ search_index_definitions.any? do |index_def|
151
+ @schema.document_types_stored_in(index_def.name).any? do |t|
152
+ t != self && !subtypes.include?(t) && !t.abstract?
153
+ end
154
+ end
127
155
  end
128
156
 
129
157
  def field_named(field_name)
@@ -120,7 +120,12 @@ module ElasticGraph
120
120
  raise Errors::NotFoundError, msg
121
121
  end
122
122
 
123
- def document_type_stored_in(index_definition_name)
123
+ # Returns all indexed document types stored in the named index definition.
124
+ # The returned set includes both abstract and concrete types. Multiple types may be returned
125
+ # when abstract types share an index with their concrete subtypes via index inheritance.
126
+ # @raise [Errors::NotFoundError] if the index definition name is not recognized
127
+ # @raise [ArgumentError] if given the name of a rollover index instead of the parent index definition name
128
+ def document_types_stored_in(index_definition_name)
124
129
  indexed_document_types_by_index_definition_name.fetch(index_definition_name) do
125
130
  if index_definition_name.include?(ROLLOVER_INDEX_INFIX_MARKER)
126
131
  raise ArgumentError, "`#{index_definition_name}` is the name of a rollover index; pass the name of the parent index definition instead."
@@ -190,16 +195,14 @@ module ElasticGraph
190
195
  end
191
196
  end
192
197
 
198
+ # Intentionally private: public callers should use `document_types_stored_in` instead.
193
199
  def indexed_document_types_by_index_definition_name
194
- @indexed_document_types_by_index_definition_name ||= indexed_document_types.each_with_object({}) do |type, hash|
195
- type.index_definitions.each do |index_def|
196
- if hash.key?(index_def.name)
197
- raise Errors::SchemaError, "DatastoreCore::IndexDefinition #{index_def.name} is used multiple times: #{type} vs #{hash[index_def.name]}"
200
+ @indexed_document_types_by_index_definition_name ||=
201
+ indexed_document_types.each_with_object(::Hash.new { |h, k| h[k] = ::Set.new }) do |type, hash|
202
+ type.index_definitions.each do |index_def|
203
+ hash[index_def.name] << type
198
204
  end
199
-
200
- hash[index_def.name] = type
201
- end
202
- end.freeze
205
+ end.freeze
203
206
  end
204
207
 
205
208
  def log_hidden_types
@@ -10,6 +10,7 @@ require "elastic_graph/datastore_core"
10
10
  require "elastic_graph/graphql/config"
11
11
  require "elastic_graph/constants"
12
12
  require "elastic_graph/support/from_yaml_file"
13
+ require "elastic_graph/support/graphql_gem_loader"
13
14
 
14
15
  module ElasticGraph
15
16
  # The main entry point for ElasticGraph GraphQL handling. Instantiate this to get access to the
@@ -132,13 +133,7 @@ module ElasticGraph
132
133
  # @private
133
134
  def graphql_gem_plugins
134
135
  @graphql_gem_plugins ||= begin
135
- require "graphql"
136
- # As per https://graphql-ruby.org/language_tools/c_parser.html, loading the
137
- # C parser causes the faster parser to be assigned as the `::GraphQL.default_parser`,
138
- # providing greater efficiency.
139
- #
140
- # We load it here since this is where we load the GraphQL gem.
141
- require "graphql/c_parser"
136
+ Support::GraphQLGemLoader.load
142
137
 
143
138
  {
144
139
  # We depend on this to avoid N+1 calls to the datastore.
@@ -197,6 +192,7 @@ module ElasticGraph
197
192
  def datastore_query_adapters
198
193
  @datastore_query_adapters ||= begin
199
194
  require "elastic_graph/graphql/aggregation/query_adapter"
195
+ require "elastic_graph/graphql/query_adapter/abstract_type_filter"
200
196
  require "elastic_graph/graphql/query_adapter/filters"
201
197
  require "elastic_graph/graphql/query_adapter/pagination"
202
198
  require "elastic_graph/graphql/query_adapter/sort"
@@ -205,6 +201,7 @@ module ElasticGraph
205
201
  schema_element_names = runtime_metadata.schema_element_names
206
202
 
207
203
  [
204
+ GraphQL::QueryAdapter::AbstractTypeFilter.new(schema_element_names),
208
205
  GraphQL::QueryAdapter::Pagination.new(schema_element_names: schema_element_names),
209
206
  GraphQL::QueryAdapter::Filters.new(
210
207
  schema_element_names: schema_element_names,
@@ -268,9 +265,7 @@ module ElasticGraph
268
265
  # at boot time instead of deferring dependency loading until we handle the first query. In other environments (such as tests),
269
266
  # it's nice to load dependencies when needed.
270
267
  def load_dependencies_eagerly
271
- require "graphql"
272
- require "graphql/c_parser"
273
-
268
+ Support::GraphQLGemLoader.load
274
269
  ::GraphQL.eager_load!
275
270
 
276
271
  # run a simple GraphQL query to force load any dependencies needed to handle GraphQL queries
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elasticgraph-graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Myron Marston
@@ -31,132 +31,112 @@ dependencies:
31
31
  requirements:
32
32
  - - '='
33
33
  - !ruby/object:Gem::Version
34
- version: 1.1.0
34
+ version: 1.2.0
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - '='
40
40
  - !ruby/object:Gem::Version
41
- version: 1.1.0
41
+ version: 1.2.0
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: elasticgraph-schema_artifacts
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
46
  - - '='
47
47
  - !ruby/object:Gem::Version
48
- version: 1.1.0
48
+ version: 1.2.0
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
53
  - - '='
54
54
  - !ruby/object:Gem::Version
55
- version: 1.1.0
55
+ version: 1.2.0
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: graphql
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
60
  - - "~>"
61
61
  - !ruby/object:Gem::Version
62
- version: 2.5.18
62
+ version: 2.6.2
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - "~>"
68
68
  - !ruby/object:Gem::Version
69
- version: 2.5.18
70
- - !ruby/object:Gem::Dependency
71
- name: graphql-c_parser
72
- requirement: !ruby/object:Gem::Requirement
73
- requirements:
74
- - - "~>"
75
- - !ruby/object:Gem::Version
76
- version: '1.1'
77
- - - ">="
78
- - !ruby/object:Gem::Version
79
- version: 1.1.3
80
- type: :runtime
81
- prerelease: false
82
- version_requirements: !ruby/object:Gem::Requirement
83
- requirements:
84
- - - "~>"
85
- - !ruby/object:Gem::Version
86
- version: '1.1'
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: 1.1.3
69
+ version: 2.6.2
90
70
  - !ruby/object:Gem::Dependency
91
71
  name: elasticgraph-admin
92
72
  requirement: !ruby/object:Gem::Requirement
93
73
  requirements:
94
74
  - - '='
95
75
  - !ruby/object:Gem::Version
96
- version: 1.1.0
76
+ version: 1.2.0
97
77
  type: :development
98
78
  prerelease: false
99
79
  version_requirements: !ruby/object:Gem::Requirement
100
80
  requirements:
101
81
  - - '='
102
82
  - !ruby/object:Gem::Version
103
- version: 1.1.0
83
+ version: 1.2.0
104
84
  - !ruby/object:Gem::Dependency
105
85
  name: elasticgraph-elasticsearch
106
86
  requirement: !ruby/object:Gem::Requirement
107
87
  requirements:
108
88
  - - '='
109
89
  - !ruby/object:Gem::Version
110
- version: 1.1.0
90
+ version: 1.2.0
111
91
  type: :development
112
92
  prerelease: false
113
93
  version_requirements: !ruby/object:Gem::Requirement
114
94
  requirements:
115
95
  - - '='
116
96
  - !ruby/object:Gem::Version
117
- version: 1.1.0
97
+ version: 1.2.0
118
98
  - !ruby/object:Gem::Dependency
119
99
  name: elasticgraph-opensearch
120
100
  requirement: !ruby/object:Gem::Requirement
121
101
  requirements:
122
102
  - - '='
123
103
  - !ruby/object:Gem::Version
124
- version: 1.1.0
104
+ version: 1.2.0
125
105
  type: :development
126
106
  prerelease: false
127
107
  version_requirements: !ruby/object:Gem::Requirement
128
108
  requirements:
129
109
  - - '='
130
110
  - !ruby/object:Gem::Version
131
- version: 1.1.0
111
+ version: 1.2.0
132
112
  - !ruby/object:Gem::Dependency
133
113
  name: elasticgraph-indexer
134
114
  requirement: !ruby/object:Gem::Requirement
135
115
  requirements:
136
116
  - - '='
137
117
  - !ruby/object:Gem::Version
138
- version: 1.1.0
118
+ version: 1.2.0
139
119
  type: :development
140
120
  prerelease: false
141
121
  version_requirements: !ruby/object:Gem::Requirement
142
122
  requirements:
143
123
  - - '='
144
124
  - !ruby/object:Gem::Version
145
- version: 1.1.0
125
+ version: 1.2.0
146
126
  - !ruby/object:Gem::Dependency
147
127
  name: elasticgraph-schema_definition
148
128
  requirement: !ruby/object:Gem::Requirement
149
129
  requirements:
150
130
  - - '='
151
131
  - !ruby/object:Gem::Version
152
- version: 1.1.0
132
+ version: 1.2.0
153
133
  type: :development
154
134
  prerelease: false
155
135
  version_requirements: !ruby/object:Gem::Requirement
156
136
  requirements:
157
137
  - - '='
158
138
  - !ruby/object:Gem::Version
159
- version: 1.1.0
139
+ version: 1.2.0
160
140
  email:
161
141
  - myron@squareup.com
162
142
  executables: []
@@ -205,6 +185,7 @@ files:
205
185
  - lib/elastic_graph/graphql/filtering/filter_value_set_extractor.rb
206
186
  - lib/elastic_graph/graphql/filtering/range_query.rb
207
187
  - lib/elastic_graph/graphql/http_endpoint.rb
188
+ - lib/elastic_graph/graphql/query_adapter/abstract_type_filter.rb
208
189
  - lib/elastic_graph/graphql/query_adapter/filters.rb
209
190
  - lib/elastic_graph/graphql/query_adapter/pagination.rb
210
191
  - lib/elastic_graph/graphql/query_adapter/requested_fields.rb
@@ -213,7 +194,7 @@ files:
213
194
  - lib/elastic_graph/graphql/query_executor.rb
214
195
  - lib/elastic_graph/graphql/resolvers/get_record_field_value.rb
215
196
  - lib/elastic_graph/graphql/resolvers/graphql_adapter_builder.rb
216
- - lib/elastic_graph/graphql/resolvers/list_records.rb
197
+ - lib/elastic_graph/graphql/resolvers/indexed_type_root_fields_resolver.rb
217
198
  - lib/elastic_graph/graphql/resolvers/nested_relationships.rb
218
199
  - lib/elastic_graph/graphql/resolvers/nested_relationships_source.rb
219
200
  - lib/elastic_graph/graphql/resolvers/object.rb
@@ -247,10 +228,10 @@ licenses:
247
228
  - MIT
248
229
  metadata:
249
230
  bug_tracker_uri: https://github.com/block/elasticgraph/issues
250
- changelog_uri: https://github.com/block/elasticgraph/releases/tag/v1.1.0
251
- documentation_uri: https://block.github.io/elasticgraph/api-docs/v1.1.0/
231
+ changelog_uri: https://github.com/block/elasticgraph/releases/tag/v1.2.0
232
+ documentation_uri: https://block.github.io/elasticgraph/api-docs/v1.2.0/
252
233
  homepage_uri: https://block.github.io/elasticgraph/
253
- source_code_uri: https://github.com/block/elasticgraph/tree/v1.1.0/elasticgraph-graphql
234
+ source_code_uri: https://github.com/block/elasticgraph/tree/v1.2.0/elasticgraph-graphql
254
235
  gem_category: core
255
236
  rdoc_options: []
256
237
  require_paths:
@@ -269,7 +250,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
269
250
  - !ruby/object:Gem::Version
270
251
  version: '0'
271
252
  requirements: []
272
- rubygems_version: 4.0.3
253
+ rubygems_version: 4.0.6
273
254
  specification_version: 4
274
255
  summary: Provides the ElasticGraph GraphQL query engine.
275
256
  test_files: []