Skip to content

Commit 14d82de

Browse files
committed
Change eDTC to extend InterfaceTypeComposer and fix various resulting type errors
1 parent 5c8bde5 commit 14d82de

30 files changed

+191
-187
lines changed

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
"typescript.format.enable": false,
77
"editor.codeActionsOnSave": {
88
"source.fixAll.eslint": true
9-
},
9+
}
1010
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"eslint-plugin-import": "2.23.4",
4343
"eslint-plugin-prettier": "3.4.0",
4444
"graphql": "15.5.1",
45-
"graphql-compose": "9.0.1",
45+
"graphql-compose": "9.0.2",
4646
"jest": "27.0.6",
4747
"mongodb-memory-server": "7.3.2",
4848
"mongoose": "5.13.3",

src/__tests__/github_issues/260-test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { schemaComposer, graphql } from 'graphql-compose';
1+
import { schemaComposer, graphql, ObjectTypeComposer } from 'graphql-compose';
22
import { composeMongoose } from '../../index';
33
import { mongoose } from '../../__mocks__/mongooseCommon';
44
import { Document } from 'mongoose';
@@ -28,6 +28,10 @@ const PostModel = mongoose.model<IPost>('Post', PostSchema);
2828
const UserTC = composeMongoose(UserModel);
2929
const PostTC = composeMongoose(PostModel);
3030

