elasticgraph-schema_artifacts 0.19.1.1 → 0.19.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.
Files changed (23) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/lib/elastic_graph/schema_artifacts/artifacts_helper_methods.rb +1 -1
  4. data/lib/elastic_graph/schema_artifacts/from_disk.rb +1 -1
  5. data/lib/elastic_graph/schema_artifacts/runtime_metadata/computation_detail.rb +1 -1
  6. data/lib/elastic_graph/schema_artifacts/runtime_metadata/enum.rb +1 -1
  7. data/lib/elastic_graph/schema_artifacts/runtime_metadata/extension.rb +19 -12
  8. data/lib/elastic_graph/schema_artifacts/runtime_metadata/extension_loader.rb +6 -77
  9. data/lib/elastic_graph/schema_artifacts/runtime_metadata/graphql_field.rb +13 -6
  10. data/lib/elastic_graph/schema_artifacts/runtime_metadata/graphql_resolver.rb +66 -0
  11. data/lib/elastic_graph/schema_artifacts/runtime_metadata/hash_dumper.rb +1 -1
  12. data/lib/elastic_graph/schema_artifacts/runtime_metadata/index_definition.rb +1 -1
  13. data/lib/elastic_graph/schema_artifacts/runtime_metadata/index_field.rb +1 -1
  14. data/lib/elastic_graph/schema_artifacts/runtime_metadata/interface_verifier.rb +109 -0
  15. data/lib/elastic_graph/schema_artifacts/runtime_metadata/object_type.rb +11 -4
  16. data/lib/elastic_graph/schema_artifacts/runtime_metadata/params.rb +3 -3
  17. data/lib/elastic_graph/schema_artifacts/runtime_metadata/relation.rb +1 -1
  18. data/lib/elastic_graph/schema_artifacts/runtime_metadata/scalar_type.rb +3 -3
  19. data/lib/elastic_graph/schema_artifacts/runtime_metadata/schema.rb +13 -4
  20. data/lib/elastic_graph/schema_artifacts/runtime_metadata/schema_element_names.rb +1 -1
  21. data/lib/elastic_graph/schema_artifacts/runtime_metadata/sort_field.rb +1 -1
  22. data/lib/elastic_graph/schema_artifacts/runtime_metadata/update_target.rb +1 -1
  23. metadata +14 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e13f3dabb5a9086592a80c8369d58479c2af9b3f3d04a28b6c339bed342bea41
4
- data.tar.gz: a119fea91764d31adca633580d06084ac1ad40866b87b224add809d69a07fd6b
3
+ metadata.gz: ed9482702dcda2510d507060aeddf082f437a2c8c306d78d96d144efc6edd59f
4
+ data.tar.gz: 762c4dc97b95094765ce55b6e88059596be673bef65a1491f14e2ded59569b86
5
5
  SHA512:
6
- metadata.gz: 4101e29cf963bb84894c16d974da595488e63fcc9e78dfebfbb748adaabb2a3a039c67785ec2aa12d0e3cabdc8ce3b140297d42be89009ddf4482590c426dfc3
7
- data.tar.gz: cc12505507fd84c0bd076e939e22a0edb06318fcc0d3032dba40d352c5e26a882cb194f3c25637f96339ff711e3b2a88e8bc627bf2614c47117535caeaf1aac9
6
+ metadata.gz: d62417bfa74d5c50c0f6fee9517422b4e19e10fd4fc77700f5690658c9860e096adeb0313c4eac9028cef9220bea56a103d8a5a85aa1aa719c757505e82f618c
7
+ data.tar.gz: eb2287a4b244ac96ba468af7e508a524a1ae28790f657e3a6db94ca06fcd63ffca5c49a0ea0d50e5f2c9b9cf1724674ccf9117fd1fc3a2f636b9837e834f07f2
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2024 Block, Inc.
3
+ Copyright (c) 2024 - 2025 Block, Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -6,6 +6,7 @@
6
6
  #
7
7
  # frozen_string_literal: true
8
8
 
9
+ require "elastic_graph/schema_artifacts/runtime_metadata/interface_verifier"
9
10
  require "elastic_graph/support/hash_util"
10
11
 
11
12
  module ElasticGraph
