mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
feat(core): Update list folders endpoint to support filter excludeFolderIdAndDescendants (no-changelog) (#13880)
This commit is contained in:
@@ -29,6 +29,7 @@ export const filterSchema = z
|
||||
parentFolderId: z.string().optional(),
|
||||
name: z.string().optional(),
|
||||
tags: z.array(z.string()).optional(),
|
||||
excludeFolderIdAndDescendants: z.string().optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
|
||||
@@ -136,6 +136,13 @@ export class FolderRepository extends Repository<FolderWithWorkflowAndSubFolderC
|
||||
|
||||
this.applyBasicFilters(query, filter);
|
||||
this.applyTagsFilter(query, Array.isArray(filter?.tags) ? filter.tags : undefined);
|
||||
|
||||
if (
|
||||
filter?.excludeFolderIdAndDescendants &&
|
||||
typeof filter.excludeFolderIdAndDescendants === 'string'
|
||||
) {
|
||||
this.applyExcludeFolderFilter(query, filter.excludeFolderIdAndDescendants);
|
||||
}
|
||||
}
|
||||
|
||||
private applyBasicFilters(
|
||||
@@ -293,4 +300,38 @@ export class FolderRepository extends Repository<FolderWithWorkflowAndSubFolderC
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
private applyExcludeFolderFilter(
|
||||
query: SelectQueryBuilder<FolderWithWorkflowAndSubFolderCount>,
|
||||
excludeFolderIdAndDescendants: string,
|
||||
): void {
|
||||
// Exclude the specific folder by ID
|
||||
query.andWhere('folder.id != :excludeFolderIdAndDescendants', {
|
||||
excludeFolderIdAndDescendants,
|
||||
});
|
||||
|
||||
// Use a WITH RECURSIVE CTE to find all child folders of the excluded folder
|
||||
const baseQuery = this.createQueryBuilder('f')
|
||||
.select('f.id', 'id')
|
||||
.addSelect('f.parentFolderId', 'parentFolderId')
|
||||
.where('f.id = :excludeFolderIdAndDescendants', { excludeFolderIdAndDescendants });
|
||||
|
||||
const recursiveQuery = this.createQueryBuilder('child')
|
||||
.select('child.id', 'id')
|
||||
.addSelect('child.parentFolderId', 'parentFolderId')
|
||||
.innerJoin('folder_tree', 'parent', 'child.parentFolderId = parent.id');
|
||||
|
||||
const subQuery = this.createQueryBuilder()
|
||||
.select('tree.id')
|
||||
.addCommonTableExpression(
|
||||
`${baseQuery.getQuery()} UNION ALL ${recursiveQuery.getQuery()}`,
|
||||
'folder_tree',
|
||||
{ recursive: true },
|
||||
)
|
||||
.from('folder_tree', 'tree')
|
||||
.setParameters({ excludeFolderIdAndDescendants });
|
||||
|
||||
// Exclude all children of the specified folder
|
||||
query.andWhere(`folder.id NOT IN (${subQuery.getQuery()})`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1014,6 +1014,39 @@ describe('GET /projects/:projectId/folders', () => {
|
||||
expect(response.body.data[0].name).toBe('Folder 3');
|
||||
});
|
||||
|
||||
test('should filter folders by excludeFolderIdAndDescendants', async () => {
|
||||
const folder1 = await createFolder(ownerProject, { name: 'folder level 1' });
|
||||
await createFolder(ownerProject, {
|
||||
name: 'folder level 1.1',
|
||||
parentFolder: folder1,
|
||||
});
|
||||
const folder12 = await createFolder(ownerProject, {
|
||||
name: 'folder level 1.2',
|
||||
parentFolder: folder1,
|
||||
});
|
||||
await createFolder(ownerProject, {
|
||||
name: 'folder level 1.2.1',
|
||||
parentFolder: folder12,
|
||||
});
|
||||
const folder122 = await createFolder(ownerProject, {
|
||||
name: 'folder level 1.2.2',
|
||||
parentFolder: folder12,
|
||||
});
|
||||
await createFolder(ownerProject, {
|
||||
name: 'folder level 1.2.2.1',
|
||||
parentFolder: folder122,
|
||||
});
|
||||
|
||||
const response = await authOwnerAgent
|
||||
.get(`/projects/${ownerProject.id}/folders`)
|
||||
.query({ filter: `{ "excludeFolderIdAndDescendants": "${folder122.id}" }` });
|
||||
|
||||
expect(response.body.data.length).toBe(4);
|
||||
expect(response.body.data.map((f: any) => f.name).sort()).toEqual(
|
||||
['folder level 1', 'folder level 1.1', 'folder level 1.2.1', 'folder level 1.2'].sort(),
|
||||
);
|
||||
});
|
||||
|
||||
test('should apply pagination with take parameter', async () => {
|
||||
// Create folders with consistent timestamps
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
|
||||
Reference in New Issue
Block a user