Skip to content

Commit

Permalink
refactor(): move apollo last utils to apollo pkg
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilmysliwiec committed Nov 9, 2021
1 parent abbcac7 commit 7aa8761
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 169 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { loadPackage } from '@nestjs/common/utils/load-package.util';
import {
DefinitionsGeneratorOptions,
GraphQLDefinitionsFactory,
} from '@nestjs/graphql-experimental';
import { extend } from '@nestjs/graphql-experimental/utils';
import { gql } from 'graphql-tag';

export class GraphQLFederationDefinitionsFactory extends GraphQLDefinitionsFactory {
protected async exploreAndEmit(
typePaths: string[],
path: string,
outputAs: 'class' | 'interface',
isDebugEnabled: boolean,
definitionsGeneratorOptions: DefinitionsGeneratorOptions,
typeDefs?: string | string[],
) {
const typePathDefs = await this.gqlTypesLoader.mergeTypesByPaths(typePaths);
const mergedTypeDefs = extend(typePathDefs, typeDefs);

const { buildSubgraphSchema }: typeof import('@apollo/subgraph') =
loadPackage('@apollo/subgraph', 'ApolloFederation', () =>
require('@apollo/subgraph'),
);

const { printSubgraphSchema } = loadPackage(
'@apollo/subgraph',
'ApolloFederation',
() => require('@apollo/subgraph'),
);

const schema = buildSubgraphSchema([
{
typeDefs: gql`
${mergedTypeDefs}
`,
resolvers: {},
},
]);
const tsFile = await this.gqlAstExplorer.explore(
gql`
${printSubgraphSchema(schema)}
`,
path,
outputAs,
definitionsGeneratorOptions,
);
await tsFile.save();
this.printMessage(
`[${new Date().toLocaleTimeString()}] The definitions have been updated.`,
isDebugEnabled,
);
}
}
56 changes: 49 additions & 7 deletions packages/apollo/lib/factories/graphql-federation.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
ScalarsExplorerService,
} from '@nestjs/graphql-experimental/services';
import { extend } from '@nestjs/graphql-experimental/utils';
import { transformSchema } from '@nestjs/graphql-experimental/utils/transform-schema.util';
import {
GraphQLAbstractType,
GraphQLField,
Expand All @@ -26,11 +25,13 @@ import {
isObjectType,
isScalarType,
isUnionType,
specifiedDirectives,
} from 'graphql';
import { gql } from 'graphql-tag';
import { forEach, isEmpty } from 'lodash';
import { ApolloAdapterOptions } from '../interfaces';
import { PluginsExplorerService } from '../services/plugins-explorer.service';
import { transformSchema } from '../utils/transform-schema.util';

export class GraphQLFederationFactory {
constructor(
Expand Down Expand Up @@ -95,12 +96,11 @@ export class GraphQLFederationFactory {
() => require('@apollo/subgraph'),
);

const autoGeneratedSchema: GraphQLSchema =
await this.gqlSchemaBuilder.buildFederatedSchema(
options.autoSchemaFile,
options,
this.resolversExplorerService.getAllCtors(),
);
const autoGeneratedSchema: GraphQLSchema = await this.buildFederatedSchema(
options.autoSchemaFile,
options,
this.resolversExplorerService.getAllCtors(),
);
let executableSchema: GraphQLSchema = buildSubgraphSchema({
typeDefs: gql(printSubgraphSchema(autoGeneratedSchema)),
resolvers: this.getResolvers(options.resolvers),
Expand Down Expand Up @@ -269,4 +269,46 @@ export class GraphQLFederationFactory {
};
return typeInFederatedSchema;
}

async buildFederatedSchema(
autoSchemaFile: string | boolean,
options: ApolloAdapterOptions,
resolvers: Function[],
) {
const scalarsMap = this.scalarsExplorerService.getScalarsMap();
try {
const buildSchemaOptions = options.buildSchemaOptions || {};
return await this.gqlSchemaBuilder.generateSchema(
resolvers,
autoSchemaFile,
{
...buildSchemaOptions,
directives: [
...specifiedDirectives,
...this.loadFederationDirectives(),
...((buildSchemaOptions && buildSchemaOptions.directives) || []),
],
scalarsMap,
schemaDirectives: options.schemaDirectives,
skipCheck: true,
},
options.sortSchema,
options.transformAutoSchemaFile && options.transformSchema,
);
} catch (err) {
if (err && err.details) {
console.error(err.details);
}
throw err;
}
}

private loadFederationDirectives() {
const { federationDirectives } = loadPackage(
'@apollo/subgraph/dist/directives',
'SchemaBuilder',
() => require('@apollo/subgraph/dist/directives'),
);
return federationDirectives;
}
}
1 change: 1 addition & 0 deletions packages/apollo/lib/factories/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './graphql-federation-definitions.factory';
1 change: 1 addition & 0 deletions packages/apollo/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './adapters';
export * from './decorators';
export * from './factories';
export * from './interfaces';
export * from './utils';
6 changes: 2 additions & 4 deletions packages/apollo/lib/interfaces/adapter-options.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,5 @@ export interface ApolloAdapterOptions

export type ApolloAdapterOptionsFactory =
GqlOptionsFactory<ApolloAdapterOptions>;
export type ApolloAdapterAsyncOptions = GqlModuleAsyncOptions<
ApolloAdapterOptions,
ApolloAdapterOptionsFactory
>;
export type ApolloAdapterAsyncOptions =
GqlModuleAsyncOptions<ApolloAdapterOptions>;
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,5 @@ export interface ApolloGatewayAdapterOptions {

export type GatewayOptionsFactory =
GqlOptionsFactory<ApolloGatewayAdapterOptions>;
export type GatewayAsyncOptions = GqlModuleAsyncOptions<
ApolloGatewayAdapterOptions,
GatewayOptionsFactory
>;
export type GatewayAsyncOptions =
GqlModuleAsyncOptions<ApolloGatewayAdapterOptions>;
12 changes: 4 additions & 8 deletions packages/apollo/tests/e2e/generated-definitions.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { INestApplication } from '@nestjs/common';
import {
GraphQLDefinitionsFactory,
GraphQLFactory,
} from '@nestjs/graphql-experimental';
import { GraphQLFactory } from '@nestjs/graphql-experimental';
import { Test } from '@nestjs/testing';
import * as fs from 'fs';
import * as path from 'path';
import * as util from 'util';
import { GraphQLFederationDefinitionsFactory } from '../../lib';
import { ApplicationModule } from '../code-first/app.module';

const readFile = util.promisify(fs.readFile);
Expand Down Expand Up @@ -282,12 +280,11 @@ describe('Generated Definitions', () => {

it('should generate for a federated graph', async () => {
const outputFile = generatedDefinitions('federation.test-definitions.ts');
const factory = new GraphQLDefinitionsFactory();
const factory = new GraphQLFederationDefinitionsFactory();
await factory.generate({
typePaths: [generatedDefinitions('federation.graphql')],
path: outputFile,
outputAs: 'class',
federation: true,
});

expect(
Expand All @@ -299,7 +296,7 @@ describe('Generated Definitions', () => {
const outputFile = generatedDefinitions(
'federation-typedef.test-definitions.ts',
);
const factory = new GraphQLDefinitionsFactory();
const factory = new GraphQLFederationDefinitionsFactory();
await factory.generate({
typePaths: [generatedDefinitions('federation-typedef.graphql')],
typeDefs: `enum Animal {
Expand All @@ -308,7 +305,6 @@ describe('Generated Definitions', () => {
}`,
path: outputFile,
outputAs: 'class',
federation: true,
});

expect(
Expand Down
107 changes: 14 additions & 93 deletions packages/graphql/lib/graphql-definitions.factory.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { makeExecutableSchema } from '@graphql-tools/schema';
import { loadPackage } from '@nestjs/common/utils/load-package.util';
import { isEmpty } from '@nestjs/common/utils/shared.utils';
import * as chokidar from 'chokidar';
import { printSchema } from 'graphql';
Expand All @@ -11,28 +10,26 @@ import {
import { GraphQLTypesLoader } from './graphql-types.loader';
import { extend, removeTempField } from './utils';

export type GenerateOptions = DefinitionsGeneratorOptions & {
typePaths: string[];
path: string;
outputAs?: 'class' | 'interface';
watch?: boolean;
debug?: boolean;
typeDefs?: string | string[];
};

export class GraphQLDefinitionsFactory {
private readonly gqlAstExplorer = new GraphQLAstExplorer();
private readonly gqlTypesLoader = new GraphQLTypesLoader();
protected readonly gqlAstExplorer = new GraphQLAstExplorer();
protected readonly gqlTypesLoader = new GraphQLTypesLoader();

async generate(
options: {
typePaths: string[];
path: string;
outputAs?: 'class' | 'interface';
watch?: boolean;
debug?: boolean;
federation?: boolean;
typeDefs?: string | string[];
} & DefinitionsGeneratorOptions,
) {
async generate(options: GenerateOptions) {
const isDebugEnabled = !(options && options.debug === false);
const typePathsExists = options.typePaths && !isEmpty(options.typePaths);
if (!typePathsExists) {
throw new Error(`"typePaths" property cannot be empty.`);
}

const isFederation = options && options.federation;
const definitionsGeneratorOptions: DefinitionsGeneratorOptions = {
emitTypenameField: options.emitTypenameField,
skipResolverArgs: options.skipResolverArgs,
Expand All @@ -58,7 +55,6 @@ export class GraphQLDefinitionsFactory {
options.typePaths,
options.path,
options.outputAs,
isFederation,
isDebugEnabled,
definitionsGeneratorOptions,
options.typeDefs,
Expand All @@ -69,88 +65,13 @@ export class GraphQLDefinitionsFactory {
options.typePaths,
options.path,
options.outputAs,
isFederation,
isDebugEnabled,
definitionsGeneratorOptions,
options.typeDefs,
);
}

private async exploreAndEmit(
typePaths: string[],
path: string,
outputAs: 'class' | 'interface',
isFederation: boolean,
isDebugEnabled: boolean,
definitionsGeneratorOptions: DefinitionsGeneratorOptions = {},
typeDefs?: string | string[],
) {
if (isFederation) {
return this.exploreAndEmitFederation(
typePaths,
path,
outputAs,
isDebugEnabled,
definitionsGeneratorOptions,
typeDefs,
);
}
return this.exploreAndEmitRegular(
typePaths,
path,
outputAs,
isDebugEnabled,
definitionsGeneratorOptions,
typeDefs,
);
}

private async exploreAndEmitFederation(
typePaths: string[],
path: string,
outputAs: 'class' | 'interface',
isDebugEnabled: boolean,
definitionsGeneratorOptions: DefinitionsGeneratorOptions,
typeDefs?: string | string[],
) {
const typePathDefs = await this.gqlTypesLoader.mergeTypesByPaths(typePaths);
const mergedTypeDefs = extend(typePathDefs, typeDefs);

const { buildSubgraphSchema }: typeof import('@apollo/subgraph') =
loadPackage('@apollo/subgraph', 'ApolloFederation', () =>
require('@apollo/subgraph'),
);

const { printSubgraphSchema } = loadPackage(
'@apollo/subgraph',
'ApolloFederation',
() => require('@apollo/subgraph'),
);

const schema = buildSubgraphSchema([
{
typeDefs: gql`
${mergedTypeDefs}
`,
resolvers: {},
},
]);
const tsFile = await this.gqlAstExplorer.explore(
gql`
${printSubgraphSchema(schema)}
`,
path,
outputAs,
definitionsGeneratorOptions,
);
await tsFile.save();
this.printMessage(
`[${new Date().toLocaleTimeString()}] The definitions have been updated.`,
isDebugEnabled,
);
}

private async exploreAndEmitRegular(
protected async exploreAndEmit(
typePaths: string[],
path: string,
outputAs: 'class' | 'interface',
Expand Down Expand Up @@ -185,7 +106,7 @@ export class GraphQLDefinitionsFactory {
);
}

private printMessage(text: string, isEnabled: boolean) {
protected printMessage(text: string, isEnabled: boolean) {
isEnabled && console.log(text);
}
}
Loading

0 comments on commit 7aa8761

Please sign in to comment.