@@ -15,36 +16,42 @@ module ElasticGraph
15
16
  # code base) that implements a standard interface to plug in custom functionality.
16
17
  #
17
18
  # Extensions are serialized using two fields:
18
- # - `extension_name`: the Ruby constant of the extension
19
+ # - `name`: the Ruby constant of the extension
19
20
  # - `require_path`: file path to `require` to load the extension
20
21
  #
21
22
  # However, an `Extension` instance represents a loaded, resolved extension.
22
23
  # We eagerly load extensions (and validate them in the `ExtensionLoader`) in
23
24
  # order to surface any issues with the extension as soon as possible. We don't
24
25
  # want to defer errors if we can detect any issues with the extension at boot time.
25
- Extension = ::Data.define(:extension_class, :require_path, :extension_config) do
26
+ Extension = ::Data.define(:extension_class, :require_path, :config, :name) do
26
27
  # @implements Extension
28
+ def initialize(extension_class:, require_path:, config:, name: extension_class.name.to_s)
29
+ super(extension_class:, require_path:, config:, name:)
30
+ end
27
31
 
28
32
  # Loads an extension using a serialized hash, via the provided `ExtensionLoader`.
29
33
  def self.load_from_hash(hash, via:)
30
- config = Support::HashUtil.symbolize_keys(hash["extension_config"] || {}) # : ::Hash[::Symbol, untyped]
31
- via.load(hash.fetch("extension_name"), from: hash.fetch("require_path"), config: config)
32
- end
33
-
34
- # The name of the extension (based on the name of the extension class).
35
- def extension_name
36
- extension_class.name.to_s
34
+ config = Support::HashUtil.symbolize_keys(hash["config"] || {}) # : ::Hash[::Symbol, untyped]
35
+ via.load(hash.fetch("name"), from: hash.fetch("require_path"), config: config)
37
36
  end
38
37
 
39
38
  # The serialized form of an extension.
40
39
  def to_dumpable_hash
41
40
  # Keys here are ordered alphabetically; please keep them that way.
42
41
  {
43
- "extension_config" => Support::HashUtil.stringify_keys(extension_config),
44
- "extension_name" => extension_name,
42
+ "config" => Support::HashUtil.stringify_keys(config),
43
+ "name" => name,
45
44
  "require_path" => require_path
46
45
  }.reject { |_, v| v.empty? }
47
46
  end
47
+
48
+ def verify_against!(interface_def)
49
+ InterfaceVerifier.verify!(extension_class, against: interface_def, constant_name: name)
50
+ end
51
+
52
+ def verify_against(interface_def)
53
+ InterfaceVerifier.verify(extension_class, against: interface_def, constant_name: name)
54
+ end
48
55
  end
49
56
  end
50
57
  end
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -8,6 +8,7 @@
8
8
 
9
9
  require "elastic_graph/errors"
10
10
  require "elastic_graph/schema_artifacts/runtime_metadata/extension"
11
+ require "elastic_graph/schema_artifacts/runtime_metadata/interface_verifier"
11
12
 
12
13
  module ElasticGraph
13
14
  module SchemaArtifacts
@@ -35,89 +36,17 @@ module ElasticGraph
35
36
  raise Errors::InvalidExtensionError, "Extension `#{constant_name}` cannot be loaded from `#{from}`, " \
36
37
  "since it has already been loaded from `#{extension.require_path}`."
37
38
  end
38
- end.with(extension_config: config)
39
+ end.with(config: config)
39
40
  end
40
41
 
41
42
  private
42
43
 
43
44
  def load_extension(constant_name, require_path)
44
45
  require require_path
