From 47e8371fb303b03a01f64e55971b7cb24165e671 Mon Sep 17 00:00:00 2001 From: Ryan Pandya Date: Fri, 22 Nov 2024 12:38:03 -0800 Subject: [PATCH] CLI can add, list, delete colors --- apps/cli/src/commands/colors.ts | 21 ++++++++++++++++++--- packages/db/schema.ts | 6 +++++- packages/trpc/package.json | 1 + packages/trpc/routers/colors.ts | 31 +++++++++++++++++++++---------- pnpm-lock.yaml | 9 ++++++--- 5 files changed, 51 insertions(+), 17 deletions(-) diff --git a/apps/cli/src/commands/colors.ts b/apps/cli/src/commands/colors.ts index 48b978d..b71c315 100644 --- a/apps/cli/src/commands/colors.ts +++ b/apps/cli/src/commands/colors.ts @@ -21,14 +21,14 @@ colorsCmd try { const colors = (await api.colors.list.query()).colors; - colors.sort((a, b) => b.numCategories - a.numCategories); + // colors.sort((a, b) => b.numCategories - a.numCategories); if (getGlobalOptions().json) { printObject(colors); } else { - const data: string[][] = [["Id", "Name", "Hexcode", "Num categories"]]; + const data: string[][] = [["Id", "Name", "Hexcode", "user"]]; colors.forEach((color) => { - data.push([color.id, color.name, color.hexcode, color.numCategories.toString()]); + data.push([color.id, color.name, color.hexcode, color.userId]); }); console.log( data.length <= 1 ? @@ -61,6 +61,21 @@ colorsCmd .catch(printError(`Failed to create the color "${name}"`)); }); +colorsCmd + .command("delete") + .description("delete a color") + .argument("", "the name of the color") + .action(async (name: string) => { + const api = getAPIClient(); + + await api.colors.delete + .mutate({ + colorName: name, + }) + .then(printSuccess(`Successfully deleted the color "${name}"`)) + .catch(printError(`Failed to delete the color "${name}"`)); + }); + // colorsCmd // .command("delete") // .description("delete a color") diff --git a/packages/db/schema.ts b/packages/db/schema.ts index 8b47144..8f4fc42 100644 --- a/packages/db/schema.ts +++ b/packages/db/schema.ts @@ -139,7 +139,11 @@ export const colors = sqliteTable( .references(() => users.id, { onDelete: "cascade" }), }, (c) => ({ - uniq: unique().on(c.userId, c.name) + // Name should be unique per user + uniq: unique().on(c.userId, c.name), + // Hexcode should start with a pound sign, or have one prepended + // TODO. No internet, so no chatGPT cheating nor regular google looking up, + // and fuck if the in built documentation makes any sense }), ); export const categories = sqliteTable( diff --git a/packages/trpc/package.json b/packages/trpc/package.json index f58f5c3..2a3779e 100644 --- a/packages/trpc/package.json +++ b/packages/trpc/package.json @@ -18,6 +18,7 @@ "drizzle-orm": "^0.33.0", "superjson": "^2.2.1", "tiny-invariant": "^1.3.3", + "title-case": "^4.3.2", "zod": "^3.23.8" }, "devDependencies": { diff --git a/packages/trpc/routers/colors.ts b/packages/trpc/routers/colors.ts index a47ce2d..a526b3e 100644 --- a/packages/trpc/routers/colors.ts +++ b/packages/trpc/routers/colors.ts @@ -9,26 +9,23 @@ import { } from "@lifetracker/shared/types/colors"; import type { Context } from "../index"; import { authedProcedure, router } from "../index"; +import { titleCase } from "title-case"; - -function conditionFromInput(input: { colorId: string }, userId: string) { - return and(eq(colors.id, input.colorId), eq(colors.userId, userId)); +function conditionFromInput(input: { colorName: string }, userId: string) { + return and(eq(titleCase(colors.name), titleCase(input.colorName)), eq(colors.userId, userId)); } async function createColor( input: ZColor, ctx: Context, ) { - - console.log("[TRPC Router] Begin Create Color"); - return ctx.db.transaction(async (trx) => { try { const result = await trx .insert(colors) .values({ - name: input.name, + name: titleCase(input.name), hexcode: input.hexcode, inverse: calcInverseColor(input.hexcode), userId: ctx.user!.id, @@ -65,7 +62,7 @@ export const colorsAppRouter = router({ id: z.string(), name: z.string(), hexcode: z.string(), - numCategories: z.number(), + userId: z.string(), }), ), })) @@ -75,13 +72,13 @@ export const colorsAppRouter = router({ id: colors.id, name: colors.name, hexcode: colors.hexcode, + userId: colors.userId, }) .from(colors); return { colors: dbColors.map(({ ...color }) => ({ ...color, - numCategories: 0, })), }; }), @@ -97,4 +94,18 @@ export const colorsAppRouter = router({ .mutation(async ({ input, ctx }) => { return createColor(input, ctx); }), -}); \ No newline at end of file + delete: authedProcedure + .input( + z.object({ + colorName: z.string(), + }), + ) + .mutation(async ({ input, ctx }) => { + const res = await ctx.db + .delete(colors) + .where(conditionFromInput(input, ctx.user.id)); + if (res.changes == 0) { + throw new TRPCError({ code: "NOT_FOUND" }); + } + }), +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index efd40a5..2cd92c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -568,6 +568,9 @@ importers: tiny-invariant: specifier: ^1.3.3 version: 1.3.3 + title-case: + specifier: ^4.3.2 + version: 4.3.2 zod: specifier: ^3.23.8 version: 3.23.8 @@ -19731,7 +19734,7 @@ snapshots: eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.33.2(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0) @@ -19785,7 +19788,7 @@ snapshots: enhanced-resolve: 5.15.0 eslint: 8.57.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.1 get-tsconfig: 4.7.2 is-core-module: 2.13.1 @@ -19824,7 +19827,7 @@ snapshots: eslint: 8.57.0 ignore: 5.3.1 - eslint-plugin-import@2.29.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-plugin-import@2.29.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3