Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/api/mutations/CreatePetMutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { PetType } from '../types/PetType';
import { PetService } from '../services/PetService';
import { GraphQLContext, Mutation } from '../../lib/graphql';
import { Pet } from '../models/Pet';
import { Logger, LoggerInterface } from '../../decorators/Logger';


interface CreatePetMutationArguments {
name: string;
Expand All @@ -24,9 +26,16 @@ export class CreatePetMutation extends AbstractGraphQLMutation<GraphQLContext<an
age: { type: new GraphQLNonNull(GraphQLInt) },
};

constructor(
private petService: PetService,
@Logger(__filename) private log: LoggerInterface
) {
super();
}

public async run(root: any, args: CreatePetMutationArguments, context: GraphQLContext<any, any>): Promise<Pet> {
const petService = context.container.get<PetService>(PetService);
const pet = await petService.create(plainToClass(Pet, args));
const pet = await this.petService.create(plainToClass(Pet, args));
this.log.info('Successfully created a new pet');
return pet;
}
}
12 changes: 9 additions & 3 deletions src/api/queries/GetPetsQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@ import { GraphQLFieldConfig, GraphQLList } from 'graphql';
import { Query, AbstractGraphQLQuery, GraphQLContext } from './../../lib/graphql';
import { PetService } from '../services/PetService';
import { PetType } from './../types/PetType';
import { Logger } from '../../core/Logger';
import { Pet } from '../models/Pet';
import { Logger, LoggerInterface } from '../../decorators/Logger';