45
- extension_class = ::Object.const_get(constant_name).tap { |ext| verify_interface(constant_name, ext) }
46
- Extension.new(extension_class, require_path, {})
47
- end
48
-
49
- def verify_interface(constant_name, extension)
50
- # @type var problems: ::Array[::String]
51
- problems = []
52
- problems.concat(verify_methods("class", extension.singleton_class, @interface_def.singleton_class))
53
-
54
- if extension.is_a?(::Module)
55
- problems.concat(verify_methods("instance", extension, @interface_def))
56
-
57
- # We care about the name exactly matching so that we can dump the extension name in a schema
58
- # artifact w/o having to pass around the original constant name.
59
- if extension.name != constant_name.delete_prefix("::")
60
- problems << "- Exposes a name (`#{extension.name}`) that differs from the provided extension name (`#{constant_name}`)"
61
- end
62
- else
63
- problems << "- Is not a class or module as expected"
64
- end
65
-
66
- if problems.any?
67
- raise Errors::InvalidExtensionError,
68
- "Extension `#{constant_name}` does not implement the expected interface correctly. Problems:\n\n" \
69
- "#{problems.join("\n")}"
70
- end
71
- end
72
-
73
- def verify_methods(type, extension, interface)
74
- interface_methods = list_instance_interface_methods(interface)
75
- extension_methods = list_instance_interface_methods(extension)
76
-
77
- # @type var problems: ::Array[::String]
78
- problems = []
79
-
80
- if (missing_methods = interface_methods - extension_methods).any?
81
- problems << "- Missing #{type} methods: #{missing_methods.map { |m| "`#{m}`" }.join(", ")}"
46
+ extension_class = ::Object.const_get(constant_name)
47
+ Extension.new(extension_class, require_path, {}, constant_name.delete_prefix("::")).tap do |ext|
48
+ ext.verify_against!(@interface_def)
82
49
  end
83
-
84
- interface_methods.intersection(extension_methods).each do |method_name|
85
- unless parameters_match?(extension, interface, method_name)
86
- interface_signature = signature_code_for(interface, method_name)
87
- extension_signature = signature_code_for(extension, method_name)
88
-
89
- problems << "- Method signature for #{type} method `#{method_name}` (`#{extension_signature}`) does not match interface (`#{interface_signature}`)"
90
- end
91
- end
92
-
93
- problems
94
- end
95
-
96
- def list_instance_interface_methods(klass)
97
- # Here we look at more than just the public methods. This is necessary for `initialize`.
98
- # If it's defined on the interface definition, we want to verify it on the extension,
99
- # but Ruby makes `initialize` private by default.
100
- klass.instance_methods(false) +
101
- klass.protected_instance_methods(false) +
102
- klass.private_instance_methods(false)
103
- end
104
-
105
- def parameters_match?(extension, interface, method_name)
106
- interface_parameters = interface.instance_method(method_name).parameters
107
- extension_parameters = extension.instance_method(method_name).parameters
108
-
109
- # Here we compare the parameters for exact equality. This is stricter than we need it
110
- # to be (it doesn't allow the parameters to have different names, for example) but it's
111
- # considerably simpler than us trying to determine what is truly required. For example,
112
- # the name doesn't matter on a positional arg, but would matter on a keyword arg.
113
- interface_parameters == extension_parameters
114
- end
115
-
116
- def signature_code_for(object, method_name)
117
- # @type var file_name: ::String?
118
- # @type var line_number: ::Integer?
119
- file_name, line_number = object.instance_method(method_name).source_location
120
- ::File.read(file_name.to_s).split("\n").fetch(line_number.to_i - 1).strip
121
50
  end
122
51
  end
123
52
  end
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -12,17 +12,19 @@ require "elastic_graph/schema_artifacts/runtime_metadata/relation"
12
12
  module ElasticGraph
13
13
  module SchemaArtifacts
14
14
  module RuntimeMetadata
15
- class GraphQLField < ::Data.define(:name_in_index, :relation, :computation_detail)
16
- EMPTY = new(nil, nil, nil)
15
+ class GraphQLField < ::Data.define(:name_in_index, :relation, :computation_detail, :resolver)
16
+ EMPTY = new(nil, nil, nil, nil)
17
17
  NAME_IN_INDEX = "name_in_index"
18
18
  RELATION = "relation"
19
19
  AGGREGATION_DETAIL = "computation_detail"
20
+ RESOLVER = "resolver"
20
21
 
21
22
  def self.from_hash(hash)
22
23
  new(
23
24
  name_in_index: hash[NAME_IN_INDEX],
24
25
  relation: hash[RELATION]&.then { |rel_hash| Relation.from_hash(rel_hash) },
25
- computation_detail: hash[AGGREGATION_DETAIL]&.then { |agg_hash| ComputationDetail.from_hash(agg_hash) }
26
+ computation_detail: hash[AGGREGATION_DETAIL]&.then { |agg_hash| ComputationDetail.from_hash(agg_hash) },
27
+ resolver: hash[RESOLVER]&.to_sym
26
28
  )
