From 56fd74c2e0076cc0fc112064701648b96ca5be89 Mon Sep 17 00:00:00 2001 From: Taylor Ninesling Date: Fri, 23 Aug 2024 14:47:05 -0500 Subject: [PATCH 1/6] Ensure directives are preserved when serializing subgraph schemas in planner --- Cargo.lock | 2 +- router-bridge/Cargo.toml | 2 +- router-bridge/js-src/plan.ts | 5 +- router-bridge/js-src/supported_features.ts | 2 + router-bridge/package-lock.json | 30 ++- router-bridge/package.json | 3 +- router-bridge/src/planner.rs | 22 ++ ...ror_display__extracts_cost_directives.snap | 197 ++++++++++++++++++ .../src/testdata/custom_cost_schema.graphql | 154 ++++++++++++++ 9 files changed, 411 insertions(+), 6 deletions(-) create mode 100644 router-bridge/src/snapshots/router_bridge__planner__error_display__extracts_cost_directives.snap create mode 100644 router-bridge/src/testdata/custom_cost_schema.graphql diff --git a/Cargo.lock b/Cargo.lock index d5deca367..3e09b5372 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1603,7 +1603,7 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "router-bridge" -version = "0.6.0-beta.0+v2.9.0-beta.0" +version = "0.6.0-beta.0+v2.9.0-beta.1" dependencies = [ "anyhow", "async-channel", diff --git a/router-bridge/Cargo.toml b/router-bridge/Cargo.toml index fbd52cd2d..bce1c754d 100644 --- a/router-bridge/Cargo.toml +++ b/router-bridge/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "router-bridge" -version = "0.6.0-beta.0+v2.9.0-beta.0" +version = "0.6.0-beta.0+v2.9.0-beta.1" authors = ["Apollo "] edition = "2018" description = "JavaScript bridge for the Apollo Router" diff --git a/router-bridge/js-src/plan.ts b/router-bridge/js-src/plan.ts index 9cb36bb0f..3bea0fdd4 100644 --- a/router-bridge/js-src/plan.ts +++ b/router-bridge/js-src/plan.ts @@ -14,6 +14,7 @@ import { printSchema, graphqlSync, } from "graphql"; +import { printSchemaWithDirectives } from "@graphql-tools/utils"; import { Operation, @@ -281,7 +282,9 @@ export class BridgeQueryPlanner { let result = new Map(); subgraphs.names().forEach((name) => { - let sdl = printSchema(subgraphs.get(name).schema.toGraphQLJSSchema({})); + let sdl = printSchemaWithDirectives( + subgraphs.get(name).schema.toGraphQLJSSchema({}) + ); result.set(name, sdl); }); diff --git a/router-bridge/js-src/supported_features.ts b/router-bridge/js-src/supported_features.ts index 65c450974..a375258be 100644 --- a/router-bridge/js-src/supported_features.ts +++ b/router-bridge/js-src/supported_features.ts @@ -7,6 +7,7 @@ import { REQUIRES_SCOPES_VERSIONS, SOURCE_VERSIONS, CONTEXT_VERSIONS, + COST_VERSIONS, } from "@apollo/federation-internals"; export const ROUTER_SUPPORTED_SUPERGRAPH_FEATURES: Set = new Set( @@ -32,3 +33,4 @@ addToRouterFeatures(REQUIRES_SCOPES_VERSIONS); addToRouterFeatures(POLICY_VERSIONS); addToRouterFeatures(SOURCE_VERSIONS); addToRouterFeatures(CONTEXT_VERSIONS); +addToRouterFeatures(COST_VERSIONS); diff --git a/router-bridge/package-lock.json b/router-bridge/package-lock.json index 2724a3d0a..a9595dbad 100644 --- a/router-bridge/package-lock.json +++ b/router-bridge/package-lock.json @@ -1,12 +1,12 @@ { "name": "@apollo/router-bridge", - "version": "2.9.0-beta.0", + "version": "2.9.0-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@apollo/router-bridge", - "version": "2.9.0-beta.0", + "version": "2.9.0-beta.1", "license": "Elastic-2.0", "dependencies": { "@apollo/core-schema": "^0.3.0", @@ -14,6 +14,7 @@ "@apollo/query-planner": "^2.9.0-beta.0", "@apollo/usage-reporting-protobuf": "^4.0.0", "@apollo/utils.usagereporting": "^3.0.0", + "@graphql-tools/utils": "9.2.1", "graphql": "16.6.0" }, "devDependencies": { @@ -333,6 +334,26 @@ "node": ">=4" } }, + "node_modules/@graphql-tools/utils": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", + "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/@jest/schemas": { "version": "29.0.0", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", @@ -1922,6 +1943,11 @@ "url": "https://github.com/sponsors/ts-graphviz" } }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, "node_modules/type-fest": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", diff --git a/router-bridge/package.json b/router-bridge/package.json index bd4008b8c..75c47a342 100644 --- a/router-bridge/package.json +++ b/router-bridge/package.json @@ -1,7 +1,7 @@ { "name": "@apollo/router-bridge", "private": true, - "version": "2.9.0-beta.0", + "version": "2.9.0-beta.1", "description": "Apollo Router JS Bridge Entrypoint", "scripts": { "build": "make-dir bundled js-dist && rm -f tsconfig.tsbuildinfo && tsc --build --verbose && node esbuild/bundler.js && cp js-dist/runtime.js js-dist/do_api_schema.js js-dist/do_introspect.js js-dist/plan_worker.js js-dist/test_logger_worker.js js-dist/test_get_random_values.js js-dist/test_url.js bundled/", @@ -32,6 +32,7 @@ "@apollo/query-planner": "^2.9.0-beta.0", "@apollo/usage-reporting-protobuf": "^4.0.0", "@apollo/utils.usagereporting": "^3.0.0", + "@graphql-tools/utils": "9.2.1", "graphql": "16.6.0" }, "devDependencies": { diff --git a/router-bridge/src/planner.rs b/router-bridge/src/planner.rs index c93ec8f43..c6340623d 100644 --- a/router-bridge/src/planner.rs +++ b/router-bridge/src/planner.rs @@ -2466,4 +2466,26 @@ feature https://specs.apollo.dev/unsupported-feature/v0.1 is for: SECURITY but i ) .unwrap()); } + + #[tokio::test] + async fn extracts_cost_directives() { + let schema = include_str!("testdata/custom_cost_schema.graphql"); + let planner = Planner::::new(schema.to_string(), Default::default()) + .await + .expect("can create planner"); + let subgraphs = planner.subgraphs().await.expect("can extract subgraphs"); + + let mut snapshot = String::new(); + for name in vec!["subgraphWithCost", "subgraphWithListSize"] { + use std::fmt::Write; + + let sdl = subgraphs.get(name).unwrap(); + _ = writeln!( + &mut snapshot, + "--------------------\n{}\n--------------------\n{}", + name, sdl + ); + } + insta::assert_snapshot!(snapshot); + } } diff --git a/router-bridge/src/snapshots/router_bridge__planner__error_display__extracts_cost_directives.snap b/router-bridge/src/snapshots/router_bridge__planner__error_display__extracts_cost_directives.snap new file mode 100644 index 000000000..69c861a46 --- /dev/null +++ b/router-bridge/src/snapshots/router_bridge__planner__error_display__extracts_cost_directives.snap @@ -0,0 +1,197 @@ +--- +source: router-bridge/src/planner.rs +expression: snapshot +--- +-------------------- +subgraphWithCost +-------------------- +schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { + query: Query +} + +directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA + +directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE + +directive @requires(fields: federation__FieldSet!) on FIELD_DEFINITION + +directive @provides(fields: federation__FieldSet!) on FIELD_DEFINITION + +directive @external(reason: String) on OBJECT | FIELD_DEFINITION + +directive @tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA + +directive @extends on OBJECT | INTERFACE + +directive @shareable repeatable on OBJECT | FIELD_DEFINITION + +directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION + +directive @override(from: String!, label: String) on FIELD_DEFINITION + +directive @composeDirective(name: String) repeatable on SCHEMA + +directive @interfaceObject on OBJECT + +directive @federation__authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM + +directive @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM + +directive @federation__policy(policies: [[federation__Policy!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM + +directive @federation__sourceAPI repeatable on SCHEMA + +directive @federation__sourceType repeatable on OBJECT | INTERFACE + +directive @federation__sourceField repeatable on FIELD_DEFINITION + +directive @federation__context(name: String!) repeatable on INTERFACE | OBJECT | UNION + +directive @federation__fromContext(field: federation__ContextFieldValue) on ARGUMENT_DEFINITION + +directive @federation__cost(weight: Int!) on ARGUMENT_DEFINITION | ENUM | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | OBJECT | SCALAR + +directive @federation__listSize(assumedSize: Int, slicingArguments: [String!], sizedFields: [String!], requireOneSlicingArgument: Boolean = true) on FIELD_DEFINITION + +enum link__Purpose { + """ + `SECURITY` features provide metadata necessary to securely resolve fields. + """ + SECURITY + """ + `EXECUTION` features provide metadata necessary for operation execution. + """ + EXECUTION +} + +scalar link__Import + +scalar federation__FieldSet + +scalar federation__Scope + +scalar federation__Policy + +scalar federation__ContextFieldValue + +enum AorB @federation__cost(weight: 15) { + A + B +} + +scalar ExpensiveInt @federation__cost(weight: 30) + +type ExpensiveObject @federation__cost(weight: 40) { + id: ID +} + +input InputTypeWithCost { + somethingWithCost: Int @federation__cost(weight: 20) +} + +type Query { + fieldWithCost: Int @federation__cost(weight: 5) + argWithCost(arg: Int @federation__cost(weight: 10)): Int + enumWithCost: AorB + inputWithCost(someInput: InputTypeWithCost): Int + scalarWithCost: ExpensiveInt + objectWithCost: ExpensiveObject + _service: _Service! +} + +scalar _Any + +type _Service { + sdl: String +} +-------------------- +subgraphWithListSize +-------------------- +schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { + query: Query +} + +directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA + +directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE + +directive @requires(fields: federation__FieldSet!) on FIELD_DEFINITION + +directive @provides(fields: federation__FieldSet!) on FIELD_DEFINITION + +directive @external(reason: String) on OBJECT | FIELD_DEFINITION + +directive @tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA + +directive @extends on OBJECT | INTERFACE + +directive @shareable repeatable on OBJECT | FIELD_DEFINITION + +directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION + +directive @override(from: String!, label: String) on FIELD_DEFINITION + +directive @composeDirective(name: String) repeatable on SCHEMA + +directive @interfaceObject on OBJECT + +directive @federation__authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM + +directive @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM + +directive @federation__policy(policies: [[federation__Policy!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM + +directive @federation__sourceAPI repeatable on SCHEMA + +directive @federation__sourceType repeatable on OBJECT | INTERFACE + +directive @federation__sourceField repeatable on FIELD_DEFINITION + +directive @federation__context(name: String!) repeatable on INTERFACE | OBJECT | UNION + +directive @federation__fromContext(field: federation__ContextFieldValue) on ARGUMENT_DEFINITION + +directive @federation__cost(weight: Int!) on ARGUMENT_DEFINITION | ENUM | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | OBJECT | SCALAR + +directive @federation__listSize(assumedSize: Int, slicingArguments: [String!], sizedFields: [String!], requireOneSlicingArgument: Boolean = true) on FIELD_DEFINITION + +enum link__Purpose { + """ + `SECURITY` features provide metadata necessary to securely resolve fields. + """ + SECURITY + """ + `EXECUTION` features provide metadata necessary for operation execution. + """ + EXECUTION +} + +scalar link__Import + +scalar federation__FieldSet + +scalar federation__Scope + +scalar federation__Policy + +scalar federation__ContextFieldValue + +type A { + id: ID +} + +type Query { + fieldWithListSize: [String!] @federation__listSize(assumedSize: 2000, requireOneSlicingArgument: false) + fieldWithDynamicListSize(first: Int = 10): SizedField @federation__listSize(slicingArguments: ["first"], sizedFields: ["items"], requireOneSlicingArgument: true) + _service: _Service! +} + +type SizedField { + items: [A] +} + +scalar _Any + +type _Service { + sdl: String +} diff --git a/router-bridge/src/testdata/custom_cost_schema.graphql b/router-bridge/src/testdata/custom_cost_schema.graphql new file mode 100644 index 000000000..d966512be --- /dev/null +++ b/router-bridge/src/testdata/custom_cost_schema.graphql @@ -0,0 +1,154 @@ +schema + @link(url: "https://specs.apollo.dev/link/v1.0") + @link(url: "https://specs.apollo.dev/join/v0.5", for: EXECUTION) + @link( + url: "https://specs.apollo.dev/cost/v0.1" + import: ["@cost", "@listSize"] + ) { + query: Query +} + +directive @cost( + weight: Int! +) on ARGUMENT_DEFINITION | ENUM | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | OBJECT | SCALAR + +directive @cost__listSize( + assumedSize: Int + slicingArguments: [String!] + sizedFields: [String!] + requireOneSlicingArgument: Boolean = true +) on FIELD_DEFINITION + +directive @join__directive( + graphs: [join__Graph!] + name: String! + args: join__DirectiveArguments +) repeatable on SCHEMA | OBJECT | INTERFACE | FIELD_DEFINITION + +directive @join__enumValue(graph: join__Graph!) repeatable on ENUM_VALUE + +directive @join__field( + graph: join__Graph + requires: join__FieldSet + provides: join__FieldSet + type: String + external: Boolean + override: String + usedOverridden: Boolean + overrideLabel: String + contextArguments: [join__ContextArgument!] +) repeatable on FIELD_DEFINITION | INPUT_FIELD_DEFINITION + +directive @join__graph(name: String!, url: String!) on ENUM_VALUE + +directive @join__implements( + graph: join__Graph! + interface: String! +) repeatable on OBJECT | INTERFACE + +directive @join__type( + graph: join__Graph! + key: join__FieldSet + extension: Boolean! = false + resolvable: Boolean! = true + isInterfaceObject: Boolean! = false +) repeatable on OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT | SCALAR + +directive @join__unionMember( + graph: join__Graph! + member: String! +) repeatable on UNION + +directive @link( + url: String + as: String + for: link__Purpose + import: [link__Import] +) repeatable on SCHEMA + +directive @listSize( + assumedSize: Int + slicingArguments: [String!] + sizedFields: [String!] + requireOneSlicingArgument: Boolean = true +) on FIELD_DEFINITION + +type A @join__type(graph: SUBGRAPHWITHLISTSIZE) { + id: ID +} + +enum AorB @join__type(graph: SUBGRAPHWITHCOST) @cost(weight: 15) { + A @join__enumValue(graph: SUBGRAPHWITHCOST) + B @join__enumValue(graph: SUBGRAPHWITHCOST) +} + +scalar ExpensiveInt @join__type(graph: SUBGRAPHWITHCOST) @cost(weight: 30) + +type ExpensiveObject @join__type(graph: SUBGRAPHWITHCOST) @cost(weight: 40) { + id: ID +} + +input InputTypeWithCost @join__type(graph: SUBGRAPHWITHCOST) { + somethingWithCost: Int @cost(weight: 20) +} + +input join__ContextArgument { + name: String! + type: String! + context: String! + selection: join__FieldValue! +} + +scalar join__DirectiveArguments + +scalar join__FieldSet + +scalar join__FieldValue + +enum join__Graph { + SUBGRAPHWITHCOST + @join__graph(name: "subgraphWithCost", url: "http://localhost:4001") + SUBGRAPHWITHLISTSIZE + @join__graph(name: "subgraphWithListSize", url: "http://localhost:4002") +} + +scalar link__Import + +enum link__Purpose { + """ + `SECURITY` features provide metadata necessary to securely resolve fields. + """ + SECURITY + + """ + `EXECUTION` features provide metadata necessary for operation execution. + """ + EXECUTION +} + +type Query + @join__type(graph: SUBGRAPHWITHCOST) + @join__type(graph: SUBGRAPHWITHLISTSIZE) { + fieldWithCost: Int @join__field(graph: SUBGRAPHWITHCOST) @cost(weight: 5) + argWithCost(arg: Int @cost(weight: 10)): Int + @join__field(graph: SUBGRAPHWITHCOST) + enumWithCost: AorB @join__field(graph: SUBGRAPHWITHCOST) + inputWithCost(someInput: InputTypeWithCost): Int + @join__field(graph: SUBGRAPHWITHCOST) + scalarWithCost: ExpensiveInt @join__field(graph: SUBGRAPHWITHCOST) + objectWithCost: ExpensiveObject @join__field(graph: SUBGRAPHWITHCOST) + fieldWithListSize: [String!] + @join__field(graph: SUBGRAPHWITHLISTSIZE) + @listSize(assumedSize: 2000, requireOneSlicingArgument: false) + fieldWithDynamicListSize(first: Int = 10): SizedField + @join__field(graph: SUBGRAPHWITHLISTSIZE) + @listSize( + slicingArguments: ["first"] + sizedFields: ["items"] + requireOneSlicingArgument: true + ) +} + +type SizedField @join__type(graph: SUBGRAPHWITHLISTSIZE) { + items: [A] +} From bec6cc0ef7965f4eede1ba85cb51b198ac0bb0e3 Mon Sep 17 00:00:00 2001 From: Taylor Ninesling Date: Fri, 23 Aug 2024 15:05:19 -0500 Subject: [PATCH 2/6] Fix existing test which now has directives preserved --- ...ter_bridge__planner__tests__subgraphs.snap | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs.snap b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs.snap index ec8d44709..ceb1634be 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs.snap @@ -2,6 +2,11 @@ source: router-bridge/src/planner.rs expression: schema --- +schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { + query: Query + mutation: Mutation +} + directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE @@ -55,7 +60,6 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY - """ `EXECUTION` features provide metadata necessary for operation execution. """ @@ -74,10 +78,10 @@ scalar federation__ContextFieldValue union AccountType = PasswordAccount | SMSAccount -type Library { - userAccount(id: ID! = 1): User +type Library @key(fields: "id") { + userAccount(id: ID! = 1): User @requires(fields: "name") id: ID! - name: String + name: String @external } type Mutation { @@ -89,7 +93,7 @@ type Name { last: String } -type PasswordAccount { +type PasswordAccount @key(fields: "email") { email: String! } @@ -100,11 +104,11 @@ type Query { _service: _Service! } -type SMSAccount { +type SMSAccount @key(fields: "number") { number: String } -type User { +type User @key(fields: "id") @key(fields: "username name{first last}") { id: ID! name: Name username: String @@ -114,9 +118,9 @@ type User { } type UserMetadata { - name: String - address: String - description: String + name: String @shareable + address: String @shareable + description: String @shareable } scalar _Any From ac6c6d2c020213381d7126c59a705c3b9d7b5593 Mon Sep 17 00:00:00 2001 From: Taylor Ninesling Date: Fri, 23 Aug 2024 15:10:25 -0500 Subject: [PATCH 3/6] Update remaining snapshots for tests that now have directives preserved --- ...r_bridge__planner__tests__subgraphs-2.snap | 37 ++++---- ...r_bridge__planner__tests__subgraphs-3.snap | 5 +- ...r_bridge__planner__tests__subgraphs-4.snap | 47 +++++----- ...r_bridge__planner__tests__subgraphs-5.snap | 45 +++++----- ...r_bridge__planner__tests__subgraphs-6.snap | 86 ++++++++++--------- 5 files changed, 118 insertions(+), 102 deletions(-) diff --git a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-2.snap b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-2.snap index 00e0468c1..a3ddecd1b 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-2.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-2.snap @@ -2,6 +2,10 @@ source: router-bridge/src/planner.rs expression: schema --- +schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { + query: Query +} + directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE @@ -55,7 +59,6 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY - """ `EXECUTION` features provide metadata necessary for operation execution. """ @@ -72,31 +75,31 @@ scalar federation__Policy scalar federation__ContextFieldValue -type Book implements Product { +type Book implements Product @key(fields: "isbn") { isbn: String! title: String year: Int similarBooks: [Book]! metadata: [MetadataOrError] - upc: String! - sku: String! - name: String - price: String - details: ProductDetails - inStock: Boolean + upc: String! @external + sku: String! @external + name: String @external + price: String @external + details: ProductDetails @external + inStock: Boolean @external } type Error { - code: Int - message: String + code: Int @shareable + message: String @shareable } type KeyValue { - key: String! - value: String! + key: String! @shareable + value: String! @shareable } -type Library { +type Library @key(fields: "id") { id: ID! name: String } @@ -117,13 +120,13 @@ interface ProductDetails { } type ProductDetailsBook implements ProductDetails { - country: String - pages: Int + country: String @shareable + pages: Int @shareable } type ProductDetailsFurniture implements ProductDetails { - country: String - color: String + country: String @shareable + color: String @shareable } type Query { diff --git a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-3.snap b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-3.snap index a07a40d06..ac67b65e0 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-3.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-3.snap @@ -2,6 +2,10 @@ source: router-bridge/src/planner.rs expression: schema --- +schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { + query: Query +} + directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE @@ -55,7 +59,6 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY - """ `EXECUTION` features provide metadata necessary for operation execution. """ diff --git a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-4.snap b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-4.snap index 026a2be04..5677b35eb 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-4.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-4.snap @@ -2,6 +2,10 @@ source: router-bridge/src/planner.rs expression: schema --- +schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { + query: Query +} + directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE @@ -55,7 +59,6 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY - """ `EXECUTION` features provide metadata necessary for operation execution. """ @@ -72,25 +75,25 @@ scalar federation__Policy scalar federation__ContextFieldValue -type Book implements Product { +type Book implements Product @key(fields: "isbn") { inStock: Boolean isCheckedOut: Boolean isbn: String! - upc: String! - sku: String! - name: String - price: String - details: ProductDetails + upc: String! @external + sku: String! @external + name: String @external + price: String @external + details: ProductDetails @external } -type Furniture implements Product { +type Furniture implements Product @key(fields: "sku") { inStock: Boolean isHeavy: Boolean sku: String! - upc: String! - name: String - price: String - details: ProductDetails + upc: String! @external + name: String @external + price: String @external + details: ProductDetails @external } interface Product { @@ -107,25 +110,25 @@ interface ProductDetails { } type ProductDetailsBook implements ProductDetails { - country: String - pages: Int + country: String @shareable + pages: Int @shareable } type ProductDetailsFurniture implements ProductDetails { - country: String - color: String + country: String @shareable + color: String @shareable } -type User { - goodDescription: Boolean +type User @key(fields: "id") { + goodDescription: Boolean @requires(fields: "metadata{description}") id: ID! - metadata: [UserMetadata] + metadata: [UserMetadata] @external } type UserMetadata { - name: String - address: String - description: String + name: String @shareable + address: String @shareable + description: String @shareable } scalar _Any diff --git a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-5.snap b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-5.snap index 78027599c..84087ca60 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-5.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-5.snap @@ -2,6 +2,10 @@ source: router-bridge/src/planner.rs expression: schema --- +schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { + query: Query +} + directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE @@ -55,7 +59,6 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY - """ `EXECUTION` features provide metadata necessary for operation execution. """ @@ -76,33 +79,33 @@ type Amazon { referrer: String } -type Book implements Product { +type Book implements Product @key(fields: "isbn") { upc: String! sku: String! - name(delimeter: String = " "): String + name(delimeter: String = " "): String @requires(fields: "title year") price: String details: ProductDetailsBook isbn: String! - title: String - year: Int - inStock: Boolean + title: String @external + year: Int @external + inStock: Boolean @external } union Brand = Ikea | Amazon -type Car implements Vehicle { +type Car implements Vehicle @key(fields: "id") { id: String! description: String price: String - retailPrice: String + retailPrice: String @external } type Error { - code: Int - message: String + code: Int @shareable + message: String @shareable } -type Furniture implements Product { +type Furniture implements Product @key(fields: "upc") @key(fields: "sku") { upc: String! sku: String! name: String @@ -110,7 +113,7 @@ type Furniture implements Product { brand: Brand metadata: [MetadataOrError] details: ProductDetailsFurniture - inStock: Boolean + inStock: Boolean @external } type Ikea { @@ -118,8 +121,8 @@ type Ikea { } type KeyValue { - key: String! - value: String! + key: String! @shareable + value: String! @shareable } union MetadataOrError = KeyValue | Error @@ -138,13 +141,13 @@ interface ProductDetails { } type ProductDetailsBook implements ProductDetails { - country: String - pages: Int + country: String @shareable + pages: Int @shareable } type ProductDetailsFurniture implements ProductDetails { - country: String - color: String + country: String @shareable + color: String @shareable } type Query { @@ -158,17 +161,17 @@ type Query { union Thing = Car | Ikea -type User { +type User @key(fields: "id") { vehicle: Vehicle thing: Thing id: ID! } -type Van implements Vehicle { +type Van implements Vehicle @key(fields: "id") { id: String! description: String price: String - retailPrice: String + retailPrice: String @external } interface Vehicle { diff --git a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-6.snap b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-6.snap index 07c14fec3..d4f23b3db 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-6.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-6.snap @@ -2,6 +2,11 @@ source: router-bridge/src/planner.rs expression: schema --- +schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { + query: Query + mutation: Mutation +} + directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE @@ -55,7 +60,6 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY - """ `EXECUTION` features provide metadata necessary for operation execution. """ @@ -72,44 +76,44 @@ scalar federation__Policy scalar federation__ContextFieldValue -type Book implements Product { +type Book implements Product @key(fields: "isbn") { reviews: [Review] - relatedReviews: [Review!]! + relatedReviews: [Review!]! @requires(fields: "similarBooks{isbn}") isbn: String! - similarBooks: [Book]! - upc: String! - sku: String! - name: String - price: String - details: ProductDetails - inStock: Boolean + similarBooks: [Book]! @external + upc: String! @external + sku: String! @external + name: String @external + price: String @external + details: ProductDetails @external + inStock: Boolean @external } -type Car implements Vehicle { - retailPrice: String +type Car implements Vehicle @key(fields: "id") { + retailPrice: String @requires(fields: "price") id: String! - price: String - description: String + price: String @external + description: String @external } type Error { - code: Int - message: String + code: Int @shareable + message: String @shareable } -type Furniture implements Product { +type Furniture implements Product @key(fields: "upc") { reviews: [Review] upc: String! - sku: String! - name: String - price: String - details: ProductDetails - inStock: Boolean + sku: String! @external + name: String @external + price: String @external + details: ProductDetails @external + inStock: Boolean @external } type KeyValue { - key: String! - value: String! + key: String! @shareable + value: String! @shareable } union MetadataOrError = KeyValue | Error @@ -135,13 +139,13 @@ interface ProductDetails { } type ProductDetailsBook implements ProductDetails { - country: String - pages: Int + country: String @shareable + pages: Int @shareable } type ProductDetailsFurniture implements ProductDetails { - country: String - color: String + country: String @shareable + color: String @shareable } type Query { @@ -150,10 +154,10 @@ type Query { _service: _Service! } -type Review { +type Review @key(fields: "id") { id: ID! body(format: Boolean = false): String - author: User + author: User @provides(fields: "username") product: Product metadata: [MetadataOrError] } @@ -163,26 +167,26 @@ input UpdateReviewInput { body: String } -type User { +type User @key(fields: "id") { reviews: [Review] numberOfReviews: Int! - goodAddress: Boolean - username: String + goodAddress: Boolean @requires(fields: "metadata{address}") + username: String @external id: ID! - metadata: [UserMetadata] + metadata: [UserMetadata] @external } type UserMetadata { - name: String - address: String - description: String + name: String @shareable + address: String @shareable + description: String @shareable } -type Van implements Vehicle { - retailPrice: String +type Van implements Vehicle @key(fields: "id") { + retailPrice: String @requires(fields: "price") id: String! - price: String - description: String + price: String @external + description: String @external } interface Vehicle { From 4ff041b6f9936a9e45b2eabead1194b4b57e7a07 Mon Sep 17 00:00:00 2001 From: Taylor Ninesling Date: Mon, 26 Aug 2024 09:23:12 -0500 Subject: [PATCH 4/6] Use fed internals schema printer --- router-bridge/js-src/plan.ts | 6 ++-- router-bridge/package-lock.json | 26 ---------------- router-bridge/package.json | 1 - ...ror_display__extracts_cost_directives.snap | 23 ++++++++++---- ...r_bridge__planner__tests__subgraphs-2.snap | 14 +++++++-- ...r_bridge__planner__tests__subgraphs-3.snap | 6 +++- ...r_bridge__planner__tests__subgraphs-4.snap | 18 ++++++++--- ...r_bridge__planner__tests__subgraphs-5.snap | 27 +++++++++++++---- ...r_bridge__planner__tests__subgraphs-6.snap | 30 ++++++++++++++----- ...ter_bridge__planner__tests__subgraphs.snap | 23 ++++++++++---- 10 files changed, 112 insertions(+), 62 deletions(-) diff --git a/router-bridge/js-src/plan.ts b/router-bridge/js-src/plan.ts index 3bea0fdd4..082b20efa 100644 --- a/router-bridge/js-src/plan.ts +++ b/router-bridge/js-src/plan.ts @@ -14,11 +14,11 @@ import { printSchema, graphqlSync, } from "graphql"; -import { printSchemaWithDirectives } from "@graphql-tools/utils"; import { Operation, operationFromDocument, + printSchema as printSchemaWithDirectives, Supergraph, } from "@apollo/federation-internals"; import { @@ -282,9 +282,7 @@ export class BridgeQueryPlanner { let result = new Map(); subgraphs.names().forEach((name) => { - let sdl = printSchemaWithDirectives( - subgraphs.get(name).schema.toGraphQLJSSchema({}) - ); + let sdl = printSchemaWithDirectives(subgraphs.get(name).schema); result.set(name, sdl); }); diff --git a/router-bridge/package-lock.json b/router-bridge/package-lock.json index a9595dbad..5105f68b6 100644 --- a/router-bridge/package-lock.json +++ b/router-bridge/package-lock.json @@ -14,7 +14,6 @@ "@apollo/query-planner": "^2.9.0-beta.0", "@apollo/usage-reporting-protobuf": "^4.0.0", "@apollo/utils.usagereporting": "^3.0.0", - "@graphql-tools/utils": "9.2.1", "graphql": "16.6.0" }, "devDependencies": { @@ -334,26 +333,6 @@ "node": ">=4" } }, - "node_modules/@graphql-tools/utils": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", - "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", - "dependencies": { - "@graphql-typed-document-node/core": "^3.1.1", - "tslib": "^2.4.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/@graphql-typed-document-node/core": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", - "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", - "peerDependencies": { - "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, "node_modules/@jest/schemas": { "version": "29.0.0", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", @@ -1943,11 +1922,6 @@ "url": "https://github.com/sponsors/ts-graphviz" } }, - "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" - }, "node_modules/type-fest": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", diff --git a/router-bridge/package.json b/router-bridge/package.json index 75c47a342..325fb9562 100644 --- a/router-bridge/package.json +++ b/router-bridge/package.json @@ -32,7 +32,6 @@ "@apollo/query-planner": "^2.9.0-beta.0", "@apollo/usage-reporting-protobuf": "^4.0.0", "@apollo/utils.usagereporting": "^3.0.0", - "@graphql-tools/utils": "9.2.1", "graphql": "16.6.0" }, "devDependencies": { diff --git a/router-bridge/src/snapshots/router_bridge__planner__error_display__extracts_cost_directives.snap b/router-bridge/src/snapshots/router_bridge__planner__error_display__extracts_cost_directives.snap index 69c861a46..b56ed608e 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__error_display__extracts_cost_directives.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__error_display__extracts_cost_directives.snap @@ -5,7 +5,10 @@ expression: snapshot -------------------- subgraphWithCost -------------------- -schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { +schema + @link(url: "https://specs.apollo.dev/link/v1.0") + @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) +{ query: Query } @@ -58,6 +61,7 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY + """ `EXECUTION` features provide metadata necessary for operation execution. """ @@ -74,14 +78,19 @@ scalar federation__Policy scalar federation__ContextFieldValue -enum AorB @federation__cost(weight: 15) { +enum AorB + @federation__cost(weight: 15) +{ A B } -scalar ExpensiveInt @federation__cost(weight: 30) +scalar ExpensiveInt + @federation__cost(weight: 30) -type ExpensiveObject @federation__cost(weight: 40) { +type ExpensiveObject + @federation__cost(weight: 40) +{ id: ID } @@ -107,7 +116,10 @@ type _Service { -------------------- subgraphWithListSize -------------------- -schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { +schema + @link(url: "https://specs.apollo.dev/link/v1.0") + @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) +{ query: Query } @@ -160,6 +172,7 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY + """ `EXECUTION` features provide metadata necessary for operation execution. """ diff --git a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-2.snap b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-2.snap index a3ddecd1b..5c0461a5d 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-2.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-2.snap @@ -2,7 +2,10 @@ source: router-bridge/src/planner.rs expression: schema --- -schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { +schema + @link(url: "https://specs.apollo.dev/link/v1.0") + @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) +{ query: Query } @@ -59,6 +62,7 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY + """ `EXECUTION` features provide metadata necessary for operation execution. """ @@ -75,7 +79,9 @@ scalar federation__Policy scalar federation__ContextFieldValue -type Book implements Product @key(fields: "isbn") { +type Book implements Product + @key(fields: "isbn") +{ isbn: String! title: String year: Int @@ -99,7 +105,9 @@ type KeyValue { value: String! @shareable } -type Library @key(fields: "id") { +type Library + @key(fields: "id") +{ id: ID! name: String } diff --git a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-3.snap b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-3.snap index ac67b65e0..85ccff517 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-3.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-3.snap @@ -2,7 +2,10 @@ source: router-bridge/src/planner.rs expression: schema --- -schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { +schema + @link(url: "https://specs.apollo.dev/link/v1.0") + @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) +{ query: Query } @@ -59,6 +62,7 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY + """ `EXECUTION` features provide metadata necessary for operation execution. """ diff --git a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-4.snap b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-4.snap index 5677b35eb..a80f0cb31 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-4.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-4.snap @@ -2,7 +2,10 @@ source: router-bridge/src/planner.rs expression: schema --- -schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { +schema + @link(url: "https://specs.apollo.dev/link/v1.0") + @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) +{ query: Query } @@ -59,6 +62,7 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY + """ `EXECUTION` features provide metadata necessary for operation execution. """ @@ -75,7 +79,9 @@ scalar federation__Policy scalar federation__ContextFieldValue -type Book implements Product @key(fields: "isbn") { +type Book implements Product + @key(fields: "isbn") +{ inStock: Boolean isCheckedOut: Boolean isbn: String! @@ -86,7 +92,9 @@ type Book implements Product @key(fields: "isbn") { details: ProductDetails @external } -type Furniture implements Product @key(fields: "sku") { +type Furniture implements Product + @key(fields: "sku") +{ inStock: Boolean isHeavy: Boolean sku: String! @@ -119,7 +127,9 @@ type ProductDetailsFurniture implements ProductDetails { color: String @shareable } -type User @key(fields: "id") { +type User + @key(fields: "id") +{ goodDescription: Boolean @requires(fields: "metadata{description}") id: ID! metadata: [UserMetadata] @external diff --git a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-5.snap b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-5.snap index 84087ca60..88d87a499 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-5.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-5.snap @@ -2,7 +2,10 @@ source: router-bridge/src/planner.rs expression: schema --- -schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { +schema + @link(url: "https://specs.apollo.dev/link/v1.0") + @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) +{ query: Query } @@ -59,6 +62,7 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY + """ `EXECUTION` features provide metadata necessary for operation execution. """ @@ -79,7 +83,9 @@ type Amazon { referrer: String } -type Book implements Product @key(fields: "isbn") { +type Book implements Product + @key(fields: "isbn") +{ upc: String! sku: String! name(delimeter: String = " "): String @requires(fields: "title year") @@ -93,7 +99,9 @@ type Book implements Product @key(fields: "isbn") { union Brand = Ikea | Amazon -type Car implements Vehicle @key(fields: "id") { +type Car implements Vehicle + @key(fields: "id") +{ id: String! description: String price: String @@ -105,7 +113,10 @@ type Error { message: String @shareable } -type Furniture implements Product @key(fields: "upc") @key(fields: "sku") { +type Furniture implements Product + @key(fields: "upc") + @key(fields: "sku") +{ upc: String! sku: String! name: String @@ -161,13 +172,17 @@ type Query { union Thing = Car | Ikea -type User @key(fields: "id") { +type User + @key(fields: "id") +{ vehicle: Vehicle thing: Thing id: ID! } -type Van implements Vehicle @key(fields: "id") { +type Van implements Vehicle + @key(fields: "id") +{ id: String! description: String price: String diff --git a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-6.snap b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-6.snap index d4f23b3db..2b8190f97 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-6.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs-6.snap @@ -2,7 +2,10 @@ source: router-bridge/src/planner.rs expression: schema --- -schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { +schema + @link(url: "https://specs.apollo.dev/link/v1.0") + @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) +{ query: Query mutation: Mutation } @@ -60,6 +63,7 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY + """ `EXECUTION` features provide metadata necessary for operation execution. """ @@ -76,7 +80,9 @@ scalar federation__Policy scalar federation__ContextFieldValue -type Book implements Product @key(fields: "isbn") { +type Book implements Product + @key(fields: "isbn") +{ reviews: [Review] relatedReviews: [Review!]! @requires(fields: "similarBooks{isbn}") isbn: String! @@ -89,7 +95,9 @@ type Book implements Product @key(fields: "isbn") { inStock: Boolean @external } -type Car implements Vehicle @key(fields: "id") { +type Car implements Vehicle + @key(fields: "id") +{ retailPrice: String @requires(fields: "price") id: String! price: String @external @@ -101,7 +109,9 @@ type Error { message: String @shareable } -type Furniture implements Product @key(fields: "upc") { +type Furniture implements Product + @key(fields: "upc") +{ reviews: [Review] upc: String! sku: String! @external @@ -154,7 +164,9 @@ type Query { _service: _Service! } -type Review @key(fields: "id") { +type Review + @key(fields: "id") +{ id: ID! body(format: Boolean = false): String author: User @provides(fields: "username") @@ -167,7 +179,9 @@ input UpdateReviewInput { body: String } -type User @key(fields: "id") { +type User + @key(fields: "id") +{ reviews: [Review] numberOfReviews: Int! goodAddress: Boolean @requires(fields: "metadata{address}") @@ -182,7 +196,9 @@ type UserMetadata { description: String @shareable } -type Van implements Vehicle @key(fields: "id") { +type Van implements Vehicle + @key(fields: "id") +{ retailPrice: String @requires(fields: "price") id: String! price: String @external diff --git a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs.snap b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs.snap index ceb1634be..6b07112e3 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__tests__subgraphs.snap @@ -2,7 +2,10 @@ source: router-bridge/src/planner.rs expression: schema --- -schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) { +schema + @link(url: "https://specs.apollo.dev/link/v1.0") + @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) +{ query: Query mutation: Mutation } @@ -60,6 +63,7 @@ enum link__Purpose { `SECURITY` features provide metadata necessary to securely resolve fields. """ SECURITY + """ `EXECUTION` features provide metadata necessary for operation execution. """ @@ -78,7 +82,9 @@ scalar federation__ContextFieldValue union AccountType = PasswordAccount | SMSAccount -type Library @key(fields: "id") { +type Library + @key(fields: "id") +{ userAccount(id: ID! = 1): User @requires(fields: "name") id: ID! name: String @external @@ -93,7 +99,9 @@ type Name { last: String } -type PasswordAccount @key(fields: "email") { +type PasswordAccount + @key(fields: "email") +{ email: String! } @@ -104,11 +112,16 @@ type Query { _service: _Service! } -type SMSAccount @key(fields: "number") { +type SMSAccount + @key(fields: "number") +{ number: String } -type User @key(fields: "id") @key(fields: "username name{first last}") { +type User + @key(fields: "id") + @key(fields: "username name{first last}") +{ id: ID! name: Name username: String From 4cf29ebc019e42cf1d3dd7b00afb23f0620c45c5 Mon Sep 17 00:00:00 2001 From: Taylor Ninesling Date: Mon, 26 Aug 2024 13:18:00 -0500 Subject: [PATCH 5/6] Fix package version --- Cargo.lock | 2 +- router-bridge/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3e09b5372..4fefbea8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1603,7 +1603,7 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "router-bridge" -version = "0.6.0-beta.0+v2.9.0-beta.1" +version = "0.6.0-beta.1+v2.9.0-beta.0" dependencies = [ "anyhow", "async-channel", diff --git a/router-bridge/Cargo.toml b/router-bridge/Cargo.toml index bce1c754d..4cae69a9c 100644 --- a/router-bridge/Cargo.toml +++ b/router-bridge/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "router-bridge" -version = "0.6.0-beta.0+v2.9.0-beta.1" +version = "0.6.0-beta.1+v2.9.0-beta.0" authors = ["Apollo "] edition = "2018" description = "JavaScript bridge for the Apollo Router" From 837f731d8a0788f7fcb85eafb15abfefe1bf02cd Mon Sep 17 00:00:00 2001 From: Taylor Ninesling Date: Mon, 26 Aug 2024 14:34:27 -0500 Subject: [PATCH 6/6] Use separate snapshots for each subgraph in extract test --- router-bridge/src/planner.rs | 13 +-- ...ner__error_display__subgraphWithCost.snap} | 100 +----------------- ...__error_display__subgraphWithListSize.snap | 96 +++++++++++++++++ 3 files changed, 99 insertions(+), 110 deletions(-) rename router-bridge/src/snapshots/{router_bridge__planner__error_display__extracts_cost_directives.snap => router_bridge__planner__error_display__subgraphWithCost.snap} (50%) create mode 100644 router-bridge/src/snapshots/router_bridge__planner__error_display__subgraphWithListSize.snap diff --git a/router-bridge/src/planner.rs b/router-bridge/src/planner.rs index c6340623d..1e00f39f3 100644 --- a/router-bridge/src/planner.rs +++ b/router-bridge/src/planner.rs @@ -2475,17 +2475,8 @@ feature https://specs.apollo.dev/unsupported-feature/v0.1 is for: SECURITY but i .expect("can create planner"); let subgraphs = planner.subgraphs().await.expect("can extract subgraphs"); - let mut snapshot = String::new(); - for name in vec!["subgraphWithCost", "subgraphWithListSize"] { - use std::fmt::Write; - - let sdl = subgraphs.get(name).unwrap(); - _ = writeln!( - &mut snapshot, - "--------------------\n{}\n--------------------\n{}", - name, sdl - ); + for (name, schema) in subgraphs { + insta::assert_snapshot!(name, schema); } - insta::assert_snapshot!(snapshot); } } diff --git a/router-bridge/src/snapshots/router_bridge__planner__error_display__extracts_cost_directives.snap b/router-bridge/src/snapshots/router_bridge__planner__error_display__subgraphWithCost.snap similarity index 50% rename from router-bridge/src/snapshots/router_bridge__planner__error_display__extracts_cost_directives.snap rename to router-bridge/src/snapshots/router_bridge__planner__error_display__subgraphWithCost.snap index b56ed608e..56a2d5334 100644 --- a/router-bridge/src/snapshots/router_bridge__planner__error_display__extracts_cost_directives.snap +++ b/router-bridge/src/snapshots/router_bridge__planner__error_display__subgraphWithCost.snap @@ -1,10 +1,7 @@ --- source: router-bridge/src/planner.rs -expression: snapshot +expression: schema --- --------------------- -subgraphWithCost --------------------- schema @link(url: "https://specs.apollo.dev/link/v1.0") @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) @@ -113,98 +110,3 @@ scalar _Any type _Service { sdl: String } --------------------- -subgraphWithListSize --------------------- -schema - @link(url: "https://specs.apollo.dev/link/v1.0") - @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) -{ - query: Query -} - -directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA - -directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE - -directive @requires(fields: federation__FieldSet!) on FIELD_DEFINITION - -directive @provides(fields: federation__FieldSet!) on FIELD_DEFINITION - -directive @external(reason: String) on OBJECT | FIELD_DEFINITION - -directive @tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA - -directive @extends on OBJECT | INTERFACE - -directive @shareable repeatable on OBJECT | FIELD_DEFINITION - -directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION - -directive @override(from: String!, label: String) on FIELD_DEFINITION - -directive @composeDirective(name: String) repeatable on SCHEMA - -directive @interfaceObject on OBJECT - -directive @federation__authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM - -directive @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM - -directive @federation__policy(policies: [[federation__Policy!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM - -directive @federation__sourceAPI repeatable on SCHEMA - -directive @federation__sourceType repeatable on OBJECT | INTERFACE - -directive @federation__sourceField repeatable on FIELD_DEFINITION - -directive @federation__context(name: String!) repeatable on INTERFACE | OBJECT | UNION - -directive @federation__fromContext(field: federation__ContextFieldValue) on ARGUMENT_DEFINITION - -directive @federation__cost(weight: Int!) on ARGUMENT_DEFINITION | ENUM | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | OBJECT | SCALAR - -directive @federation__listSize(assumedSize: Int, slicingArguments: [String!], sizedFields: [String!], requireOneSlicingArgument: Boolean = true) on FIELD_DEFINITION - -enum link__Purpose { - """ - `SECURITY` features provide metadata necessary to securely resolve fields. - """ - SECURITY - - """ - `EXECUTION` features provide metadata necessary for operation execution. - """ - EXECUTION -} - -scalar link__Import - -scalar federation__FieldSet - -scalar federation__Scope - -scalar federation__Policy - -scalar federation__ContextFieldValue - -type A { - id: ID -} - -type Query { - fieldWithListSize: [String!] @federation__listSize(assumedSize: 2000, requireOneSlicingArgument: false) - fieldWithDynamicListSize(first: Int = 10): SizedField @federation__listSize(slicingArguments: ["first"], sizedFields: ["items"], requireOneSlicingArgument: true) - _service: _Service! -} - -type SizedField { - items: [A] -} - -scalar _Any - -type _Service { - sdl: String -} diff --git a/router-bridge/src/snapshots/router_bridge__planner__error_display__subgraphWithListSize.snap b/router-bridge/src/snapshots/router_bridge__planner__error_display__subgraphWithListSize.snap new file mode 100644 index 000000000..59c1a205d --- /dev/null +++ b/router-bridge/src/snapshots/router_bridge__planner__error_display__subgraphWithListSize.snap @@ -0,0 +1,96 @@ +--- +source: router-bridge/src/planner.rs +expression: schema +--- +schema + @link(url: "https://specs.apollo.dev/link/v1.0") + @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override", "@composeDirective", "@interfaceObject"]) +{ + query: Query +} + +directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA + +directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE + +directive @requires(fields: federation__FieldSet!) on FIELD_DEFINITION + +directive @provides(fields: federation__FieldSet!) on FIELD_DEFINITION + +directive @external(reason: String) on OBJECT | FIELD_DEFINITION + +directive @tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA + +directive @extends on OBJECT | INTERFACE + +directive @shareable repeatable on OBJECT | FIELD_DEFINITION + +directive @inaccessible on FIELD_DEFINITION | OBJECT | INTERFACE | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION + +directive @override(from: String!, label: String) on FIELD_DEFINITION + +directive @composeDirective(name: String) repeatable on SCHEMA + +directive @interfaceObject on OBJECT + +directive @federation__authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM + +directive @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM + +directive @federation__policy(policies: [[federation__Policy!]!]!) on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM + +directive @federation__sourceAPI repeatable on SCHEMA + +directive @federation__sourceType repeatable on OBJECT | INTERFACE + +directive @federation__sourceField repeatable on FIELD_DEFINITION + +directive @federation__context(name: String!) repeatable on INTERFACE | OBJECT | UNION + +directive @federation__fromContext(field: federation__ContextFieldValue) on ARGUMENT_DEFINITION + +directive @federation__cost(weight: Int!) on ARGUMENT_DEFINITION | ENUM | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | OBJECT | SCALAR + +directive @federation__listSize(assumedSize: Int, slicingArguments: [String!], sizedFields: [String!], requireOneSlicingArgument: Boolean = true) on FIELD_DEFINITION + +enum link__Purpose { + """ + `SECURITY` features provide metadata necessary to securely resolve fields. + """ + SECURITY + + """ + `EXECUTION` features provide metadata necessary for operation execution. + """ + EXECUTION +} + +scalar link__Import + +scalar federation__FieldSet + +scalar federation__Scope + +scalar federation__Policy + +scalar federation__ContextFieldValue + +type A { + id: ID +} + +type Query { + fieldWithListSize: [String!] @federation__listSize(assumedSize: 2000, requireOneSlicingArgument: false) + fieldWithDynamicListSize(first: Int = 10): SizedField @federation__listSize(slicingArguments: ["first"], sizedFields: ["items"], requireOneSlicingArgument: true) + _service: _Service! +} + +type SizedField { + items: [A] +} + +scalar _Any + +type _Service { + sdl: String +}