fix: update belongs to many association that target key is not primary key (#4146)

This commit is contained in:
ChengLei Shao 2024-04-24 14:58:39 +08:00 committed by GitHub
parent 5c7004ff43
commit b65ee6a602
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 169 additions and 8 deletions

View File

@ -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);
});
});
});

View File

@ -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',

View File

@ -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;

View File

@ -148,10 +148,9 @@ export class UpdateGuard {
return value;
}
const associationKeyName =
associationObj.associationType == 'BelongsTo' || associationObj.associationType == 'HasOne'
? (<any>associationObj).targetKey
: associationObj.target.primaryKeyAttribute;
const associationKeyName = (<any>associationObj).targetKey
? (<any>associationObj).targetKey
: associationObj.target.primaryKeyAttribute;
if (value[associationKeyName]) {
return lodash.pick(value, [associationKeyName, ...Object.keys(associationObj.target.associations)]);