27
29
  end
28
30
 
@@ -31,7 +33,8 @@ module ElasticGraph
31
33
  # Keys here are ordered alphabetically; please keep them that way.
32
34
  AGGREGATION_DETAIL => computation_detail&.to_dumpable_hash,
33
35
  NAME_IN_INDEX => name_in_index,
34
- RELATION => relation&.to_dumpable_hash
36
+ RELATION => relation&.to_dumpable_hash,
37
+ RESOLVER => resolver&.to_s
35
38
  }
36
39
  end
37
40
 
@@ -39,7 +42,11 @@ module ElasticGraph
39
42
  # `name_in_graphql`. Fields that have not been customized in some way do not need to be
40
43
  # included in the dumped runtime metadata.
41
44
  def needed?(name_in_graphql)
42
- !!relation || !!computation_detail || name_in_index&.!=(name_in_graphql) || false
45
+ !!relation ||
46
+ !!computation_detail ||
47
+ name_in_index&.!=(name_in_graphql) ||
48
+ !resolver.nil? ||
49
+ false
43
50
  end
44
51
 
45
52
  def with_computation_detail(empty_bucket_value:, function:)
@@ -0,0 +1,66 @@
1
+ # Copyright 2024 - 2025 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
+ require "elastic_graph/schema_artifacts/runtime_metadata/extension_loader"
10
+
11
+ module ElasticGraph
12
+ module SchemaArtifacts
13
+ module RuntimeMetadata
14
+ class GraphQLResolver < ::Data.define(:needs_lookahead, :resolver_ref)
15
+ def self.with_lookahead_loader
16
+ @with_lookahead_loader ||= ExtensionLoader.new(InterfaceWithLookahead)
17
+ end
18
+
19
+ def self.without_lookahead_loader
20
+ @without_lookahead_loader ||= ExtensionLoader.new(InterfaceWithoutLookahead)
21
+ end
22
+
23
+ NEEDS_LOOKAHEAD = "needs_lookahead"
24
+ RESOLVER_REF = "resolver_ref"
25
+
26
+ def load_resolver
27
+ loader = needs_lookahead ? GraphQLResolver.with_lookahead_loader : GraphQLResolver.without_lookahead_loader
28
+ Extension.load_from_hash(resolver_ref, via: loader)
29
+ end
30
+
31
+ def self.from_hash(hash)
32
+ new(
33
+ needs_lookahead: hash.fetch(NEEDS_LOOKAHEAD),
34
+ resolver_ref: hash.fetch(RESOLVER_REF)
35
+ )
36
+ end
37
+
38
+ def to_dumpable_hash
39
+ {
40
+ # Keys here are ordered alphabetically; please keep them that way.
41
+ NEEDS_LOOKAHEAD => needs_lookahead,
42
+ RESOLVER_REF => resolver_ref
43
+ }
44
+ end
45
+
46
+ class InterfaceWithLookahead
47
+ def initialize(elasticgraph_graphql:, config:)
48
+ # must be defined, but nothing to do
49
+ end
50
+
51
+ def resolve(field:, object:, args:, context:, lookahead:)
52
+ end
53
+ end
54
+
55
+ class InterfaceWithoutLookahead
56
+ def initialize(elasticgraph_graphql:, config:)
57
+ # must be defined, but nothing to do
58
+ end
59
+
60
+ def resolve(field:, object:, args:, context:)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -0,0 +1,109 @@
1
+ # Copyright 2024 - 2025 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
+ require "elastic_graph/errors"
10
+
11
+ module ElasticGraph
12
+ module SchemaArtifacts
13
+ module RuntimeMetadata
14
+ # Responsible for verifying extensions. This requires an interface definition
15
+ # (a class or module with empty method definitions that just serves to define what
16
+ # loaded extensions must implement). That allows us to verify the extension implements
17
+ # the interface correctly ahead of time, rather than deferring exceptions to when the
18
+ # extension is later used.
19
+ #
20
+ # Note, however, that this does not guarantee no runtime exceptions from the use of the
21
+ # extension: the extension may return invalid return values, or throw exceptions when
22
+ # called. But this verifies the interface to the extent that we can.
23
+ module InterfaceVerifier
24
+ class << self
25
+ def verify!(extension, against:, constant_name:)
26
+ problems = verify(extension, against:, constant_name:)
27
+
28
+ if problems.any?
29
+ raise Errors::InvalidExtensionError,
30
+ "Extension `#{constant_name}` does not implement the expected interface correctly. Problems:\n\n" \
31
+ "#{problems.join("\n")}"
32
+ end
33
+ end
34
+
35
+ def verify(extension, against:, constant_name:)
36
+ problems = [] # : ::Array[::String]
37
+ problems.concat(verify_methods("class", extension.singleton_class, against.singleton_class))
38
+
39
+ if extension.is_a?(::Module)
40
+ problems.concat(verify_methods("instance", extension, against))
41
+
42
+ # We care about the name exactly matching so that we can dump the extension name in a schema
43
+ # artifact w/o having to pass around the original constant name.
44
+ if extension.name != constant_name.delete_prefix("::")
45
+ problems << "- Exposes a name (`#{extension.name}`) that differs from the provided extension name (`#{constant_name}`)"
46
+ end
47
+ else
48
+ problems << "- Is not a class or module as expected"
49
+ end
50
+
51
+ problems
52
+ end
53
+
54
+ private
55
+
56
+ def verify_methods(type, extension, interface)
57
+ interface_methods = list_instance_interface_methods(interface)
58
+ extension_methods = list_instance_interface_methods(extension)
59
+
60
+ # @type var problems: ::Array[::String]
61
+ problems = []
62
+
63
+ if (missing_methods = interface_methods - extension_methods).any?
64
+ problems << "- Missing #{type} methods: #{missing_methods.map { |m| "`#{m}`" }.join(", ")}"
65
+ end
66
+
67
+ interface_methods.intersection(extension_methods).each do |method_name|
68
+ unless parameters_match?(extension, interface, method_name)
69
+ interface_signature = signature_code_for(interface, method_name)
70
+ extension_signature = signature_code_for(extension, method_name)
71
+
72
+ problems << "- Method signature for #{type} method `#{method_name}` (`#{extension_signature}`) does not match interface (`#{interface_signature}`)"
73
+ end
74
+ end
75
+
76
+ problems
77
+ end
78
+
79
+ def list_instance_interface_methods(klass)
80
+ # Here we look at more than just the public methods. This is necessary for `initialize`.
81
+ # If it's defined on the interface definition, we want to verify it on the extension,
82
+ # but Ruby makes `initialize` private by default.
83
+ klass.instance_methods(false) +
84
+ klass.protected_instance_methods(false) +
85
+ klass.private_instance_methods(false)
86
+ end
87
+
88
+ def parameters_match?(extension, interface, method_name)
89
+ interface_parameters = interface.instance_method(method_name).parameters
90
+ extension_parameters = extension.instance_method(method_name).parameters
91
+
92
+ # Here we compare the parameters for exact equality. This is stricter than we need it
93
+ # to be (it doesn't allow the parameters to have different names, for example) but it's
94
+ # considerably simpler than us trying to determine what is truly required. For example,
95
+ # the name doesn't matter on a positional arg, but would matter on a keyword arg.
96
+ interface_parameters == extension_parameters
97
+ end
98
+
99
+ def signature_code_for(object, method_name)
100
+ # @type var file_name: ::String?
101
+ # @type var line_number: ::Integer?
102
+ file_name, line_number = object.instance_method(method_name).source_location
103
+ ::File.read(file_name.to_s).split("\n").fetch(line_number.to_i - 1).strip
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -50,8 +50,9 @@ module ElasticGraph
50
50
  UpdateTarget.from_hash(update_target_hash)
