@apollo/gateway 0.43.1 → 2.0.0-alpha.1
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.
- package/CHANGELOG.md +2 -4
- package/LICENSE +95 -0
- package/dist/executeQueryPlan.d.ts +2 -3
- package/dist/executeQueryPlan.d.ts.map +1 -1
- package/dist/executeQueryPlan.js +2 -27
- package/dist/executeQueryPlan.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -41
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
- package/src/__tests__/build-query-plan.feature +34 -24
- package/src/__tests__/buildQueryPlan.test.ts +76 -840
- package/src/__tests__/executeQueryPlan.test.ts +543 -537
- package/src/__tests__/execution-utils.ts +20 -26
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +26 -4
- package/src/__tests__/gateway/reporting.test.ts +0 -14
- package/src/__tests__/integration/abstract-types.test.ts +40 -52
- package/src/__tests__/integration/boolean.test.ts +3 -1
- package/src/__tests__/integration/complex-key.test.ts +40 -55
- package/src/__tests__/integration/configuration.test.ts +5 -5
- package/src/__tests__/integration/custom-directives.test.ts +8 -2
- package/src/__tests__/integration/multiple-key.test.ts +10 -11
- package/src/__tests__/integration/requires.test.ts +2 -2
- package/src/__tests__/integration/scope.test.ts +19 -30
- package/src/__tests__/integration/value-types.test.ts +31 -31
- package/src/__tests__/loadSupergraphSdlFromStorage.test.ts +217 -142
- package/src/__tests__/queryPlanCucumber.test.ts +4 -18
- package/src/core/__tests__/core.test.ts +1 -0
- package/src/executeQueryPlan.ts +1 -32
- package/src/index.ts +39 -80
- package/src/utilities/__tests__/cleanErrorOfInaccessibleElements.test.ts +4 -4
- package/LICENSE.md +0 -21
- package/dist/core/index.d.ts +0 -13
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -43
- package/dist/core/index.js.map +0 -1
- package/src/__tests__/build-query-plan-fragmentization.feature +0 -282
- package/src/core/index.ts +0 -51
package/src/index.ts
CHANGED
|
@@ -11,14 +11,8 @@ import {
|
|
|
11
11
|
isIntrospectionType,
|
|
12
12
|
GraphQLSchema,
|
|
13
13
|
VariableDefinitionNode,
|
|
14
|
-
DocumentNode,
|
|
15
|
-
print,
|
|
16
|
-
parse,
|
|
17
|
-
Source,
|
|
18
14
|
} from 'graphql';
|
|
19
15
|
import {
|
|
20
|
-
composeAndValidate,
|
|
21
|
-
compositionHasErrors,
|
|
22
16
|
ServiceDefinition,
|
|
23
17
|
} from '@apollo/federation';
|
|
24
18
|
import loglevel from 'loglevel';
|
|
@@ -41,7 +35,6 @@ import {
|
|
|
41
35
|
QueryPlanner,
|
|
42
36
|
QueryPlan,
|
|
43
37
|
prettyFormatQueryPlan,
|
|
44
|
-
toAPISchema,
|
|
45
38
|
} from '@apollo/query-planner';
|
|
46
39
|
import {
|
|
47
40
|
ServiceEndpointDefinition,
|
|
@@ -71,11 +64,15 @@ import {
|
|
|
71
64
|
} from './config';
|
|
72
65
|
import { loadSupergraphSdlFromStorage } from './loadSupergraphSdlFromStorage';
|
|
73
66
|
import { getServiceDefinitionsFromStorage } from './legacyLoadServicesFromStorage';
|
|
74
|
-
import { buildComposedSchema } from '@apollo/query-planner';
|
|
75
67
|
import { SpanStatusCode } from '@opentelemetry/api';
|
|
76
68
|
import { OpenTelemetrySpanNames, tracer } from './utilities/opentelemetry';
|
|
77
|
-
|
|
78
|
-
import {
|
|
69
|
+
|
|
70
|
+
import {
|
|
71
|
+
buildSupergraphSchema,
|
|
72
|
+
operationFromDocument,
|
|
73
|
+
Schema,
|
|
74
|
+
} from '@apollo/federation-internals';
|
|
75
|
+
import { composeServices } from '@apollo/composition'
|
|
79
76
|
|
|
80
77
|
type DataSourceMap = {
|
|
81
78
|
[serviceName: string]: { url?: string; dataSource: GraphQLDataSource };
|
|
@@ -176,6 +173,13 @@ interface GraphQLServiceEngineConfig {
|
|
|
176
173
|
|
|
177
174
|
export class ApolloGateway implements GraphQLService {
|
|
178
175
|
public schema?: GraphQLSchema;
|
|
176
|
+
// Same as a `schema` but as a `Schema` to avoid reconverting when we need it.
|
|
177
|
+
// TODO(sylvain): if we add caching in `Schema.toGraphQLJSSchema`, we could maybe only keep `apiSchema`
|
|
178
|
+
// and make `schema` a getter (though `schema` does rely on `wrapSchemaWithAliasResolver` so this should
|
|
179
|
+
// be accounted for and this may look ugly). Unsure if moving from a member to a getter could break anyone externally however
|
|
180
|
+
// (also unclear why we expose a mutable member public in the first place; don't everything break if the
|
|
181
|
+
// use manually assigns `schema`?).
|
|
182
|
+
private apiSchema?: Schema;
|
|
179
183
|
private serviceMap: DataSourceMap = Object.create(null);
|
|
180
184
|
private config: GatewayConfig;
|
|
181
185
|
private logger: Logger;
|
|
@@ -193,7 +197,7 @@ export class ApolloGateway implements GraphQLService {
|
|
|
193
197
|
private serviceSdlCache = new Map<string, string>();
|
|
194
198
|
private warnedStates: WarnedStates = Object.create(null);
|
|
195
199
|
private queryPlanner?: QueryPlanner;
|
|
196
|
-
private
|
|
200
|
+
private supergraphSdl?: string;
|
|
197
201
|
private fetcher: typeof fetch;
|
|
198
202
|
private compositionId?: string;
|
|
199
203
|
private state: GatewayState;
|
|
@@ -439,14 +443,13 @@ export class ApolloGateway implements GraphQLService {
|
|
|
439
443
|
// Synchronously load a statically configured schema, update class instance's
|
|
440
444
|
// schema and query planner.
|
|
441
445
|
private loadStatic(config: StaticGatewayConfig) {
|
|
442
|
-
let schema:
|
|
446
|
+
let schema: Schema;
|
|
443
447
|
let supergraphSdl: string;
|
|
444
448
|
try {
|
|
445
449
|
({ schema, supergraphSdl } = isLocalConfig(config)
|
|
446
450
|
? this.createSchemaFromServiceList(config.localServiceList)
|
|
447
451
|
: this.createSchemaFromSupergraphSdl(config.supergraphSdl));
|
|
448
|
-
|
|
449
|
-
this.parsedSupergraphSdl = parse(supergraphSdl);
|
|
452
|
+
this.supergraphSdl = supergraphSdl;
|
|
450
453
|
this.updateWithSchemaAndNotify(schema, supergraphSdl, true);
|
|
451
454
|
} catch (e) {
|
|
452
455
|
this.state = { phase: 'failed to load' };
|
|
@@ -532,7 +535,7 @@ export class ApolloGateway implements GraphQLService {
|
|
|
532
535
|
this.experimental_didUpdateComposition(
|
|
533
536
|
{
|
|
534
537
|
serviceDefinitions: result.serviceDefinitions,
|
|
535
|
-
schema,
|
|
538
|
+
schema: schema.toGraphQLJSSchema(),
|
|
536
539
|
...(this.compositionMetadata && {
|
|
537
540
|
compositionMetadata: this.compositionMetadata,
|
|
538
541
|
}),
|
|
@@ -558,15 +561,14 @@ export class ApolloGateway implements GraphQLService {
|
|
|
558
561
|
return;
|
|
559
562
|
}
|
|
560
563
|
|
|
561
|
-
// TODO(trevor): #580 redundant parse
|
|
562
564
|
// This may throw, so we'll calculate early (specifically before making any updates)
|
|
563
565
|
// In the case that it throws, the gateway will:
|
|
564
566
|
// * on initial load, throw the error
|
|
565
567
|
// * on update, log the error and don't update
|
|
566
|
-
const
|
|
568
|
+
const { schema, supergraphSdl } = this.createSchemaFromSupergraphSdl(result.supergraphSdl);
|
|
567
569
|
|
|
568
570
|
const previousSchema = this.schema;
|
|
569
|
-
const previousSupergraphSdl = this.
|
|
571
|
+
const previousSupergraphSdl = this.supergraphSdl;
|
|
570
572
|
const previousCompositionId = this.compositionId;
|
|
571
573
|
|
|
572
574
|
if (previousSchema) {
|
|
@@ -576,11 +578,8 @@ export class ApolloGateway implements GraphQLService {
|
|
|
576
578
|
await this.maybePerformServiceHealthCheck(result);
|
|
577
579
|
|
|
578
580
|
this.compositionId = result.id;
|
|
579
|
-
this.
|
|
581
|
+
this.supergraphSdl = result.supergraphSdl;
|
|
580
582
|
|
|
581
|
-
const { schema, supergraphSdl } = this.createSchemaFromSupergraphSdl(
|
|
582
|
-
result.supergraphSdl,
|
|
583
|
-
);
|
|
584
583
|
|
|
585
584
|
if (!supergraphSdl) {
|
|
586
585
|
this.logger.error(
|
|
@@ -594,12 +593,12 @@ export class ApolloGateway implements GraphQLService {
|
|
|
594
593
|
{
|
|
595
594
|
compositionId: result.id,
|
|
596
595
|
supergraphSdl: result.supergraphSdl,
|
|
597
|
-
schema,
|
|
596
|
+
schema: schema.toGraphQLJSSchema(),
|
|
598
597
|
},
|
|
599
598
|
previousCompositionId && previousSupergraphSdl && previousSchema
|
|
600
599
|
? {
|
|
601
600
|
compositionId: previousCompositionId,
|
|
602
|
-
supergraphSdl:
|
|
601
|
+
supergraphSdl: previousSupergraphSdl,
|
|
603
602
|
schema: previousSchema,
|
|
604
603
|
}
|
|
605
604
|
: undefined,
|
|
@@ -612,13 +611,14 @@ export class ApolloGateway implements GraphQLService {
|
|
|
612
611
|
// ensure we do not forget to update some of that state, and to avoid scenarios where
|
|
613
612
|
// concurrently executing code sees partially-updated state.
|
|
614
613
|
private updateWithSchemaAndNotify(
|
|
615
|
-
coreSchema:
|
|
614
|
+
coreSchema: Schema,
|
|
616
615
|
coreSupergraphSdl: string,
|
|
617
616
|
// Once we remove the deprecated onSchemaChange() method, we can remove this.
|
|
618
617
|
legacyDontNotifyOnSchemaChangeListeners: boolean = false,
|
|
619
618
|
): void {
|
|
620
619
|
if (this.queryPlanStore) this.queryPlanStore.flush();
|
|
621
|
-
this.
|
|
620
|
+
this.apiSchema = coreSchema.toAPISchema();
|
|
621
|
+
this.schema = wrapSchemaWithAliasResolver(this.apiSchema.toGraphQLJSSchema());
|
|
622
622
|
this.queryPlanner = new QueryPlanner(coreSchema);
|
|
623
623
|
|
|
624
624
|
// Notify onSchemaChange listeners of the updated schema
|
|
@@ -658,10 +658,9 @@ export class ApolloGateway implements GraphQLService {
|
|
|
658
658
|
// This is the last chance to bail out of a schema update.
|
|
659
659
|
if (this.config.serviceHealthCheck) {
|
|
660
660
|
const serviceList = isSupergraphSdlUpdate(update)
|
|
661
|
-
? //
|
|
662
|
-
// Parsing could technically fail and throw here, but parseability has
|
|
661
|
+
? // Parsing of the supergraph SDL could technically fail and throw here, but parseability has
|
|
663
662
|
// already been confirmed slightly earlier in the code path
|
|
664
|
-
this.serviceListFromSupergraphSdl(
|
|
663
|
+
this.serviceListFromSupergraphSdl(update.supergraphSdl)
|
|
665
664
|
: // Existence of this is determined in advance with an early return otherwise
|
|
666
665
|
update.serviceDefinitions!;
|
|
667
666
|
// Here we need to construct new datasources based on the new schema info
|
|
@@ -726,10 +725,9 @@ export class ApolloGateway implements GraphQLService {
|
|
|
726
725
|
.join('\n')}`,
|
|
727
726
|
);
|
|
728
727
|
|
|
729
|
-
const compositionResult =
|
|
730
|
-
|
|
731
|
-
if (
|
|
732
|
-
const { errors } = compositionResult;
|
|
728
|
+
const compositionResult = composeServices(serviceList);
|
|
729
|
+
const errors = compositionResult.errors;
|
|
730
|
+
if (errors) {
|
|
733
731
|
if (this.experimental_didFailComposition) {
|
|
734
732
|
this.experimental_didFailComposition({
|
|
735
733
|
errors,
|
|
@@ -744,60 +742,25 @@ export class ApolloGateway implements GraphQLService {
|
|
|
744
742
|
errors.map((e) => '\t' + e.message).join('\n'),
|
|
745
743
|
);
|
|
746
744
|
} else {
|
|
747
|
-
const { supergraphSdl } = compositionResult;
|
|
748
745
|
this.createServices(serviceList);
|
|
749
|
-
|
|
750
|
-
const schema = buildComposedSchema(parse(supergraphSdl));
|
|
751
|
-
|
|
752
746
|
this.logger.debug('Schema loaded and ready for execution');
|
|
753
|
-
|
|
754
|
-
// This is a workaround for automatic wrapping of all fields, which Apollo
|
|
755
|
-
// Server does in the case of implementing resolver wrapping for plugins.
|
|
756
|
-
// Here we wrap all fields with support for resolving aliases as part of the
|
|
757
|
-
// root value which happens because aliases are resolved by sub services and
|
|
758
|
-
// the shape of the root value already contains the aliased fields as
|
|
759
|
-
// responseNames
|
|
760
747
|
return {
|
|
761
|
-
schema:
|
|
762
|
-
supergraphSdl,
|
|
748
|
+
schema: compositionResult.schema,
|
|
749
|
+
supergraphSdl: compositionResult.supergraphSdl,
|
|
763
750
|
};
|
|
764
751
|
}
|
|
765
752
|
}
|
|
766
753
|
|
|
767
|
-
private serviceListFromSupergraphSdl(
|
|
768
|
-
supergraphSdl
|
|
769
|
-
): Omit<ServiceDefinition, 'typeDefs'>[] {
|
|
770
|
-
const schema = buildComposedSchema(supergraphSdl);
|
|
771
|
-
return this.serviceListFromComposedSchema(schema);
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
private serviceListFromComposedSchema(schema: GraphQLSchema) {
|
|
775
|
-
const graphMap = schema.extensions?.federation?.graphs;
|
|
776
|
-
if (!graphMap) {
|
|
777
|
-
throw Error(`Couldn't find graph map in composed schema`);
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
return Array.from(graphMap.values());
|
|
754
|
+
private serviceListFromSupergraphSdl(supergraphSdl: string): Omit<ServiceDefinition, 'typeDefs'>[] {
|
|
755
|
+
return buildSupergraphSchema(supergraphSdl)[1];
|
|
781
756
|
}
|
|
782
757
|
|
|
783
758
|
private createSchemaFromSupergraphSdl(supergraphSdl: string) {
|
|
784
|
-
const
|
|
785
|
-
new Source(supergraphSdl, 'supergraphSdl'),
|
|
786
|
-
)
|
|
787
|
-
.check() // run basic core schema compliance checks
|
|
788
|
-
.check(featureSupport); // run supported feature check
|
|
789
|
-
|
|
790
|
-
// TODO(trevor): #580 redundant parse
|
|
791
|
-
this.parsedSupergraphSdl = core.document;
|
|
792
|
-
|
|
793
|
-
const schema = buildComposedSchema(this.parsedSupergraphSdl);
|
|
794
|
-
|
|
795
|
-
const serviceList = this.serviceListFromComposedSchema(schema);
|
|
796
|
-
|
|
759
|
+
const [schema, serviceList] = buildSupergraphSchema(supergraphSdl);
|
|
797
760
|
this.createServices(serviceList);
|
|
798
761
|
|
|
799
762
|
return {
|
|
800
|
-
schema
|
|
763
|
+
schema,
|
|
801
764
|
supergraphSdl,
|
|
802
765
|
};
|
|
803
766
|
}
|
|
@@ -1059,7 +1022,6 @@ export class ApolloGateway implements GraphQLService {
|
|
|
1059
1022
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1060
1023
|
return { errors: validationErrors };
|
|
1061
1024
|
}
|
|
1062
|
-
|
|
1063
1025
|
let queryPlan: QueryPlan | undefined;
|
|
1064
1026
|
if (this.queryPlanStore) {
|
|
1065
1027
|
queryPlan = await this.queryPlanStore.get(queryPlanStoreKey);
|
|
@@ -1070,12 +1032,9 @@ export class ApolloGateway implements GraphQLService {
|
|
|
1070
1032
|
OpenTelemetrySpanNames.PLAN,
|
|
1071
1033
|
(span) => {
|
|
1072
1034
|
try {
|
|
1035
|
+
const operation = operationFromDocument(this.apiSchema!, document, request.operationName);
|
|
1073
1036
|
// TODO(#631): Can we be sure the query planner has been initialized here?
|
|
1074
|
-
return this.queryPlanner!.buildQueryPlan(
|
|
1075
|
-
autoFragmentization: Boolean(
|
|
1076
|
-
this.config.experimental_autoFragmentization,
|
|
1077
|
-
),
|
|
1078
|
-
});
|
|
1037
|
+
return this.queryPlanner!.buildQueryPlan(operation);
|
|
1079
1038
|
} catch (err) {
|
|
1080
1039
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1081
1040
|
throw err;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { toAPISchema } from "@apollo/query-planner";
|
|
1
|
+
import { execute, GraphQLError, parse } from "graphql";
|
|
3
2
|
import { cleanErrorOfInaccessibleNames } from "../cleanErrorOfInaccessibleNames";
|
|
3
|
+
import { buildSchema } from "@apollo/federation-internals";
|
|
4
4
|
|
|
5
5
|
describe('cleanErrorOfInaccessibleNames', () => {
|
|
6
|
-
|
|
6
|
+
const coreSchema = buildSchema(`
|
|
7
7
|
directive @core(
|
|
8
8
|
feature: String!,
|
|
9
9
|
as: String,
|
|
@@ -46,7 +46,7 @@ describe('cleanErrorOfInaccessibleNames', () => {
|
|
|
46
46
|
inaccessibleField: String @inaccessible
|
|
47
47
|
}
|
|
48
48
|
`);
|
|
49
|
-
schema = toAPISchema(
|
|
49
|
+
const schema = coreSchema.toAPISchema().toGraphQLJSSchema();
|
|
50
50
|
|
|
51
51
|
it('removes inaccessible type names from error messages', async () => {
|
|
52
52
|
const result = await execute(schema, parse('{fooField{someField}}'), {
|
package/LICENSE.md
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
The MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2020- Apollo Graph, Inc.
|
|
4
|
-
Copyright (c) 2019-2020 Meteor Development Group, Inc.
|
|
5
|
-
|
|
6
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
7
|
-
this software and associated documentation files (the "Software"), to deal in
|
|
8
|
-
the Software without restriction, including without limitation the rights to
|
|
9
|
-
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
10
|
-
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
11
|
-
subject to the following conditions:
|
|
12
|
-
|
|
13
|
-
The above copyright notice and this permission notice shall be included in all
|
|
14
|
-
copies or substantial portions of the Software.
|
|
15
|
-
|
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
18
|
-
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
19
|
-
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
20
|
-
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
21
|
-
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/dist/core/index.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { CoreSchemaContext, Feature } from '@apollo/core-schema';
|
|
2
|
-
export declare const ErrUnsupportedFeature: (feature: Feature) => import("@apollo/core-schema/dist/error").GraphQLErrorExt<"UnsupportedFeature"> & {
|
|
3
|
-
message: string;
|
|
4
|
-
feature: Feature;
|
|
5
|
-
nodes: import("graphql").DirectiveNode[];
|
|
6
|
-
};
|
|
7
|
-
export declare const ErrForUnsupported: (core: Feature, ...features: readonly Feature[]) => import("@apollo/core-schema/dist/error").GraphQLErrorExt<"ForUnsupported"> & {
|
|
8
|
-
message: string;
|
|
9
|
-
features: readonly Feature[];
|
|
10
|
-
nodes: import("graphql").DirectiveNode[];
|
|
11
|
-
};
|
|
12
|
-
export declare function featureSupport(this: CoreSchemaContext): void;
|
|
13
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/core/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAO,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAUtE,eAAO,MAAM,qBAAqB,YAAa,OAAO;;;;CAKlD,CAAC;AAEL,eAAO,MAAM,iBAAiB,SAAU,OAAO,eAAe,SAAS,OAAO,EAAE;;;;CAO5E,CAAC;AAEL,wBAAgB,cAAc,CAAC,IAAI,EAAE,iBAAiB,QAwBrD"}
|
package/dist/core/index.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.featureSupport = exports.ErrForUnsupported = exports.ErrUnsupportedFeature = void 0;
|
|
4
|
-
const core_schema_1 = require("@apollo/core-schema");
|
|
5
|
-
const SUPPORTED_FEATURES = new Set([
|
|
6
|
-
'https://specs.apollo.dev/core/v0.1',
|
|
7
|
-
'https://specs.apollo.dev/core/v0.2',
|
|
8
|
-
'https://specs.apollo.dev/join/v0.1',
|
|
9
|
-
'https://specs.apollo.dev/tag/v0.1',
|
|
10
|
-
'https://specs.apollo.dev/inaccessible/v0.1',
|
|
11
|
-
]);
|
|
12
|
-
const ErrUnsupportedFeature = (feature) => (0, core_schema_1.err)('UnsupportedFeature', {
|
|
13
|
-
message: `feature ${feature.url} is for: ${feature.purpose} but is unsupported`,
|
|
14
|
-
feature,
|
|
15
|
-
nodes: [feature.directive],
|
|
16
|
-
});
|
|
17
|
-
exports.ErrUnsupportedFeature = ErrUnsupportedFeature;
|
|
18
|
-
const ErrForUnsupported = (core, ...features) => (0, core_schema_1.err)('ForUnsupported', {
|
|
19
|
-
message: `the \`for:\` argument is unsupported by version ${core.url.version} ` +
|
|
20
|
-
`of the core spec. Please upgrade to at least @core v0.2 (https://specs.apollo.dev/core/v0.2).`,
|
|
21
|
-
features,
|
|
22
|
-
nodes: [core.directive, ...features.map(f => f.directive)]
|
|
23
|
-
});
|
|
24
|
-
exports.ErrForUnsupported = ErrForUnsupported;
|
|
25
|
-
function featureSupport() {
|
|
26
|
-
const coreVersionZeroDotOne = this.features.find('https://specs.apollo.dev/core/v0.1', true);
|
|
27
|
-
if (coreVersionZeroDotOne) {
|
|
28
|
-
const purposefulFeatures = [...this.features].filter(f => f.purpose);
|
|
29
|
-
if (purposefulFeatures.length > 0)
|
|
30
|
-
this.report((0, exports.ErrForUnsupported)(coreVersionZeroDotOne, ...purposefulFeatures));
|
|
31
|
-
}
|
|
32
|
-
for (const feature of this.features) {
|
|
33
|
-
if (!feature.purpose)
|
|
34
|
-
continue;
|
|
35
|
-
if (feature.purpose === 'EXECUTION' || feature.purpose === 'SECURITY') {
|
|
36
|
-
if (!SUPPORTED_FEATURES.has(feature.url.base.toString())) {
|
|
37
|
-
this.report((0, exports.ErrUnsupportedFeature)(feature));
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
exports.featureSupport = featureSupport;
|
|
43
|
-
//# sourceMappingURL=index.js.map
|
package/dist/core/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";;;AAAA,qDAAsE;AAEtE,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC;IACjC,oCAAoC;IACpC,oCAAoC;IACpC,oCAAoC;IACpC,mCAAmC;IACnC,4CAA4C;CAC7C,CAAC,CAAC;AAEI,MAAM,qBAAqB,GAAG,CAAC,OAAgB,EAAE,EAAE,CACxD,IAAA,iBAAG,EAAC,oBAAoB,EAAE;IACxB,OAAO,EAAE,WAAW,OAAO,CAAC,GAAG,YAAY,OAAO,CAAC,OAAO,qBAAqB;IAC/E,OAAO;IACP,KAAK,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;CAC3B,CAAC,CAAC;AALQ,QAAA,qBAAqB,yBAK7B;AAEE,MAAM,iBAAiB,GAAG,CAAC,IAAa,EAAE,GAAG,QAA4B,EAAE,EAAE,CAClF,IAAA,iBAAG,EAAC,gBAAgB,EAAE;IACpB,OAAO,EACL,mDAAmD,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG;QACtE,+FAA+F;IACjG,QAAQ;IACR,KAAK,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;CAC3D,CAAC,CAAC;AAPQ,QAAA,iBAAiB,qBAOzB;AAEL,SAAgB,cAAc;IAC5B,MAAM,qBAAqB,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAC9C,oCAAoC,EACpC,IAAI,CACL,CAAC;IAIF,IAAI,qBAAqB,EAAE;QACzB,MAAM,kBAAkB,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;QACpE,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,IAAA,yBAAiB,EAAC,qBAAqB,EAAE,GAAG,kBAAkB,CAAC,CAAC,CAAA;KAG/E;IAED,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE;QACnC,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,SAAS;QAC/B,IAAI,OAAO,CAAC,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,OAAO,KAAK,UAAU,EAAE;YACrE,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE;gBACxD,IAAI,CAAC,MAAM,CAAC,IAAA,6BAAqB,EAAC,OAAO,CAAC,CAAC,CAAC;aAC7C;SACF;KACF;AACH,CAAC;AAxBD,wCAwBC"}
|
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
Feature: Build Query Plan > Auto-fragmentization
|
|
2
|
-
|
|
3
|
-
Scenario: experimental compression to downstream services should generate fragments internally to downstream requests
|
|
4
|
-
Given query
|
|
5
|
-
"""
|
|
6
|
-
query {
|
|
7
|
-
topReviews {
|
|
8
|
-
body
|
|
9
|
-
author
|
|
10
|
-
product {
|
|
11
|
-
name
|
|
12
|
-
price
|
|
13
|
-
details {
|
|
14
|
-
country
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
"""
|
|
20
|
-
When using autofragmentization
|
|
21
|
-
Then query plan
|
|
22
|
-
"""
|
|
23
|
-
{
|
|
24
|
-
"kind": "QueryPlan",
|
|
25
|
-
"node": {
|
|
26
|
-
"kind": "Sequence",
|
|
27
|
-
"nodes": [
|
|
28
|
-
{
|
|
29
|
-
"kind": "Fetch",
|
|
30
|
-
"serviceName": "reviews",
|
|
31
|
-
"variableUsages": [],
|
|
32
|
-
"operation": "{topReviews{...__QueryPlanFragment_1__}}fragment __QueryPlanFragment_1__ on Review{body author product{...__QueryPlanFragment_0__}}fragment __QueryPlanFragment_0__ on Product{__typename ...on Book{__typename isbn}...on Furniture{__typename upc}}"
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
"kind": "Parallel",
|
|
36
|
-
"nodes": [
|
|
37
|
-
{
|
|
38
|
-
"kind": "Sequence",
|
|
39
|
-
"nodes": [
|
|
40
|
-
{
|
|
41
|
-
"kind": "Flatten",
|
|
42
|
-
"path": ["topReviews", "@", "product"],
|
|
43
|
-
"node": {
|
|
44
|
-
"kind": "Fetch",
|
|
45
|
-
"serviceName": "books",
|
|
46
|
-
"requires": [
|
|
47
|
-
{
|
|
48
|
-
"kind": "InlineFragment",
|
|
49
|
-
"typeCondition": "Book",
|
|
50
|
-
"selections": [
|
|
51
|
-
{ "kind": "Field", "name": "__typename" },
|
|
52
|
-
{ "kind": "Field", "name": "isbn" }
|
|
53
|
-
]
|
|
54
|
-
}
|
|
55
|
-
],
|
|
56
|
-
"variableUsages": [],
|
|
57
|
-
"operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Book{__typename isbn title year}}}"
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
"kind": "Flatten",
|
|
62
|
-
"path": ["topReviews", "@", "product"],
|
|
63
|
-
"node": {
|
|
64
|
-
"kind": "Fetch",
|
|
65
|
-
"serviceName": "product",
|
|
66
|
-
"requires": [
|
|
67
|
-
{
|
|
68
|
-
"kind": "InlineFragment",
|
|
69
|
-
"typeCondition": "Book",
|
|
70
|
-
"selections": [
|
|
71
|
-
{ "kind": "Field", "name": "__typename" },
|
|
72
|
-
{ "kind": "Field", "name": "isbn" },
|
|
73
|
-
{ "kind": "Field", "name": "title" },
|
|
74
|
-
{ "kind": "Field", "name": "year" }
|
|
75
|
-
]
|
|
76
|
-
}
|
|
77
|
-
],
|
|
78
|
-
"variableUsages": [],
|
|
79
|
-
"operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Book{name}}}"
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
]
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"kind": "Flatten",
|
|
86
|
-
"path": ["topReviews", "@", "product"],
|
|
87
|
-
"node": {
|
|
88
|
-
"kind": "Fetch",
|
|
89
|
-
"serviceName": "product",
|
|
90
|
-
"requires": [
|
|
91
|
-
{
|
|
92
|
-
"kind": "InlineFragment",
|
|
93
|
-
"typeCondition": "Furniture",
|
|
94
|
-
"selections": [
|
|
95
|
-
{ "kind": "Field", "name": "__typename" },
|
|
96
|
-
{ "kind": "Field", "name": "upc" }
|
|
97
|
-
]
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
"kind": "InlineFragment",
|
|
101
|
-
"typeCondition": "Book",
|
|
102
|
-
"selections": [
|
|
103
|
-
{ "kind": "Field", "name": "__typename" },
|
|
104
|
-
{ "kind": "Field", "name": "isbn" }
|
|
105
|
-
]
|
|
106
|
-
}
|
|
107
|
-
],
|
|
108
|
-
"variableUsages": [],
|
|
109
|
-
"operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Furniture{name price details{country}}...on Book{price details{country}}}}"
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
]
|
|
113
|
-
}
|
|
114
|
-
]
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
"""
|
|
118
|
-
|
|
119
|
-
Scenario: experimental compression to downstream services shouldn't generate fragments for selection sets of length 2 or less
|
|
120
|
-
Given query
|
|
121
|
-
"""
|
|
122
|
-
query {
|
|
123
|
-
topReviews {
|
|
124
|
-
body
|
|
125
|
-
author
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
"""
|
|
129
|
-
When using autofragmentization
|
|
130
|
-
Then query plan
|
|
131
|
-
"""
|
|
132
|
-
{
|
|
133
|
-
"kind": "QueryPlan",
|
|
134
|
-
"node": {
|
|
135
|
-
"kind": "Fetch",
|
|
136
|
-
"serviceName": "reviews",
|
|
137
|
-
"variableUsages": [],
|
|
138
|
-
"operation": "{topReviews{body author}}"
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
"""
|
|
142
|
-
|
|
143
|
-
Scenario: experimental compression to downstream services should generate fragments for selection sets of length 3 or greater
|
|
144
|
-
Given query
|
|
145
|
-
"""
|
|
146
|
-
query {
|
|
147
|
-
topReviews {
|
|
148
|
-
id
|
|
149
|
-
body
|
|
150
|
-
author
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
"""
|
|
154
|
-
When using autofragmentization
|
|
155
|
-
Then query plan
|
|
156
|
-
"""
|
|
157
|
-
{
|
|
158
|
-
"kind": "QueryPlan",
|
|
159
|
-
"node": {
|
|
160
|
-
"kind": "Fetch",
|
|
161
|
-
"serviceName": "reviews",
|
|
162
|
-
"variableUsages": [],
|
|
163
|
-
"operation": "{topReviews{...__QueryPlanFragment_0__}}fragment __QueryPlanFragment_0__ on Review{id body author}"
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
"""
|
|
167
|
-
|
|
168
|
-
Scenario: experimental compression to downstream services should generate fragments correctly when aliases are used
|
|
169
|
-
Given query
|
|
170
|
-
"""
|
|
171
|
-
query {
|
|
172
|
-
reviews: topReviews {
|
|
173
|
-
content: body
|
|
174
|
-
author
|
|
175
|
-
product {
|
|
176
|
-
name
|
|
177
|
-
cost: price
|
|
178
|
-
details {
|
|
179
|
-
origin: country
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
"""
|
|
185
|
-
When using autofragmentization
|
|
186
|
-
Then query plan
|
|
187
|
-
"""
|
|
188
|
-
{
|
|
189
|
-
"kind": "QueryPlan",
|
|
190
|
-
"node": {
|
|
191
|
-
"kind": "Sequence",
|
|
192
|
-
"nodes": [
|
|
193
|
-
{
|
|
194
|
-
"kind": "Fetch",
|
|
195
|
-
"serviceName": "reviews",
|
|
196
|
-
"variableUsages": [],
|
|
197
|
-
"operation": "{reviews:topReviews{...__QueryPlanFragment_1__}}fragment __QueryPlanFragment_1__ on Review{content:body author product{...__QueryPlanFragment_0__}}fragment __QueryPlanFragment_0__ on Product{__typename ...on Book{__typename isbn}...on Furniture{__typename upc}}"
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
"kind": "Parallel",
|
|
201
|
-
"nodes": [
|
|
202
|
-
{
|
|
203
|
-
"kind": "Sequence",
|
|
204
|
-
"nodes": [
|
|
205
|
-
{
|
|
206
|
-
"kind": "Flatten",
|
|
207
|
-
"path": ["reviews", "@", "product"],
|
|
208
|
-
"node": {
|
|
209
|
-
"kind": "Fetch",
|
|
210
|
-
"serviceName": "books",
|
|
211
|
-
"requires": [
|
|
212
|
-
{
|
|
213
|
-
"kind": "InlineFragment",
|
|
214
|
-
"typeCondition": "Book",
|
|
215
|
-
"selections": [
|
|
216
|
-
{ "kind": "Field", "name": "__typename" },
|
|
217
|
-
{ "kind": "Field", "name": "isbn" }
|
|
218
|
-
]
|
|
219
|
-
}
|
|
220
|
-
],
|
|
221
|
-
"variableUsages": [],
|
|
222
|
-
"operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Book{__typename isbn title year}}}"
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
"kind": "Flatten",
|
|
227
|
-
"path": ["reviews", "@", "product"],
|
|
228
|
-
"node": {
|
|
229
|
-
"kind": "Fetch",
|
|
230
|
-
"serviceName": "product",
|
|
231
|
-
"requires": [
|
|
232
|
-
{
|
|
233
|
-
"kind": "InlineFragment",
|
|
234
|
-
"typeCondition": "Book",
|
|
235
|
-
"selections": [
|
|
236
|
-
{ "kind": "Field", "name": "__typename" },
|
|
237
|
-
{ "kind": "Field", "name": "isbn" },
|
|
238
|
-
{ "kind": "Field", "name": "title" },
|
|
239
|
-
{ "kind": "Field", "name": "year" }
|
|
240
|
-
]
|
|
241
|
-
}
|
|
242
|
-
],
|
|
243
|
-
"variableUsages": [],
|
|
244
|
-
"operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Book{name}}}"
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
]
|
|
248
|
-
},
|
|
249
|
-
{
|
|
250
|
-
"kind": "Flatten",
|
|
251
|
-
"path": ["reviews", "@", "product"],
|
|
252
|
-
"node": {
|
|
253
|
-
"kind": "Fetch",
|
|
254
|
-
"serviceName": "product",
|
|
255
|
-
"requires": [
|
|
256
|
-
{
|
|
257
|
-
"kind": "InlineFragment",
|
|
258
|
-
"typeCondition": "Furniture",
|
|
259
|
-
"selections": [
|
|
260
|
-
{ "kind": "Field", "name": "__typename" },
|
|
261
|
-
{ "kind": "Field", "name": "upc" }
|
|
262
|
-
]
|
|
263
|
-
},
|
|
264
|
-
{
|
|
265
|
-
"kind": "InlineFragment",
|
|
266
|
-
"typeCondition": "Book",
|
|
267
|
-
"selections": [
|
|
268
|
-
{ "kind": "Field", "name": "__typename" },
|
|
269
|
-
{ "kind": "Field", "name": "isbn" }
|
|
270
|
-
]
|
|
271
|
-
}
|
|
272
|
-
],
|
|
273
|
-
"variableUsages": [],
|
|
274
|
-
"operation": "query($representations:[_Any!]!){_entities(representations:$representations){...on Furniture{name cost:price details{origin:country}}...on Book{cost:price details{origin:country}}}}"
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
]
|
|
278
|
-
}
|
|
279
|
-
]
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
"""
|