diff --git a/packages/core/database/src/collection.ts b/packages/core/database/src/collection.ts index f65973479..a5ec7bbe1 100644 --- a/packages/core/database/src/collection.ts +++ b/packages/core/database/src/collection.ts @@ -149,7 +149,7 @@ export class Collection< tableName() { const { name, tableName } = this.options; const tName = tableName || name; - return this.db.options.underscored ? snakeCase(tName) : tName; + return this.options.underscored ? snakeCase(tName) : tName; } protected sequelizeModelOptions() { @@ -246,10 +246,12 @@ export class Collection< } checkFieldType(name: string, options: FieldOptions) { - if (!this.db.options.underscored) { + if (!this.options.underscored) { return; } + const fieldName = options.field || snakeCase(name); + const field = this.findField((f) => { if (f.name === name) { return false; @@ -259,9 +261,11 @@ export class Collection< } return snakeCase(f.name) === fieldName; }); + if (!field) { return; } + if (options.type !== field.type) { throw new Error(`fields with same column must be of the same type ${JSON.stringify(options)}`); } diff --git a/packages/core/database/src/database.ts b/packages/core/database/src/database.ts index 5e8a66af1..2c77ea711 100644 --- a/packages/core/database/src/database.ts +++ b/packages/core/database/src/database.ts @@ -311,7 +311,7 @@ export class Database extends EventEmitter implements AsyncEmitter { initListener() { this.on('beforeDefine', (model, options) => { - if (this.options.underscored) { + if (this.options.underscored && options.underscored === undefined) { options.underscored = true; } }); @@ -353,6 +353,10 @@ export class Database extends EventEmitter implements AsyncEmitter { }); this.on('beforeDefineCollection', (options) => { + if (this.options.underscored && options.underscored === undefined) { + options.underscored = true; + } + if (options.underscored) { if (lodash.get(options, 'sortable.scopeKey')) { options.sortable.scopeKey = snakeCase(options.sortable.scopeKey); @@ -617,7 +621,7 @@ export class Database extends EventEmitter implements AsyncEmitter { throw Error(`unsupported field type ${type}`); } - if (options.field && this.options.underscored) { + if (options.field && context.collection.options.underscored) { options.field = snakeCase(options.field); } diff --git a/packages/core/database/src/view-collection.ts b/packages/core/database/src/view-collection.ts index ff8f9eafd..363317290 100644 --- a/packages/core/database/src/view-collection.ts +++ b/packages/core/database/src/view-collection.ts @@ -4,6 +4,7 @@ export class ViewCollection extends Collection { constructor(options: CollectionOptions, context: CollectionContext) { options.autoGenId = false; options.timestamps = false; + options.underscored = false; super(options, context); } diff --git a/packages/plugins/collection-manager/src/__tests__/view/view-collection.test.ts b/packages/plugins/collection-manager/src/__tests__/view/view-collection.test.ts index 73c841093..8f80ef656 100644 --- a/packages/plugins/collection-manager/src/__tests__/view/view-collection.test.ts +++ b/packages/plugins/collection-manager/src/__tests__/view/view-collection.test.ts @@ -49,6 +49,34 @@ describe('view collection', function () { expect(results.length).toBe(1); }); + it('should support view with uppercase field in underscored env', async () => { + if (!db.options.underscored) { + return; + } + + const dropViewSQL = `DROP VIEW IF EXISTS test_view`; + await db.sequelize.query(dropViewSQL); + const viewSQL = `CREATE VIEW test_view AS select 1+1 as "Uppercase"`; + await db.sequelize.query(viewSQL); + + await collectionRepository.create({ + values: { + name: 'view_collection', + viewName: 'test_view', + isView: true, + fields: [{ type: 'string', name: 'Uppercase', field: 'Uppercase' }], + schema: db.inDialect('postgres') ? 'public' : undefined, + }, + context: {}, + }); + + const viewCollection = db.getCollection('view_collection'); + + expect(viewCollection.model.rawAttributes['Uppercase'].field).toEqual('Uppercase'); + const results = await viewCollection.repository.find(); + expect(results.length).toBe(1); + }); + it('should create view collection by view name', async () => { const dropViewSQL = `DROP VIEW IF EXISTS test_view`; await db.sequelize.query(dropViewSQL);