Skip to content

Commit

Permalink
Add containsSupergraphSpec (#44)
Browse files Browse the repository at this point in the history
This method is meant to quickly check if
`transformSupergraphToPublicSchema` is needed.
Obviously, in most cases when `transformSupergraphToPublicSchema` is
used, a provided schema contains Supergraph spec (join__Graph etc).

Why do I create it then?
We have a special case in GraphQL Hive where we persist the output of
`transformSupergraphToPublicSchema`, but when Apollo Federation adds
something new, we might want to run this method again to remove new
pieces.

#### Performance

I used a Supergraph SDL with ~20k LOC and create three copies.
First copy used `field(whatever: join__Graph)` as an argument somewhere
in the middle.
Second copy had `scalar join__DirectiveArguments`, also in the middle of
the file.
Third copy had `directive @join__directive` definition (yeah yeah, in
the middle).

I wrote three versions of `containsSupergraphSpec` to make sure it has
minimal performance footprint.

1. for-loop over all federation scalars, enums and directives that used
`sdl.includes("[name") or sdl.includes(" name")`
2. same for-loop but directives where checked first
3. regex (current implementation).

I ran it 1000 times and I got (average):
1. 1.56 ms
2. 0.83 ms
3. 0.59 ms
  • Loading branch information
kamilkisiela authored Feb 22, 2024
1 parent 7d797fe commit de983b0
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/tricky-badgers-punch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@theguild/federation-composition': patch
---

Add containsSupergraphSpec to detect if Supergraph related scalars, enums or directives are used
17 changes: 17 additions & 0 deletions src/graphql/contains-supergraph-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { federationDirectives, federationEnums, federationScalars } from "./transform-supergraph-to-public-schema.js";


const supergraphSpecDetectionRegex = new RegExp(
Array.from(federationScalars)
.concat(Array.from(federationEnums))
// "[NAME" or " NAME" for scalars and enums
.map(name => [`\\[${name}`, `\\s${name}`])
.flat(2)
// "@NAME" for directives
.concat(Array.from(federationDirectives).map(name => `@${name}`))
.join('|'),
);

export function containsSupergraphSpec(sdl: string): boolean {
return supergraphSpecDetectionRegex.test(sdl);
}
12 changes: 9 additions & 3 deletions src/graphql/transform-supergraph-to-public-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@ import {
type SchemaDefinitionNode,
} from 'graphql';

const federationScalars = new Set(['_FieldSet', 'link__Import', 'join__FieldSet']);
const federationEnums = new Set(['core__Purpose', 'join__Graph', 'link__Purpose']);
const federationDirectives = new Set([
export const federationScalars = new Set([
'_FieldSet',
'link__Import',
'join__FieldSet',
'join__DirectiveArguments',
]);
export const federationEnums = new Set(['core__Purpose', 'join__Graph', 'link__Purpose']);
export const federationDirectives = new Set([
'link',
'tag',
'join__graph',
'join__type',
'join__implements',
'join__unionMember',
'join__directive',
'join__enumValue',
'join__field',
'inaccessible',
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export * from './compose.js';
export * from './types.js';
export * from './validate.js';
export { transformSupergraphToPublicSchema } from './graphql/transform-supergraph-to-public-schema.js';
export { containsSupergraphSpec } from './graphql/contains-supergraph-spec.js';
export { sortSDL } from './graphql/sort-sdl.js';

0 comments on commit de983b0

Please sign in to comment.