Skip to content

Commit 5c8bde5

Browse files
committed
2 parents 595b147 + 8bb278e commit 5c8bde5

File tree

8 files changed

+161
-96
lines changed

8 files changed

+161
-96
lines changed

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,23 @@
3434
},
3535
"devDependencies": {
3636
"@types/jest": "26.0.24",
37-
"@typescript-eslint/eslint-plugin": "4.28.2",
38-
"@typescript-eslint/parser": "4.28.2",
39-
"eslint": "7.30.0",
37+
"@typescript-eslint/eslint-plugin": "4.28.4",
38+
"@typescript-eslint/parser": "4.28.4",
39+
"eslint": "7.31.0",
4040
"eslint-config-airbnb-base": "14.2.1",
4141
"eslint-config-prettier": "8.3.0",
4242
"eslint-plugin-import": "2.23.4",
4343
"eslint-plugin-prettier": "3.4.0",
4444
"graphql": "15.5.1",
4545
"graphql-compose": "9.0.1",
4646
"jest": "27.0.6",
47-
"mongodb-memory-server": "7.2.0",
48-
"mongoose": "5.13.2",
47+
"mongodb-memory-server": "7.3.2",
48+
"mongoose": "5.13.3",
4949
"prettier": "2.3.2",
5050
"request": "2.88.2",
5151
"rimraf": "3.0.2",
5252
"semantic-release": "17.4.4",
53-
"ts-jest": "27.0.3",
53+
"ts-jest": "27.0.4",
5454
"typescript": "4.3.5"
5555
},
5656
"scripts": {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { composeMongoose } from '../../index';
2+
import { mongoose } from '../../__mocks__/mongooseCommon';
3+
4+
// mongoose.set('debug', true);
5+
6+
const WithSubSchema = new mongoose.Schema({
7+
subDocument: new mongoose.Schema({
8+
field: { type: String, default: 'Hey' },
9+
}),
10+
});
11+
12+
const WithoutSubSchema = new mongoose.Schema({
13+
subDocument: {
14+
field: { type: String, default: 'Hey' },
15+
},
16+
});
17+
18+
const WithSubModel = mongoose.model('WithSubModel', WithSubSchema);
19+
const WithoutSubModel = mongoose.model('WithoutSubModel', WithoutSubSchema);
20+
21+
describe('defaultsAsNonNull falsely reports non-nullability for subdocuments that have a Schema - issue #358', () => {
22+
it('with sub schema', async () => {
23+
const WithSubTC = composeMongoose(WithSubModel, { defaultsAsNonNull: true });
24+
25+
// sub-Schema breaks the "recursive default value assignation" behavior
26+
const data = new WithSubModel().subDocument;
27+
expect(data).toEqual(undefined);
28+
29+
// so field should not be non-null
30+
expect(WithSubTC.getFieldTypeName('subDocument')).toBe('WithSubModelSubDocument');
31+
});
32+
33+
it('as nested fields', async () => {
34+
const WithoutSubTC = composeMongoose(WithoutSubModel, { defaultsAsNonNull: true });
35+
36+
const data = new WithoutSubModel().subDocument;
37+
expect(data).toEqual({ field: 'Hey' });
38+
39+
// should be non-null!
40+
expect(WithoutSubTC.getFieldTypeName('subDocument')).toBe('WithoutSubModelSubDocument!');
41+
});
42+
});

src/composeMongoose.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,12 @@ function makeFieldsNonNullWithDefaultValues(
173173
const fc = tc.getField(fieldName);
174174
// traverse nested Object types
175175
if (fc.type instanceof ObjectTypeComposer) {
176+
if (fc.extensions?.isSingleNestedMongooseSchema) {
177+
// sub-Schema breaks the "recursive default value assignation" behavior
178+
// @see https://github.com/graphql-compose/graphql-compose-mongoose/issues/358
179+
return;
180+
}
181+
176182
makeFieldsNonNullWithDefaultValues(fc.type);
177183
if (fc.type.getExtension('hasFieldsWithDefaultValue')) {
178184
tc.makeFieldNonNull(fieldName);

src/fieldsConverter.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,12 @@ export function convertModelToGraphQL<TDoc extends Document, TContext>(
205205
description: _getFieldDescription(mongooseField),
206206
};
207207

208+
if (mongooseField?.schema && (mongooseField as any)?.$isSingleNested) {
209+
graphqlFields[fieldName].extensions = {
210+
isSingleNestedMongooseSchema: true,
211+
};
212+
}
213+
208214
if (mongooseField?.defaultValue !== null && mongooseField?.defaultValue !== undefined) {
209215
if (!graphqlFields[fieldName].extensions) graphqlFields[fieldName].extensions = {};
210216
(graphqlFields as any)[fieldName].extensions.defaultValue = mongooseField?.defaultValue;

src/resolvers/connection.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ export type ConnectionResolverOpts<TContext = any> = Omit<
2424
_ConnectionResolverOpts<TContext>,
2525
'countResolver' | 'findManyResolver' | 'sort'
2626
> & {
27+
findManyResolver?: Resolver;
28+
countResolver?: Resolver;
2729
countOpts?: CountResolverOpts;
2830
findManyOpts?: FindManyResolverOpts;
2931
sort?: _ConnectionSortMapOpts;
@@ -61,11 +63,11 @@ export function connection<TSource = any, TContext = any, TDoc extends Document
6163
};
6264
});
6365

64-
const { findManyOpts, countOpts, ...restOpts } = opts || {};
66+
const { findManyOpts, countOpts, findManyResolver, countResolver, ...restOpts } = opts || {};
6567

6668
return prepareConnectionResolver<any, any>(tc, {
67-
findManyResolver: findMany(model, tc, findManyOpts),
68-
countResolver: count(model, tc, countOpts),
69+
findManyResolver: findManyResolver || findMany(model, tc, findManyOpts),
70+
countResolver: countResolver || count(model, tc, countOpts),
6971
sort: sortConfigs,
7072
...restOpts,
7173
});

src/resolvers/helpers/filter.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
ObjectTypeComposer,
55
InterfaceTypeComposer,
66
ObjectTypeComposerArgumentConfigMap,
7+
InputTypeComposer,
78
} from 'graphql-compose';
89
import type { Model, Document } from 'mongoose';
910
import { isObject, toMongoFilterDottedObject, getIndexedFieldNamesForGraphQL } from '../../utils';
@@ -102,24 +103,30 @@ export function filterHelperArgs<TDoc extends Document = any>(
102103

103104
const { prefix, suffix } = opts;
104105
const filterTypeName: string = `${prefix}${typeComposer.getTypeName()}${suffix}`;
105-
const itc = typeComposer.getInputTypeComposer().clone(filterTypeName);
106106

107-
makeFieldsRecursiveNullable(itc, { prefix, suffix });
107+
let itc;
108+
if (typeComposer.schemaComposer.hasInstance(filterTypeName, InputTypeComposer)) {
109+
itc = typeComposer.schemaComposer.getITC(filterTypeName);
110+
} else {
111+
itc = typeComposer.getInputTypeComposer().clone(filterTypeName);
108112

109-
itc.removeField(removeFields);
113+
makeFieldsRecursiveNullable(itc, { prefix, suffix });
110114

111-
if (opts.requiredFields) {
112-
itc.makeFieldNonNull(opts.requiredFields);
113-
}
115+
itc.removeField(removeFields);
114116

115-
if (itc.getFieldNames().length === 0) {
116-
return {} as any;
117-
}
117+
if (opts.requiredFields) {
118+
itc.makeFieldNonNull(opts.requiredFields);
119+
}
118120

119-
if (!opts.baseTypeName) {
120-
opts.baseTypeName = typeComposer.getTypeName();
121+
if (itc.getFieldNames().length === 0) {
122+
return {} as any;
123+
}
124+
125+
if (!opts.baseTypeName) {
126+
opts.baseTypeName = typeComposer.getTypeName();
127+
}
128+
addFilterOperators(itc, model, opts);
121129
}
122-
addFilterOperators(itc, model, opts);
123130

124131
return {
125132
filter: {

src/resolvers/pagination.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export type PaginationResolverOpts = Omit<
1313
_PaginationResolverOpts,
1414
'countResolver' | 'findManyResolver'
1515
> & {
16+
findManyResolver?: Resolver;
17+
countResolver?: Resolver;
1618
countOpts?: CountResolverOpts;
1719
findManyOpts?: FindManyResolverOpts;
1820
};
@@ -22,10 +24,10 @@ export function pagination<TSource = any, TContext = any, TDoc extends Document
2224
tc: ObjectTypeComposer<TDoc, TContext> | InterfaceTypeComposer<TDoc, TContext>,
2325
opts?: PaginationResolverOpts
2426
): Resolver<TSource, TContext, PaginationTArgs, TDoc> {
25-
const { countOpts, findManyOpts, ...restOpts } = opts || {};
27+
const { countOpts, findManyOpts, findManyResolver, countResolver, ...restOpts } = opts || {};
2628
const resolver = preparePaginationResolver<any, any>(tc, {
27-
findManyResolver: findMany(model, tc, findManyOpts),
28-
countResolver: count(model, tc, countOpts),
29+
findManyResolver: findManyResolver || findMany(model, tc, findManyOpts),
30+
countResolver: countResolver || count(model, tc, countOpts),
2931
...restOpts,
3032
});
3133
return resolver;

0 commit comments

Comments
 (0)