diff --git a/packages/datasource-customizer/src/collection-customizer.ts b/packages/datasource-customizer/src/collection-customizer.ts index 6a900b365..c55753d8a 100644 --- a/packages/datasource-customizer/src/collection-customizer.ts +++ b/packages/datasource-customizer/src/collection-customizer.ts @@ -1,6 +1,7 @@ import { CollectionSchema, CollectionUtils, + ColumnSchema, Logger, Operator, SchemaUtils, @@ -46,7 +47,7 @@ export default class CollectionCustomizer< readonly name: string; get schema(): CollectionSchema { - return this.stack.validation.getCollection(this.name).schema; + return this.stack.binary.getCollection(this.name).schema; } constructor( @@ -646,6 +647,28 @@ export default class CollectionCustomizer< }); } + /** + * Mark a field as optional + * + * Be wary that your database might still refuse empty values if it requires one + * @param name the name of the column you would like optional + * @example + * .setFieldNullable('userName'); + */ + setFieldNullable(name: TColumnName): this { + return this.pushCustomization(async () => { + const column = this.schema.fields[name]; + + if (column && column?.type === 'Column') { + (column as ColumnSchema).allowNull = true; + + column.validation = column.validation?.filter( + validation => validation.operator !== 'Present', + ); + } + }); + } + private pushRelation(name: string, definition: RelationDefinition): this { return this.pushCustomization(async () => { this.stack.relation.getCollection(this.name).addRelation(name, definition); diff --git a/packages/datasource-customizer/src/datasource-customizer.ts b/packages/datasource-customizer/src/datasource-customizer.ts index 65217f88e..23d66e191 100644 --- a/packages/datasource-customizer/src/datasource-customizer.ts +++ b/packages/datasource-customizer/src/datasource-customizer.ts @@ -40,16 +40,14 @@ export default class DataSourceCustomizer { * Retrieve schema of the agent */ get schema(): DataSourceSchema { - return this.stack.validation.schema; + return this.stack.binary.schema; } /** * Get list of customizable collections */ get collections(): CollectionCustomizer[] { - return this.stack.validation.collections.map(c => - this.getCollection(c.name as TCollectionName), - ); + return this.stack.binary.collections.map(c => this.getCollection(c.name as TCollectionName)); } constructor(options?: Options) { diff --git a/packages/datasource-customizer/test/collection-customizer.test.ts b/packages/datasource-customizer/test/collection-customizer.test.ts index 5cf16ca95..92f6f6320 100644 --- a/packages/datasource-customizer/test/collection-customizer.test.ts +++ b/packages/datasource-customizer/test/collection-customizer.test.ts @@ -87,6 +87,12 @@ describe('Builder > Collection', () => { filterOperators: new Set(['Equal', 'In']), }), title: factories.columnSchema.build({ columnType: 'String' }), + numberOfPages: factories.columnSchema.build({ columnType: 'Number', allowNull: false }), + numberOfCoWriter: factories.columnSchema.build({ + columnType: 'Number', + allowNull: false, + validation: [{ operator: 'Present' }, { operator: 'LessThan', value: '3' }], + }), }, }), }), @@ -98,8 +104,9 @@ describe('Builder > Collection', () => { // @ts-ignore const { stack } = dsc; const customizer = new CollectionCustomizer(dsc, stack, 'authors'); + const bookCustomizer = new CollectionCustomizer(dsc, stack, 'books'); - return { dsc, customizer, stack }; + return { dsc, customizer, stack, bookCustomizer }; }; describe('use', () => { @@ -873,4 +880,42 @@ describe('Builder > Collection', () => { expect(self).toEqual(customizer); }); }); + + describe('setFieldNullable', () => { + describe('when the field is already optional', () => { + it('should not change anything', async () => { + const { dsc, bookCustomizer } = await setup(); + + const self = bookCustomizer.setFieldNullable('title'); + await dsc.getDataSource(logger); + + expect((self.schema.fields.title as ColumnSchema).allowNull).toStrictEqual(true); + }); + }); + + describe('when the field is not optional', () => { + it('should make it optional', async () => { + const { dsc, bookCustomizer } = await setup(); + + const self = bookCustomizer.setFieldNullable('numberOfPages'); + await dsc.getDataSource(logger); + + expect((self.schema.fields.numberOfPages as ColumnSchema).allowNull).toStrictEqual(true); + }); + + describe('when the field also include `Present` validation', () => { + it('should make it optional and remove validation', async () => { + const { dsc, bookCustomizer } = await setup(); + + const self = bookCustomizer.setFieldNullable('numberOfCoWriter'); + await dsc.getDataSource(logger); + + const column = self.schema.fields.numberOfCoWriter as ColumnSchema; + expect(column.allowNull).toStrictEqual(true); + expect(column.validation).toHaveLength(1); + expect(column.validation[0].operator).toBe('LessThan'); + }); + }); + }); + }); });