aboutsummaryrefslogtreecommitdiffstats
path: root/packages/trpc
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2024-04-19 00:09:27 +0100
committerGitHub <noreply@github.com>2024-04-19 00:09:27 +0100
commite0999f701cd1834c3d940113cd8dd5247c5fe95f (patch)
treec4169a564ecd3f933e711bcc8ef7db20532174ea /packages/trpc
parentdeba31ee010f785a9739fd4df8a64a3056c9593d (diff)
downloadkarakeep-e0999f701cd1834c3d940113cd8dd5247c5fe95f.tar.zst
feature: Nested lists (#110). Fixes #62
* feature: Add support for nested lists * prevent moving the parent to a subtree
Diffstat (limited to 'packages/trpc')
-rw-r--r--packages/trpc/routers/lists.ts79
1 files changed, 49 insertions, 30 deletions
diff --git a/packages/trpc/routers/lists.ts b/packages/trpc/routers/lists.ts
index 74b4f737..5cab0ac3 100644
--- a/packages/trpc/routers/lists.ts
+++ b/packages/trpc/routers/lists.ts
@@ -10,6 +10,15 @@ import type { Context } from "../index";
import { authedProcedure, router } from "../index";
import { ensureBookmarkOwnership } from "./bookmarks";
+const zNewBookmarkListSchema = z.object({
+ name: z
+ .string()
+ .min(1, "List name can't be empty")
+ .max(20, "List name is at most 20 chars"),
+ icon: z.string(),
+ parentId: z.string().nullish(),
+});
+
export const ensureListOwnership = experimental_trpcMiddleware<{
ctx: Context;
input: { listId: string };
@@ -44,41 +53,50 @@ export const ensureListOwnership = experimental_trpcMiddleware<{
export const listsAppRouter = router({
create: authedProcedure
+ .input(zNewBookmarkListSchema)
+ .output(zBookmarkListSchema)
+ .mutation(async ({ input, ctx }) => {
+ const [result] = await ctx.db
+ .insert(bookmarkLists)
+ .values({
+ name: input.name,
+ icon: input.icon,
+ userId: ctx.user.id,
+ parentId: input.parentId,
+ })
+ .returning();
+ return result;
+ }),
+ edit: authedProcedure
.input(
- z.object({
- name: z
- .string()
- .min(1, "List name can't be empty")
- .max(20, "List name is at most 20 chars"),
- icon: z.string(),
- }),
+ zNewBookmarkListSchema
+ .partial()
+ .merge(z.object({ listId: z.string() }))
+ .refine((val) => val.parentId != val.listId, {
+ message: "List can't be its own parent",
+ path: ["parentId"],
+ }),
)
.output(zBookmarkListSchema)
.mutation(async ({ input, ctx }) => {
- try {
- const result = await ctx.db
- .insert(bookmarkLists)
- .values({
- name: input.name,
- icon: input.icon,
- userId: ctx.user.id,
- })
- .returning();
- return result[0];
- } catch (e) {
- if (e instanceof SqliteError) {
- if (e.code == "SQLITE_CONSTRAINT_UNIQUE") {
- throw new TRPCError({
- code: "BAD_REQUEST",
- message: "List already exists",
- });
- }
- }
- throw new TRPCError({
- code: "INTERNAL_SERVER_ERROR",
- message: "Something went wrong",
- });
+ const result = await ctx.db
+ .update(bookmarkLists)
+ .set({
+ name: input.name,
+ icon: input.icon,
+ parentId: input.parentId,
+ })
+ .where(
+ and(
+ eq(bookmarkLists.id, input.listId),
+ eq(bookmarkLists.userId, ctx.user.id),
+ ),
+ )
+ .returning();
+ if (result.length == 0) {
+ throw new TRPCError({ code: "NOT_FOUND" });
}
+ return result[0];
}),
delete: authedProcedure
.input(
@@ -187,6 +205,7 @@ export const listsAppRouter = router({
id: res.id,
name: res.name,
icon: res.icon,
+ parentId: res.parentId,
bookmarks: res.bookmarksInLists.map((b) => b.bookmarkId),
};
}),