From 4449325489a3aa9c919cbf8df78e57f446b1e6c4 Mon Sep 17 00:00:00 2001 From: Chareice Date: Thu, 9 Feb 2023 13:01:25 +0800 Subject: [PATCH 01/19] fix: pg schema in sync runner --- packages/core/database/src/sync-runner.ts | 30 ++++++----- .../inherits/inherited-collection.test.ts | 50 +++++++++++++++++++ 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/packages/core/database/src/sync-runner.ts b/packages/core/database/src/sync-runner.ts index 18272e324..a31573ef2 100644 --- a/packages/core/database/src/sync-runner.ts +++ b/packages/core/database/src/sync-runner.ts @@ -7,6 +7,8 @@ export class SyncRunner { const inheritedCollection = model.collection as InheritedCollection; const db = inheritedCollection.context.database; + const schemaName = db.options.schema || 'public'; + const dialect = db.sequelize.getDialect(); const queryInterface = db.sequelize.getQueryInterface(); @@ -27,7 +29,7 @@ export class SyncRunner { const parentTables = parents.map((parent) => parent.model.tableName); - const tableName = model.getTableName(); + const tableName = model.tableName; const attributes = model.tableAttributes; @@ -44,6 +46,7 @@ export class SyncRunner { `SELECT column_default FROM information_schema.columns WHERE table_name = '${parent}' + and table_schema = '${schemaName}' and "column_name" = 'id';`, { transaction, @@ -60,7 +63,7 @@ export class SyncRunner { throw new Error(`Can't find sequence name of ${parent}`); } - const regex = new RegExp(/nextval\('("?\w+"?)\'.*\)/); + const regex = new RegExp(/nextval\('(.*)'::regclass\)/); const match = regex.exec(columnDefault); const sequenceName = match[1]; @@ -82,25 +85,24 @@ export class SyncRunner { } } - await this.createTable(tableName, childAttributes, options, model, parentTables); + await this.createTable(tableName, childAttributes, options, model, parentTables, schemaName); if (maxSequenceName) { const parentsDeep = Array.from(db.inheritanceMap.getParents(inheritedCollection.name)).map( (parent) => db.getCollection(parent).model.tableName, ); - const sequenceTables = [...parentsDeep, tableName]; + const sequenceTables = [...parentsDeep, tableName.toString()]; for (const sequenceTable of sequenceTables) { - const queryName = Boolean(sequenceTable.match(/[A-Z]/)) ? `"${sequenceTable}"` : sequenceTable; + const queryName = + Boolean(sequenceTable.match(/[A-Z]/)) && !sequenceTable.includes(`"`) ? `"${sequenceTable}"` : sequenceTable; const idColumnQuery = await queryInterface.sequelize.query( ` - SELECT true - FROM pg_attribute - WHERE attrelid = '${queryName}'::regclass -- cast to a registered class (table) -AND attname = 'id' -AND NOT attisdropped + SELECT column_name +FROM information_schema.columns +WHERE table_name='${queryName}' and column_name='id' and table_schema = '${schemaName}'; `, { transaction, @@ -112,7 +114,7 @@ AND NOT attisdropped } await queryInterface.sequelize.query( - `alter table "${sequenceTable}" + `alter table "${schemaName}"."${sequenceTable}" alter column id set default nextval('${maxSequenceName}')`, { transaction, @@ -132,7 +134,9 @@ AND NOT attisdropped } } - static async createTable(tableName, attributes, options, model, parentTables) { + static async createTable(tableName, attributes, options, model, parentTables, schema) { + tableName = model.queryGenerator.addSchema({ tableName, _schema: schema, _schemaDelimiter: '' }); + let sql = ''; options = { ...options }; @@ -157,7 +161,7 @@ AND NOT attisdropped sql = `${queryGenerator.createTableQuery(tableName, attributes, options)}`.replace( ';', - ` INHERITS (${parentTables.map((t) => `"${t}"`).join(', ')});`, + ` INHERITS (${parentTables.map((t) => `"${schema}"."${t}"`).join(', ')});`, ); return await model.sequelize.query(sql, options); diff --git a/packages/plugins/collection-manager/src/__tests__/inherits/inherited-collection.test.ts b/packages/plugins/collection-manager/src/__tests__/inherits/inherited-collection.test.ts index 60f954384..dc7f898bd 100644 --- a/packages/plugins/collection-manager/src/__tests__/inherits/inherited-collection.test.ts +++ b/packages/plugins/collection-manager/src/__tests__/inherits/inherited-collection.test.ts @@ -3,6 +3,56 @@ import Application from '@nocobase/server'; import { createApp } from '..'; import { pgOnly } from '@nocobase/test'; +pgOnly()('Inherited Collection', () => { + let db: Database; + let app: Application; + + let collectionRepository: Repository; + + let fieldsRepository: Repository; + + beforeEach(async () => { + app = await createApp({ + database: { + schema: 'testSchema', + }, + }); + + db = app.db; + + collectionRepository = db.getCollection('collections').repository; + fieldsRepository = db.getCollection('fields').repository; + }); + + afterEach(async () => { + await app.destroy(); + }); + + it('should create inherited collection in difference schema', async () => { + await collectionRepository.create({ + values: { + name: 'b', + fields: [ + { + name: 'name', + type: 'string', + }, + ], + }, + context: {}, + }); + + await collectionRepository.create({ + values: { + name: 'a', + inherits: ['b'], + fields: [{ type: 'string', name: 'bField' }], + }, + context: {}, + }); + }); +}); + pgOnly()('Inherited Collection', () => { let db: Database; let app: Application; From 9c9c39c0cd5702f36963f4a630c50d8f9820ba41 Mon Sep 17 00:00:00 2001 From: Chareice Date: Thu, 9 Feb 2023 22:00:30 +0800 Subject: [PATCH 02/19] fix: restore with pg schema --- .../plugins/duplicator/src/server/restorer.ts | 42 ++++++++++++++----- .../ui-schema-storage/src/repository.ts | 2 +- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/packages/plugins/duplicator/src/server/restorer.ts b/packages/plugins/duplicator/src/server/restorer.ts index eed4daa36..22f752341 100644 --- a/packages/plugins/duplicator/src/server/restorer.ts +++ b/packages/plugins/duplicator/src/server/restorer.ts @@ -127,12 +127,12 @@ export class Restorer extends AppMigrator { const metaContent = await fsPromises.readFile(collectionMetaPath, 'utf8'); const meta = JSON.parse(metaContent); - const tableName = meta.tableName; + const tableName = this.quoteTable(meta.tableName); try { // disable trigger if (this.app.db.inDialect('postgres')) { - await this.app.db.sequelize.query(`ALTER TABLE IF EXISTS "${tableName}" DISABLE TRIGGER ALL`); + await this.app.db.sequelize.query(`ALTER TABLE IF EXISTS ${tableName} DISABLE TRIGGER ALL`); } await this.importCollection({ @@ -144,7 +144,7 @@ export class Restorer extends AppMigrator { }); } finally { if (this.app.db.inDialect('postgres')) { - await this.app.db.sequelize.query(`ALTER TABLE IF EXISTS "${tableName}" ENABLE TRIGGER ALL`); + await this.app.db.sequelize.query(`ALTER TABLE IF EXISTS ${tableName} ENABLE TRIGGER ALL`); } } }; @@ -199,6 +199,25 @@ export class Restorer extends AppMigrator { await decompress(backupFilePath, this.workDir); } + quoteTable(tableName) { + // @ts-ignore + tableName = this.app.db.sequelize.getQueryInterface().queryGenerator.quoteTable(this.addSchema(tableName)); + + return tableName; + } + + addSchema(tableName) { + if (this.app.db.options.schema) { + // @ts-ignore + tableName = this.app.db.sequelize.getQueryInterface().queryGenerator.addSchema({ + tableName, + _schema: this.app.db.options.schema, + }); + } + + return tableName; + } + async importCollection(options: { name: string; insert?: boolean; @@ -216,15 +235,16 @@ export class Restorer extends AppMigrator { const meta = JSON.parse(metaContent); app.log.info(`collection meta ${metaContent}`); - const tableName = meta.tableName; + const addSchemaTableName = this.addSchema(meta.tableName); + const tableName = this.quoteTable(meta.tableName); if (options.clear !== false) { // truncate old data - let sql = `TRUNCATE TABLE "${tableName}"`; + let sql = `TRUNCATE TABLE ${tableName}`; if (app.db.inDialect('sqlite')) { sql = `DELETE - FROM "${tableName}"`; + FROM ${tableName}`; } await app.db.sequelize.query(sqlAdapter(app.db, sql)); @@ -282,7 +302,7 @@ export class Restorer extends AppMigrator { //@ts-ignore const sql = collection.model.queryInterface.queryGenerator.bulkInsertQuery( - tableName, + addSchemaTableName, rowsWithMeta, {}, fieldMappedAttributes, @@ -303,18 +323,20 @@ export class Restorer extends AppMigrator { if (this.app.db.inDialect('postgres')) { const sequenceNameResult = await app.db.sequelize.query( `SELECT column_default FROM information_schema.columns WHERE - table_name='${collection.model.tableName}' and "column_name" = 'id';`, + table_name='${collection.model.tableName}' and "column_name" = 'id' and table_schema = '${ + app.db.options.schema || 'public' + }';`, ); if (sequenceNameResult[0].length) { const columnDefault = sequenceNameResult[0][0]['column_default']; if (columnDefault.includes(`${collection.model.tableName}_id_seq`)) { - const regex = new RegExp(/nextval\('("?\w+"?)\'.*\)/); + const regex = new RegExp(/nextval\('(.*)'::regclass\)/); const match = regex.exec(columnDefault); const sequenceName = match[1]; const maxVal = await app.db.sequelize.query( - `SELECT MAX("${primaryKeyAttribute.field}") FROM "${collection.model.tableName}"`, + `SELECT MAX("${primaryKeyAttribute.field}") FROM ${tableName}`, { type: 'SELECT', }, diff --git a/packages/plugins/ui-schema-storage/src/repository.ts b/packages/plugins/ui-schema-storage/src/repository.ts index 5c85b65dd..68bc02e17 100644 --- a/packages/plugins/ui-schema-storage/src/repository.ts +++ b/packages/plugins/ui-schema-storage/src/repository.ts @@ -103,7 +103,7 @@ export class UiSchemaRepository extends Repository { tableNameAdapter(tableName) { if (this.database.sequelize.getDialect() === 'postgres') { - return `"${tableName}"`; + return `"${this.database.options.schema || 'public'}"."${tableName}"`; } return tableName; } From 5e603b5a5263c815f5647abeefde6e691a3494f9 Mon Sep 17 00:00:00 2001 From: Chareice Date: Fri, 10 Feb 2023 12:52:23 +0800 Subject: [PATCH 03/19] chore: databse utils --- .../core/database/src/database-utils/index.ts | 38 +++++++++++++++++++ packages/core/database/src/database.ts | 3 ++ packages/core/database/src/sync-runner.ts | 15 +++++--- .../plugins/duplicator/src/server/restorer.ts | 27 +++---------- 4 files changed, 56 insertions(+), 27 deletions(-) create mode 100644 packages/core/database/src/database-utils/index.ts diff --git a/packages/core/database/src/database-utils/index.ts b/packages/core/database/src/database-utils/index.ts new file mode 100644 index 000000000..513ba1d3f --- /dev/null +++ b/packages/core/database/src/database-utils/index.ts @@ -0,0 +1,38 @@ +import Database from '../database'; +import lodash from 'lodash'; + +export default class DatabaseUtils { + constructor(public db: Database) {} + + addSchema(tableName, schema?) { + if (this.db.options.schema) { + schema = this.db.options.schema; + } + + if (schema) { + // @ts-ignore + tableName = this.db.sequelize.getQueryInterface().queryGenerator.addSchema({ + tableName, + _schema: this.db.options.schema, + }); + } + + return tableName; + } + + quoteTable(tableName) { + const queryGenerator = this.db.sequelize.getQueryInterface().queryGenerator; + // @ts-ignore + tableName = queryGenerator.quoteTable(lodash.isPlainObject(tableName) ? tableName : this.addSchema(tableName)); + + return tableName; + } + + schema() { + if (!this.db.inDialect('postgres')) { + return undefined; + } + + return this.db.options.schema || 'public'; + } +} diff --git a/packages/core/database/src/database.ts b/packages/core/database/src/database.ts index 563766056..a1eface0b 100644 --- a/packages/core/database/src/database.ts +++ b/packages/core/database/src/database.ts @@ -61,6 +61,8 @@ import { ValidateListener, } from './types'; +import DatabaseUtils from './database-utils'; + export interface MergeOptions extends merge.Options {} export interface PendingOptions { @@ -155,6 +157,7 @@ export class Database extends EventEmitter implements AsyncEmitter { modelCollection = new Map, Collection>(); tableNameCollectionMap = new Map(); + utils = new DatabaseUtils(this); referenceMap = new ReferencesMap(); inheritanceMap = new InheritanceMap(); diff --git a/packages/core/database/src/sync-runner.ts b/packages/core/database/src/sync-runner.ts index a31573ef2..91cf7cae9 100644 --- a/packages/core/database/src/sync-runner.ts +++ b/packages/core/database/src/sync-runner.ts @@ -31,6 +31,9 @@ export class SyncRunner { const tableName = model.tableName; + const schemaTableName = db.utils.addSchema(tableName); + const quoteTableName = db.utils.quoteTable(tableName); + const attributes = model.tableAttributes; const childAttributes = lodash.pickBy(attributes, (value) => { @@ -85,7 +88,7 @@ export class SyncRunner { } } - await this.createTable(tableName, childAttributes, options, model, parentTables, schemaName); + await this.createTable(schemaTableName, childAttributes, options, model, parentTables, db); if (maxSequenceName) { const parentsDeep = Array.from(db.inheritanceMap.getParents(inheritedCollection.name)).map( @@ -134,9 +137,7 @@ WHERE table_name='${queryName}' and column_name='id' and table_schema = '${schem } } - static async createTable(tableName, attributes, options, model, parentTables, schema) { - tableName = model.queryGenerator.addSchema({ tableName, _schema: schema, _schemaDelimiter: '' }); - + static async createTable(tableName, attributes, options, model, parentTables, db) { let sql = ''; options = { ...options }; @@ -161,7 +162,11 @@ WHERE table_name='${queryName}' and column_name='id' and table_schema = '${schem sql = `${queryGenerator.createTableQuery(tableName, attributes, options)}`.replace( ';', - ` INHERITS (${parentTables.map((t) => `"${schema}"."${t}"`).join(', ')});`, + ` INHERITS (${parentTables + .map((t) => { + return db.utils.quoteTable(db.utils.addSchema(t, db.options.schema)); + }) + .join(', ')});`, ); return await model.sequelize.query(sql, options); diff --git a/packages/plugins/duplicator/src/server/restorer.ts b/packages/plugins/duplicator/src/server/restorer.ts index 22f752341..2d20eb030 100644 --- a/packages/plugins/duplicator/src/server/restorer.ts +++ b/packages/plugins/duplicator/src/server/restorer.ts @@ -127,7 +127,7 @@ export class Restorer extends AppMigrator { const metaContent = await fsPromises.readFile(collectionMetaPath, 'utf8'); const meta = JSON.parse(metaContent); - const tableName = this.quoteTable(meta.tableName); + const tableName = this.app.db.utils.quoteTable(meta.tableName); try { // disable trigger @@ -199,25 +199,6 @@ export class Restorer extends AppMigrator { await decompress(backupFilePath, this.workDir); } - quoteTable(tableName) { - // @ts-ignore - tableName = this.app.db.sequelize.getQueryInterface().queryGenerator.quoteTable(this.addSchema(tableName)); - - return tableName; - } - - addSchema(tableName) { - if (this.app.db.options.schema) { - // @ts-ignore - tableName = this.app.db.sequelize.getQueryInterface().queryGenerator.addSchema({ - tableName, - _schema: this.app.db.options.schema, - }); - } - - return tableName; - } - async importCollection(options: { name: string; insert?: boolean; @@ -225,6 +206,8 @@ export class Restorer extends AppMigrator { rowCondition?: (row: any) => boolean; }) { const app = this.app; + const db = app.db; + const collectionName = options.name; const dir = this.workDir; const collection = app.db.getCollection(collectionName); @@ -235,8 +218,8 @@ export class Restorer extends AppMigrator { const meta = JSON.parse(metaContent); app.log.info(`collection meta ${metaContent}`); - const addSchemaTableName = this.addSchema(meta.tableName); - const tableName = this.quoteTable(meta.tableName); + const addSchemaTableName = db.utils.addSchema(meta.tableName); + const tableName = db.utils.quoteTable(meta.tableName); if (options.clear !== false) { // truncate old data From f69b062b4ffcdb99d57153358e2c1d6a7481702a Mon Sep 17 00:00:00 2001 From: Chareice Date: Sat, 11 Feb 2023 09:41:59 +0800 Subject: [PATCH 04/19] fix: test --- packages/core/test/src/mockServer.ts | 1 + packages/plugins/collection-manager/src/__tests__/index.ts | 1 + .../src/__tests__/inherits/inherited-collection.test.ts | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/test/src/mockServer.ts b/packages/core/test/src/mockServer.ts index 034fdffce..5341ead20 100644 --- a/packages/core/test/src/mockServer.ts +++ b/packages/core/test/src/mockServer.ts @@ -57,6 +57,7 @@ interface Resource { export class MockServer extends Application { async loadAndInstall(options: any = {}) { await this.load({ method: 'install' }); + await this.install({ ...options, sync: { diff --git a/packages/plugins/collection-manager/src/__tests__/index.ts b/packages/plugins/collection-manager/src/__tests__/index.ts index 6e9dcf4c3..7888983ee 100644 --- a/packages/plugins/collection-manager/src/__tests__/index.ts +++ b/packages/plugins/collection-manager/src/__tests__/index.ts @@ -9,6 +9,7 @@ export async function createApp(options = {}) { ...options, }); + await app.db.sync({}); app.plugin(PluginErrorHandler, { name: 'error-handler' }); app.plugin(Plugin, { name: 'collection-manager' }); app.plugin(PluginUiSchema, { name: 'ui-schema-storage' }); diff --git a/packages/plugins/collection-manager/src/__tests__/inherits/inherited-collection.test.ts b/packages/plugins/collection-manager/src/__tests__/inherits/inherited-collection.test.ts index dc7f898bd..9f624564f 100644 --- a/packages/plugins/collection-manager/src/__tests__/inherits/inherited-collection.test.ts +++ b/packages/plugins/collection-manager/src/__tests__/inherits/inherited-collection.test.ts @@ -359,7 +359,6 @@ pgOnly()('Inherited Collection', () => { const studentCollection = await db.getCollection('students'); - console.log(studentCollection.fields); await studentCollection.repository.create({ values: { name: 'foo', From a1060eff71a22b2066720f63508da265bc24ea69 Mon Sep 17 00:00:00 2001 From: ChengLei Shao Date: Tue, 14 Feb 2023 16:16:19 +0800 Subject: [PATCH 05/19] Update nocobase-test.yml --- .github/workflows/nocobase-test.yml | 103 +++------------------------- 1 file changed, 8 insertions(+), 95 deletions(-) diff --git a/.github/workflows/nocobase-test.yml b/.github/workflows/nocobase-test.yml index ab3c1b1a7..c5fb8f294 100644 --- a/.github/workflows/nocobase-test.yml +++ b/.github/workflows/nocobase-test.yml @@ -20,6 +20,7 @@ jobs: strategy: matrix: node_version: ['16', '18'] + underscored: [true, false] runs-on: ubuntu-latest container: node:${{ matrix.node_version }} steps: @@ -36,12 +37,14 @@ jobs: env: DB_DIALECT: sqlite DB_STORAGE: /tmp/db.sqlite + DB_UNDERSCORED: ${{ matrix.underscored }} postgres-test: strategy: matrix: node_version: ['16', '18'] - + underscored: [true, false] + schema: [public, nocobase] runs-on: ubuntu-latest container: node:${{ matrix.node_version }} services: @@ -77,11 +80,14 @@ jobs: DB_USER: nocobase DB_PASSWORD: password DB_DATABASE: nocobase + DB_UNDERSCORED: ${{ matrix.underscored }} + DB_SCHEMA: ${{ matrix.schema }} mysql-test: strategy: matrix: node_version: ['16', '18'] + underscored: [true, false] runs-on: ubuntu-latest container: node:${{ matrix.node_version }} services: @@ -109,97 +115,4 @@ jobs: DB_USER: root DB_PASSWORD: password DB_DATABASE: nocobase - - sqlite-underscored-test: - strategy: - matrix: - node_version: ['16'] - runs-on: ubuntu-latest - container: node:${{ matrix.node_version }} - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node_version }} - uses: actions/setup-node@v2 - with: - node-version: ${{ matrix.node_version }} - cache: 'yarn' - - run: yarn install - - name: Test with Sqlite - run: yarn test - env: - DB_DIALECT: sqlite - DB_STORAGE: /tmp/db.sqlite - DB_UNDERSCORED: true - - postgres-underscored-test: - strategy: - matrix: - node_version: ['16'] - - runs-on: ubuntu-latest - container: node:${{ matrix.node_version }} - services: - # Label used to access the service container - postgres: - # Docker Hub image - image: postgres:10 - # Provide the password for postgres - env: - POSTGRES_USER: nocobase - POSTGRES_PASSWORD: password - # Set health checks to wait until postgres has started - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node_version }} - uses: actions/setup-node@v2 - with: - node-version: ${{ matrix.node_version }} - cache: 'yarn' - - run: yarn install - - name: Test with postgres - run: yarn test - env: - DB_DIALECT: postgres - DB_HOST: postgres - DB_PORT: 5432 - DB_USER: nocobase - DB_PASSWORD: password - DB_DATABASE: nocobase - DB_UNDERSCORED: true - - mysql-underscored-test: - strategy: - matrix: - node_version: ['16'] - runs-on: ubuntu-latest - container: node:${{ matrix.node_version }} - services: - mysql: - image: mysql:8 - env: - MYSQL_ROOT_PASSWORD: password - MYSQL_DATABASE: nocobase - options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node_version }} - uses: actions/setup-node@v2 - with: - node-version: ${{ matrix.node_version }} - cache: 'yarn' - - run: yarn install - - name: Test with MySQL - run: yarn test - env: - DB_DIALECT: mysql - DB_HOST: mysql - DB_PORT: 3306 - DB_USER: root - DB_PASSWORD: password - DB_DATABASE: nocobase - DB_UNDERSCORED: true + DB_UNDERSCORED: ${{ matrix.underscored }} From f1c269cb5719853f022faf9ec5a6d65f6f0c49aa Mon Sep 17 00:00:00 2001 From: Chareice Date: Tue, 14 Feb 2023 17:57:29 +0800 Subject: [PATCH 06/19] fix: test --- .../src/__tests__/migrations/update-id-to-bigint.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/collection-manager/src/__tests__/migrations/update-id-to-bigint.test.ts b/packages/plugins/collection-manager/src/__tests__/migrations/update-id-to-bigint.test.ts index 4e88826d7..e972925f2 100644 --- a/packages/plugins/collection-manager/src/__tests__/migrations/update-id-to-bigint.test.ts +++ b/packages/plugins/collection-manager/src/__tests__/migrations/update-id-to-bigint.test.ts @@ -74,7 +74,7 @@ excludeSqlite()('update id to bigint test', () => { db.getCollection(collectionName) ? db.getCollection(collectionName).model.tableName : collectionName, ); - if (process.env.DB_UNDERSCORED) { + if (db.options.underscored) { fieldName = lodash.snakeCase(fieldName); } From 50401827137f7175e7c83baf29bec87125f5368f Mon Sep 17 00:00:00 2001 From: Chareice Date: Tue, 14 Feb 2023 19:53:23 +0800 Subject: [PATCH 07/19] chore: db schema test options --- packages/core/database/src/mock-database.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/database/src/mock-database.ts b/packages/core/database/src/mock-database.ts index 3e093d081..fb4692b94 100644 --- a/packages/core/database/src/mock-database.ts +++ b/packages/core/database/src/mock-database.ts @@ -32,6 +32,7 @@ export function getConfigByEnv() { }, timezone: process.env.DB_TIMEZONE, underscored: process.env.DB_UNDERSCORED === 'true', + schema: process.env.DB_SCHEMA, }; } From 1589d11e82cc0258522747d86d914b9386baea4a Mon Sep 17 00:00:00 2001 From: Chareice Date: Tue, 14 Feb 2023 20:04:49 +0800 Subject: [PATCH 08/19] feat: collection add schema table name method --- packages/core/database/src/collection.ts | 12 +++++++++++- packages/core/database/src/database.ts | 8 ++++++-- .../plugins/collection-manager/src/models/field.ts | 10 +++++----- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/packages/core/database/src/collection.ts b/packages/core/database/src/collection.ts index 3c43342bf..8908def2d 100644 --- a/packages/core/database/src/collection.ts +++ b/packages/core/database/src/collection.ts @@ -7,7 +7,7 @@ import { QueryInterfaceDropTableOptions, SyncOptions, Transactionable, - Utils + Utils, } from 'sequelize'; import { Database } from './database'; import { Field, FieldOptions } from './fields'; @@ -532,4 +532,14 @@ export class Collection< public isParent() { return this.context.database.inheritanceMap.isParentNode(this.name); } + + public addSchemaTableName() { + const tableName = this.model.tableName; + + if (this.options.schema) { + return this.db.utils.addSchema(tableName, this.options.schema); + } + + return tableName; + } } diff --git a/packages/core/database/src/database.ts b/packages/core/database/src/database.ts index 9224bfed8..3fb68af5c 100644 --- a/packages/core/database/src/database.ts +++ b/packages/core/database/src/database.ts @@ -15,7 +15,7 @@ import { Sequelize, SyncOptions, Transactionable, - Utils + Utils, } from 'sequelize'; import { SequelizeStorage, Umzug } from 'umzug'; import { Collection, CollectionOptions, RepositoryType } from './collection'; @@ -58,7 +58,7 @@ import { SyncListener, UpdateListener, UpdateWithAssociationsListener, - ValidateListener + ValidateListener, } from './types'; import { snakeCase } from './utils'; @@ -324,6 +324,10 @@ export class Database extends EventEmitter implements AsyncEmitter { }); } } + + if (this.options.schema && !options.schema) { + options.schema = this.options.schema; + } }); } diff --git a/packages/plugins/collection-manager/src/models/field.ts b/packages/plugins/collection-manager/src/models/field.ts index 239a989b2..62cc73b82 100644 --- a/packages/plugins/collection-manager/src/models/field.ts +++ b/packages/plugins/collection-manager/src/models/field.ts @@ -107,7 +107,7 @@ export class FieldModel extends MagicAttributeModel { const queryInterface = this.db.sequelize.getQueryInterface() as any; - const existsIndexes = await queryInterface.showIndex(collection.model.tableName, { + const existsIndexes = await queryInterface.showIndex(collection.addSchemaTableName(), { transaction: options.transaction, }); @@ -121,7 +121,7 @@ export class FieldModel extends MagicAttributeModel { if (existUniqueIndex) { const existsUniqueConstraints = await queryInterface.showConstraint( - collection.model.tableName, + collection.addSchemaTableName(), constraintName, {}, ); @@ -133,7 +133,7 @@ export class FieldModel extends MagicAttributeModel { // @ts-ignore await collection.sync({ ...options, force: false, alter: { drop: false } }); - await queryInterface.addConstraint(tableName, { + await queryInterface.addConstraint(collection.addSchemaTableName(), { type: 'unique', fields: [columnName], name: constraintName, @@ -142,7 +142,7 @@ export class FieldModel extends MagicAttributeModel { } if (!unique && existsUniqueConstraint) { - await queryInterface.removeConstraint(collection.model.tableName, constraintName, { + await queryInterface.removeConstraint(collection.addSchemaTableName(), constraintName, { transaction: options.transaction, }); } @@ -164,7 +164,7 @@ export class FieldModel extends MagicAttributeModel { const queryInterface = collection.db.sequelize.getQueryInterface(); await queryInterface.changeColumn( - collection.model.tableName, + collection.addSchemaTableName(), collection.model.rawAttributes[this.get('name')].field, { type: field.dataType, From ee3db22c8aaedae23ad58e24779cf7a895fced22 Mon Sep 17 00:00:00 2001 From: Chareice Date: Tue, 14 Feb 2023 20:15:32 +0800 Subject: [PATCH 09/19] fix: update to bigint test --- .../src/__tests__/http-api/collections.test.ts | 2 +- .../migrations/update-id-to-bigint.test.ts | 13 ++++++------- .../20221121111113-update-id-to-bigint.ts | 8 +++++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/plugins/collection-manager/src/__tests__/http-api/collections.test.ts b/packages/plugins/collection-manager/src/__tests__/http-api/collections.test.ts index 208c4faac..e7da82ed0 100644 --- a/packages/plugins/collection-manager/src/__tests__/http-api/collections.test.ts +++ b/packages/plugins/collection-manager/src/__tests__/http-api/collections.test.ts @@ -97,7 +97,7 @@ describe('collections repository', () => { const testCollection = app.db.getCollection('test'); - const tableInfo = await app.db.sequelize.getQueryInterface().describeTable(testCollection.model.tableName); + const tableInfo = await app.db.sequelize.getQueryInterface().describeTable(testCollection.addSchemaTableName()); expect(tableInfo['field']).toBeDefined(); }); diff --git a/packages/plugins/collection-manager/src/__tests__/migrations/update-id-to-bigint.test.ts b/packages/plugins/collection-manager/src/__tests__/migrations/update-id-to-bigint.test.ts index e972925f2..363b705d5 100644 --- a/packages/plugins/collection-manager/src/__tests__/migrations/update-id-to-bigint.test.ts +++ b/packages/plugins/collection-manager/src/__tests__/migrations/update-id-to-bigint.test.ts @@ -68,17 +68,16 @@ excludeSqlite()('update id to bigint test', () => { await db.sync(); const assertBigInt = async (collectionName, fieldName) => { - const tableInfo = await db.sequelize - .getQueryInterface() - .describeTable( - db.getCollection(collectionName) ? db.getCollection(collectionName).model.tableName : collectionName, - ); + const tableName = db.getCollection(collectionName) + ? db.getCollection(collectionName).addSchemaTableName() + : collectionName; + + const tableInfo = await db.sequelize.getQueryInterface().describeTable(tableName); if (db.options.underscored) { fieldName = lodash.snakeCase(fieldName); } - console.log(`${collectionName}, ${fieldName}`, tableInfo[fieldName].type); expect(tableInfo[fieldName].type).toBe('BIGINT'); }; @@ -92,7 +91,7 @@ excludeSqlite()('update id to bigint test', () => { let usersTableInfo = await db.sequelize .getQueryInterface() - .describeTable(db.getCollection('users').model.tableName); + .describeTable(db.getCollection('users').addSchemaTableName()); assertInteger(usersTableInfo.id.type); diff --git a/packages/plugins/collection-manager/src/migrations/20221121111113-update-id-to-bigint.ts b/packages/plugins/collection-manager/src/migrations/20221121111113-update-id-to-bigint.ts index 48e7cabbe..d7563aa05 100644 --- a/packages/plugins/collection-manager/src/migrations/20221121111113-update-id-to-bigint.ts +++ b/packages/plugins/collection-manager/src/migrations/20221121111113-update-id-to-bigint.ts @@ -34,6 +34,8 @@ export default class UpdateIdToBigIntMigrator extends Migration { let sql; const tableName = model.tableName; + const addSchemaTableName = db.utils.addSchema(tableName); + const quoteTableName = db.utils.quoteTable(addSchemaTableName); const collection = db.modelCollection.get(model); @@ -52,7 +54,7 @@ export default class UpdateIdToBigIntMigrator extends Migration { if (model.rawAttributes[fieldName].type instanceof DataTypes.INTEGER) { if (db.inDialect('postgres')) { - sql = `ALTER TABLE "${tableName}" ALTER COLUMN "${columnName}" SET DATA TYPE BIGINT;`; + sql = `ALTER TABLE ${quoteTableName} ALTER COLUMN "${columnName}" SET DATA TYPE BIGINT;`; } else if (db.inDialect('mysql')) { const dataTypeOrOptions = model.rawAttributes[fieldName]; const attributeName = fieldName; @@ -70,7 +72,7 @@ export default class UpdateIdToBigIntMigrator extends Migration { }, ); - sql = queryGenerator.changeColumnQuery(tableName, query); + sql = queryGenerator.changeColumnQuery(addSchemaTableName, query); sql = sql.replace(' PRIMARY KEY;', ' ;'); } @@ -85,7 +87,7 @@ export default class UpdateIdToBigIntMigrator extends Migration { } if (db.inDialect('postgres')) { - const sequenceQuery = `SELECT pg_get_serial_sequence('"${model.tableName}"', '${columnName}');`; + const sequenceQuery = `SELECT pg_get_serial_sequence('${quoteTableName}', '${columnName}');`; const [result] = await this.sequelize.query(sequenceQuery, {}); const sequenceName = result[0]['pg_get_serial_sequence']; From 130fe227042e5eb0a1b886bd579127a6b7304bab Mon Sep 17 00:00:00 2001 From: Chareice Date: Tue, 14 Feb 2023 21:34:23 +0800 Subject: [PATCH 10/19] fix: schema test --- packages/core/database/src/database.ts | 6 ++-- packages/core/database/src/mock-database.ts | 2 +- packages/core/database/src/utils.ts | 31 +++++++++++++++++++ packages/core/test/src/mockServer.ts | 2 +- .../__tests__/http-api/collections.test.ts | 4 +-- .../collection-manager/src/models/field.ts | 6 +--- .../src/__tests__/action.test.ts | 3 +- .../__tests__/ui-schema-repository.test.ts | 3 +- .../src/__tests__/ui-schema.test.ts | 2 +- 9 files changed, 43 insertions(+), 16 deletions(-) diff --git a/packages/core/database/src/database.ts b/packages/core/database/src/database.ts index 3fb68af5c..0ba129e3d 100644 --- a/packages/core/database/src/database.ts +++ b/packages/core/database/src/database.ts @@ -60,7 +60,7 @@ import { UpdateWithAssociationsListener, ValidateListener, } from './types'; -import { snakeCase } from './utils'; +import { patchSequelizeQueryInterface, snakeCase } from './utils'; import DatabaseUtils from './database-utils'; @@ -200,9 +200,10 @@ export class Database extends EventEmitter implements AsyncEmitter { // https://github.com/sequelize/sequelize/issues/1774 require('pg').defaults.parseInt8 = true; } + this.options = opts; this.sequelize = new Sequelize(opts); - this.options = opts; + this.collections = new Map(); this.modelHook = new ModelHook(this); @@ -266,6 +267,7 @@ export class Database extends EventEmitter implements AsyncEmitter { }); this.initListener(); + patchSequelizeQueryInterface(this); } initListener() { diff --git a/packages/core/database/src/mock-database.ts b/packages/core/database/src/mock-database.ts index fb4692b94..8ce980526 100644 --- a/packages/core/database/src/mock-database.ts +++ b/packages/core/database/src/mock-database.ts @@ -32,7 +32,7 @@ export function getConfigByEnv() { }, timezone: process.env.DB_TIMEZONE, underscored: process.env.DB_UNDERSCORED === 'true', - schema: process.env.DB_SCHEMA, + schema: process.env.DB_SCHEMA !== 'public' ? process.env.DB_SCHEMA : undefined, }; } diff --git a/packages/core/database/src/utils.ts b/packages/core/database/src/utils.ts index 173fc17b8..6fbbcc8c7 100644 --- a/packages/core/database/src/utils.ts +++ b/packages/core/database/src/utils.ts @@ -2,6 +2,7 @@ import crypto from 'crypto'; import { IdentifierError } from './errors/identifier-error'; import { Model } from './model'; import lodash from 'lodash'; +import Database from './database'; type HandleAppendsQueryOptions = { templateModel: any; @@ -82,3 +83,33 @@ export function getTableName(collectionName: string, options) { export function snakeCase(name: string) { return require('sequelize').Utils.underscore(name); } + +export function patchSequelizeQueryInterface(db: Database) { + if (db.inDialect('postgres')) { + //@ts-ignore + const queryGenerator = db.sequelize.dialect.queryGenerator; + + queryGenerator.showConstraintsQuery = (tableName, constraintName) => { + const lines = [ + 'SELECT constraint_catalog AS "constraintCatalog",', + 'constraint_schema AS "constraintSchema",', + 'constraint_name AS "constraintName",', + 'table_catalog AS "tableCatalog",', + 'table_schema AS "tableSchema",', + 'table_name AS "tableName",', + 'constraint_type AS "constraintType",', + 'is_deferrable AS "isDeferrable",', + 'initially_deferred AS "initiallyDeferred"', + 'from INFORMATION_SCHEMA.table_constraints', + `WHERE table_name='${tableName}'`, + `AND constraint_name='${constraintName}'`, + ]; + + if (db.options.schema && db.options.schema !== 'public') { + lines.push(`AND table_schema='${db.options.schema}'`); + } + + return lines.join(' '); + }; + } +} diff --git a/packages/core/test/src/mockServer.ts b/packages/core/test/src/mockServer.ts index 5341ead20..0272a287f 100644 --- a/packages/core/test/src/mockServer.ts +++ b/packages/core/test/src/mockServer.ts @@ -70,7 +70,7 @@ export class MockServer extends Application { } async cleanDb() { - await this.db.sequelize.getQueryInterface().dropAllTables(); + await this.db.clean({ drop: true }); } agent(): SuperAgentTest & { resource: (name: string, resourceOf?: any) => Resource } { diff --git a/packages/plugins/collection-manager/src/__tests__/http-api/collections.test.ts b/packages/plugins/collection-manager/src/__tests__/http-api/collections.test.ts index e7da82ed0..d3d3f61fa 100644 --- a/packages/plugins/collection-manager/src/__tests__/http-api/collections.test.ts +++ b/packages/plugins/collection-manager/src/__tests__/http-api/collections.test.ts @@ -504,7 +504,7 @@ describe('collections repository', () => { const indexes = (await app.db.sequelize .getQueryInterface() - .showIndex(app.db.getCollection('test').model.tableName)) as any; + .showIndex(app.db.getCollection('test').addSchemaTableName())) as any; const columnName = app.db.getCollection('test').model.rawAttributes.testField.field; @@ -528,7 +528,7 @@ describe('collections repository', () => { const afterIndexes = (await app.db.sequelize .getQueryInterface() - .showIndex(app.db.getCollection('test').model.tableName)) as any; + .showIndex(app.db.getCollection('test').addSchemaTableName())) as any; expect( afterIndexes.find( diff --git a/packages/plugins/collection-manager/src/models/field.ts b/packages/plugins/collection-manager/src/models/field.ts index 62cc73b82..783ae522f 100644 --- a/packages/plugins/collection-manager/src/models/field.ts +++ b/packages/plugins/collection-manager/src/models/field.ts @@ -120,11 +120,7 @@ export class FieldModel extends MagicAttributeModel { let constraintName = `${tableName}_${field.name}_uk`; if (existUniqueIndex) { - const existsUniqueConstraints = await queryInterface.showConstraint( - collection.addSchemaTableName(), - constraintName, - {}, - ); + const existsUniqueConstraints = await queryInterface.showConstraint(tableName, constraintName, {}); existsUniqueConstraint = existsUniqueConstraints[0]; } diff --git a/packages/plugins/ui-schema-storage/src/__tests__/action.test.ts b/packages/plugins/ui-schema-storage/src/__tests__/action.test.ts index 0cdf4a9e2..40138c05f 100644 --- a/packages/plugins/ui-schema-storage/src/__tests__/action.test.ts +++ b/packages/plugins/ui-schema-storage/src/__tests__/action.test.ts @@ -13,8 +13,7 @@ describe('action test', () => { db = app.db; - const queryInterface = db.sequelize.getQueryInterface(); - await queryInterface.dropAllTables(); + await db.clean({ drop: true }); app.plugin(PluginUiSchema, { name: 'ui-schema-storage' }); diff --git a/packages/plugins/ui-schema-storage/src/__tests__/ui-schema-repository.test.ts b/packages/plugins/ui-schema-storage/src/__tests__/ui-schema-repository.test.ts index 723d268a6..7004fea86 100644 --- a/packages/plugins/ui-schema-storage/src/__tests__/ui-schema-repository.test.ts +++ b/packages/plugins/ui-schema-storage/src/__tests__/ui-schema-repository.test.ts @@ -22,8 +22,7 @@ describe('ui_schema repository', () => { db = app.db; - const queryInterface = db.sequelize.getQueryInterface(); - await queryInterface.dropAllTables(); + await db.clean({ drop: true }); app.plugin(PluginUiSchema, { name: 'ui-schema-storage' }); diff --git a/packages/plugins/ui-schema-storage/src/__tests__/ui-schema.test.ts b/packages/plugins/ui-schema-storage/src/__tests__/ui-schema.test.ts index 0846ef451..fda699246 100644 --- a/packages/plugins/ui-schema-storage/src/__tests__/ui-schema.test.ts +++ b/packages/plugins/ui-schema-storage/src/__tests__/ui-schema.test.ts @@ -20,7 +20,7 @@ describe('ui-schema', () => { db = app.db; - await db.sequelize.getQueryInterface().dropAllTables(); + await db.clean({ drop: true }); app.plugin(PluginUiSchema, { name: 'ui-schema-storage' }); From f82be2a207c5e03cb06252b643252f2517adaa50 Mon Sep 17 00:00:00 2001 From: Chareice Date: Tue, 14 Feb 2023 21:35:44 +0800 Subject: [PATCH 11/19] chore: show constraints query path --- packages/core/database/src/utils.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/core/database/src/utils.ts b/packages/core/database/src/utils.ts index 6fbbcc8c7..bbe041c30 100644 --- a/packages/core/database/src/utils.ts +++ b/packages/core/database/src/utils.ts @@ -89,7 +89,13 @@ export function patchSequelizeQueryInterface(db: Database) { //@ts-ignore const queryGenerator = db.sequelize.dialect.queryGenerator; + const originalShowConstraintsQuery = queryGenerator.showConstraintsQuery; + queryGenerator.showConstraintsQuery = (tableName, constraintName) => { + if (!constraintName) { + return originalShowConstraintsQuery.call(queryGenerator, tableName, constraintName); + } + const lines = [ 'SELECT constraint_catalog AS "constraintCatalog",', 'constraint_schema AS "constraintSchema",', From 408383becf579eea634534d99018c6efa68bad4e Mon Sep 17 00:00:00 2001 From: Chareice Date: Tue, 14 Feb 2023 21:36:42 +0800 Subject: [PATCH 12/19] chore: show constraints query path --- packages/core/database/src/utils.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/core/database/src/utils.ts b/packages/core/database/src/utils.ts index bbe041c30..c11c98cf3 100644 --- a/packages/core/database/src/utils.ts +++ b/packages/core/database/src/utils.ts @@ -89,13 +89,7 @@ export function patchSequelizeQueryInterface(db: Database) { //@ts-ignore const queryGenerator = db.sequelize.dialect.queryGenerator; - const originalShowConstraintsQuery = queryGenerator.showConstraintsQuery; - queryGenerator.showConstraintsQuery = (tableName, constraintName) => { - if (!constraintName) { - return originalShowConstraintsQuery.call(queryGenerator, tableName, constraintName); - } - const lines = [ 'SELECT constraint_catalog AS "constraintCatalog",', 'constraint_schema AS "constraintSchema",', @@ -108,9 +102,12 @@ export function patchSequelizeQueryInterface(db: Database) { 'initially_deferred AS "initiallyDeferred"', 'from INFORMATION_SCHEMA.table_constraints', `WHERE table_name='${tableName}'`, - `AND constraint_name='${constraintName}'`, ]; + if (!constraintName) { + lines.push(`AND constraint_name='${constraintName}'`); + } + if (db.options.schema && db.options.schema !== 'public') { lines.push(`AND table_schema='${db.options.schema}'`); } From 91f19c2419ab2779dbc233e7610072fa15ca8ec8 Mon Sep 17 00:00:00 2001 From: ChengLei Shao Date: Tue, 14 Feb 2023 21:44:44 +0800 Subject: [PATCH 13/19] Update nocobase-test.yml --- .github/workflows/nocobase-test.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/nocobase-test.yml b/.github/workflows/nocobase-test.yml index c5fb8f294..ed1e221e7 100644 --- a/.github/workflows/nocobase-test.yml +++ b/.github/workflows/nocobase-test.yml @@ -7,13 +7,9 @@ on: - develop paths: - 'packages/**' - # paths-ignore: - # - 'docs/**' pull_request: paths: - 'packages/**' - # paths-ignore: - # - 'docs/**' jobs: sqlite-test: From 15753647366fb28fa62f586c5fee007fd8c8b8a5 Mon Sep 17 00:00:00 2001 From: Chareice Date: Wed, 15 Feb 2023 00:18:41 +0800 Subject: [PATCH 14/19] chore: test --- packages/core/database/src/collection.ts | 4 ++++ packages/plugins/duplicator/src/server/__tests__/dump.test.ts | 2 +- packages/plugins/duplicator/src/server/dumper.ts | 2 +- .../ui-schema-storage/src/__tests__/ui-schema-model.test.ts | 4 +--- .../src/__tests__/ui-schema-repository-with-cache.test.ts | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/core/database/src/collection.ts b/packages/core/database/src/collection.ts index 8908def2d..c4898c506 100644 --- a/packages/core/database/src/collection.ts +++ b/packages/core/database/src/collection.ts @@ -542,4 +542,8 @@ export class Collection< return tableName; } + + public quotedTableName() { + return this.db.utils.quoteTable(this.addSchemaTableName()); + } } diff --git a/packages/plugins/duplicator/src/server/__tests__/dump.test.ts b/packages/plugins/duplicator/src/server/__tests__/dump.test.ts index cb532bdb2..c344f3981 100644 --- a/packages/plugins/duplicator/src/server/__tests__/dump.test.ts +++ b/packages/plugins/duplicator/src/server/__tests__/dump.test.ts @@ -19,6 +19,7 @@ describe('dump', () => { app = mockServer(); db = app.db; + await app.cleanDb(); app.db.collection({ name: 'users', @@ -52,7 +53,6 @@ describe('dump', () => { fields: [], }); - await app.cleanDb(); await db.sync(); }); diff --git a/packages/plugins/duplicator/src/server/dumper.ts b/packages/plugins/duplicator/src/server/dumper.ts index 7762d142b..f820852a4 100644 --- a/packages/plugins/duplicator/src/server/dumper.ts +++ b/packages/plugins/duplicator/src/server/dumper.ts @@ -177,7 +177,7 @@ ORDER BY table_schema, table_name`, const dataStream = fs.createWriteStream(dataFilePath); const rows = await app.db.sequelize.query( - sqlAdapter(app.db, `SELECT * FROM ${collection.isParent() ? 'ONLY' : ''} "${collection.model.tableName}"`), + sqlAdapter(app.db, `SELECT * FROM ${collection.isParent() ? 'ONLY' : ''} ${collection.quotedTableName()}`), { type: 'SELECT', }, diff --git a/packages/plugins/ui-schema-storage/src/__tests__/ui-schema-model.test.ts b/packages/plugins/ui-schema-storage/src/__tests__/ui-schema-model.test.ts index 8f6e6fc51..0ddf01011 100644 --- a/packages/plugins/ui-schema-storage/src/__tests__/ui-schema-model.test.ts +++ b/packages/plugins/ui-schema-storage/src/__tests__/ui-schema-model.test.ts @@ -19,9 +19,7 @@ describe('ui schema model', () => { db = app.db; - const queryInterface = db.sequelize.getQueryInterface(); - await queryInterface.dropAllTables(); - + await db.clean({ drop: true }); app.plugin(PluginUiSchema, { name: 'ui-schema-storage' }); await app.load(); diff --git a/packages/plugins/ui-schema-storage/src/__tests__/ui-schema-repository-with-cache.test.ts b/packages/plugins/ui-schema-storage/src/__tests__/ui-schema-repository-with-cache.test.ts index cfb3860d6..86b44cc97 100644 --- a/packages/plugins/ui-schema-storage/src/__tests__/ui-schema-repository-with-cache.test.ts +++ b/packages/plugins/ui-schema-storage/src/__tests__/ui-schema-repository-with-cache.test.ts @@ -23,7 +23,7 @@ describe('ui_schema repository with cache', () => { db = app.db; cache = app.cache; - await db.sequelize.getQueryInterface().dropAllTables(); + await db.clean({ drop: true }); app.plugin(PluginUiSchema, { name: 'ui-schema-storage' }); From d3fb665e61f2256891011742b6e64ff45aaa741d Mon Sep 17 00:00:00 2001 From: Chareice Date: Wed, 15 Feb 2023 10:10:44 +0800 Subject: [PATCH 15/19] fix: test --- packages/plugins/collection-manager/src/__tests__/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/collection-manager/src/__tests__/index.ts b/packages/plugins/collection-manager/src/__tests__/index.ts index 7888983ee..26d3c74c7 100644 --- a/packages/plugins/collection-manager/src/__tests__/index.ts +++ b/packages/plugins/collection-manager/src/__tests__/index.ts @@ -9,7 +9,7 @@ export async function createApp(options = {}) { ...options, }); - await app.db.sync({}); + await app.db.clean({ drop: true }); app.plugin(PluginErrorHandler, { name: 'error-handler' }); app.plugin(Plugin, { name: 'collection-manager' }); app.plugin(PluginUiSchema, { name: 'ui-schema-storage' }); From 05243d03ca4b636b0b34e67c18f16288c9443449 Mon Sep 17 00:00:00 2001 From: Chareice Date: Wed, 15 Feb 2023 11:55:53 +0800 Subject: [PATCH 16/19] fix: test --- packages/plugins/collection-manager/src/__tests__/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/plugins/collection-manager/src/__tests__/index.ts b/packages/plugins/collection-manager/src/__tests__/index.ts index 26d3c74c7..a9b57aedd 100644 --- a/packages/plugins/collection-manager/src/__tests__/index.ts +++ b/packages/plugins/collection-manager/src/__tests__/index.ts @@ -10,6 +10,8 @@ export async function createApp(options = {}) { }); await app.db.clean({ drop: true }); + await app.db.sync({}); + app.plugin(PluginErrorHandler, { name: 'error-handler' }); app.plugin(Plugin, { name: 'collection-manager' }); app.plugin(PluginUiSchema, { name: 'ui-schema-storage' }); From d232a7bb502cc9c1ca25920b97e515f44e22a02c Mon Sep 17 00:00:00 2001 From: Chareice Date: Wed, 15 Feb 2023 12:13:32 +0800 Subject: [PATCH 17/19] fix: test table name --- packages/plugins/duplicator/src/server/__tests__/dump.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/duplicator/src/server/__tests__/dump.test.ts b/packages/plugins/duplicator/src/server/__tests__/dump.test.ts index c344f3981..1f141fcbe 100644 --- a/packages/plugins/duplicator/src/server/__tests__/dump.test.ts +++ b/packages/plugins/duplicator/src/server/__tests__/dump.test.ts @@ -148,7 +148,7 @@ $$`); await db.sequelize.query(` CREATE TRIGGER last_name_changes BEFORE UPDATE - ON ${app.db.getCollection('users').model.tableName} + ON ${app.db.getCollection('users').quotedTableName()} FOR EACH ROW EXECUTE PROCEDURE trigger_function(); `); From 897cede1600a54659ce4eff1bb3b3244ddd41582 Mon Sep 17 00:00:00 2001 From: Chareice Date: Wed, 15 Feb 2023 17:08:35 +0800 Subject: [PATCH 18/19] fix: inherited collection test --- .../inherits/inherited-collection.test.ts | 50 ----------------- .../inhertied-collection-with-schema.test.ts | 54 +++++++++++++++++++ 2 files changed, 54 insertions(+), 50 deletions(-) create mode 100644 packages/plugins/collection-manager/src/__tests__/inherits/inhertied-collection-with-schema.test.ts diff --git a/packages/plugins/collection-manager/src/__tests__/inherits/inherited-collection.test.ts b/packages/plugins/collection-manager/src/__tests__/inherits/inherited-collection.test.ts index 9f624564f..18a248110 100644 --- a/packages/plugins/collection-manager/src/__tests__/inherits/inherited-collection.test.ts +++ b/packages/plugins/collection-manager/src/__tests__/inherits/inherited-collection.test.ts @@ -3,56 +3,6 @@ import Application from '@nocobase/server'; import { createApp } from '..'; import { pgOnly } from '@nocobase/test'; -pgOnly()('Inherited Collection', () => { - let db: Database; - let app: Application; - - let collectionRepository: Repository; - - let fieldsRepository: Repository; - - beforeEach(async () => { - app = await createApp({ - database: { - schema: 'testSchema', - }, - }); - - db = app.db; - - collectionRepository = db.getCollection('collections').repository; - fieldsRepository = db.getCollection('fields').repository; - }); - - afterEach(async () => { - await app.destroy(); - }); - - it('should create inherited collection in difference schema', async () => { - await collectionRepository.create({ - values: { - name: 'b', - fields: [ - { - name: 'name', - type: 'string', - }, - ], - }, - context: {}, - }); - - await collectionRepository.create({ - values: { - name: 'a', - inherits: ['b'], - fields: [{ type: 'string', name: 'bField' }], - }, - context: {}, - }); - }); -}); - pgOnly()('Inherited Collection', () => { let db: Database; let app: Application; diff --git a/packages/plugins/collection-manager/src/__tests__/inherits/inhertied-collection-with-schema.test.ts b/packages/plugins/collection-manager/src/__tests__/inherits/inhertied-collection-with-schema.test.ts new file mode 100644 index 000000000..1b5406fde --- /dev/null +++ b/packages/plugins/collection-manager/src/__tests__/inherits/inhertied-collection-with-schema.test.ts @@ -0,0 +1,54 @@ +import Database, { Repository } from '@nocobase/database'; +import Application from '@nocobase/server'; +import { createApp } from '..'; +import { pgOnly } from '@nocobase/test'; + +pgOnly()('Inherited Collection with schema options', () => { + let db: Database; + let app: Application; + + let collectionRepository: Repository; + + let fieldsRepository: Repository; + + beforeEach(async () => { + app = await createApp({ + database: { + schema: 'testSchema', + }, + }); + + db = app.db; + + collectionRepository = db.getCollection('collections').repository; + fieldsRepository = db.getCollection('fields').repository; + }); + + afterEach(async () => { + await app.destroy(); + }); + + it('should create inherited collection in difference schema', async () => { + await collectionRepository.create({ + values: { + name: 'b', + fields: [ + { + name: 'name', + type: 'string', + }, + ], + }, + context: {}, + }); + + await collectionRepository.create({ + values: { + name: 'a', + inherits: ['b'], + fields: [{ type: 'string', name: 'bField' }], + }, + context: {}, + }); + }); +}); From 542175f454bd7020f0f8655cbbcccbc2300c5758 Mon Sep 17 00:00:00 2001 From: ChengLei Shao Date: Thu, 16 Feb 2023 01:46:23 +0000 Subject: [PATCH 19/19] feat: beforeSubAppLoad event --- .../multi-app-manager/src/models/application.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/plugins/multi-app-manager/src/models/application.ts b/packages/plugins/multi-app-manager/src/models/application.ts index 1cb36c0b4..88dd4c8e9 100644 --- a/packages/plugins/multi-app-manager/src/models/application.ts +++ b/packages/plugins/multi-app-manager/src/models/application.ts @@ -9,7 +9,12 @@ export interface registerAppOptions extends Transactionable { } export class ApplicationModel extends Model { - static async handleAppStart(app: Application, options: registerAppOptions) { + static async handleAppStart(mainApp: Application, app: Application, options: registerAppOptions) { + await mainApp.emit('beforeSubAppLoad', { + mainApp, + subApp: app, + }); + await app.load(); if (!(await app.isInstalled())) { @@ -35,6 +40,7 @@ export class ApplicationModel extends Model { const app = mainApp.appManager.createApplication(appName, { ...options.appOptionsFactory(appName, mainApp), ...appOptions, + name: appName, }); const isInstalled = await (async () => { @@ -52,7 +58,7 @@ export class ApplicationModel extends Model { await options.dbCreator(app); } - await AppModel.handleAppStart(app, options); + await AppModel.handleAppStart(mainApp, app, options); await AppModel.update( {