mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 09:47:10 +00:00
Fix: change strategy from add to set for updateAssociations (#33)
* test: add belongsTo case * fix: change update strategy from add to set
This commit is contained in:
parent
0a0d09119b
commit
05f815655f
@ -237,6 +237,22 @@ describe('model', () => {
|
|||||||
const authorizedPost = await Post.findByPk(post.id);
|
const authorizedPost = await Post.findByPk(post.id);
|
||||||
expect(authorizedPost.user_id).toBe(user.id);
|
expect(authorizedPost.user_id).toBe(user.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('update with exist model', async () => {
|
||||||
|
const [User, Post] = db.getModels(['users', 'posts']);
|
||||||
|
const user1 = await User.create();
|
||||||
|
const user2 = await Post.create();
|
||||||
|
const post = await Post.create();
|
||||||
|
await post.updateAssociations({
|
||||||
|
user: user1.id
|
||||||
|
});
|
||||||
|
await post.updateAssociations({
|
||||||
|
user: user2.id
|
||||||
|
});
|
||||||
|
|
||||||
|
const authorizedPost = await Post.findByPk(post.id);
|
||||||
|
expect(authorizedPost.user_id).toBe(user2.id);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hasMany', () => {
|
describe('hasMany', () => {
|
||||||
@ -368,6 +384,26 @@ describe('model', () => {
|
|||||||
{ id: 4, content: 'content4' }
|
{ id: 4, content: 'content4' }
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('update with different primaryKey/row/object', async () => {
|
||||||
|
const [Post, Comment] = db.getModels(['posts', 'comments']);
|
||||||
|
const post = await Post.create();
|
||||||
|
const comments = await Comment.bulkCreate([{}, {}, {}, {}]);
|
||||||
|
await post.updateAssociations({
|
||||||
|
comments
|
||||||
|
});
|
||||||
|
await post.updateAssociations({
|
||||||
|
comments: comments
|
||||||
|
.filter(({ id }) => Boolean(id % 2))
|
||||||
|
.concat(...[await Comment.create()])
|
||||||
|
});
|
||||||
|
|
||||||
|
const postComments = await Comment.findAll({
|
||||||
|
where: { post_id: post.id },
|
||||||
|
attributes: ['id']
|
||||||
|
});
|
||||||
|
expect(postComments.map(({ id }) => id)).toEqual([1,3,5]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('belongsToMany', () => {
|
describe('belongsToMany', () => {
|
||||||
@ -410,6 +446,23 @@ describe('model', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('update with exist rows/primaryKeys and new objects', async () => {
|
||||||
|
const [Post, Tag, PostTag] = db.getModels(['posts', 'tags', 'posts_tags']);
|
||||||
|
const post = await Post.create();
|
||||||
|
const tags = await Tag.bulkCreate([{}, {}, {}, {}]);
|
||||||
|
await post.updateAssociations({
|
||||||
|
tags: tags.map(item => item.id)
|
||||||
|
});
|
||||||
|
await post.updateAssociations({
|
||||||
|
tags: tags.filter(({ id }) => Boolean(id % 2)).concat(await Tag.create({}))
|
||||||
|
});
|
||||||
|
const tagged = await PostTag.findAll({
|
||||||
|
where: { post_id: post.id },
|
||||||
|
attributes: ['tag_id']
|
||||||
|
});
|
||||||
|
expect(tagged.map(({ tag_id }) => tag_id)).toEqual([1,3,5]);
|
||||||
|
});
|
||||||
|
|
||||||
it('update other with exist rows/primaryKeys', async () => {
|
it('update other with exist rows/primaryKeys', async () => {
|
||||||
const [Post, Tag, PostTag] = db.getModels(['posts', 'tags', 'posts_tags']);
|
const [Post, Tag, PostTag] = db.getModels(['posts', 'tags', 'posts_tags']);
|
||||||
const post = await Post.create();
|
const post = await Post.create();
|
||||||
|
@ -320,8 +320,8 @@ export abstract class Model extends SequelizeModel {
|
|||||||
// 准备设置的关联主键
|
// 准备设置的关联主键
|
||||||
const toSetPks = new Set();
|
const toSetPks = new Set();
|
||||||
const toSetUks = new Set();
|
const toSetUks = new Set();
|
||||||
// 筛选后准备添加的关联主键
|
// 筛选后准备设置的关联主键
|
||||||
const toAddItems = new Set();
|
const toSetItems = new Set();
|
||||||
// 准备添加的关联对象
|
// 准备添加的关联对象
|
||||||
const toUpsertObjects = [];
|
const toUpsertObjects = [];
|
||||||
|
|
||||||
@ -358,9 +358,10 @@ export abstract class Model extends SequelizeModel {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/* 仅传关联键处理开始 */
|
/* 仅传关联键处理开始 */
|
||||||
// 查找已存在的关联数据
|
// 查找已存在的数据
|
||||||
const byPkExistItems = toSetPks.size ? await this[accessors.get]({
|
const byPkExistItems = toSetPks.size ? await Target.findAll({
|
||||||
...opts,
|
...opts,
|
||||||
|
// @ts-ignore
|
||||||
where: {
|
where: {
|
||||||
[targetPk]: {
|
[targetPk]: {
|
||||||
[Op.in]: Array.from(toSetPks)
|
[Op.in]: Array.from(toSetPks)
|
||||||
@ -368,36 +369,11 @@ export abstract class Model extends SequelizeModel {
|
|||||||
},
|
},
|
||||||
attributes: [targetPk]
|
attributes: [targetPk]
|
||||||
}) : [];
|
}) : [];
|
||||||
const pkExistItems = new Map();
|
|
||||||
byPkExistItems.forEach(item => {
|
byPkExistItems.forEach(item => {
|
||||||
pkExistItems.set(item[targetPk], item);
|
toSetItems.add(item);
|
||||||
});
|
});
|
||||||
for (const key of toSetPks) {
|
|
||||||
if (!pkExistItems.has(key)) {
|
|
||||||
toAddItems.add(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const byUkExistItems = await this[accessors.get]({
|
const byUkExistItems = toSetUks.size ? await Target.findAll({
|
||||||
...opts,
|
|
||||||
where: {
|
|
||||||
[targetKey]: {
|
|
||||||
[Op.in]: Array.from(toSetUks)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
attributes: [targetPk, targetKey],
|
|
||||||
transaction
|
|
||||||
});
|
|
||||||
const ukExistItems = new Map();
|
|
||||||
byUkExistItems.forEach(item => {
|
|
||||||
ukExistItems.set(item[targetKey], item);
|
|
||||||
});
|
|
||||||
for (const key of toSetUks) {
|
|
||||||
if (ukExistItems.has(key)) {
|
|
||||||
toSetUks.delete(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const byUkItems = toSetUks.size ? await Target.findAll({
|
|
||||||
...opts,
|
...opts,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
where: {
|
where: {
|
||||||
@ -407,11 +383,12 @@ export abstract class Model extends SequelizeModel {
|
|||||||
},
|
},
|
||||||
attributes: [targetPk, targetKey]
|
attributes: [targetPk, targetKey]
|
||||||
}) : [];
|
}) : [];
|
||||||
byUkItems.forEach(item => {
|
byUkExistItems.forEach(item => {
|
||||||
toAddItems.add(item);
|
toSetItems.add(item);
|
||||||
});
|
});
|
||||||
/* 仅传关联键处理结束 */
|
/* 仅传关联键处理结束 */
|
||||||
|
|
||||||
|
const belongsToManyList = [];
|
||||||
/* 值为对象处理开始 */
|
/* 值为对象处理开始 */
|
||||||
for (const item of toUpsertObjects) {
|
for (const item of toUpsertObjects) {
|
||||||
let target;
|
let target;
|
||||||
@ -431,10 +408,26 @@ export abstract class Model extends SequelizeModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (association instanceof BelongsToMany) {
|
if (association instanceof BelongsToMany) {
|
||||||
// TODO(optimize): 这里暂时未能批量执行
|
belongsToManyList.push({
|
||||||
await this[accessors.add](target, opts);
|
item,
|
||||||
const ThroughModel = association.getThroughModel();
|
target
|
||||||
const throughName = association.getThroughName();
|
});
|
||||||
|
}
|
||||||
|
toSetItems.add(target);
|
||||||
|
|
||||||
|
await target.updateAssociations(item, opts);
|
||||||
|
}
|
||||||
|
/* 值为对象处理结束 */
|
||||||
|
|
||||||
|
// 添加所有计算后的关联
|
||||||
|
await this[accessors.set](Array.from(toSetItems), opts);
|
||||||
|
|
||||||
|
// 后处理 belongsToMany 的更新内容
|
||||||
|
if (belongsToManyList.length) {
|
||||||
|
const ThroughModel = (association as BelongsToMany).getThroughModel();
|
||||||
|
const throughName = (association as BelongsToMany).getThroughName();
|
||||||
|
|
||||||
|
for (const { item, target } of belongsToManyList) {
|
||||||
const throughValues = item[throughName];
|
const throughValues = item[throughName];
|
||||||
if (typeof throughValues === 'object') {
|
if (typeof throughValues === 'object') {
|
||||||
const { foreignKey, sourceKey, otherKey } = association.options;
|
const { foreignKey, sourceKey, otherKey } = association.options;
|
||||||
@ -448,16 +441,8 @@ export abstract class Model extends SequelizeModel {
|
|||||||
await through.update(throughValues, opts);
|
await through.update(throughValues, opts);
|
||||||
await through.updateAssociations(throughValues, opts);
|
await through.updateAssociations(throughValues, opts);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
toAddItems.add(target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await target.updateAssociations(item, opts);
|
|
||||||
}
|
}
|
||||||
/* 值为对象处理结束 */
|
|
||||||
|
|
||||||
// 添加所有计算后的关联
|
|
||||||
await this[accessors.add](Array.from(toAddItems), opts);
|
|
||||||
|
|
||||||
if (!options.transaction) {
|
if (!options.transaction) {
|
||||||
await transaction.commit();
|
await transaction.commit();
|
||||||
|
Loading…
Reference in New Issue
Block a user