diff --git a/packages/core/database/src/model.ts b/packages/core/database/src/model.ts index 38f189b6e..e5224f8b9 100644 --- a/packages/core/database/src/model.ts +++ b/packages/core/database/src/model.ts @@ -153,6 +153,15 @@ export class Model { let db: Database; @@ -19,6 +20,49 @@ describe('collections repository', () => { await app.destroy(); }); + it('should set collection schema from env', async () => { + if (!db.inDialect('postgres')) { + return; + } + + const plugin = app.getPlugin('collection-manager'); + plugin.schema = 'testSchema'; + + await Collection.repository.create({ + values: { + name: 'posts', + }, + context: {}, + }); + + const postsCollection = db.getCollection('posts'); + expect(postsCollection.options.schema).toEqual('testSchema'); + + await Collection.repository.create({ + values: { + name: 'tags', + }, + context: {}, + }); + + await Field.repository.create({ + values: { + name: 'posts', + type: 'belongsToMany', + target: 'posts', + through: 'posts_tags', + foreignKey: 'tag_id', + otherKey: 'post_id', + interface: 'm2m', + collectionName: 'tags', + }, + context: {}, + }); + + const throughCollection = db.getCollection('posts_tags'); + expect(throughCollection.options.schema).toEqual('testSchema'); + }); + test('create underscored field', async () => { if (process.env.DB_UNDERSCORED !== 'true') { return; diff --git a/packages/plugins/collection-manager/src/__tests__/fields/children.test.ts b/packages/plugins/collection-manager/src/__tests__/fields/children.test.ts deleted file mode 100644 index 04bce1c1a..000000000 --- a/packages/plugins/collection-manager/src/__tests__/fields/children.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import Database, { Collection as DBCollection } from '@nocobase/database'; -import Application from '@nocobase/server'; -import { createApp } from '..'; - -describe('children options', () => { - let db: Database; - let app: Application; - let Collection: DBCollection; - let Field: DBCollection; - - beforeEach(async () => { - app = await createApp(); - db = app.db; - Collection = db.getCollection('collections'); - Field = db.getCollection('fields'); - await Collection.repository.create({ - values: { - name: 'tests', - }, - }); - await Collection.repository.create({ - values: { - name: 'foos', - }, - }); - }); - - afterEach(async () => { - await app.destroy(); - }); - - it('when there are no children, the target collection is not created', async () => { - const field = await Field.repository.create({ - values: { - type: 'hasMany', - collectionName: 'tests', - }, - }); - const json = field.toJSON(); - expect(json).toMatchObject({ - type: 'hasMany', - collectionName: 'tests', - sourceKey: 'id', - targetKey: 'id', - }); - expect(json.name).toBeDefined(); - expect(json.target).toBeDefined(); - expect(json.foreignKey).toBeDefined(); - // 无 children 时,target collection 不创建 - const target = await Collection.model.findOne({ - where: { - name: json.target, - }, - }); - expect(target).toBeNull(); - }); - - it('the collectionName of the child field is the target of the parent field', async () => { - const field = await Field.repository.create({ - values: { - type: 'hasMany', - collectionName: 'tests', - children: [{ type: 'string' }, { type: 'string' }], - }, - }); - const json = field.toJSON(); - const target = await Collection.model.findOne({ - where: { - name: json.target, - }, - }); - expect(target).toBeDefined(); - // 子字段的 collectionName 是父字段的 target - for (const child of json.children) { - expect(child.collectionName).toBe(json.target); - } - }); -}); diff --git a/packages/plugins/collection-manager/src/hooks/afterCreateForForeignKeyField.ts b/packages/plugins/collection-manager/src/hooks/afterCreateForForeignKeyField.ts index e722f32cf..ea19961f2 100644 --- a/packages/plugins/collection-manager/src/hooks/afterCreateForForeignKeyField.ts +++ b/packages/plugins/collection-manager/src/hooks/afterCreateForForeignKeyField.ts @@ -152,6 +152,7 @@ export function afterCreateForForeignKeyField(db: Database) { isThrough: true, sortable: false, }, + context, transaction, }); } diff --git a/packages/plugins/collection-manager/src/repositories/collection-repository.ts b/packages/plugins/collection-manager/src/repositories/collection-repository.ts index e0df996ca..bd378e47a 100644 --- a/packages/plugins/collection-manager/src/repositories/collection-repository.ts +++ b/packages/plugins/collection-manager/src/repositories/collection-repository.ts @@ -66,10 +66,12 @@ export class CollectionRepository extends Repository { ...field.options, }); } + await this.create({ values: { ...options, fields, + from: 'db2cm', }, }); } diff --git a/packages/plugins/collection-manager/src/server.ts b/packages/plugins/collection-manager/src/server.ts index 54c9fb068..299dd7664 100644 --- a/packages/plugins/collection-manager/src/server.ts +++ b/packages/plugins/collection-manager/src/server.ts @@ -1,6 +1,4 @@ import path from 'path'; - -import lodash from 'lodash'; import { UniqueConstraintError } from 'sequelize'; import PluginErrorHandler from '@nocobase/plugin-error-handler'; @@ -11,7 +9,6 @@ import { CollectionRepository } from '.'; import { afterCreateForForeignKeyField, afterCreateForReverseField, - beforeCreateForChildrenCollection, beforeCreateForReverseField, beforeDestroyForeignKey, beforeInitOptions, @@ -19,9 +16,17 @@ import { import { InheritedCollection } from '@nocobase/database'; import { CollectionModel, FieldModel } from './models'; +import * as process from 'process'; +import lodash from 'lodash'; export class CollectionManagerPlugin extends Plugin { + public schema: string; + async beforeLoad() { + if (process.env.COLLECTION_MANAGER_SCHEMA) { + this.schema = process.env.COLLECTION_MANAGER_SCHEMA; + } + this.app.db.registerModels({ CollectionModel, FieldModel, @@ -48,25 +53,29 @@ export class CollectionManagerPlugin extends Plugin { ], }); - this.app.db.on('fields.beforeUpdate', async (model, options) => { - const newValue = options.values; - if ( - model.get('reverseKey') && - lodash.get(newValue, 'reverseField') && - !lodash.get(newValue, 'reverseField.key') - ) { - const field = await this.app.db - .getModel('fields') - .findByPk(model.get('reverseKey'), { transaction: options.transaction }); - if (field) { - throw new Error('cant update field without a reverseField key'); - } + this.app.db.on('collections.beforeCreate', async (model) => { + if (this.app.db.inDialect('postgres') && this.schema && model.get('from') != 'db2cm') { + model.set('schema', this.schema); } }); + this.app.db.on( + 'collections.afterCreateWithAssociations', + async (model: CollectionModel, { context, transaction }) => { + if (context) { + await model.migrate({ + transaction, + }); + } + }, + ); + + this.app.db.on('collections.beforeDestroy', async (model: CollectionModel, options) => { + await model.remove(options); + }); + // 要在 beforeInitOptions 之前处理 this.app.db.on('fields.beforeCreate', beforeCreateForReverseField(this.app.db)); - this.app.db.on('fields.beforeCreate', beforeCreateForChildrenCollection(this.app.db)); this.app.db.on('fields.beforeCreate', async (model, options) => { const collectionName = model.get('collectionName'); @@ -91,17 +100,6 @@ export class CollectionManagerPlugin extends Plugin { this.app.db.on('fields.afterCreate', afterCreateForReverseField(this.app.db)); - this.app.db.on( - 'collections.afterCreateWithAssociations', - async (model: CollectionModel, { context, transaction }) => { - if (context) { - await model.migrate({ - transaction, - }); - } - }, - ); - this.app.db.on('fields.afterCreate', async (model: FieldModel, { context, transaction }) => { if (context) { await model.migrate({ @@ -114,6 +112,22 @@ export class CollectionManagerPlugin extends Plugin { // after migrate this.app.db.on('fields.afterCreate', afterCreateForForeignKeyField(this.app.db)); + this.app.db.on('fields.beforeUpdate', async (model, options) => { + const newValue = options.values; + if ( + model.get('reverseKey') && + lodash.get(newValue, 'reverseField') && + !lodash.get(newValue, 'reverseField.key') + ) { + const field = await this.app.db + .getModel('fields') + .findByPk(model.get('reverseKey'), { transaction: options.transaction }); + if (field) { + throw new Error('cant update field without a reverseField key'); + } + } + }); + this.app.db.on('fields.afterUpdate', async (model: FieldModel, { context, transaction }) => { const prevOptions = model.previous('options'); const currentOptions = model.get('options'); @@ -158,10 +172,6 @@ export class CollectionManagerPlugin extends Plugin { }); }); - this.app.db.on('collections.beforeDestroy', async (model: CollectionModel, options) => { - await model.remove(options); - }); - this.app.db.on('fields.afterDestroy', async (model: FieldModel, options) => { const { transaction } = options; const collectionName = model.get('collectionName');