elasticgraph-apollo 0.18.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +63 -0
  4. data/apollo_tests_implementation/Dockerfile +66 -0
  5. data/apollo_tests_implementation/Gemfile +27 -0
  6. data/apollo_tests_implementation/Rakefile +22 -0
  7. data/apollo_tests_implementation/config/products_schema.rb +173 -0
  8. data/apollo_tests_implementation/config/settings.yaml +34 -0
  9. data/apollo_tests_implementation/config.ru +122 -0
  10. data/apollo_tests_implementation/docker-compose.yaml +18 -0
  11. data/apollo_tests_implementation/lib/test_implementation_extension.rb +58 -0
  12. data/apollo_tests_implementation/wait_for_datastore.sh +17 -0
  13. data/elasticgraph-apollo.gemspec +27 -0
  14. data/lib/elastic_graph/apollo/graphql/engine_extension.rb +52 -0
  15. data/lib/elastic_graph/apollo/graphql/entities_field_resolver.rb +305 -0
  16. data/lib/elastic_graph/apollo/graphql/http_endpoint_extension.rb +45 -0
  17. data/lib/elastic_graph/apollo/graphql/service_field_resolver.rb +30 -0
  18. data/lib/elastic_graph/apollo/schema_definition/api_extension.rb +385 -0
  19. data/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb +119 -0
  20. data/lib/elastic_graph/apollo/schema_definition/argument_extension.rb +20 -0
  21. data/lib/elastic_graph/apollo/schema_definition/entity_type_extension.rb +30 -0
  22. data/lib/elastic_graph/apollo/schema_definition/enum_type_extension.rb +23 -0
  23. data/lib/elastic_graph/apollo/schema_definition/enum_value_extension.rb +20 -0
  24. data/lib/elastic_graph/apollo/schema_definition/factory_extension.rb +104 -0
  25. data/lib/elastic_graph/apollo/schema_definition/field_extension.rb +59 -0
  26. data/lib/elastic_graph/apollo/schema_definition/graphql_sdl_enumerator_extension.rb +69 -0
  27. data/lib/elastic_graph/apollo/schema_definition/input_type_extension.rb +20 -0
  28. data/lib/elastic_graph/apollo/schema_definition/interface_type_extension.rb +25 -0
  29. data/lib/elastic_graph/apollo/schema_definition/object_type_extension.rb +28 -0
  30. data/lib/elastic_graph/apollo/schema_definition/scalar_type_extension.rb +23 -0
  31. data/lib/elastic_graph/apollo/schema_definition/state_extension.rb +23 -0
  32. data/lib/elastic_graph/apollo/schema_definition/union_type_extension.rb +20 -0
  33. data/script/boot_eg_apollo_implementation +22 -0
  34. data/script/export_docker_env_vars.sh +15 -0
  35. data/script/test_compatibility +54 -0
  36. metadata +472 -0
