Merge branch 'main' into next

This commit is contained in:
nocobase[bot] 2024-10-28 02:20:05 +00:00
commit 75adb3f865
2 changed files with 102 additions and 37 deletions

View File

@ -570,4 +570,46 @@ describe('tree path test', () => {
// await treeCollection.removeFromDb(); // await treeCollection.removeFromDb();
// expect(await db.getCollection(name).existsInDb()).toBeFalsy(); // expect(await db.getCollection(name).existsInDb()).toBeFalsy();
// }) // })
it('should update paths when remove children', async () => {
const data = await treeCollection.repository.create({
values: {
name: 'a1',
children: [
{
name: 'b1',
},
{
name: 'b2',
},
],
},
});
const b1 = data.get('children')[0];
const b2 = data.get('children')[1];
const tks = [b1.get(treeCollection.filterTargetKey), b2.get(treeCollection.filterTargetKey)];
const paths = await db.getRepository(name).find({
filter: {
[nodePkColumnName]: {
$in: tks,
},
},
});
expect(paths.length).toBe(2);
expect(paths[0].get('path')).toBe('/1/2');
expect(paths[1].get('path')).toBe('/1/3');
// @ts-ignore
await db.getRepository(`${treeCollection.name}.children`, data.get(treeCollection.filterTargetKey)).remove(tks);
const paths2 = await db.getRepository(name).find({
filter: {
[nodePkColumnName]: {
$in: tks,
},
},
});
console.log(paths2);
expect(paths2.length).toBe(2);
expect(paths2[0].get('path')).toBe('/2');
expect(paths2[1].get('path')).toBe('/3');
});
}); });

View File

@ -14,11 +14,6 @@ import lodash from 'lodash';
import { Transaction } from 'sequelize'; import { Transaction } from 'sequelize';
import { TreeCollection } from './tree-collection'; import { TreeCollection } from './tree-collection';
const getFilterTargetKey = (model: Model) => {
// @ts-ignore
return model.constructor.collection.filterTargetKey;
};
class PluginCollectionTreeServer extends Plugin { class PluginCollectionTreeServer extends Plugin {
async beforeLoad() { async beforeLoad() {
const condition = (options) => { const condition = (options) => {
@ -55,7 +50,7 @@ class PluginCollectionTreeServer extends Plugin {
//afterCreate //afterCreate
this.db.on(`${collection.name}.afterCreate`, async (model: Model, options) => { this.db.on(`${collection.name}.afterCreate`, async (model: Model, options) => {
const { transaction } = options; const { transaction } = options;
const tk = getFilterTargetKey(model); const tk = collection.filterTargetKey;
let path = `/${model.get(tk)}`; let path = `/${model.get(tk)}`;
path = await this.getTreePath(model, path, collection, name, transaction); path = await this.getTreePath(model, path, collection, name, transaction);
const rootPk = path.split('/')[1]; const rootPk = path.split('/')[1];
@ -71,49 +66,35 @@ class PluginCollectionTreeServer extends Plugin {
//afterUpdate //afterUpdate
this.db.on(`${collection.name}.afterUpdate`, async (model: Model, options) => { this.db.on(`${collection.name}.afterUpdate`, async (model: Model, options) => {
const tk = getFilterTargetKey(model); const tk = collection.filterTargetKey;
// only update parentId and filterTargetKey // only update parentId and filterTargetKey
if (!(model._changed.has(tk) || model._changed.has(parentForeignKey))) { if (!(model._changed.has(tk) || model._changed.has(parentForeignKey))) {
return; return;
} }
const { transaction } = options; const { transaction } = options;
let path = `/${model.get(tk)}`; await this.updateTreePath(model, collection, name, transaction);
path = await this.getTreePath(model, path, collection, name, transaction); });
const collectionTreePath = this.db.getCollection(name);
const nodePkColumnName = collectionTreePath.getField('nodePk').columnName();
const pathData = await this.app.db.getRepository(name).findOne({
filter: {
[nodePkColumnName]: model.get(tk),
},
transaction,
});
const relatedNodes = await this.app.db.getRepository(name).find({ // after remove
filter: { this.db.on(`${collection.name}.afterBulkUpdate`, async (options) => {
path: { const tk = collection.filterTargetKey;
$startsWith: `${pathData.get('path')}`, if (!(options.where && options.where[tk])) {
}, return;
}
const instances = await this.db.getRepository(collection.name).find({
where: {
[tk]: options.where[tk],
}, },
transaction, transaction: options.transaction,
}); });
const rootPk = path.split('/')[1]; for (const model of instances) {
for (const node of relatedNodes) { await this.updateTreePath(model, collection, name, options.transaction);
await this.app.db.getRepository(name).update({
values: {
path: node.get('path').replace(`${pathData.get('path')}`, path),
rootPk: rootPk ? Number(rootPk) : null,
},
filter: {
[nodePkColumnName]: node.get('nodePk'),
},
transaction,
});
} }
}); });
//afterDestroy //afterDestroy
this.db.on(`${collection.name}.afterDestroy`, async (model: Model, options: DestroyOptions) => { this.db.on(`${collection.name}.afterDestroy`, async (model: Model, options: DestroyOptions) => {
const tk = getFilterTargetKey(model); const tk = collection.filterTargetKey;
await this.app.db.getRepository(name).destroy({ await this.app.db.getRepository(name).destroy({
filter: { filter: {
nodePk: model.get(tk), nodePk: model.get(tk),
@ -164,7 +145,7 @@ class PluginCollectionTreeServer extends Plugin {
pathCollectionName: string, pathCollectionName: string,
transaction?: Transaction, transaction?: Transaction,
) { ) {
const tk = getFilterTargetKey(model); const tk = collection.filterTargetKey;
const parentForeignKey = collection.treeParentField?.foreignKey || 'parentId'; const parentForeignKey = collection.treeParentField?.foreignKey || 'parentId';
if (model.get(parentForeignKey) && model.get(parentForeignKey) !== null) { if (model.get(parentForeignKey) && model.get(parentForeignKey) !== null) {
const parent = await this.app.db.getRepository(collection.name).findOne({ const parent = await this.app.db.getRepository(collection.name).findOne({
@ -195,6 +176,48 @@ class PluginCollectionTreeServer extends Plugin {
} }
return path; return path;
} }
private async updateTreePath(
model: Model,
collection: Collection,
pathCollectionName: string,
transaction: Transaction,
) {
const tk = collection.filterTargetKey;
let path = `/${model.get(tk)}`;
path = await this.getTreePath(model, path, collection, pathCollectionName, transaction);
const collectionTreePath = this.db.getCollection(pathCollectionName);
const nodePkColumnName = collectionTreePath.getField('nodePk').columnName();
const pathData = await this.app.db.getRepository(pathCollectionName).findOne({
filter: {
[nodePkColumnName]: model.get(tk),
},
transaction,
});
const relatedNodes = await this.app.db.getRepository(pathCollectionName).find({
filter: {
path: {
$startsWith: `${pathData.get('path')}`,
},
},
transaction,
});
const rootPk = path.split('/')[1];
for (const node of relatedNodes) {
const newPath = node.get('path').replace(pathData.get('path'), path);
await this.app.db.getRepository(pathCollectionName).update({
values: {
path: newPath,
rootPk: rootPk ? Number(rootPk) : null,
},
filter: {
[nodePkColumnName]: node.get('nodePk'),
},
transaction,
});
}
}
} }
export default PluginCollectionTreeServer; export default PluginCollectionTreeServer;