Skip to content

Commit b65ee6a

Browse files
authoredApr 24, 2024
fix: update belongs to many association that target key is not primary key (nocobase#4146)
1 parent 5c7004f commit b65ee6a

File tree

4 files changed

+169
-8
lines changed

4 files changed

+169
-8
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { Database, mockDatabase } from '@nocobase/database';
2+
3+
describe('association target key', async () => {
4+
let db: Database;
5+
6+
beforeEach(async () => {
7+
db = mockDatabase();
8+
9+
await db.clean({ drop: true });
10+
});
11+
12+
afterEach(async () => {
13+
await db.close();
14+
});
15+
16+
describe('belongs to many', async () => {
17+
let Post;
18+
let Tag;
19+
beforeEach(async () => {
20+
Post = db.collection({
21+
name: 'posts',
22+
fields: [
23+
{ type: 'string', name: 'title' },
24+
{ type: 'string', name: 'content' },
25+
{
26+
type: 'belongsToMany',
27+
name: 'tags',
28+
target: 'tags',
29+
through: 'posts_tags',
30+
sourceKey: 'id',
31+
foreignKey: 'post_id',
32+
otherKey: 'tag_name',
33+
targetKey: 'name',
34+
},
35+
],
36+
});
37+
38+
Tag = db.collection({
39+
name: 'tags',
40+
fields: [{ type: 'string', name: 'name', unique: true }],
41+
});
42+
43+
await db.sync({
44+
force: true,
45+
});
46+
});
47+
48+
it('should set with association', async () => {
49+
await Post.repository.create({
50+
values: {
51+
title: 'post1',
52+
tags: [{ name: 'tag1' }, { name: 'tag2' }],
53+
},
54+
});
55+
56+
const post1 = await Post.repository.findOne({
57+
filter: {
58+
title: 'post1',
59+
},
60+
appends: ['tags'],
61+
});
62+
63+
expect(post1.tags.length).toBe(2);
64+
});
65+
66+
it('should create with association', async () => {
67+
await Tag.repository.create({
68+
values: [
69+
{
70+
name: 'tag1',
71+
},
72+
{
73+
name: 'tag2',
74+
},
75+
],
76+
});
77+
78+
await Post.repository.create({
79+
values: {
80+
title: 'post1',
81+
tags: [{ name: 'tag1' }, { name: 'tag2' }],
82+
},
83+
});
84+
85+
const post1 = await Post.repository.findOne({
86+
filter: {
87+
title: 'post1',
88+
},
89+
appends: ['tags'],
90+
});
91+
92+
expect(post1.tags.length).toBe(2);
93+
});
94+
});
95+
});

‎packages/core/database/src/__tests__/update-guard.test.ts

+65-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ describe('update-guard', () => {
99
let User: Collection;
1010
let Post: Collection;
1111
let Comment: Collection;
12+
let Tag: Collection;
1213

1314
beforeEach(async () => {
1415
db = mockDatabase();
@@ -20,6 +21,16 @@ describe('update-guard', () => {
2021
{ type: 'string', name: 'name' },
2122
{ type: 'integer', name: 'age' },
2223
{ type: 'hasMany', name: 'posts' },
24+
{
25+
type: 'belongsToMany',
26+
name: 'tags',
27+
target: 'tags',
28+
through: 'users_tags',
29+
sourceKey: 'id',
30+
foreignKey: 'userId',
31+
otherKey: 'tagName',
32+
targetKey: 'name',
33+
},
2334
],
2435
});
2536

@@ -48,29 +59,61 @@ describe('update-guard', () => {
4859
],
4960
});
5061

62+
Tag = db.collection({
63+
name: 'tags',
64+
fields: [{ type: 'string', name: 'name', unique: true }],
65+
});
66+
5167
await db.sync({
5268
force: true,
5369
alter: { drop: false },
5470
});
5571

5672
const repository = User.repository;
5773

58-
await repository.createMany({
59-
records: [
74+
await repository.create({
75+
values: [
6076
{
6177
name: 'u1',
6278
age: 10,
6379
posts: [{ title: 'u1t1', comments: [{ content: 'u1t1c1' }] }],
80+
tags: [
81+
{
82+
name: 't1',
83+
},
84+
{
85+
name: 't2',
86+
},
87+
],
6488
},
6589
{
6690
name: 'u2',
6791
age: 20,
6892
posts: [{ title: 'u2t1', comments: [{ content: 'u2t1c1' }] }],
93+
tags: [
94+
{
95+
name: 't1',
96+
},
97+
{
98+
name: 't2',
99+
},
100+
],
69101
},
70102
{
71103
name: 'u3',
72104
age: 30,
73105
posts: [{ title: 'u3t1', comments: [{ content: 'u3t1c1' }] }],
106+
tags: [
107+
{
108+
name: 't1',
109+
},
110+
{
111+
name: 't2',
112+
},
113+
{
114+
name: 't3',
115+
},
116+
],
74117
},
75118
],
76119
});
@@ -80,6 +123,26 @@ describe('update-guard', () => {
80123
await db.close();
81124
});
82125

126+
test('association values', async () => {
127+
const values = {
128+
name: 'u1',
129+
tags: [
130+
{
131+
name: 't1',
132+
},
133+
{
134+
name: 't2',
135+
},
136+
],
137+
};
138+
139+
const guard = new UpdateGuard();
140+
guard.setModel(User.model);
141+
142+
const sanitized = guard.sanitize(values);
143+
console.log(sanitized);
144+
});
145+
83146
test('white list', () => {
84147
const values = {
85148
name: '123',

‎packages/core/database/src/update-associations.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,11 @@ export async function updateMultipleAssociation(
442442
const targetKey = (association as any).targetKey || 'id';
443443

444444
if (item[targetKey]) {
445-
setItems.push(item[targetKey]);
445+
const attributes = {
446+
[targetKey]: item[targetKey],
447+
};
448+
const instance = association.target.build(attributes, { isNewRecord: false });
449+
setItems.push(instance);
446450
}
447451

448452
objectItems.push(item);
@@ -511,7 +515,7 @@ export async function updateMultipleAssociation(
511515
}
512516
const addAccessor = association.accessors.add;
513517

514-
await model[addAccessor](instance[association.target.primaryKeyAttribute], accessorOptions);
518+
await model[addAccessor](instance, accessorOptions);
515519

516520
if (!recursive) {
517521
continue;

‎packages/core/database/src/update-guard.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,9 @@ export class UpdateGuard {
148148
return value;
149149
}
150150

151-
const associationKeyName =
152-
associationObj.associationType == 'BelongsTo' || associationObj.associationType == 'HasOne'
153-
? (<any>associationObj).targetKey
154-
: associationObj.target.primaryKeyAttribute;
151+
const associationKeyName = (<any>associationObj).targetKey
152+
? (<any>associationObj).targetKey
153+
: associationObj.target.primaryKeyAttribute;
155154

156155
if (value[associationKeyName]) {
157156
return lodash.pick(value, [associationKeyName, ...Object.keys(associationObj.target.associations)]);

0 commit comments

Comments
 (0)
Please sign in to comment.