diff --git a/packages/core/database/src/__tests__/associations/target-key.test.ts b/packages/core/database/src/__tests__/associations/target-key.test.ts new file mode 100644 index 0000000000..70e16f6956 --- /dev/null +++ b/packages/core/database/src/__tests__/associations/target-key.test.ts @@ -0,0 +1,95 @@ +import { Database, mockDatabase } from '@nocobase/database'; + +describe('association target key', async () => { + let db: Database; + + beforeEach(async () => { + db = mockDatabase(); + + await db.clean({ drop: true }); + }); + + afterEach(async () => { + await db.close(); + }); + + describe('belongs to many', async () => { + let Post; + let Tag; + beforeEach(async () => { + Post = db.collection({ + name: 'posts', + fields: [ + { type: 'string', name: 'title' }, + { type: 'string', name: 'content' }, + { + type: 'belongsToMany', + name: 'tags', + target: 'tags', + through: 'posts_tags', + sourceKey: 'id', + foreignKey: 'post_id', + otherKey: 'tag_name', + targetKey: 'name', + }, + ], + }); + + Tag = db.collection({ + name: 'tags', + fields: [{ type: 'string', name: 'name', unique: true }], + }); + + await db.sync({ + force: true, + }); + }); + + it('should set with association', async () => { + await Post.repository.create({ + values: { + title: 'post1', + tags: [{ name: 'tag1' }, { name: 'tag2' }], + }, + }); + + const post1 = await Post.repository.findOne({ + filter: { + title: 'post1', + }, + appends: ['tags'], + }); + + expect(post1.tags.length).toBe(2); + }); + + it('should create with association', async () => { + await Tag.repository.create({ + values: [ + { + name: 'tag1', + }, + { + name: 'tag2', + }, + ], + }); + + await Post.repository.create({ + values: { + title: 'post1', + tags: [{ name: 'tag1' }, { name: 'tag2' }], + }, + }); + + const post1 = await Post.repository.findOne({ + filter: { + title: 'post1', + }, + appends: ['tags'], + }); + + expect(post1.tags.length).toBe(2); + }); + }); +}); diff --git a/packages/core/database/src/__tests__/update-guard.test.ts b/packages/core/database/src/__tests__/update-guard.test.ts index 322b6f4994..96dda9823e 100644 --- a/packages/core/database/src/__tests__/update-guard.test.ts +++ b/packages/core/database/src/__tests__/update-guard.test.ts @@ -9,6 +9,7 @@ describe('update-guard', () => { let User: Collection; let Post: Collection; let Comment: Collection; + let Tag: Collection; beforeEach(async () => { db = mockDatabase(); @@ -20,6 +21,16 @@ describe('update-guard', () => { { type: 'string', name: 'name' }, { type: 'integer', name: 'age' }, { type: 'hasMany', name: 'posts' }, + { + type: 'belongsToMany', + name: 'tags', + target: 'tags', + through: 'users_tags', + sourceKey: 'id', + foreignKey: 'userId', + otherKey: 'tagName', + targetKey: 'name', + }, ], }); @@ -48,6 +59,11 @@ describe('update-guard', () => { ], }); + Tag = db.collection({ + name: 'tags', + fields: [{ type: 'string', name: 'name', unique: true }], + }); + await db.sync({ force: true, alter: { drop: false }, @@ -55,22 +71,49 @@ describe('update-guard', () => { const repository = User.repository; - await repository.createMany({ - records: [ + await repository.create({ + values: [ { name: 'u1', age: 10, posts: [{ title: 'u1t1', comments: [{ content: 'u1t1c1' }] }], + tags: [ + { + name: 't1', + }, + { + name: 't2', + }, + ], }, { name: 'u2', age: 20, posts: [{ title: 'u2t1', comments: [{ content: 'u2t1c1' }] }], + tags: [ + { + name: 't1', + }, + { + name: 't2', + }, + ], }, { name: 'u3', age: 30, posts: [{ title: 'u3t1', comments: [{ content: 'u3t1c1' }] }], + tags: [ + { + name: 't1', + }, + { + name: 't2', + }, + { + name: 't3', + }, + ], }, ], }); @@ -80,6 +123,26 @@ describe('update-guard', () => { await db.close(); }); + test('association values', async () => { + const values = { + name: 'u1', + tags: [ + { + name: 't1', + }, + { + name: 't2', + }, + ], + }; + + const guard = new UpdateGuard(); + guard.setModel(User.model); + + const sanitized = guard.sanitize(values); + console.log(sanitized); + }); + test('white list', () => { const values = { name: '123', diff --git a/packages/core/database/src/update-associations.ts b/packages/core/database/src/update-associations.ts index 3076bc9cec..12e83082a0 100644 --- a/packages/core/database/src/update-associations.ts +++ b/packages/core/database/src/update-associations.ts @@ -442,7 +442,11 @@ export async function updateMultipleAssociation( const targetKey = (association as any).targetKey || 'id'; if (item[targetKey]) { - setItems.push(item[targetKey]); + const attributes = { + [targetKey]: item[targetKey], + }; + const instance = association.target.build(attributes, { isNewRecord: false }); + setItems.push(instance); } objectItems.push(item); @@ -511,7 +515,7 @@ export async function updateMultipleAssociation( } const addAccessor = association.accessors.add; - await model[addAccessor](instance[association.target.primaryKeyAttribute], accessorOptions); + await model[addAccessor](instance, accessorOptions); if (!recursive) { continue; diff --git a/packages/core/database/src/update-guard.ts b/packages/core/database/src/update-guard.ts index a8603758e7..7b72af184b 100644 --- a/packages/core/database/src/update-guard.ts +++ b/packages/core/database/src/update-guard.ts @@ -148,10 +148,9 @@ export class UpdateGuard { return value; } - const associationKeyName = - associationObj.associationType == 'BelongsTo' || associationObj.associationType == 'HasOne' - ? (associationObj).targetKey - : associationObj.target.primaryKeyAttribute; + const associationKeyName = (associationObj).targetKey + ? (associationObj).targetKey + : associationObj.target.primaryKeyAttribute; if (value[associationKeyName]) { return lodash.pick(value, [associationKeyName, ...Object.keys(associationObj.target.associations)]);