From 56bbdc346d9745998171410e9ea6f24ed8f2a5cd Mon Sep 17 00:00:00 2001 From: Michael Beaumont Date: Tue, 28 Apr 2020 11:26:14 +0200 Subject: [PATCH 1/3] Add customization options to connection resolver --- src/resolvers/connection.d.ts | 11 ++++++++--- src/resolvers/connection.js | 31 ++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/resolvers/connection.d.ts b/src/resolvers/connection.d.ts index e1f96764..803e0e96 100644 --- a/src/resolvers/connection.d.ts +++ b/src/resolvers/connection.d.ts @@ -1,4 +1,4 @@ -import { Resolver, ObjectTypeComposer } from 'graphql-compose'; +import { Resolver, ObjectTypeComposer, ObjectTypeComposerFieldConfigMap } from 'graphql-compose'; // import { ConnectionSortMapOpts } from 'graphql-compose-connection'; import { Model } from 'mongoose'; import { MongoId } from '../types/mongoid'; @@ -7,12 +7,17 @@ import { FilterHelperArgs, SortHelperArgs } from './helpers'; // @ts-todo The ConnectionSortMapOpts is not available yet since graphql-compose-connection doesn't have types for now, // fallback to a simple object. -export type ConnectionSortMapOpts = { [opt: string]: any }; +export type ConnectionOpts = { [opt: string]: any } & { + connectionResolverName?: string, + findResolverName?: string; + countResolverName?: string; + edgeFields?: ObjectTypeComposerFieldConfigMap; +}; export default function connection( model: Model, tc: ObjectTypeComposer, - opts?: ConnectionSortMapOpts, + opts?: ConnectionOpts, ): Resolver | undefined; export function prepareCursorQuery( diff --git a/src/resolvers/connection.js b/src/resolvers/connection.js index 44027194..1143612f 100644 --- a/src/resolvers/connection.js +++ b/src/resolvers/connection.js @@ -3,19 +3,28 @@ import type { MongooseDocument } from 'mongoose'; import type { ConnectionSortMapOpts as _ConnectionSortMapOpts } from 'graphql-compose-connection'; -import type { Resolver, ObjectTypeComposer } from 'graphql-compose'; +import type { + Resolver, + ObjectTypeComposer, + ObjectTypeComposerFieldConfigMap, +} from 'graphql-compose'; import { getUniqueIndexes, extendByReversedIndexes, type IndexT, } from '../utils/getIndexesFromModel'; -export type ConnectionSortMapOpts = _ConnectionSortMapOpts; +export type ConnectionOpts = _ConnectionSortMapOpts & { + edgeFields?: ObjectTypeComposerFieldConfigMap, + connectionResolverName?: string, + findResolverName?: string, + countResolverName?: string, +}; export default function connection( model: Class, // === MongooseModel tc: ObjectTypeComposer, - opts?: ConnectionSortMapOpts + opts: ConnectionOpts = {} ): ?Resolver { try { require.resolve('graphql-compose-connection'); @@ -56,14 +65,22 @@ export default function connection( }, }; }); - + const { + connectionResolverName = 'connection', + findResolverName = 'findMany', + countResolverName = 'count', + edgeFields, + ...sortOptions + } = opts; return prepareConnectionResolver(tc, { - findResolverName: 'findMany', - countResolverName: 'count', + connectionResolverName, + findResolverName, + countResolverName, sort: { ...sortConfigs, - ...opts, + ...sortOptions, }, + edgeFields, }); } From c5bbbb2b497c7ac43bb8cd50c13c324f623c008f Mon Sep 17 00:00:00 2001 From: PeteMac88 Date: Tue, 12 May 2020 18:01:43 +0200 Subject: [PATCH 2/3] fix: flow type checking --- src/composeWithMongoose.d.ts | 4 ++-- src/composeWithMongoose.js | 4 ++-- src/resolvers/connection.d.ts | 2 +- src/resolvers/connection.js | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/composeWithMongoose.d.ts b/src/composeWithMongoose.d.ts index b82f88f0..cd222e8c 100644 --- a/src/composeWithMongoose.d.ts +++ b/src/composeWithMongoose.d.ts @@ -4,7 +4,7 @@ import { ObjectTypeComposer, } from 'graphql-compose'; import { Document, Model } from 'mongoose'; -import { ConnectionSortMapOpts } from './resolvers/connection'; +import { ConnectionOpts } from './resolvers/connection'; import { FilterHelperArgsOpts, LimitHelperArgsOpts, @@ -107,7 +107,7 @@ export type TypeConverterResolversOpts = { | { filter?: FilterHelperArgsOpts | false; }; - connection?: ConnectionSortMapOpts | false; + connection?: ConnectionOpts | false; pagination?: PaginationResolverOpts | false; }; diff --git a/src/composeWithMongoose.js b/src/composeWithMongoose.js index 461cb947..8538bb02 100644 --- a/src/composeWithMongoose.js +++ b/src/composeWithMongoose.js @@ -14,7 +14,7 @@ import type { } from './resolvers/helpers'; import MongoID from './types/mongoid'; import type { PaginationResolverOpts } from './resolvers/pagination'; -import type { ConnectionSortMapOpts } from './resolvers/connection'; +import type { ConnectionOpts } from './resolvers/connection'; export type ComposeWithMongooseOpts = {| schemaComposer?: SchemaComposer, @@ -111,7 +111,7 @@ export type TypeConverterResolversOpts = { | { filter?: FilterHelperArgsOpts | false, }, - connection?: ConnectionSortMapOpts | false, + connection?: ConnectionOpts | false, pagination?: PaginationResolverOpts | false, }; diff --git a/src/resolvers/connection.d.ts b/src/resolvers/connection.d.ts index 803e0e96..e7c23e8d 100644 --- a/src/resolvers/connection.d.ts +++ b/src/resolvers/connection.d.ts @@ -7,7 +7,7 @@ import { FilterHelperArgs, SortHelperArgs } from './helpers'; // @ts-todo The ConnectionSortMapOpts is not available yet since graphql-compose-connection doesn't have types for now, // fallback to a simple object. -export type ConnectionOpts = { [opt: string]: any } & { +export type ConnectionOpts = { [opt: string]: any } & { connectionResolverName?: string, findResolverName?: string; countResolverName?: string; diff --git a/src/resolvers/connection.js b/src/resolvers/connection.js index 1143612f..42b65645 100644 --- a/src/resolvers/connection.js +++ b/src/resolvers/connection.js @@ -14,7 +14,7 @@ import { type IndexT, } from '../utils/getIndexesFromModel'; -export type ConnectionOpts = _ConnectionSortMapOpts & { +export type ConnectionOpts = _ConnectionSortMapOpts & { edgeFields?: ObjectTypeComposerFieldConfigMap, connectionResolverName?: string, findResolverName?: string, @@ -24,7 +24,7 @@ export type ConnectionOpts = _ConnectionSortMapOpts & { export default function connection( model: Class, // === MongooseModel tc: ObjectTypeComposer, - opts: ConnectionOpts = {} + opts?: ConnectionOpts ): ?Resolver { try { require.resolve('graphql-compose-connection'); @@ -71,7 +71,7 @@ export default function connection( countResolverName = 'count', edgeFields, ...sortOptions - } = opts; + } = opts || {}; return prepareConnectionResolver(tc, { connectionResolverName, findResolverName, From 614f44eda31b8801f480aaeb4e40b5aa7dc0a4c6 Mon Sep 17 00:00:00 2001 From: PeteMac88 Date: Tue, 12 May 2020 18:55:37 +0200 Subject: [PATCH 3/3] chore: add tests --- src/resolvers/__tests__/connection-test.js | 48 ++++++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/src/resolvers/__tests__/connection-test.js b/src/resolvers/__tests__/connection-test.js index d5daa37b..c1f308f9 100644 --- a/src/resolvers/__tests__/connection-test.js +++ b/src/resolvers/__tests__/connection-test.js @@ -140,26 +140,38 @@ describe('connection() resolver', () => { await user2.save(); }); - it('should return Resolver object', () => { + it('should return Resolver object with default name', () => { const resolver = connection(UserModel, UserTC); + if (!resolver) throw new Error('Connection resolver is undefined'); expect(resolver).toBeInstanceOf(Resolver); + expect(resolver.getNestedName()).toEqual('connection'); + }); + + it('should return Resolver object with custom name', () => { + const resolver = connection(UserModel, UserTC, { + // $FlowFixMe + connectionResolverName: 'customConnection', + }); + if (!resolver) throw new Error('Connection resolver is undefined'); + expect(resolver).toBeInstanceOf(Resolver); + expect(resolver.getNestedName()).toEqual('customConnection'); }); it('Resolver object should have `filter` arg', () => { const resolver = connection(UserModel, UserTC); - if (!resolver) throw new Error('Connection resolveris undefined'); + if (!resolver) throw new Error('Connection resolver is undefined'); expect(resolver.hasArg('filter')).toBe(true); }); it('Resolver object should have `sort` arg', () => { const resolver = connection(UserModel, UserTC); - if (!resolver) throw new Error('Connection resolveris undefined'); + if (!resolver) throw new Error('Connection resolver is undefined'); expect(resolver.hasArg('sort')).toBe(true); }); it('Resolver object should have `connection args', () => { const resolver = connection(UserModel, UserTC); - if (!resolver) throw new Error('Connection resolveris undefined'); + if (!resolver) throw new Error('Connection resolver is undefined'); expect(resolver.hasArg('first')).toBe(true); expect(resolver.hasArg('last')).toBe(true); expect(resolver.hasArg('before')).toBe(true); @@ -169,14 +181,14 @@ describe('connection() resolver', () => { describe('Resolver.resolve():Promise', () => { it('should be fulfilled Promise', async () => { const resolver = connection(UserModel, UserTC); - if (!resolver) throw new Error('Connection resolveris undefined'); + if (!resolver) throw new Error('Connection resolver is undefined'); const result = resolver.resolve({ args: { first: 20 } }); await expect(result).resolves.toBeDefined(); }); it('should return array of documents in `edges`', async () => { const resolver = connection(UserModel, UserTC); - if (!resolver) throw new Error('Connection resolveris undefined'); + if (!resolver) throw new Error('Connection resolver is undefined'); const result = await resolver.resolve({ args: { first: 20 } }); expect(result.edges).toBeInstanceOf(Array); @@ -188,7 +200,7 @@ describe('connection() resolver', () => { it('should limit records', async () => { const resolver = connection(UserModel, UserTC); - if (!resolver) throw new Error('Connection resolveris undefined'); + if (!resolver) throw new Error('Connection resolver is undefined'); const result = await resolver.resolve({ args: { first: 1 } }); expect(result.edges).toBeInstanceOf(Array); @@ -197,7 +209,7 @@ describe('connection() resolver', () => { it('should sort records', async () => { const resolver = connection(UserModel, UserTC); - if (!resolver) throw new Error('Connection resolveris undefined'); + if (!resolver) throw new Error('Connection resolver is undefined'); const result1 = await resolver.resolve({ args: { sort: { _id: 1 }, first: 1 }, @@ -212,7 +224,7 @@ describe('connection() resolver', () => { it('should return mongoose documents', async () => { const resolver = connection(UserModel, UserTC); - if (!resolver) throw new Error('Connection resolveris undefined'); + if (!resolver) throw new Error('Connection resolver is undefined'); const result = await resolver.resolve({ args: { first: 20 } }); expect(result.edges[0].node).toBeInstanceOf(UserModel); @@ -275,6 +287,24 @@ describe('connection() resolver', () => { expect(result).toHaveProperty('edges.0.node', { overrides: true }); }); + + it('should return mongoose documents for custom resolvers from opts', async () => { + schemaComposer.clear(); + UserTC = convertModelToGraphQL(UserModel, 'User', schemaComposer); + UserTC.setResolver('customFindMany', findMany(UserModel, UserTC)); + UserTC.setResolver('customCount', count(UserModel, UserTC)); + const resolver = connection(UserModel, UserTC, { + // $FlowFixMe + findResolverName: 'customFindMany', + // $FlowFixMe + countResolverName: 'customCount', + }); + if (!resolver) throw new Error('Connection resolver is undefined'); + + const result = await resolver.resolve({ args: { first: 20 } }); + expect(result.edges[0].node).toBeInstanceOf(UserModel); + expect(result.edges[1].node).toBeInstanceOf(UserModel); + }); }); }); });