@Query()
export class GetPetsQuery extends AbstractGraphQLQuery<GraphQLContext<any, any>, Pet[], any> implements GraphQLFieldConfig {
public type = new GraphQLList(PetType);
public allow = [];
public args = {};

private log = new Logger(__filename);
constructor(
private petService: PetService,
@Logger(__filename) private log: LoggerInterface
) {
super();
}

public async run(root: any, args: any, context: GraphQLContext<any, any>): Promise<Pet[]> {
const pets = await context.container.get<PetService>(PetService).find();
const pets = await this.petService.find();
this.log.info(`Found ${pets.length} pets`);
return pets;
}
Expand Down
12 changes: 9 additions & 3 deletions src/api/queries/GetUsersQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,24 @@ import { Query, AbstractGraphQLQuery, GraphQLContext } from './../../lib/graphql
import { UserService } from '../services/UserService';
import { UserType } from './../types/UserType';
import { User } from '../models/User';
import { Logger } from '../../core/Logger';
import { Logger, LoggerInterface } from '../../decorators/Logger';


@Query()
export class GetUsersQuery extends AbstractGraphQLQuery<GraphQLContext<any, any>, User[], any> implements GraphQLFieldConfig {
public type = new GraphQLList(UserType);
public allow = [];
public args = {};

private log = new Logger(__filename);
constructor(
private userService: UserService,
@Logger(__filename) private log: LoggerInterface
) {
super();
}

public async run(root: any, args: any, context: GraphQLContext<any, any>): Promise<User[]> {
const users = await context.container.get<UserService>(UserService).find();
const users = await this.userService.find();
this.log.info(`Found ${users.length} users`);
return users;
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/graphql/Mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { getMetadataArgsStorage } from './index';
export function Mutation(): any {
return (object: () => void) => {
getMetadataArgsStorage().mutations.push({
name: object.name,
target: object,
});
};
Expand Down
1 change: 1 addition & 0 deletions src/lib/graphql/MutationMetadataArgs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface MutationMetadataArgs {
name: string;
/**
* Indicates object which is used by this controller.
*/
Expand Down
1 change: 1 addition & 0 deletions src/lib/graphql/Query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { getMetadataArgsStorage } from './index';
export function Query(): any {
return (object: () => void) => {
getMetadataArgsStorage().queries.push({
name: object.name,
target: object,
});
};
Expand Down
1 change: 1 addition & 0 deletions src/lib/graphql/QueryMetadataArgs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface QueryMetadataArgs {
name: string;
/**
* Indicates object which is used by this controller.
*/
Expand Down
71 changes: 71 additions & 0 deletions src/lib/graphql/container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@

/**
* Container options.
*/
export interface UseContainerOptions {

/**
* If set to true, then default container will be used in the case if given container haven't returned anything.
*/
fallback?: boolean;

/**
* If set to true, then default container will be used in the case if given container thrown an exception.
*/
fallbackOnErrors?: boolean;

}

/**
* Container to be used by this library for inversion control. If container was not implicitly set then by default
* container simply creates a new instance of the given class.
*/
const defaultContainer: { get<T>(someClass: { new(...args: any[]): T } | (() => void)): T } = new (class {
private instances: Array<{ type: any, object: any }> = [];
public get<T>(someClass: { new(...args: any[]): T }): T {
let instance = this.instances.find(i => i.type === someClass);
if (!instance) {
instance = { type: someClass, object: new someClass() };
this.instances.push(instance);
}

return instance.object;
}
})();

let userContainer: { get<T>(someClass: { new(...args: any[]): T } | (() => void)): T };
let userContainerOptions: UseContainerOptions;

/**
* Sets container to be used by this library.
*/
export function useContainer(iocContainer: { get(someClass: any): any }, options?: UseContainerOptions): void {
userContainer = iocContainer;
if (options) {
userContainerOptions = options;
}
}

/**
* Gets the IOC container used by this library.
*/
export function getFromContainer<T>(someClass: { new(...args: any[]): T } | (() => void)): T {
if (userContainer) {
try {
const instance = userContainer.get(someClass);
if (instance) {
return instance;
}

if (!userContainerOptions || !userContainerOptions.fallback) {
return instance;
}

} catch (error) {
if (!userContainerOptions || !userContainerOptions.fallbackOnErrors) {
throw error;
}
}
}
return defaultContainer.get<T>(someClass);
}
12 changes: 7 additions & 5 deletions src/lib/graphql/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import * as GraphQLHTTP from 'express-graphql';
import * as DataLoader from 'dataloader';
import { GraphQLSchema, GraphQLObjectType } from 'graphql';
import { Container as container, ObjectType } from 'typedi';
import { Repository, getCustomRepository, getRepository } from 'typeorm';

import { GraphQLContext, GraphQLContextDataLoader } from './GraphQLContext';
import { MetadataArgsStorage } from './MetadataArgsStorage';
import { importClassesFromDirectories } from './importClassesFromDirectories';
import { handlingErrors, getErrorCode, getErrorMessage } from './graphql-error-handling';
import { ensureInputOrder } from './dataloader';
import { Repository, getCustomRepository, getRepository } from 'typeorm';
import { getFromContainer } from './container';

// -------------------------------------------------------------------------
// Main exports
Expand All @@ -22,6 +23,7 @@ export * from './AbstractGraphQLHooks';
export * from './AbstractGraphQLQuery';
export * from './GraphQLContext';
export * from './graphql-error-handling';
export * from './container';

// -------------------------------------------------------------------------
// Main Functions
Expand Down Expand Up @@ -168,8 +170,8 @@ export function createSchema(options: GraphQLSchemaOptions): GraphQLSchema {
}

const queries = {};
queryClasses.forEach(queryClass => {
queries[createQueryName(queryClass.name)] = new queryClass();
getMetadataArgsStorage().queries.forEach(queryMetdadata => {
queries[createQueryName(queryMetdadata.name)] = getFromContainer(queryMetdadata.target);
});

const RootQuery = new GraphQLObjectType({
Expand All @@ -186,8 +188,8 @@ export function createSchema(options: GraphQLSchemaOptions): GraphQLSchema {
}

const mutations = {};
mutationClasses.forEach(mutationClass => {
mutations[createMutationName(mutationClass.name)] = new mutationClass();
getMetadataArgsStorage().mutations.forEach(mutationMetdadata => {
mutations[createMutationName(mutationMetdadata.name)] = getFromContainer(mutationMetdadata.target);
});

const RootMutation: GraphQLObjectType = new GraphQLObjectType({
Expand Down
2 changes: 2 additions & 0 deletions src/loaders/iocLoader.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Container } from 'typedi';
import { useContainer as ormUseContainer } from 'typeorm';
import { useContainer as routingUseContainer } from 'routing-controllers';
import { useContainer as graphqlUseContainer } from '../lib/graphql';
import { MicroframeworkSettings, MicroframeworkLoader } from 'microframework-w3tec';


Expand All @@ -11,5 +12,6 @@ export const iocLoader: MicroframeworkLoader = (settings: MicroframeworkSettings
*/
routingUseContainer(Container);
ormUseContainer(Container);
graphqlUseContainer(Container);

};