31+
if (!(UserTC instanceof ObjectTypeComposer) || !(PostTC instanceof ObjectTypeComposer)) {
32+
throw new Error('TCs should return ObjectTypeComposers');
33+
}
34+
3135
PostTC.addRelation('author', {
3236
resolver: UserTC.mongooseResolvers.dataLoader({
3337
lean: true, // <---- `Lean` loads record from DB without support of mongoose getters & virtuals

src/__tests__/github_issues/263-test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { schemaComposer, graphql } from 'graphql-compose';
1+
import { schemaComposer, graphql, ObjectTypeComposer } from 'graphql-compose';
22
import { composeMongoose } from '../../index';
33
import { mongoose } from '../../__mocks__/mongooseCommon';
44

@@ -28,6 +28,10 @@ const PostModel = mongoose.model<IPost>('Post', PostSchema);
2828
const UserTC = composeMongoose(UserModel);
2929
const PostTC = composeMongoose(PostModel);
3030

31+
if (!(UserTC instanceof ObjectTypeComposer) || !(PostTC instanceof ObjectTypeComposer)) {
32+
throw new Error('TCs should return ObjectTypeComposers');
33+
}
34+
3135
PostTC.addRelation('author', {
3236
resolver: UserTC.mongooseResolvers.dataLoader({ lean: true }),
3337
prepareArgs: {

src/composeMongoose.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import type { SchemaComposer, Resolver, InputTypeComposer } from 'graphql-compose';
1+
import type {
2+
SchemaComposer,
3+
Resolver,
4+
InputTypeComposer,
5+
InterfaceTypeComposer,
6+
} from 'graphql-compose';
27
import { schemaComposer as globalSchemaComposer, ObjectTypeComposer } from 'graphql-compose';
38
import type { Model, Document } from 'mongoose';
49
import { EDiscriminatorTypeComposer } from './enhancedDiscriminators';
@@ -162,7 +167,7 @@ export function composeMongoose<TDoc extends Document, TContext = any>(
162167
}
163168

164169
function makeFieldsNonNullWithDefaultValues(
165-
tc: ObjectTypeComposer,
170+
tc: ObjectTypeComposer | InterfaceTypeComposer,
166171
alreadyWorked = new Set()
167172
): void {
168173
if (alreadyWorked.has(tc)) return;
@@ -198,7 +203,7 @@ function makeFieldsNonNullWithDefaultValues(
198203
}
199204

200205
export function prepareFields(
201-
tc: ObjectTypeComposer<any, any>,
206+
tc: ObjectTypeComposer<any, any> | InterfaceTypeComposer<any, any>,
202207
opts: ComposeMongooseOpts<any> = {}
203208
): void {
204209
const onlyFields = opts?.onlyFields || opts?.fields?.only;
@@ -212,7 +217,7 @@ export function prepareFields(
212217
}
213218

214219
export function createInputType(
215-
tc: ObjectTypeComposer<any, any>,
220+
tc: ObjectTypeComposer<any, any> | InterfaceTypeComposer<any, any>,
216221
inputTypeOpts: TypeConverterInputTypeOpts = {}
217222
): void {
218223
const inputTypeComposer = tc.getInputTypeComposer();

src/composeWithMongoose.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable no-use-before-define, no-param-reassign, global-require */
22

3-
import type { ObjectTypeComposer, SchemaComposer } from 'graphql-compose';
4-
import { schemaComposer as globalSchemaComposer } from 'graphql-compose';
3+
import type { SchemaComposer } from 'graphql-compose';
4+
import { ObjectTypeComposer, schemaComposer as globalSchemaComposer } from 'graphql-compose';
55
import type { Model, Document } from 'mongoose';
66
import { convertModelToGraphQL } from './fieldsConverter';
77
import { resolverFactory, AllResolversOpts } from './resolvers';
@@ -53,6 +53,13 @@ export function composeWithMongoose<TDoc extends Document, TContext = any>(
5353

5454
const tc = convertModelToGraphQL(m, name, sc);
5555

56+
if (!(tc instanceof ObjectTypeComposer)) {
57+
// should be impossible I hope
58+
throw new Error(
59+
'composeWithMongoose does not support discriminator mode, use composeMongoose or composeWithMongooseDiscriminators instead'
60+
);
61+
}
62+
5663
if (opts.description) {
5764
tc.setDescription(opts.description);
5865
}

src/enhancedDiscriminators/__tests__/eDiscriminatorTypeComposer-test.ts

Lines changed: 50 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -30,34 +30,32 @@ const composeMongoose = <TDoc extends Document, TContext = any>(
3030
return generatedTC;
3131
};
3232

33-
let baseDTC: EDiscriminatorTypeComposer<any, any>;
34-
let DInterface: InterfaceTypeComposer<any, any>;
33+
let eDTC: EDiscriminatorTypeComposer<any, any>;
3534
let DInputObject: ObjectTypeComposer<any, any>;
3635

3736
beforeEach(() => {
38-
baseDTC = composeMongoose(CharacterModel);
39-
DInterface = schemaComposer.getIFTC(baseDTC.getTypeName());
40-
DInputObject = baseDTC.getDInputObject();
37+
eDTC = composeMongoose(CharacterModel);
38+
DInputObject = eDTC.getDInputObject();
4139
});
4240

4341
afterEach(() => {
44-
baseDTC.schemaComposer.clear();
42+
eDTC.schemaComposer.clear();
4543
});
4644

4745
describe('EDiscriminatorTypeComposer', () => {
48-
it('has an interface object DInterface as the type name', () => {
49-
expect(baseDTC.getDInterface()).toEqual(schemaComposer.getAnyTC(baseDTC.getTypeName()));
50-
});
51-
5246
it('throws an error when default (__t) discriminator key is set', () => {
53-
baseDTC.schemaComposer.clear();
47+
eDTC.schemaComposer.clear();
5448
const { CharacterModel: noDKeyModel } = getCharacterModels(undefined, 'noDKeyCharacter');
5549
const errorCall = () => composeMongoose(noDKeyModel);
5650
expect(errorCall).toThrowError(
5751
'A custom discriminator key must be set on the model options in mongoose for discriminator behaviour to function correctly'
5852
);
5953
});
6054

55+
it('should have type resolvers for discriminated models', () => {
56+
expect(eDTC.getTypeResolverNames()).toHaveLength(2);
57+
});
58+
6159
it('should not be used on models without discriminators', () => {
6260
const { DroidModel } = getCharacterModels(undefined, 'noDiscrim');
6361
const noDiscrim = composeMongooseRaw(DroidModel, dComposeOpts);
@@ -66,15 +64,11 @@ describe('EDiscriminatorTypeComposer', () => {
6664

6765
describe('Custom Getters', () => {
6866
test('getting discriminator key', () => {
69-
expect(baseDTC.getDKey()).toEqual(defaultDKey);
70-
});
71-
72-
test('getting discriminator interface', () => {
73-
expect(baseDTC.getDInterface()).toBe(DInterface);
67+
expect(eDTC.getDKey()).toEqual(defaultDKey);
7468
});
7569

7670
test('getting discriminator input object TC', () => {
77-
expect(baseDTC.getDInputObject()).toBe(DInputObject);
71+
expect(eDTC.getDInputObject()).toBe(DInputObject);
7872
});
7973
});
8074

@@ -102,35 +96,33 @@ describe('EDiscriminatorTypeComposer', () => {
10296
});
10397
});
10498

105-
describe('DInterface', () => {
99+
describe('eDTC', () => {
106100
it('shares field names with base model used to compose it', () => {
107-
expect(DInterface.getFieldNames()).toEqual(
101+
expect(eDTC.getFieldNames()).toEqual(
108102
expect.arrayContaining(
109103
Object.keys(CharacterModel.schema.paths).filter((x) => !x.startsWith('__'))
110104
)
111105
);
112106
});
113107

114108
it('should be an instance of InterfaceTypeComposer', () => {
115-
expect(DInterface instanceof InterfaceTypeComposer).toBeTruthy();
109+
expect(eDTC instanceof InterfaceTypeComposer).toBeTruthy();
116110
});
117111

118112
it('should have the input TC from DInputObject as input TC', () => {
119-
expect(DInterface.getInputTypeComposer()).toEqual(
120-
baseDTC.getDInputObject().getInputTypeComposer()
121-
);
113+
expect(eDTC.getInputTypeComposer()).toEqual(eDTC.getDInputObject().getInputTypeComposer());
122114
});
123115
});
124116

125117
describe('Get Discriminator TCs', () => {
126118
it('returns discrimTCs with mongooseResolvers present', () => {
127-
Object.values(baseDTC.getDiscriminatorTCs()).forEach((discimTC) => {
119+
Object.values(eDTC.getDiscriminatorTCs()).forEach((discimTC) => {
128120
expect(discimTC).toHaveProperty('mongooseResolvers');
129121
});
130122
});
131123
it('returns empty object with mongooseResolvers missing', () => {
132-
(baseDTC.discrimTCs[Object.keys(baseDTC.discrimTCs)[0]] as any).mongooseResolvers = undefined;
133-
Object.values(baseDTC.getDiscriminatorTCs()).forEach((discimTC) => {
124+
(eDTC.discrimTCs[Object.keys(eDTC.discrimTCs)[0]] as any).mongooseResolvers = undefined;
125+
Object.values(eDTC.getDiscriminatorTCs()).forEach((discimTC) => {
134126
expect(discimTC).toHaveProperty('mongooseResolvers');
135127
});
136128
});
@@ -139,71 +131,63 @@ describe('EDiscriminatorTypeComposer', () => {
139131
describe('Overridden eDTC Class Methods', () => {
140132
describe('Set Field', () => {
141133
it('updates field on all child TCs', () => {
142-
baseDTC.setField('newField', 'String');
143-
expect(baseDTC.hasField('newField')).toBeTruthy();
144-
expect(DInterface.hasField('newField')).toBeTruthy();
134+
eDTC.setField('newField', 'String');
135+
expect(eDTC.hasField('newField')).toBeTruthy();
145136
expect(DInputObject.hasField('newField')).toBeTruthy();
146-
Object.values(baseDTC.discrimTCs).forEach((dTC) => {
137+
Object.values(eDTC.discrimTCs).forEach((dTC) => {
147138
expect(dTC.hasField('newField')).toBeTruthy();
148139
});
149140
});
150141

151142
it('updates input TC when field is added', () => {
152-
baseDTC.setField('inputField', 'String');
153-
expect(schemaComposer.getIFTC(baseDTC.getTypeName()).getInputTypeComposer()).toEqual(
143+
eDTC.setField('inputField', 'String');
144+
expect(schemaComposer.getIFTC(eDTC.getTypeName()).getInputTypeComposer()).toEqual(
154145
DInputObject.getInputTypeComposer()
155146
);
156147
});
157148
});
158149

159150
describe('Set Extensions', () => {
160151
it('updates field on all child TCs', () => {
161-
baseDTC.setExtensions({ newField: 'testExtension' });
162-
expect(baseDTC.hasExtension('newField')).toBeTruthy();
163-
expect(DInterface.hasExtension('newField')).toBeTruthy();
152+
eDTC.setExtensions({ newField: 'testExtension' });
153+
expect(eDTC.hasExtension('newField')).toBeTruthy();
164154
expect(DInputObject.hasExtension('newField')).toBeTruthy();
165-
Object.values(baseDTC.discrimTCs).forEach((dTC) => {
155+
Object.values(eDTC.discrimTCs).forEach((dTC) => {
166156
expect(dTC.hasExtension('newField')).toBeTruthy();
167157
});
168158
});
169159
});
170160

171161
describe('Remove Field', () => {
172162
it('deletes field on all child TCs', () => {
173-
baseDTC.addFields({ toDelete: 'String' });
163+
eDTC.addFields({ toDelete: 'String' });
174164
// check field added
175-
expect(baseDTC.hasField('toDelete')).toBeTruthy();
176-
expect(DInterface.hasField('toDelete')).toBeTruthy();
165+
expect(eDTC.hasField('toDelete')).toBeTruthy();
177166
expect(DInputObject.hasField('toDelete')).toBeTruthy();
178-
Object.values(baseDTC.discrimTCs).forEach((dTC) => {
167+
Object.values(eDTC.discrimTCs).forEach((dTC) => {
179168
expect(dTC.hasField('toDelete')).toBeTruthy();
180169
});
181170

182-
baseDTC.removeField('toDelete');
183-
expect(baseDTC.hasField('toDelete')).toBeFalsy();
184-
expect(DInterface.hasField('toDelete')).toBeFalsy();
171+
eDTC.removeField('toDelete');
172+
expect(eDTC.hasField('toDelete')).toBeFalsy();
185173
expect(DInputObject.hasField('toDelete')).toBeFalsy();
186-
Object.values(baseDTC.discrimTCs).forEach((dTC) => {
174+
Object.values(eDTC.discrimTCs).forEach((dTC) => {
187175
expect(dTC.hasField('toDelete')).toBeFalsy();
188176
});
189177
});
190178
});
191179

192180
describe('Remove Other Fields', () => {
193181
it('removes all other fields from base TC from all child TCs', () => {
194-
baseDTC.addFields({ toKeep: 'String' });
182+
eDTC.addFields({ toKeep: 'String' });
195183

196-
const otherFields = baseDTC
197-
.getDInterface()
198-
.getFieldNames()
199-
.filter((field) => field !== 'toKeep');
200-
baseDTC.removeOtherFields('toKeep');
184+
const otherFields = eDTC.getFieldNames().filter((field) => field !== 'toKeep');
185+
eDTC.removeOtherFields('toKeep');
201186

202187
otherFields.forEach((removedField) => {
203-
expect(baseDTC.hasField(removedField)).toBeFalsy();
204-
expect(DInterface.hasField(removedField)).toBeFalsy();
188+
expect(eDTC.hasField(removedField)).toBeFalsy();
205189
expect(DInputObject.hasField(removedField)).toBeFalsy();
206-
Object.values(baseDTC.discrimTCs).forEach((dTC) => {
190+
Object.values(eDTC.discrimTCs).forEach((dTC) => {
207191
expect(dTC.hasField(removedField)).toBeFalsy();
208192
});
209193
});
@@ -215,42 +199,39 @@ describe('EDiscriminatorTypeComposer', () => {
215199
const fieldOrder = ['_id', 'appearsIn', 'friends', 'kind', 'type'];
216200
const fieldOrderString = fieldOrder.join('');
217201

218-
baseDTC.reorderFields(fieldOrder);
202+
eDTC.reorderFields(fieldOrder);
219203

220-
expect(baseDTC.getFieldNames().join('').startsWith(fieldOrderString)).toBeTruthy();
221-
expect(DInterface.getFieldNames().join('').startsWith(fieldOrderString)).toBeTruthy();
204+
expect(eDTC.getFieldNames().join('').startsWith(fieldOrderString)).toBeTruthy();
222205
expect(DInputObject.getFieldNames().join('').startsWith(fieldOrderString)).toBeTruthy();
223-
Object.values(baseDTC.discrimTCs).forEach((dTC) => {
206+
Object.values(eDTC.discrimTCs).forEach((dTC) => {
224207
expect(dTC.getFieldNames().join('').startsWith(fieldOrderString)).toBeTruthy();
225208
});
226209
});
227210
});
228211

229212
describe('Make Fields Nullable/Non-null', () => {
230213
it('makes a nullable field non-null', () => {
231-
baseDTC.addFields({ initialNullable: 'String' });
232-
expect(baseDTC.isFieldNonNull('initialNullable')).toBeFalsy();
214+
eDTC.addFields({ initialNullable: 'String' });
215+
expect(eDTC.isFieldNonNull('initialNullable')).toBeFalsy();
233216

234-
baseDTC.makeFieldNonNull('initialNullable');
217+
eDTC.makeFieldNonNull('initialNullable');
235218

236-
expect(baseDTC.isFieldNonNull('initialNullable')).toBeTruthy();
237-
expect(DInterface.isFieldNonNull('initialNullable')).toBeTruthy();
219+
expect(eDTC.isFieldNonNull('initialNullable')).toBeTruthy();
238220
expect(DInputObject.isFieldNonNull('initialNullable')).toBeTruthy();
239-
Object.values(baseDTC.discrimTCs).forEach((dTC) => {
221+
Object.values(eDTC.discrimTCs).forEach((dTC) => {
240222
expect(dTC.isFieldNonNull('initialNullable')).toBeTruthy();
241223
});
242224
});
243225

244226
it('makes a non-null field nullable', () => {
245-
baseDTC.addFields({ initialNonNull: 'String!' });
246-
expect(baseDTC.isFieldNonNull('initialNonNull')).toBeTruthy();
227+
eDTC.addFields({ initialNonNull: 'String!' });
228+
expect(eDTC.isFieldNonNull('initialNonNull')).toBeTruthy();
247229

248-
baseDTC.makeFieldNullable('initialNonNull');
230+
eDTC.makeFieldNullable('initialNonNull');
249231

250-
expect(baseDTC.isFieldNonNull('initialNonNull')).toBeFalsy();
251-
expect(DInterface.isFieldNonNull('initialNonNull')).toBeFalsy();
232+
expect(eDTC.isFieldNonNull('initialNonNull')).toBeFalsy();
252233
expect(DInputObject.isFieldNonNull('initialNonNull')).toBeFalsy();
253-
Object.values(baseDTC.discrimTCs).forEach((dTC) => {
234+
Object.values(eDTC.discrimTCs).forEach((dTC) => {
254235
expect(dTC.isFieldNonNull('initialNonNull')).toBeFalsy();
255236
});
256237
});

0 commit comments

Comments
 (0)