@@ -0,0 +1,104 @@
1
+ # Copyright 2024 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/apollo/schema_definition/argument_extension"
10
+ require "elastic_graph/apollo/schema_definition/enum_type_extension"
11
+ require "elastic_graph/apollo/schema_definition/enum_value_extension"
12
+ require "elastic_graph/apollo/schema_definition/field_extension"
13
+ require "elastic_graph/apollo/schema_definition/graphql_sdl_enumerator_extension"
14
+ require "elastic_graph/apollo/schema_definition/input_type_extension"
15
+ require "elastic_graph/apollo/schema_definition/interface_type_extension"
16
+ require "elastic_graph/apollo/schema_definition/object_type_extension"
17
+ require "elastic_graph/apollo/schema_definition/scalar_type_extension"
18
+ require "elastic_graph/apollo/schema_definition/union_type_extension"
19
+
20
+ module ElasticGraph
21
+ module Apollo
22
+ module SchemaDefinition
23
+ # Extension module applied to `ElasticGraph::SchemaDefinition::Factory` to add Apollo tagging support.
24
+ module FactoryExtension
25
+ # Steep has a hard type with the arg splats here.
26
+ __skip__ = def new_field(**kwargs)
27
+ super(**kwargs) do |field|
28
+ field.extend FieldExtension
29
+ yield field if block_given?
30
+ end
31
+ end
32
+
33
+ def new_graphql_sdl_enumerator(all_types_except_root_query_type)
34
+ super.tap do |enum|
35
+ enum.extend GraphQLSDLEnumeratorExtension
36
+ end
37
+ end
38
+
39
+ def new_argument(field, name, value_type)
40
+ super(field, name, value_type) do |type|
41
+ type.extend ArgumentExtension
42
+ yield type if block_given?
43
+ end
44
+ end
45
+
46
+ def new_enum_type(name)
47
+ super(name) do |type|
48
+ type.extend EnumTypeExtension
49
+ yield type
50
+ end
51
+ end
52
+
53
+ def new_enum_value(name, original_name)
54
+ super(name, original_name) do |type|
55
+ type.extend EnumValueExtension
56
+ yield type if block_given?
57
+ end
58
+ end
59
+
60
+ def new_input_type(name)
61
+ super(name) do |type|
62
+ type.extend InputTypeExtension
63
+ yield type
64
+ end
65
+ end
66
+
67
+ def new_interface_type(name)
68
+ super(name) do |type|
69
+ type.extend InterfaceTypeExtension
70
+ yield type
71
+ end
72
+ end
73
+
74
+ # Here we override `object_type` in order to automatically add the apollo `@key` directive to indexed types.
75
+ def new_object_type(name)
76
+ super(name) do |raw_type|
77
+ raw_type.extend ObjectTypeExtension
78
+ type = raw_type # : ElasticGraph::SchemaDefinition::SchemaElements::ObjectType & ObjectTypeExtension
79
+
80
+ yield type if block_given?
81
+
82
+ if type.indexed? && type.graphql_fields_by_name.key?("id")
83
+ type.apollo_key fields: "id"
84
+ end
85
+ end
86
+ end
87
+
88
+ def new_scalar_type(name)
89
+ super(name) do |type|
90
+ type.extend ScalarTypeExtension
91
+ yield type
92
+ end
93
+ end
94
+
95
+ def new_union_type(name)
96
+ super(name) do |type|
97
+ type.extend UnionTypeExtension
98
+ yield type
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,59 @@
1
+ # Copyright 2024 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/apollo/schema_definition/apollo_directives"
10
+
11
+ module ElasticGraph
12
+ module Apollo
13
+ module SchemaDefinition
14
+ # Extension module applied to `ElasticGraph::SchemaDefinition::SchemaElements::Field` to add Apollo tagging support.
15
+ module FieldExtension
16
+ include ApolloDirectives::Authenticated
17
+ include ApolloDirectives::External
18
+ include ApolloDirectives::Inaccessible
19
+ include ApolloDirectives::Override
20
+ include ApolloDirectives::Policy
21
+ include ApolloDirectives::Provides
22
+ include ApolloDirectives::Requires
23
+ include ApolloDirectives::RequiresScopes
24
+ include ApolloDirectives::Shareable
25
+ include ApolloDirectives::Tag
26
+
27
+ # Extension method designed to support Apollo's contract variant tagging:
28
+ #
29
+ # https://www.apollographql.com/docs/studio/contracts/
30
+ #
31
+ # Calling this method on a field will cause the field to be tagged and also every schema element derived from
32
+ # the field (e.g. the filter field, the aggregation field, an the sort order enum), ensuring that all capabilities
33
+ # related to the field are available in the contract variant.
34
+ def tag_with(tag_name)
35
+ on_each_generated_schema_element do |element|
36
+ needs_tagging =
37
+ if element.is_a?(ElasticGraph::SchemaDefinition::SchemaElements::SortOrderEnumValue)
38
+ # Each sort order enum value is based on a full field path (e.g. `parentField_subField_furtherNestedField_ASC`).
39
+ # We must only tag the enum if each part of the full field path is also tagged. In this example, we should only
40
+ # tag the enum value if `parentField`, `subField`, and `furtherNestedField` are all tagged.
41
+ element.sort_order_field_path.all? { |f| FieldExtension.tagged_with?(f, tag_name) }
42
+ else
43
+ true
44
+ end
45
+
46
+ if needs_tagging && !FieldExtension.tagged_with?(element, tag_name)
47
+ (_ = element).apollo_tag name: tag_name
48
+ end
49
+ end
50
+ end
51
+
52
+ # Helper method that indicates if the given schema element has a specific tag.
53
+ def self.tagged_with?(element, tag_name)
54
+ element.directives.any? { |dir| dir.name == "tag" && dir.arguments == {name: tag_name} }
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,69 @@
1
+ # Copyright 2024 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
+ module Apollo
11
+ module SchemaDefinition
12
+ # Module designed to be extended onto an `ElasticGraph::SchemaDefinition::GraphQLSDLEnumerator`
13
+ # instance to customize the schema artifacts to support Apollo.
14
+ module GraphQLSDLEnumeratorExtension
15
+ def root_query_type
16
+ super.tap do |type_or_nil|
17
+ # @type var type: ElasticGraph::SchemaDefinition::SchemaElements::ObjectType
18
+ type = _ = type_or_nil
19
+
20
+ if schema_def_state.object_types_by_name.values.any?(&:indexed?)
21
+ type.field "_entities", "[_Entity]!" do |f|
22
+ f.documentation <<~EOS
23
+ A field required by the [Apollo Federation subgraph
24
+ spec](https://www.apollographql.com/docs/federation/subgraph-spec/#query_entities):
25
+
26
+ > The graph router uses this root-level `Query` field to directly fetch fields of entities defined by a subgraph.
27
+ >
28
+ > This field must take a `representations` argument of type `[_Any!]!` (a non-nullable list of non-nullable
29
+ > [`_Any` scalars](https://www.apollographql.com/docs/federation/subgraph-spec/#scalar-_any)). Its return type must be `[_Entity]!` (a non-nullable list of _nullable_
30
+ > objects that belong to the [`_Entity` union](https://www.apollographql.com/docs/federation/subgraph-spec/#union-_entity)).
31
+ >
32
+ > Each entry in the `representations` list must be validated with the following rules:
33
+ >
34
+ > - A representation must include a `__typename` string field.
35
+ > - A representation must contain all fields included in the fieldset of a `@key` directive applied to the corresponding entity definition.
36
+ >
37
+ > For details, see [Resolving entity fields with `Query._entities`](https://www.apollographql.com/docs/federation/subgraph-spec/#resolving-entity-fields-with-query_entities).
38
+
39
+ Not intended for use by clients other than Apollo.
40
+ EOS
41
+
42
+ f.argument "representations", "[_Any!]!" do |a|
43
+ a.documentation <<~EOS
44
+ A list of entity data blobs from other apollo subgraphs. For more information (and
45
+ to see an example of what form this argument takes), see the [Apollo Federation subgraph
46
+ spec](https://www.apollographql.com/docs/federation/subgraph-spec/#resolve-requests-for-entities).
47
+ EOS
48
+ end
49
+ end
50
+ end
51
+
52
+ type.field "_service", "_Service!" do |f|
53
+ f.documentation <<~EOS
54
+ A field required by the [Apollo Federation subgraph
55
+ spec](https://www.apollographql.com/docs/federation/subgraph-spec/#query_service):
56
+
57
+ > This field of the root `Query` type must return a non-nullable [`_Service` type](https://www.apollographql.com/docs/federation/subgraph-spec/#type-_service).
58
+
59
+ > For details, see [Enhanced introspection with `Query._service`](https://www.apollographql.com/docs/federation/subgraph-spec/#enhanced-introspection-with-query_service).
60
+
61
+ Not intended for use by clients other than Apollo.
62
+ EOS
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,20 @@
1
+ # Copyright 2024 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/apollo/schema_definition/apollo_directives"
10
+
11
+ module ElasticGraph
12
+ module Apollo
13
+ module SchemaDefinition
14
+ module InputTypeExtension
15
+ include ApolloDirectives::Inaccessible
16
+ include ApolloDirectives::Tag
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright 2024 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/apollo/schema_definition/apollo_directives"
10
+
11
+ module ElasticGraph
12
+ module Apollo
13
+ module SchemaDefinition
14
+ module InterfaceTypeExtension
15
+ include ApolloDirectives::Authenticated
16
+ include ApolloDirectives::Extends
17
+ include ApolloDirectives::Inaccessible
18
+ include ApolloDirectives::Key
19
+ include ApolloDirectives::Policy
20
+ include ApolloDirectives::RequiresScopes
21
+ include ApolloDirectives::Tag
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,28 @@
1
+ # Copyright 2024 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/apollo/schema_definition/apollo_directives"
10
+
11
+ module ElasticGraph
12
+ module Apollo
13
+ module SchemaDefinition
14
+ module ObjectTypeExtension
15
+ include ApolloDirectives::Authenticated
16
+ include ApolloDirectives::Extends
17
+ include ApolloDirectives::External
18
+ include ApolloDirectives::Inaccessible
19
+ include ApolloDirectives::InterfaceObject
20
+ include ApolloDirectives::Key
21
+ include ApolloDirectives::Policy
22
+ include ApolloDirectives::RequiresScopes
23
+ include ApolloDirectives::Shareable
24
+ include ApolloDirectives::Tag
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ # Copyright 2024 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/apollo/schema_definition/apollo_directives"
10
+
11
+ module ElasticGraph
12
+ module Apollo
13
+ module SchemaDefinition
14
+ module ScalarTypeExtension
15
+ include ApolloDirectives::Authenticated
16
+ include ApolloDirectives::Inaccessible
17
+ include ApolloDirectives::Policy
18
+ include ApolloDirectives::RequiresScopes
19
+ include ApolloDirectives::Tag
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # Copyright 2024 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
+ module Apollo
11
+ module SchemaDefinition
12
+ # Extension module applied to `ElasticGraph::SchemaDefinition::State` to support extra Apollo state.
13
+ module StateExtension
14
+ # @dynamic apollo_directive_definitions, apollo_directive_definitions=
15
+ attr_accessor :apollo_directive_definitions
16
+
17
+ def self.extended(state)
18
+ state.apollo_directive_definitions = [] # Ensure it's never `nil`.
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ # Copyright 2024 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/apollo/schema_definition/apollo_directives"
10
+
11
+ module ElasticGraph
12
+ module Apollo
13
+ module SchemaDefinition
14
+ module UnionTypeExtension
15
+ include ApolloDirectives::Inaccessible
16
+ include ApolloDirectives::Tag
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Abort script at first error, when a command exits with non-zero status.
4
+ # Verbose form of `set -e`.
5
+ set -o errexit
6
+
7
+ # Attempt to use undefined variable outputs error message, and forces an exit
8
+ # Verbose form of `set -u`.
9
+ set -o nounset
10
+
11
+ # If set, the return value of a pipeline is the value of the last (rightmost)
12
+ # command to exit with a non-zero status, or zero if all commands in the
13
+ # pipeline exit successfully.
14
+ set -o pipefail
15
+
16
+ # Print a trace of simple commands.
17
+ # Verbose form of `set -x`.
18
+ set -o xtrace
19
+
20
+ script_dir=$(dirname $0)
21
+ source $script_dir/export_docker_env_vars.sh
22
+ docker compose -f $script_dir/../apollo_tests_implementation/docker-compose.yaml up --build
@@ -0,0 +1,15 @@
1
+ script_dir=$(dirname $0)
2
+
3
+ # Use the current max Elasticsearch version we test against.
4
+ export VERSION=$(ruby -ryaml -e "puts YAML.load_file('$script_dir/../../config/tested_database_versions.yaml').fetch('elasticsearch').max_by { |v| Gem::Version.new(v) }")
5
+
6
+ # Use the same Ruby version in the docker container as what we are currently using.
7
+ export RUBY_VERSION=$(ruby -e "puts RUBY_VERSION")
8
+
9
+ # Call the ENV "apollo" instead of "test" or "local" to avoid interference with
10
+ # the Elasticsearch container booted for those envs.
11
+ export ENV=apollo
12
+
13
+ # Apollo federation version used to generate the schema artifacts.
14
+ # TODO: Move to v2.6 once it is supported by the test suite.
15
+ export TARGET_APOLLO_FEDERATION_VERSION=2.3
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Abort script at first error, when a command exits with non-zero status.
4
+ # Verbose form of `set -e`.
5
+ set -o errexit
6
+
7
+ # Attempt to use undefined variable outputs error message, and forces an exit
8
+ # Verbose form of `set -u`.
9
+ set -o nounset
10
+
11
+ # If set, the return value of a pipeline is the value of the last (rightmost)
12
+ # command to exit with a non-zero status, or zero if all commands in the
13
+ # pipeline exit successfully.
14
+ set -o pipefail
15
+
16
+ # Print a trace of simple commands.
17
+ # Verbose form of `set -x`.
18
+ set -o xtrace
19
+
20
+ script_dir=$(dirname $0)
21
+
22
+ # Default to the Apollo federation version 2.6, as higher versions are not supported by the test suite properly.
23
+ apollo_federation_version=${1:-2.6}
24
+
25
+ # Latest version as of 2024-05-08. Gotten from:
26
+ # https://www.npmjs.com/package/@apollo/federation-subgraph-compatibility?activeTab=versions
27
+ apollo_subgraph_tests_version=2.2.0
28
+
29
+ TARGET_APOLLO_FEDERATION_VERSION=$apollo_federation_version bundle exec rake \
30
+ --rakefile $script_dir/../apollo_tests_implementation/Rakefile schema_artifacts:dump
31
+
32
+ source $script_dir/export_docker_env_vars.sh
33
+
34
+ # Running the tests produces some artifacts we don't want at our project root, so we run it from a tmp directory.
35
+ rm -rf $script_dir/../../tmp/apollo_compat_test
36
+ mkdir -p $script_dir/../../tmp/apollo_compat_test
37
+
38
+ pushd $script_dir/../../tmp/apollo_compat_test
39
+
40
+ # The latest apollo/federation-subgraph-compatibility tests target federation v2.3, and
41
+ # when we target lower federation versions (e.g. v2.0), we get warnings from some of the tests.
42
+ # So we only want to `--failOnWarning` when targeting federation versions higher versions
43
+ # (e.g. v2.3, v2.5, v2.6).
44
+ additional_flags=$([ "$apollo_federation_version" == "2.0" ] && echo "" || echo "--failOnWarning" )
45
+
46
+ TARGET_APOLLO_FEDERATION_VERSION=2.3 npx --yes \
47
+ @apollo/federation-subgraph-compatibility@${apollo_subgraph_tests_version} docker \
48
+ --compose ../../elasticgraph-apollo/apollo_tests_implementation/docker-compose.yaml \
49
+ --path /graphql \
50
+ --schema ../../elasticgraph-apollo/apollo_tests_implementation/config/schema/artifacts/schema.graphql \
51
+ --debug \
52
+ --failOnRequired $additional_flags
53
+
54
+ popd