Skip to content

Commit

Permalink
chore(): publish next release
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilmysliwiec committed May 11, 2019
1 parent ece361b commit 775beca
Show file tree
Hide file tree
Showing 51 changed files with 449 additions and 154 deletions.
19 changes: 0 additions & 19 deletions integration/type-graphql/recipes/models/recipe.ts

This file was deleted.

35 changes: 0 additions & 35 deletions integration/type-graphql/schema.gql

This file was deleted.

6 changes: 5 additions & 1 deletion lib/decorators/args.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ export function Args(
let argOptions = {} as BasicOptions;
let property = propertyOrOptions;

if (propertyOrOptions && isObject(propertyOrOptions)) {
if (
propertyOrOptions &&
isObject(propertyOrOptions) &&
!(propertyOrOptions as PipeTransform).transform
) {
property = (propertyOrOptions as Record<string, any>).name;
typeFn = (propertyOrOptions as Record<string, any>).type;
argOptions = {
Expand Down
31 changes: 28 additions & 3 deletions lib/decorators/resolvers.utils.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { SetMetadata, Type } from '@nestjs/common';
import { isFunction, isString } from '@nestjs/common/utils/shared.utils';
import {
isFunction,
isObject,
isString,
} from '@nestjs/common/utils/shared.utils';
import * as optional from 'optional';
import { Resolvers } from '../enums/resolvers.enum';
import {
AdvancedOptions,
ReturnTypeFunc,
} from '../external/type-graphql.types';
import {
FIELD_TYPENAME,
RESOLVER_DELEGATE_METADATA,
RESOLVER_NAME_METADATA,
RESOLVER_PROPERTY_METADATA,
Expand All @@ -32,21 +35,43 @@ export function addResolverMetadata(
SetMetadata(RESOLVER_NAME_METADATA, name)(target, key, descriptor);
}

export function createPropertyDecorator(
typeFunc?: ReturnTypeFunc,
options?: AdvancedOptions,
): MethodDecorator;
export function createPropertyDecorator(
propertyName?: string,
typeFunc?: ReturnTypeFunc,
options?: AdvancedOptions,
);
export function createPropertyDecorator(
propertyNameOrFunc?: string | ReturnTypeFunc,
typeFuncOrOptions?: ReturnTypeFunc | AdvancedOptions,
advancedOptions?: AdvancedOptions,
): MethodDecorator {
return (
target: Function | Object,
key?: string | symbol,
descriptor?: any,
) => {
let [propertyName, typeFunc, options] = isFunction(propertyNameOrFunc)
? [undefined, propertyNameOrFunc, typeFuncOrOptions]
: [propertyNameOrFunc, typeFuncOrOptions, advancedOptions];

SetMetadata(RESOLVER_NAME_METADATA, propertyName)(target, key, descriptor);
SetMetadata(RESOLVER_PROPERTY_METADATA, true)(target, key, descriptor);

const isField = propertyName !== FIELD_TYPENAME && key !== FIELD_TYPENAME;
const isField = true;
if (FieldResolver && isField) {
options = isObject(options)
? {
name: propertyName as string,
...options,
}
: propertyName
? { name: propertyName as string }
: undefined;

lazyMetadataStorage.store(() =>
FieldResolver(typeFunc, options)(target, key, descriptor),
);
Expand Down
8 changes: 5 additions & 3 deletions lib/graphql-schema-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,20 @@ export class GraphQLSchemaBuilder {
) {}

async build(
emitSchemaFile: string | boolean,
autoSchemaFile: string | boolean,
options: BuildSchemaOptions = {},
resolvers: Function[],
): Promise<any> {
lazyMetadataStorage.load();

const buildSchema = this.loadBuildSchemaFactory();
const scalarsMap = this.scalarsExplorerService.getScalarsMap();
return await buildSchema({
...options,
emitSchemaFile,
emitSchemaFile: autoSchemaFile !== true ? autoSchemaFile : false,
scalarsMap,
resolvers: ['---.js'], // NOTE: Added to omit options validation
validate: false,
resolvers,
});
}

Expand Down
75 changes: 70 additions & 5 deletions lib/graphql.factory.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { Injectable } from '@nestjs/common';
import { gql, makeExecutableSchema, mergeSchemas } from 'apollo-server-express';
import { existsSync, lstatSync, readFileSync } from 'fs';
import { GraphQLSchema, printSchema } from 'graphql';
import { isEmpty } from 'lodash';
import {
GraphQLObjectType,
GraphQLSchema,
GraphQLSchemaConfig,
printSchema,
} from 'graphql';
import { forEach, isEmpty } from 'lodash';
import { GraphQLAstExplorer } from './graphql-ast.explorer';
import { GraphQLSchemaBuilder } from './graphql-schema-builder';
import { GqlModuleOptions } from './interfaces/gql-module-options.interface';
Expand Down Expand Up @@ -33,23 +38,35 @@ export class GraphQLFactory {
options.transformSchema ? await options.transformSchema(schema) : schema;

if (options.autoSchemaFile) {
const autoGeneratedSchema = await this.gqlSchemaBuilder.build(
const autoGeneratedSchema: GraphQLSchema = await this.gqlSchemaBuilder.build(
options.autoSchemaFile,
options.buildSchemaOptions,
this.resolversExplorerService.getAllCtors(),
);
const executableSchema = makeExecutableSchema({
resolvers: extend(typesResolvers, options.resolvers),
typeDefs: gql`
${printSchema(autoGeneratedSchema)}
`,
resolverValidationOptions: options.resolverValidationOptions,
resolverValidationOptions: {
...(options.resolverValidationOptions || {}),
requireResolversForResolveType: false,
},
});
const schema = options.schema
let schema = options.schema
? mergeSchemas({
schemas: [options.schema, executableSchema],
})
: executableSchema;

const autoGeneratedSchemaConfig = autoGeneratedSchema.toConfig();
const executableSchemaConfig = executableSchema.toConfig();
const schemaConfig = this.overrideOrExtendResolvers(
executableSchemaConfig,
autoGeneratedSchemaConfig,
);

schema = new GraphQLSchema(schemaConfig);
return {
...options,
typeDefs: undefined,
Expand Down Expand Up @@ -85,6 +102,54 @@ export class GraphQLFactory {
};
}

overrideOrExtendResolvers(
executableSchemaConfig: GraphQLSchemaConfig,
autoGeneratedSchemaConfig: GraphQLSchemaConfig,
): GraphQLSchemaConfig {
const schemaConfig = autoGeneratedSchemaConfig;
const rootResolverKeys: ('mutation' | 'query' | 'subscription')[] = [
'mutation',
'query',
'subscription',
];

rootResolverKeys.forEach(key => {
const executableSchemaFields = executableSchemaConfig[key].getFields();
const schemaFields = schemaConfig[key].getFields();

forEach(executableSchemaFields, (value, resolverName) => {
if (schemaFields[resolverName]) {
schemaFields[resolverName].resolve =
executableSchemaFields[resolverName].resolve;
} else {
schemaFields[resolverName] = executableSchemaFields[resolverName];
}
});
});

const getAutoGeneratedFieldByName = (name: string): GraphQLObjectType =>
autoGeneratedSchemaConfig.types.find(
type => type.name === name,
) as GraphQLObjectType;
executableSchemaConfig.types
.filter(type => type instanceof GraphQLObjectType)
.forEach((type: GraphQLObjectType) => {
const fields = type.getFields();
forEach(fields, (value, key) => {
if (!value.resolve) {
return;
}
const autoGeneratedField = getAutoGeneratedFieldByName(type.name);
if (!autoGeneratedField) {
return;
}
autoGeneratedField.getFields()[key].resolve = value.resolve;
});
});

return schemaConfig;
}

createDelegates(): (mergeInfo: any) => any {
return this.delegatesExplorerService.explore();
}
Expand Down
6 changes: 3 additions & 3 deletions lib/services/base-explorer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ export class BaseExplorerService {
);
}

flatMap<T = ResolverMetadata[]>(
flatMap<T = ResolverMetadata>(
modules: Module[],
callback: (instance: InstanceWrapper, moduleRef: Module) => T,
): T {
callback: (instance: InstanceWrapper, moduleRef: Module) => T | T[],
): T[] {
const invokeMap = () =>
modules.map(module =>
[...module.providers.values()].map(wrapper =>
Expand Down
27 changes: 27 additions & 0 deletions lib/services/resolvers-explorer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,20 @@ export class ResolversExplorerService extends BaseExplorerService {
transform: Function = identity,
) {
const paramsFactory = this.gqlParamsFactory;
const isPropertyResolver = ![
Resolvers.MUTATION,
Resolvers.QUERY,
Resolvers.SUBSCRIPTION,
].some(type => type === resolver.type);

const contextOptions = isPropertyResolver
? {
guards: false,
filters: false,
interceptors: false,
}
: undefined;

if (isRequestScoped) {
const resolverCallback = async (...args: any[]) => {
const gqlContext = paramsFactory.exchangeKeyForValue(
Expand Down Expand Up @@ -154,6 +168,7 @@ export class ResolversExplorerService extends BaseExplorerService {
paramsFactory,
contextId,
wrapper.id,
contextOptions,
);
return callback(...args);
};
Expand All @@ -165,6 +180,9 @@ export class ResolversExplorerService extends BaseExplorerService {
resolver.methodName,
PARAM_ARGS_METADATA,
paramsFactory,
undefined,
undefined,
contextOptions,
);
return resolverCallback;
}
Expand Down Expand Up @@ -199,6 +217,15 @@ export class ResolversExplorerService extends BaseExplorerService {
};
}

getAllCtors(): Function[] {
const modules = this.getModules(
this.modulesContainer,
this.gqlOptions.include || [],
);
const resolvers = this.flatMap(modules, instance => instance.metatype);
return resolvers;
}

private registerContextProvider<T = any>(request: T, contextId: ContextId) {
const coreModuleArray = [...this.modulesContainer.entries()]
.filter(
Expand Down
4 changes: 4 additions & 0 deletions lib/utils/async-iterator.util.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { $$asyncIterator } from 'iterall';

type AsyncIterator<T> = {
next(value?: any): Promise<IteratorResult<T>>;
};

export const createAsyncIterator = async <T = any>(
lazyFactory: Promise<AsyncIterator<T>>,
filterFn: Function,
Expand Down
Loading

0 comments on commit 775beca

Please sign in to comment.