diff --git a/src/__tests__/github_issues/358-test.ts b/src/__tests__/github_issues/358-test.ts new file mode 100644 index 00000000..3f45edc1 --- /dev/null +++ b/src/__tests__/github_issues/358-test.ts @@ -0,0 +1,42 @@ +import { composeMongoose } from '../../index'; +import { mongoose } from '../../__mocks__/mongooseCommon'; + +// mongoose.set('debug', true); + +const WithSubSchema = new mongoose.Schema({ + subDocument: new mongoose.Schema({ + field: { type: String, default: 'Hey' }, + }), +}); + +const WithoutSubSchema = new mongoose.Schema({ + subDocument: { + field: { type: String, default: 'Hey' }, + }, +}); + +const WithSubModel = mongoose.model('WithSubModel', WithSubSchema); +const WithoutSubModel = mongoose.model('WithoutSubModel', WithoutSubSchema); + +describe('defaultsAsNonNull falsely reports non-nullability for subdocuments that have a Schema - issue #358', () => { + it('with sub schema', async () => { + const WithSubTC = composeMongoose(WithSubModel, { defaultsAsNonNull: true }); + + // sub-Schema breaks the "recursive default value assignation" behavior + const data = new WithSubModel().subDocument; + expect(data).toEqual(undefined); + + // so field should not be non-null + expect(WithSubTC.getFieldTypeName('subDocument')).toBe('WithSubModelSubDocument'); + }); + + it('as nested fields', async () => { + const WithoutSubTC = composeMongoose(WithoutSubModel, { defaultsAsNonNull: true }); + + const data = new WithoutSubModel().subDocument; + expect(data).toEqual({ field: 'Hey' }); + + // should be non-null! + expect(WithoutSubTC.getFieldTypeName('subDocument')).toBe('WithoutSubModelSubDocument!'); + }); +}); diff --git a/src/composeMongoose.ts b/src/composeMongoose.ts index 0500fa74..456f0458 100644 --- a/src/composeMongoose.ts +++ b/src/composeMongoose.ts @@ -163,6 +163,12 @@ function makeFieldsNonNullWithDefaultValues( const fc = tc.getField(fieldName); // traverse nested Object types if (fc.type instanceof ObjectTypeComposer) { + if (fc.extensions?.isSingleNestedMongooseSchema) { + // sub-Schema breaks the "recursive default value assignation" behavior + // @see https://github.com/graphql-compose/graphql-compose-mongoose/issues/358 + return; + } + makeFieldsNonNullWithDefaultValues(fc.type); if (fc.type.getExtension('hasFieldsWithDefaultValue')) { tc.makeFieldNonNull(fieldName); diff --git a/src/fieldsConverter.ts b/src/fieldsConverter.ts index aa01d8e2..a2e07240 100644 --- a/src/fieldsConverter.ts +++ b/src/fieldsConverter.ts @@ -189,6 +189,12 @@ export function convertModelToGraphQL( description: _getFieldDescription(mongooseField), }; + if (mongooseField?.schema && (mongooseField as any)?.$isSingleNested) { + graphqlFields[fieldName].extensions = { + isSingleNestedMongooseSchema: true, + }; + } + if (mongooseField?.defaultValue !== null && mongooseField?.defaultValue !== undefined) { if (!graphqlFields[fieldName].extensions) graphqlFields[fieldName].extensions = {}; (graphqlFields as any)[fieldName].extensions.defaultValue = mongooseField?.defaultValue;