/* tslint:disable no-unused-variable */ // Define GraphQL resolvers using Feathers services and BatchLoaders. (Can be re-generated.) import { App } from '../../app.interface'; import { Paginated, Params } from '@feathersjs/feathers'; import { getByDot, setByDot } from 'feathers-hooks-common'; import { GraphQLFieldResolver } from 'graphql'; import { GraphQLResolveInfo } from 'graphql/type/definition'; import { ArgMap, ResolverContext, ResolverMap } from './graphql.interfaces'; export interface BatchloaderResolverOptions { convertArgsToParams: any; convertArgsToFeathers: (args: any[]) => (...args: any[]) => Params; extractAllItems: any; extractFirstItem: any; feathersBatchLoader: { feathersBatchLoader: any, }; } // !code: imports // !end // !code: init // !end let moduleExports = function batchLoaderResolvers(app: App, options: BatchloaderResolverOptions ) { // tslint:disable-next-line let { convertArgsToParams, convertArgsToFeathers, extractAllItems, extractFirstItem, feathersBatchLoader: { feathersBatchLoader } } = options; // ! code: max-batch-size let defaultPaginate = app.get('paginate'); let maxBatchSize = defaultPaginate && typeof defaultPaginate.max === 'number' ? defaultPaginate.max : undefined; // !end // ! code: extra_auth_props const convertArgs = convertArgsToFeathers([]); // !end // ! code: services let roles = app.service('/roles'); let teams = app.service('/teams'); let users = app.service('/users'); // !end // ! code: get-result // Given a fieldName in the parent record, return the result from a BatchLoader // The result will be an object (or null), or an array of objects (possibly empty). function getResult( batchLoaderName: string, fieldName: string, isArray?: boolean ): GraphQLFieldResolver { const contentByDot = `batchLoaders.${batchLoaderName}`; // `content.app = app` is the Feathers app object. // `content.batchLoaders = {}` is where the BatchLoaders for a request are stored. return (parent: any, args: ArgMap, content: ResolverContext, ast: GraphQLResolveInfo) => { let batchLoader = getByDot(content, contentByDot); if (!batchLoader) { batchLoader = getBatchLoader(batchLoaderName, parent, args, content, ast); setByDot(content, contentByDot, batchLoader); } const returns1 = batchLoader.load(parent[fieldName]); return !isArray ? returns1 : returns1.then((result: any) => result || []); }; } // !end // A transient BatchLoader can be created only when (one of) its resolver has been called, // as the BatchLoader loading function may require data from the 'args' passed to the resolver. // Note that each resolver's 'args' are static throughout a GraphQL call. function getBatchLoader( dataLoaderName: string, parent: any, args: ArgMap, content: ResolverContext, ast: GraphQLResolveInfo ): ResolverMap { let feathersParams; switch (dataLoaderName) { /* Persistent BatchLoaders. Stored in `content.batchLoaders._persisted`. */ // ! code: bl-persisted // case '_persisted.user.one.id': // service user, returns one object, key is field id // !end /* Transient BatchLoaders shared among resolvers. Stored in `content.batchLoaders._shared`. */ // ! code: bl-shared // *.*: User // case '_shared.user.one.id': // service user, returns one object, key is field id // !end /* Transient BatchLoaders used by only one resolver. Stored in `content.batchLoaders`. */ // Role.users: [User!] // ! code: bl-Role-users case 'Role.users': return feathersBatchLoader(dataLoaderName, '[!]', 'roleId', (keys: string[]) => { feathersParams = convertArgs(args, content, null, { query: { roleId: { $in: keys }, $sort: undefined }, _populate: 'skip', paginate: false }); return users.find(feathersParams); }, maxBatchSize // Max #keys in a BatchLoader func call. ); // !end // Team.members: [User!] // ! code: bl-Team-members case 'Team.members': return feathersBatchLoader(dataLoaderName, '[!]', '_id', (keys: string[]) => { feathersParams = convertArgs(args, content, null, { query: { _id: { $in: keys }, $sort: undefined }, _populate: 'skip', paginate: false }); return users.find(feathersParams); }, maxBatchSize // Max #keys in a BatchLoader func call. ); // !end // User.role(query: JSON, params: JSON, key: JSON): Role // ! code: bl-User-role case 'User.role': return feathersBatchLoader(dataLoaderName, '', '_id', (keys: string[]) => { feathersParams = convertArgs(args, content, null, { query: { _id: { $in: keys }, $sort: undefined }, _populate: 'skip', paginate: false }); return roles.find(feathersParams); }, maxBatchSize // Max #keys in a BatchLoader func call. ); // !end // User.teams(query: JSON, params: JSON, key: JSON): [Team!] // ! code: bl-User-teams case 'User.teams': return feathersBatchLoader(dataLoaderName, '[!]', 'memberIds', (keys: string[]) => { feathersParams = convertArgs(args, content, null, { query: { memberIds: { $in: keys }, $sort: undefined }, _populate: 'skip', paginate: false }); return teams.find(feathersParams); }, maxBatchSize // Max #keys in a BatchLoader func call. ); // !end /* Throw on unknown BatchLoader name. */ default: // ! code: bl-default throw new Error(`GraphQL query requires BatchLoader named '${dataLoaderName}' but no definition exists for it.`); // !end } } let returns: ResolverMap = { Role: { // users: [User!] // ! code: resolver-Role-users users: getResult('Role.users', '_id', true), // !end }, Team: { // members: [User!] // ! code: resolver-Team-members members: getResult('Team.members', 'memberIds', true), // !end }, User: { // fullName: String! // ! code: resolver-User-fullName-non fullName: (parent, args, content, ast) => { throw Error('GraphQL fieldName User.fullName is not calculated.'); }, // !end // role(query: JSON, params: JSON, key: JSON): Role // ! code: resolver-User-role role: getResult('User.role', 'roleId'), // !end // teams(query: JSON, params: JSON, key: JSON): [Team!] // ! code: resolver-User-teams teams: getResult('User.teams', '_id', true), // !end }, // !code: resolver_field_more // !end Query: { // ! code: query-Role // getRole(query: JSON, params: JSON, key: JSON): Role getRole(parent, args, content, ast) { const feathersParams = convertArgs(args, content, ast); return roles.get(args.key, feathersParams).then(extractFirstItem); }, // findRole(query: JSON, params: JSON): [Role!] findRole(parent, args, content, ast) { const feathersParams = convertArgs(args, content, ast, { query: { $sort: { name: 1 } } }); return roles.find(feathersParams).then(paginate(content)).then(extractAllItems); }, // !end // ! code: query-Team // getTeam(query: JSON, params: JSON, key: JSON): Team getTeam(parent, args, content, ast) { const feathersParams = convertArgs(args, content, ast); return teams.get(args.key, feathersParams).then(extractFirstItem); }, // findTeam(query: JSON, params: JSON): [Team!] findTeam(parent, args, content, ast) { const feathersParams = convertArgs(args, content, ast, { query: { $sort: { name: 1 } } }); return teams.find(feathersParams).then(paginate(content)).then(extractAllItems); }, // !end // ! code: query-User // getUser(query: JSON, params: JSON, key: JSON): User getUser(parent, args, content, ast) { const feathersParams = convertArgs(args, content, ast); return users.get(args.key, feathersParams).then(extractFirstItem); }, // findUser(query: JSON, params: JSON): [User!] findUser(parent, args, content, ast) { const feathersParams = convertArgs(args, content, ast, { query: { $sort: { lastName: 1, firstName: 1 } } }); return users.find(feathersParams).then(paginate(content)).then(extractAllItems); }, // !end // !code: resolver_query_more // !end }, }; // !code: func_return // !end return returns; }; // !code: more // !end // !code: exports // !end export default moduleExports; function paginate(content: any) { return (result: any[] | Paginated) => { content.pagination = !isPaginated(result) ? undefined : { total: result.total, limit: result.limit, skip: result.skip, }; return result; }; } function isPaginated(it: T[] | Paginated): it is Paginated { return !!(it as any).data; } // !code: funcs // !end // !code: end // !end