diff --git a/packages/core/data-source-manager/src/collection.ts b/packages/core/data-source-manager/src/collection.ts index 43191d66c6..7e86663ec3 100644 --- a/packages/core/data-source-manager/src/collection.ts +++ b/packages/core/data-source-manager/src/collection.ts @@ -1,7 +1,11 @@ import { CollectionOptions, ICollection, ICollectionManager, IRepository } from './types'; +import { default as lodash } from 'lodash'; +import merge from 'deepmerge'; +import { Field } from '@nocobase/database'; export class Collection implements ICollection { repository: IRepository; + fields: Map = new Map(); constructor( protected options: CollectionOptions, @@ -10,6 +14,30 @@ export class Collection implements ICollection { this.setRepository(options.repository); } + updateOptions(options: CollectionOptions, mergeOptions?: any) { + let newOptions = lodash.cloneDeep(options); + newOptions = merge(this.options, newOptions, mergeOptions); + this.options = newOptions; + + if (options.repository) { + this.setRepository(options.repository); + } + + return this; + } + + setField(name: string, options: any) { + const field = this.getField(name); + + if (field) { + field.updateOptions(options); + } + } + + getField(name: string): F { + return this.fields.get(name); + } + protected setRepository(repository: any) { this.repository = this.collectionManager.getRegisteredRepository(repository || 'Repository'); } diff --git a/packages/core/data-source-manager/src/types.ts b/packages/core/data-source-manager/src/types.ts index 61cb57f334..bd865741c7 100644 --- a/packages/core/data-source-manager/src/types.ts +++ b/packages/core/data-source-manager/src/types.ts @@ -7,6 +7,8 @@ export type CollectionOptions = { export interface ICollection { repository: any; + updateOptions(options: any): void; + setField(name: string, options: any): void; [key: string]: any; } export interface IModel { @@ -36,11 +38,13 @@ export interface ICollectionManager { getRegisteredRepository(key: string): IRepository; defineCollection(options: CollectionOptions): ICollection; + extendCollection(collectionOptions: CollectionOptions, mergeOptions?: MergeOptions): ICollection; hasCollection(name: string): boolean; getCollection(name: string): ICollection; + getCollections(): Array; getRepository(name: string, sourceId?: string | number): R; sync(): Promise; } diff --git a/packages/plugins/@nocobase/plugin-data-source-manager/src/server/__tests__/data-sources.test.ts b/packages/plugins/@nocobase/plugin-data-source-manager/src/server/__tests__/data-sources.test.ts index b09c346e99..1e27b2475e 100644 --- a/packages/plugins/@nocobase/plugin-data-source-manager/src/server/__tests__/data-sources.test.ts +++ b/packages/plugins/@nocobase/plugin-data-source-manager/src/server/__tests__/data-sources.test.ts @@ -44,57 +44,85 @@ describe('data source', async () => { expect(mockDataSource).toBeInstanceOf(MockDataSource); }); - it('should get collections from datasource', async () => { - const loadFn = vi.fn(); + describe('data source collections', () => { + beforeEach(async () => { + class MockCollectionManager extends CollectionManager {} + class MockDataSource extends DataSource { + async load(): Promise { + this.collectionManager.defineCollection({ + name: 'posts', + fields: [ + { + type: 'string', + name: 'title', + }, + { + type: 'hasMany', + name: 'comments', + }, + ], + }); - class MockCollectionManager extends CollectionManager {} - class MockDataSource extends DataSource { - async load(): Promise { - this.collectionManager.defineCollection({ - name: 'mock', - fields: [ - { - type: 'string', - name: 'title', - }, - ], - }); + this.collectionManager.defineCollection({ + name: 'comments', + fields: [ + { + type: 'string', + name: 'content', + }, + { + type: 'belongsTo', + name: 'post', + }, + ], + }); + } - this.collectionManager.defineCollection({ - name: 'mock2', - fields: [ - { - type: 'string', - name: 'title', - }, - ], - }); + createCollectionManager(options?: any) { + return new MockCollectionManager(); + } } - createCollectionManager(options?: any) { - return new MockCollectionManager(); - } - } + app.dataSourceManager.factory.register('mock', MockDataSource); - app.dataSourceManager.factory.register('mock', MockDataSource); - - await app.db.getRepository('dataSources').create({ - values: { - key: 'mockInstance1', - type: 'mock', - displayName: 'Mock', - options: {}, - }, + await app.db.getRepository('dataSources').create({ + values: { + key: 'mockInstance1', + type: 'mock', + displayName: 'Mock', + options: {}, + }, + }); }); - const listResp = await app.agent().resource('dataSources').list(); - expect(listResp.status).toBe(200); + it('should get collections from datasource', async () => { + const listResp = await app.agent().resource('dataSources').list(); + expect(listResp.status).toBe(200); - // get collections - const collectionsResp = await app.agent().resource('dataSources.collections', 'mockInstance1').list(); - expect(collectionsResp.status).toBe(200); - const data = collectionsResp.body.data; + // get collections + const collectionsResp = await app.agent().resource('dataSources.collections', 'mockInstance1').list(); + expect(collectionsResp.status).toBe(200); + const data = collectionsResp.body.data; - expect(data.length).toBe(2); + expect(data.length).toBe(2); + }); + + it('should edit datasource collections', async () => { + // edit collections + const editResp = await app + .agent() + .resource('dataSources.collections', 'mockInstance1.posts') + .update({ + values: { + title: '标题 Collection', + }, + }); + + expect(editResp.status).toBe(200); + + const dataSource = app.dataSourceManager.dataSources.get('mockInstance1'); + const collection = dataSource.collectionManager.getCollection('posts'); + expect(collection.options.title).toBe('标题 Collection'); + }); }); }); diff --git a/packages/plugins/@nocobase/plugin-data-source-manager/src/server/models/data-source.ts b/packages/plugins/@nocobase/plugin-data-source-manager/src/server/models/data-source.ts index ffcb5264ec..95b1dc238d 100644 --- a/packages/plugins/@nocobase/plugin-data-source-manager/src/server/models/data-source.ts +++ b/packages/plugins/@nocobase/plugin-data-source-manager/src/server/models/data-source.ts @@ -11,6 +11,7 @@ export class DataSourceModel extends MagicAttributeModel { ...createOptions, name: this.get('key'), }); + await app.dataSourceManager.add(instance); } } diff --git a/packages/plugins/@nocobase/plugin-data-source-manager/src/server/models/remote-collection-model.ts b/packages/plugins/@nocobase/plugin-data-source-manager/src/server/models/remote-collection-model.ts index 81116ee6bc..399d37c244 100644 --- a/packages/plugins/@nocobase/plugin-data-source-manager/src/server/models/remote-collection-model.ts +++ b/packages/plugins/@nocobase/plugin-data-source-manager/src/server/models/remote-collection-model.ts @@ -6,10 +6,9 @@ export class RemoteCollectionModel extends MagicAttributeModel { const { app } = loadOptions; const collectionOptions = this.get(); - const databaseName = this.get('connectionName'); - const database = app.getDb(databaseName); - const collectionName = this.get('name'); - const collection = database.getCollection(collectionName); + const dataSourceName = this.get('dataSourceKey'); + const dataSource = app.dataSourceManager.dataSources.get(dataSourceName); + const collection = dataSource.collectionManager.getCollection(collectionOptions.name); collection.updateOptions(collectionOptions); } } diff --git a/packages/plugins/@nocobase/plugin-data-source-manager/src/server/plugin.ts b/packages/plugins/@nocobase/plugin-data-source-manager/src/server/plugin.ts index d49ff6beb5..eed6cd83d1 100644 --- a/packages/plugins/@nocobase/plugin-data-source-manager/src/server/plugin.ts +++ b/packages/plugins/@nocobase/plugin-data-source-manager/src/server/plugin.ts @@ -155,7 +155,7 @@ export class PluginDataSourceManagerServer extends Plugin { }); }); - this.app.db.on('remoteCollections.afterSave', async (model: RemoteCollectionModel) => { + this.app.db.on('dataSourcesCollections.afterSave', async (model: RemoteCollectionModel) => { model.load({ app: this.app, }); diff --git a/packages/plugins/@nocobase/plugin-data-source-manager/src/server/resourcers/data-sources-collections.ts b/packages/plugins/@nocobase/plugin-data-source-manager/src/server/resourcers/data-sources-collections.ts index 4d76861f0e..acca69503a 100644 --- a/packages/plugins/@nocobase/plugin-data-source-manager/src/server/resourcers/data-sources-collections.ts +++ b/packages/plugins/@nocobase/plugin-data-source-manager/src/server/resourcers/data-sources-collections.ts @@ -47,31 +47,32 @@ export default { async update(ctx, next) { const params = ctx.action.params; - const { filterByTk: name } = params; - const databaseName = ctx.get('x-database'); + const { filterByTk: name, associatedIndex: collectionWithDataSource } = params; - let remoteCollectionRecord = await ctx.db.getRepository('remoteCollections').findOne({ + const [dataSourceKey, collectionName] = collectionWithDataSource.split('.'); + + let dataSourceCollectionRecord = await ctx.db.getRepository('dataSourcesCollections').findOne({ filter: { - name, - connectionName: databaseName, + name: collectionName, + dataSourceKey, }, }); - if (!remoteCollectionRecord) { - remoteCollectionRecord = await ctx.db.getRepository('remoteCollections').create({ + if (!dataSourceCollectionRecord) { + dataSourceCollectionRecord = await ctx.db.getRepository('dataSourcesCollections').create({ values: { ...params.values, - name, - connectionName: databaseName, + name: collectionName, + dataSourceKey, }, }); } else { - await remoteCollectionRecord.update({ + await dataSourceCollectionRecord.update({ ...params.values, }); } - ctx.body = remoteCollectionRecord.toJSON(); + ctx.body = dataSourceCollectionRecord.toJSON(); await next(); },