Skip to content

Instantly share code, notes, and snippets.

@dimensi
Created November 29, 2018 11:27
Show Gist options
  • Select an option

  • Save dimensi/6fb03e39ae1b5d82ff736c034b556ae3 to your computer and use it in GitHub Desktop.

Select an option

Save dimensi/6fb03e39ae1b5d82ff736c034b556ae3 to your computer and use it in GitHub Desktop.
type-graphql BaseResolver
import camelCase from 'camelcase'
import { GraphQLResolveInfo } from 'graphql'
import pluralize from 'pluralize'
import {
Arg,
Authorized,
Ctx,
Info,
Int,
Mutation,
Query,
Resolver,
} from 'type-graphql'
import { Repository } from 'typeorm'
import { InjectRepository } from 'typeorm-typedi-extensions'
import { Permission, PermissionsObject } from '../auth'
import { Context } from '../helpers'
import { nullable } from '../utils'
import {
addToArgsRelations,
getRelationsForQuery,
setRelationsForMutation,
} from '../utils/relations'
export function createBaseResolver<
T extends object,
C extends object,
U extends object,
F extends object
> (
objectType: new () => T,
createInput: new () => C,
updateInput: new () => U,
findInput: new () => F,
permissions: PermissionsObject,
) {
@Resolver({ isAbstract: true })
abstract class BaseResolver {
@InjectRepository(objectType)
protected readonly repository: Repository<T>
@Authorized()
@Query(type => [objectType], {
name: camelCase(pluralize.plural(objectType.name)),
})
async getAll (
@Info() info: GraphQLResolveInfo,
@Arg('where', type => findInput, nullable()) where?: F,
): Promise<T[]> {
const relationsArr = getRelationsForQuery(info, this.repository)
return this.repository.find(addToArgsRelations(relationsArr, where))
}
@Authorized()
@Query(type => objectType, {
nullable: true,
name: camelCase(objectType.name),
})
async getOne (
@Info() info: GraphQLResolveInfo,
@Arg('id', type => Int, nullable()) id?: number,
@Arg('where', () => findInput, nullable()) where?: F,
): Promise<T> {
const relationsArr = getRelationsForQuery(info, this.repository)
console.log(relationsArr)
if (where) {
return this.repository.findOne(addToArgsRelations(relationsArr, where))
}
return this.repository.findOne(id, addToArgsRelations(relationsArr))
}
@Authorized()
@Permission(permissions.create)
@Mutation(returns => objectType, {
name: camelCase(['create', objectType.name]),
})
async create (
@Info() info: GraphQLResolveInfo,
@Arg('data', type => createInput) data: C,
): Promise<T> {
const relationsArr = getRelationsForQuery(info, this.repository)
await setRelationsForMutation(
this.repository,
data,
)
const { id }: any = this.repository.save(Object.assign(
new objectType(),
data,
) as any)
return this.repository.findOne(id, addToArgsRelations(relationsArr))
}
@Authorized()
@Permission(permissions.update)
@Mutation(returns => objectType, {
name: camelCase(['update', objectType.name]),
})
async update (
@Info() info: GraphQLResolveInfo,
@Arg('id', type => Int) id: number,
@Arg('data', type => updateInput) data: U,
): Promise<T> {
try {
const relationsArr = getRelationsForQuery(info, this.repository)
const entity = await this.repository.findOneOrFail(id)
await setRelationsForMutation(this.repository, data)
Object.assign(entity, data)
await this.repository.save(entity as any)
return this.repository.findOne(
id,
addToArgsRelations(relationsArr),
)
} catch (err) {
throw new Error('Not found')
}
}
@Authorized()
@Permission(permissions.delete)
@Mutation(returns => objectType, {
name: camelCase(['delete', objectType.name]),
...nullable(),
})
async delete (
@Info() info: GraphQLResolveInfo,
@Arg('id', type => Int) id: number,
): Promise<T> {
try {
const relationsArr = getRelationsForQuery(info, this.repository)
const entity = await this.repository.findOneOrFail(id, addToArgsRelations(relationsArr))
const removedEntity = await this.repository.remove(entity)
return Object.assign(removedEntity, { id })
} catch (err) {
throw new Error('Not found')
}
}
@Query(type => Boolean, {
name: camelCase(['can', 'create', objectType.name]),
})
canCreate (@Ctx() ctx: Context): boolean | Promise<boolean> {
return permissions.create({
context: ctx,
} as any)
}
@Query(type => Boolean, {
name: camelCase(['can', 'update', objectType.name]),
})
canUpdate (
@Arg('id', type => Int) id: number,
@Ctx() ctx: Context,
): boolean | Promise<boolean> {
return permissions.update({
context: ctx,
args: {
id,
},
} as any)
}
@Query(type => Boolean, {
name: camelCase(['can', 'delete', objectType.name]),
})
canDelete (
@Arg('id', type => Int) id: number,
@Ctx() ctx: Context,
): boolean | Promise<boolean> {
return permissions.delete({
context: ctx,
args: {
id,
},
} as any)
}
}
return BaseResolver
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment