Merge pull request #4797 from Infisical/fix/folder-sorting

[ENG-4074] fix: folder name sorting
This commit is contained in:
Piyush Gupta
2025-11-05 22:39:23 +05:30
committed by GitHub
3 changed files with 33 additions and 21 deletions
@@ -419,13 +419,14 @@ export const secretFolderDALFactory = (db: TDbClient) => {
.select( .select(
selectAllTableCols(TableName.SecretFolder), selectAllTableCols(TableName.SecretFolder),
db.raw( db.raw(
`DENSE_RANK() OVER (ORDER BY ${TableName.SecretFolder}."name" ${ `DENSE_RANK() OVER (ORDER BY ${TableName.SecretFolder}."name" COLLATE "en-x-icu" ${orderDirection === OrderByDirection.ASC ? "ASC" : "DESC"}) as rank`
orderDirection ?? OrderByDirection.ASC
}) as rank`
), ),
db.ref("slug").withSchema(TableName.Environment).as("environment") db.ref("slug").withSchema(TableName.Environment).as("environment")
) )
.orderBy(`${TableName.SecretFolder}.${orderBy}`, orderDirection); .orderByRaw(
`${TableName.SecretFolder}.?? COLLATE "en-x-icu" ${orderDirection === OrderByDirection.ASC ? "ASC" : "DESC"}`,
[orderBy]
);
if (limit) { if (limit) {
const rankOffset = offset + 1; // ranks start from 1 const rankOffset = offset + 1; // ranks start from 1
@@ -434,7 +435,10 @@ export const secretFolderDALFactory = (db: TDbClient) => {
.select("*") .select("*")
.from<Awaited<typeof query>[number]>("w") .from<Awaited<typeof query>[number]>("w")
.where("w.rank", ">=", rankOffset) .where("w.rank", ">=", rankOffset)
.andWhere("w.rank", "<", rankOffset + limit); .andWhere("w.rank", "<", rankOffset + limit)
.orderByRaw(`"w".?? COLLATE "en-x-icu" ${orderDirection === OrderByDirection.ASC ? "ASC" : "DESC"}`, [
orderBy
]);
} }
const folders = await query; const folders = await query;
@@ -445,7 +449,10 @@ export const secretFolderDALFactory = (db: TDbClient) => {
} }
}; };
const findByEnvsDeep = async ({ parentIds }: TFindFoldersDeepByParentIdsDTO, tx?: Knex) => { const findByEnvsDeep = async (
{ parentIds, orderBy = SecretsOrderBy.Name, orderDirection = OrderByDirection.ASC }: TFindFoldersDeepByParentIdsDTO,
tx?: Knex
) => {
try { try {
const folders = await (tx || db.replicaNode()) const folders = await (tx || db.replicaNode())
.withRecursive("parents", (qb) => .withRecursive("parents", (qb) =>
@@ -480,7 +487,9 @@ export const secretFolderDALFactory = (db: TDbClient) => {
.select<(TSecretFolders & { path: string; depth: number; environment: string })[]>("*") .select<(TSecretFolders & { path: string; depth: number; environment: string })[]>("*")
.from("parents") .from("parents")
.orderBy("depth") .orderBy("depth")
.orderBy(`name`); .orderByRaw(`"parents".?? COLLATE "en-x-icu" ${orderDirection === OrderByDirection.ASC ? "ASC" : "DESC"}`, [
orderBy
]);
return folders; return folders;
} catch (error) { } catch (error) {
@@ -14,6 +14,7 @@ import { PgSqlLock } from "@app/keystore/keystore";
import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { OrderByDirection, OrgServiceActor } from "@app/lib/types"; import { OrderByDirection, OrgServiceActor } from "@app/lib/types";
import { ActorType } from "@app/services/auth/auth-type"; import { ActorType } from "@app/services/auth/auth-type";
import { SecretsOrderBy } from "@app/services/secret/secret-types";
import { buildFolderPath } from "@app/services/secret-folder/secret-folder-fns"; import { buildFolderPath } from "@app/services/secret-folder/secret-folder-fns";
import { import {
@@ -781,7 +782,11 @@ export const secretFolderServiceFactory = ({
if (!parentFolder) return []; if (!parentFolder) return [];
if (recursive) { if (recursive) {
const recursiveFolders = await folderDAL.findByEnvsDeep({ parentIds: [parentFolder.id] }); const recursiveFolders = await folderDAL.findByEnvsDeep({
parentIds: [parentFolder.id],
orderBy: orderBy || SecretsOrderBy.Name,
orderDirection: orderDirection || OrderByDirection.ASC
});
// remove the parent folder // remove the parent folder
return recursiveFolders return recursiveFolders
.filter((folder) => { .filter((folder) => {
@@ -800,19 +805,15 @@ export const secretFolderServiceFactory = ({
})); }));
} }
const folders = await folderDAL.find( const folders = await folderDAL.findByMultiEnv({
{ environmentIds: [env.id],
envId: env.id, parentIds: [parentFolder.id],
parentId: parentFolder.id, search,
isReserved: false, orderBy: orderBy || SecretsOrderBy.Name,
$search: search ? { name: `%${search}%` } : undefined orderDirection: orderDirection || OrderByDirection.ASC,
}, limit,
{ offset
sort: orderBy ? [[orderBy, orderDirection ?? OrderByDirection.ASC]] : undefined, });
limit,
offset
}
);
if (lastSecretModified) { if (lastSecretModified) {
return folders.filter((el) => return folders.filter((el) =>
el.lastSecretModified ? el.lastSecretModified >= new Date(lastSecretModified) : false el.lastSecretModified ? el.lastSecretModified >= new Date(lastSecretModified) : false
@@ -64,6 +64,8 @@ export type TGetFoldersDeepByEnvsDTO = {
export type TFindFoldersDeepByParentIdsDTO = { export type TFindFoldersDeepByParentIdsDTO = {
parentIds: string[]; parentIds: string[];
orderBy?: SecretsOrderBy;
orderDirection?: OrderByDirection;
}; };
export type TCreateManyFoldersDTO = { export type TCreateManyFoldersDTO = {