Skip to content

Commit

Permalink
feat(store): remove getNestedFileGroup (#723)
Browse files Browse the repository at this point in the history
The query builder now supports everything you ever need of the `getNestedFileGroup` function and more. Check the release notes for a migration guide.
  • Loading branch information
dirkdev98 authored Feb 24, 2021
1 parent c251c3c commit f405275
Show file tree
Hide file tree
Showing 11 changed files with 255 additions and 183 deletions.
1 change: 1 addition & 0 deletions gen/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export function applyStoreStructure(app) {
.keys({
name: T.string().optional(),
order: T.number()
.searchable()
.default("Math.floor(Date.now() / 1000000)")
.docs("Hack to get an increasing integer by default"),
meta: T.object("fileGroupMeta")
Expand Down
46 changes: 0 additions & 46 deletions packages/store/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,31 +228,6 @@ export interface FileGroup {
deletedAt: Date;
}

export interface NestedFileGroup {
id: string;
name?: string;
order: number;
meta: {};
parent?: string;
isDirectory: boolean;
file?:
| {
id: string;
bucketName?: string;
contentLength?: number;
contentType?: string;
name?: string;
createdAt?: string;
updatedAt?: string;
}
| undefined
| string;
createdAt: Date;
updatedAt: Date;
deletedAt: Date;
children?: NestedFileGroup[];
}

/**
* Assigns children of the provided fileGroup to the parent.
* Returns the affected children.
Expand All @@ -262,27 +237,6 @@ export function hoistChildrenToParent(
fileGroup: FileGroup,
): Promise<FileGroup[]>;

/**
* Update the order of the provided id's in relation to each other.
* This function does not check if all files are in the same group.
*/
export function updateFileGroupOrder(
sql: Postgres,
ids: string[],
): Promise<void>;

/**
* Return a result with nested file groups and files, sorted completely by the order id.
*/
export function getNestedFileGroups(
sql: Postgres,
where?: {
deletedAtIncludeNotNull?: boolean;
rootId?: string;
excludeFiles?: boolean;
},
): Promise<NestedFileGroup[]>;

export interface FileCacheOptions {
/**
* Maximum byte size of a file to be stored in memory
Expand Down
1 change: 0 additions & 1 deletion packages/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export {
export {
hoistChildrenToParent,
updateFileGroupOrder,
getNestedFileGroups,
} from "./src/file-group.js";

export { FileCache } from "./src/file-cache.js";
Expand Down
1 change: 1 addition & 0 deletions packages/store/migrations/008-file-group-order-idx.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CREATE INDEX "fileGroupOrderIdx" ON "fileGroup" ("order");
115 changes: 0 additions & 115 deletions packages/store/src/file-group.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { isNil } from "@compas/stdlib";
import { queries } from "./generated.js";
import { query } from "./query.js";

Expand Down Expand Up @@ -30,78 +29,6 @@ const fileGroupQueries = {

return q.exec(sql);
},

/**
* Returns a list of all files under the rootId
* If rootId is not defined, all roots are followed
*
* @param {Postgres} sql
* @param {{
* deletedAtIncludeNotNull?: boolean,
* rootId?: string,
* excludeFiles?: boolean
* }} where
* @returns {Promise<StoreFileGroupView[]>}
*/
getNestedFiles: (sql, where) => sql`
WITH
RECURSIVE
cte AS (
SELECT fgv."id",
fgv."name",
jsonb_build_object('id', fgv."file") AS "file",
fgv."parent",
fgv."order",
fgv."createdAt",
fgv."updatedAt",
fgv."deletedAt",
fgv."isDirectory",
lpad(fgv."order"::text, 8) AS "sortKey"
FROM "fileGroupView" fgv
WHERE
((coalesce(${
where?.rootId ?? null
}, NULL) IS NULL AND fgv."parent" IS NULL) OR
fgv."id" = ${where?.rootId ?? null})
AND (${
where?.deletedAtIncludeNotNull ?? false
} IS TRUE OR fgv."deletedAt" IS NULL)
UNION ALL
SELECT fgv."id",
fgv."name",
to_jsonb(file.*) AS "file",
fgv."parent",
fgv."order",
fgv."createdAt",
fgv."updatedAt",
fgv."deletedAt",
fgv."isDirectory",
concat(cte."sortKey", ':', lpad(fgv."order"::text, 8)) AS "sortKey"
FROM "fileGroupView" fgv
INNER JOIN cte ON fgv."parent" = cte.id
LEFT JOIN file ON fgv.file = file.id
WHERE
(${
where?.deletedAtIncludeNotNull ?? false
} IS TRUE OR fgv."deletedAt" IS NULL)
AND (${
where?.excludeFiles ?? false
} IS FALSE OR fgv."isDirectory" IS TRUE)
)
SELECT "id",
"name",
"file",
"parent",
"order",
"createdAt",
"updatedAt",
"deletedAt",
"isDirectory"
FROM cte
ORDER BY "sortKey";
`,
};

/**
Expand Down Expand Up @@ -135,45 +62,3 @@ export async function hoistChildrenToParent(sql, fileGroup) {
export async function updateFileGroupOrder(sql, ids) {
await fileGroupQueries.updateOrderByIds(sql, ids);
}

/**
* Return a result with nested file groups and files, sorted completely by the order id.
* Note that this will be removed when the query builder is able to use `order by` clauses.
*
* @since 0.1.0
*
* @param {Postgres} sql
* @param {{
* deletedAtIncludeNotNull?: boolean,
* rootId?: string,
* excludeFiles?: boolean
* }} [where]
* @returns {Promise<NestedFileGroupWithFiles[]>}
*/
export async function getNestedFileGroups(sql, where = {}) {
const files = await fileGroupQueries.getNestedFiles(sql, where);

const idMap = {};
const result = [];
for (let i = 0; i < files.length; ++i) {
const thisFile = files[i];
if (isNil(idMap[thisFile.id]) && thisFile.isDirectory) {
idMap[thisFile.id] = thisFile;
thisFile.children = [];
}

if (isNil(thisFile.parent)) {
delete thisFile.parent;

result.push(thisFile);
} else {
idMap[thisFile.parent].children.push(thisFile);
}

if (isNil(thisFile.file?.id)) {
delete thisFile.file;
}
}

return result;
}
41 changes: 31 additions & 10 deletions packages/store/src/file-group.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { mainTestFn, test } from "@compas/cli";
import { isNil, uuid } from "@compas/stdlib";
import {
getNestedFileGroups,
hoistChildrenToParent,
updateFileGroupOrder,
} from "./file-group.js";
import { hoistChildrenToParent, updateFileGroupOrder } from "./file-group.js";
import { createOrUpdateFile } from "./files.js";
import { queries } from "./generated.js";
import { queryFileGroup } from "./generated/database/fileGroup.js";
Expand Down Expand Up @@ -108,19 +104,39 @@ test("store/file-group", async (t) => {
});

t.test("getNestedFiles without files, but preserve order", async (t) => {
const result = await getNestedFileGroups(sql, { excludeFiles: true });
const result = await queryFileGroup({
orderBy: ["order"],
children: {
orderBy: ["order"],
children: {
orderBy: ["order"],
},
},
where: {
parentIsNull: true,
},
}).exec(sql);

t.equal(result[0].id, groups.top1, "correct order");
t.equal(result[1].id, groups.top2, "correct order");

t.equal(result[0].children.length, 1);
t.equal(result[0].children[0].id, groups.sub1);
t.equal(result[0].children[0].children.length, 0);
t.equal(result[1].children.length, 0);
t.equal(result[0].children[0].children.length, 3);
t.equal(result[1].children.length, 3);
});

t.test("getNestedFiles with files", async (t) => {
const result = await getNestedFileGroups(sql, { rootId: groups.top2 });
const result = await queryFileGroup({
orderBy: ["order"],
children: {
orderBy: ["order"],
file: {},
},
where: {
id: groups.top2,
},
}).exec(sql);

t.equal(result.length, 1);
t.equal(result[0].children.length, 3);
Expand Down Expand Up @@ -171,7 +187,12 @@ test("store/file-group", async (t) => {
await hoistChildrenToParent(sql, files[0]);
await queries.fileGroupDelete(sql, { id: files[0].id });

const result = await getNestedFileGroups(sql, { rootId: groups.top1 });
const result = await queryFileGroup({
children: {},
where: {
id: groups.top1,
},
}).exec(sql);

t.equal(result.length, 1);
t.equal(result[0].children.length, 2);
Expand Down
Loading

0 comments on commit f405275

Please sign in to comment.