51
51
  end || []
52
52
 
53
- graphql_fields_by_name = hash[GRAPHQL_FIELDS_BY_NAME]&.transform_values do |field_hash|
54
- GraphQLField.from_hash(field_hash)
53
+ graphql_fields_by_name = hash[GRAPHQL_FIELDS_BY_NAME]&.to_h do |name, field_hash|
54
+ field_hash = field_hash.merge(GraphQLField::NAME_IN_INDEX => name) unless field_hash[GraphQLField::NAME_IN_INDEX]
55
+ [name, GraphQLField.from_hash(field_hash)]
55
56
  end || {}
56
57
 
57
58
  new(
@@ -65,10 +66,16 @@ module ElasticGraph
65
66
  end
66
67
 
67
68
  def to_dumpable_hash
69
+ dumped_graphql_fields_by_name =
70
+ HashDumper.dump_hash(graphql_fields_by_name.to_h do |name, field|
71
+ field = field.with(name_in_index: nil) if field.name_in_index == name
72
+ [name, field]
73
+ end, &:to_dumpable_hash)
74
+
68
75
  {
69
76
  # Keys here are ordered alphabetically; please keep them that way.
70
77
  ELASTICGRAPH_CATEGORY => elasticgraph_category&.to_s,
71
- GRAPHQL_FIELDS_BY_NAME => HashDumper.dump_hash(graphql_fields_by_name, &:to_dumpable_hash),
78
+ GRAPHQL_FIELDS_BY_NAME => dumped_graphql_fields_by_name,
72
79
  GRAPHQL_ONLY_RETURN_TYPE => graphql_only_return_type ? true : nil,
73
80
  INDEX_DEFINITION_NAMES => index_definition_names,
74
81
  SOURCE_TYPE => source_type,
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -52,8 +52,8 @@ module ElasticGraph
52
52
 
53
53
  def value_for(event_or_prepared_record)
54
54
  case cardinality
55
- when :many then Support::HashUtil.fetch_leaf_values_at_path(event_or_prepared_record, source_path) { [] }
56
- when :one then Support::HashUtil.fetch_value_at_path(event_or_prepared_record, source_path) { nil }
55
+ when :many then Support::HashUtil.fetch_leaf_values_at_path(event_or_prepared_record, source_path.split(".")) { [] }
56
+ when :one then Support::HashUtil.fetch_value_at_path(event_or_prepared_record, source_path.split(".")) { nil }
57
57
  end
58
58
  end
59
59
  end
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -22,12 +22,12 @@ module ElasticGraph
22
22
  end
23
23
 
24
24
  DEFAULT_COERCION_ADAPTER_REF = {
25
- "extension_name" => "ElasticGraph::GraphQL::ScalarCoercionAdapters::NoOp",
25
+ "name" => "ElasticGraph::GraphQL::ScalarCoercionAdapters::NoOp",
26
26
  "require_path" => "elastic_graph/graphql/scalar_coercion_adapters/no_op"
27
27
  }
28
28
 
29
29
  DEFAULT_INDEXING_PREPARER_REF = {
30
- "extension_name" => "ElasticGraph::Indexer::IndexingPreparers::NoOp",
30
+ "name" => "ElasticGraph::Indexer::IndexingPreparers::NoOp",
31
31
  "require_path" => "elastic_graph/indexer/indexing_preparers/no_op"
32
32
  }
33
33
 
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -9,6 +9,7 @@
9
9
  require "elastic_graph/schema_artifacts/runtime_metadata/enum"
10
10
  require "elastic_graph/schema_artifacts/runtime_metadata/extension"
11
11
  require "elastic_graph/schema_artifacts/runtime_metadata/extension_loader"
12
+ require "elastic_graph/schema_artifacts/runtime_metadata/graphql_resolver"
12
13
  require "elastic_graph/schema_artifacts/runtime_metadata/hash_dumper"
13
14
  require "elastic_graph/schema_artifacts/runtime_metadata/index_definition"
14
15
  require "elastic_graph/schema_artifacts/runtime_metadata/object_type"
@@ -27,6 +28,7 @@ module ElasticGraph
27
28
  :index_definitions_by_name,
28
29
  :schema_element_names,
29
30
  :graphql_extension_modules,
31
+ :graphql_resolvers_by_name,
30
32
  :static_script_ids_by_scoped_name
31
33
  )
32
34
  OBJECT_TYPES_BY_NAME = "object_types_by_name"
@@ -35,6 +37,7 @@ module ElasticGraph
35
37
  INDEX_DEFINITIONS_BY_NAME = "index_definitions_by_name"
36
38
  SCHEMA_ELEMENT_NAMES = "schema_element_names"
37
39
  GRAPHQL_EXTENSION_MODULES = "graphql_extension_modules"
40
+ GRAPHQL_RESOLVERS_BY_NAME = "graphql_resolvers_by_name"
38
41
  STATIC_SCRIPT_IDS_BY_NAME = "static_script_ids_by_scoped_name"
39
42
 
40
43
  def self.from_hash(hash, for_context:)
@@ -56,18 +59,22 @@ module ElasticGraph
56
59
 
57
60
  schema_element_names = SchemaElementNames.from_hash(hash.fetch(SCHEMA_ELEMENT_NAMES))
58
61
 
59
- loader = ExtensionLoader.new(Module.new)
62
+ extension_loader = ExtensionLoader.new(Module.new)
60
63
  graphql_extension_modules =
61
64
  if for_context == :graphql
62
65
  hash[GRAPHQL_EXTENSION_MODULES]&.map do |ext_mod_hash|
63
- Extension.load_from_hash(ext_mod_hash, via: loader)
66
+ Extension.load_from_hash(ext_mod_hash, via: extension_loader)
64
67
  end || []
65
68
  else
66
- # Avoid loading GraphQL extrnsion modules if we're not in a GraphQL context. We can't count
69
+ # Avoid loading GraphQL extension modules if we're not in a GraphQL context. We can't count
67
70
  # on the extension modules even being available to load in other contexts.
68
71
  [] # : ::Array[Extension]
69
72
  end
70
73
 
74
+ graphql_resolvers_by_name = hash[GRAPHQL_RESOLVERS_BY_NAME]&.to_h do |name, resolver_hash|
75
+ [name.to_sym, GraphQLResolver.from_hash(resolver_hash)]
76
+ end || {}
77
+
71
78
  static_script_ids_by_scoped_name = hash[STATIC_SCRIPT_IDS_BY_NAME] || {}
72
79
 
73
80
  new(
@@ -77,6 +84,7 @@ module ElasticGraph
77
84
  index_definitions_by_name: index_definitions_by_name,
78
85
  schema_element_names: schema_element_names,
79
86
  graphql_extension_modules: graphql_extension_modules,
87
+ graphql_resolvers_by_name: graphql_resolvers_by_name,
80
88
  static_script_ids_by_scoped_name: static_script_ids_by_scoped_name
81
89
  )
82
90
  end
@@ -86,6 +94,7 @@ module ElasticGraph
86
94
  # Keys here are ordered alphabetically; please keep them that way.
87
95
  ENUM_TYPES_BY_NAME => HashDumper.dump_hash(enum_types_by_name, &:to_dumpable_hash),
88
96
  GRAPHQL_EXTENSION_MODULES => graphql_extension_modules.map(&:to_dumpable_hash),
97
+ GRAPHQL_RESOLVERS_BY_NAME => HashDumper.dump_hash(graphql_resolvers_by_name.transform_keys(&:to_s), &:to_dumpable_hash),
89
98
  INDEX_DEFINITIONS_BY_NAME => HashDumper.dump_hash(index_definitions_by_name, &:to_dumpable_hash),
90
99
  OBJECT_TYPES_BY_NAME => HashDumper.dump_hash(object_types_by_name, &:to_dumpable_hash),
91
100
  SCALAR_TYPES_BY_NAME => HashDumper.dump_hash(scalar_types_by_name, &:to_dumpable_hash),
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Block, Inc.
1
+ # Copyright 2024 - 2025 Block, Inc.
2
2
  #
3
3
  # Use of this source code is governed by an MIT-style
4
4
  # license that can be found in the LICENSE file or at
metadata CHANGED
@@ -1,16 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elasticgraph-schema_artifacts
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.1.1
4
+ version: 0.19.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Myron Marston
8
8
  - Ben VandenBos
9
9
  - Block Engineering
10
- autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2025-02-07 00:00:00.000000000 Z
12
+ date: 2025-04-09 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: elasticgraph-support
@@ -18,43 +17,42 @@ dependencies:
18
17
  requirements:
19
18
  - - '='
20
19
  - !ruby/object:Gem::Version
21
- version: 0.19.1.1
20
+ version: 0.19.2.0
22
21
  type: :runtime
23
22
  prerelease: false
24
23
  version_requirements: !ruby/object:Gem::Requirement
25
24
  requirements:
26
25
  - - '='
27
26
  - !ruby/object:Gem::Version
28
- version: 0.19.1.1
27
+ version: 0.19.2.0
29
28
  - !ruby/object:Gem::Dependency
30
29
  name: elasticgraph-graphql
31
30
  requirement: !ruby/object:Gem::Requirement
32
31
  requirements:
33
32
  - - '='
34
33
  - !ruby/object:Gem::Version
35
- version: 0.19.1.1
34
+ version: 0.19.2.0
36
35
  type: :development
37
36
  prerelease: false
38
37
  version_requirements: !ruby/object:Gem::Requirement
39
38
  requirements:
40
39
  - - '='
41
40
  - !ruby/object:Gem::Version
42
- version: 0.19.1.1
41
+ version: 0.19.2.0
43
42
  - !ruby/object:Gem::Dependency
44
43
  name: elasticgraph-indexer
45
44
  requirement: !ruby/object:Gem::Requirement
46
45
  requirements:
47
46
  - - '='
48
47
  - !ruby/object:Gem::Version
49
- version: 0.19.1.1
48
+ version: 0.19.2.0
50
49
  type: :development
51
50
  prerelease: false
52
51
  version_requirements: !ruby/object:Gem::Requirement
53
52
  requirements:
54
53
  - - '='
55
54
  - !ruby/object:Gem::Version
56
- version: 0.19.1.1
57
- description:
55
+ version: 0.19.2.0
58
56
  email:
59
57
  - myron@squareup.com
60
58
  executables: []
@@ -70,9 +68,11 @@ files:
70
68
  - lib/elastic_graph/schema_artifacts/runtime_metadata/extension.rb
71
69
  - lib/elastic_graph/schema_artifacts/runtime_metadata/extension_loader.rb
72
70
  - lib/elastic_graph/schema_artifacts/runtime_metadata/graphql_field.rb
71
+ - lib/elastic_graph/schema_artifacts/runtime_metadata/graphql_resolver.rb
73
72
  - lib/elastic_graph/schema_artifacts/runtime_metadata/hash_dumper.rb
74
73
  - lib/elastic_graph/schema_artifacts/runtime_metadata/index_definition.rb
75
74
  - lib/elastic_graph/schema_artifacts/runtime_metadata/index_field.rb
75
+ - lib/elastic_graph/schema_artifacts/runtime_metadata/interface_verifier.rb
76
76
  - lib/elastic_graph/schema_artifacts/runtime_metadata/object_type.rb
77
77
  - lib/elastic_graph/schema_artifacts/runtime_metadata/params.rb
78
78
  - lib/elastic_graph/schema_artifacts/runtime_metadata/relation.rb
@@ -86,12 +86,11 @@ licenses:
86
86
  - MIT
87
87
  metadata:
88
88
  bug_tracker_uri: https://github.com/block/elasticgraph/issues
89
- changelog_uri: https://github.com/block/elasticgraph/releases/tag/v0.19.1.1
90
- documentation_uri: https://block.github.io/elasticgraph/docs/main/
89
+ changelog_uri: https://github.com/block/elasticgraph/releases/tag/v0.19.2.0
90
+ documentation_uri: https://block.github.io/elasticgraph/api-docs/v0.19.2.0/
91
91
  homepage_uri: https://block.github.io/elasticgraph/
92
- source_code_uri: https://github.com/block/elasticgraph/tree/v0.19.1.1/elasticgraph-schema_artifacts
92
+ source_code_uri: https://github.com/block/elasticgraph/tree/v0.19.2.0/elasticgraph-schema_artifacts
93
93
  gem_category: core
94
- post_install_message:
95
94
  rdoc_options: []
96
95
  require_paths:
97
96
  - lib
@@ -109,8 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
108
  - !ruby/object:Gem::Version
110
109
  version: '0'
111
110
  requirements: []
112
- rubygems_version: 3.5.22
113
- signing_key:
111
+ rubygems_version: 3.6.2
114
112
  specification_version: 4
115
113
  summary: ElasticGraph gem containing code related to generated schema artifacts.
116
114
  test_files: []