241 lines
7.3 KiB
TypeScript
241 lines
7.3 KiB
TypeScript
import { experimental_trpcMiddleware, TRPCError } from "@trpc/server";
|
|
import { and, desc, eq, inArray, notExists } from "drizzle-orm";
|
|
import { z } from "zod";
|
|
|
|
import { SqliteError } from "@lifetracker/db";
|
|
import { labels } from "@lifetracker/db/schema";
|
|
import {
|
|
zLabelSchema,
|
|
zGetLabelResponseSchema,
|
|
zUpdateLabelRequestSchema
|
|
} from "@lifetracker/shared/types/labels";
|
|
import type { Context } from "../index";
|
|
import { authedProcedure, router } from "../index";
|
|
|
|
|
|
function conditionFromInput(input: { labelId: string }, userId: string) {
|
|
return and(eq(labels.id, input.labelId), eq(labels.userId, userId));
|
|
}
|
|
|
|
async function createLabel(
|
|
input: z.infer<typeof zLabelSchema>,
|
|
ctx: Context,
|
|
) {
|
|
|
|
console.log("Creating a label");
|
|
|
|
return ctx.db.transaction(async (trx) => {
|
|
|
|
try {
|
|
const result = await trx
|
|
.insert(labels)
|
|
.values({
|
|
name: input.name,
|
|
code: input.code,
|
|
description: input.description,
|
|
color: input.color,
|
|
userId: ctx.user!.id,
|
|
})
|
|
.returning({
|
|
id: labels.id,
|
|
name: labels.name,
|
|
code: labels.code,
|
|
description: labels.description,
|
|
color: labels.color,
|
|
});
|
|
return result[0];
|
|
} catch (e) {
|
|
if (e instanceof SqliteError) {
|
|
if (e.code == "SQLITE_CONSTRAINT_UNIQUE") {
|
|
throw new TRPCError({
|
|
code: "BAD_REQUEST",
|
|
message: "Line 48 trpc routers labels.ts",
|
|
});
|
|
}
|
|
}
|
|
throw new TRPCError({
|
|
code: "INTERNAL_SERVER_ERROR",
|
|
message: "Something went wrong",
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
export const labelsAppRouter = router({
|
|
labelStats: authedProcedure
|
|
.output(
|
|
z.record(
|
|
z.string(),
|
|
z.object({
|
|
numEntries: z.number(),
|
|
}),
|
|
),
|
|
)
|
|
.query(async ({ ctx }) => {
|
|
const [labelIds] = await Promise.all([
|
|
ctx.db.select({ id: labels.id }).from(labels)
|
|
]);
|
|
|
|
const results: Record<
|
|
string,
|
|
{ numEntries: number }
|
|
> = {};
|
|
for (const label of labelIds) {
|
|
results[label.id] = {
|
|
numEntries: 3330,
|
|
};
|
|
}
|
|
return results;
|
|
}),
|
|
list: authedProcedure
|
|
.output(
|
|
z.object({
|
|
labels: z.array(zGetLabelResponseSchema),
|
|
}),
|
|
)
|
|
.query(async ({ ctx }) => {
|
|
const res = await ctx.db
|
|
.select({
|
|
id: labels.id,
|
|
name: labels.name,
|
|
code: labels.code,
|
|
color: labels.color,
|
|
description: labels.description,
|
|
})
|
|
.from(labels)
|
|
.where(eq(labels.userId, ctx.user.id));
|
|
|
|
return {
|
|
labels: res.map((r) => ({
|
|
id: r.id,
|
|
name: r.name,
|
|
code: r.code,
|
|
color: r.color,
|
|
description: r.description,
|
|
numEntries: 420,
|
|
})),
|
|
};
|
|
}),
|
|
get: authedProcedure
|
|
.input(
|
|
z.object({
|
|
labelId: z.string(),
|
|
}),
|
|
)
|
|
.output(zGetLabelResponseSchema)
|
|
.query(async ({ input, ctx }) => {
|
|
const res = await ctx.db
|
|
.select({
|
|
id: labels.id,
|
|
name: labels.name
|
|
})
|
|
.from(labels)
|
|
.where(
|
|
and(
|
|
conditionFromInput(input, ctx.user.id),
|
|
eq(labels.userId, ctx.user.id),
|
|
),
|
|
);
|
|
|
|
if (res.length == 0) {
|
|
throw new TRPCError({ code: "NOT_FOUND" });
|
|
}
|
|
|
|
const numEntriesWithLabel = res.reduce<
|
|
Record<ZLabeledByEnum, number>
|
|
>(
|
|
(acc, curr) => {
|
|
if (curr.labeledBy) {
|
|
acc[curr.labeledBy]++;
|
|
}
|
|
return acc;
|
|
},
|
|
{ ai: 0, human: 0 },
|
|
);
|
|
|
|
return {
|
|
id: res[0].id,
|
|
name: res[0].name,
|
|
numEntries: 420
|
|
};
|
|
}),
|
|
create: authedProcedure
|
|
.input(zLabelSchema)
|
|
.output(
|
|
z.object({
|
|
id: z.string(),
|
|
code: z.number(),
|
|
name: z.string(),
|
|
color: z.string().default("#000000"),
|
|
description: z.string().optional(),
|
|
}),
|
|
)
|
|
.mutation(async ({ input, ctx }) => {
|
|
console.log("Just started creating a label");
|
|
return createLabel(input, ctx);
|
|
}),
|
|
update: authedProcedure
|
|
.input(zUpdateLabelRequestSchema)
|
|
.output(
|
|
z.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
userId: z.string(),
|
|
createdAt: z.date(),
|
|
}),
|
|
)
|
|
.mutation(async ({ input, ctx }) => {
|
|
console.log(input);
|
|
console.log(ctx);
|
|
console.log("TEEEEEEEEEEEEEEEEEEEEEST\n\n\n\n\n");
|
|
try {
|
|
const res = await ctx.db
|
|
.update(bookmarkTags)
|
|
.set({
|
|
name: input.name,
|
|
})
|
|
.where(
|
|
and(
|
|
eq(bookmarkTags.id, input.tagId),
|
|
eq(bookmarkTags.userId, ctx.user.id),
|
|
),
|
|
)
|
|
.returning();
|
|
|
|
if (res.length == 0) {
|
|
throw new TRPCError({ code: "NOT_FOUND" });
|
|
}
|
|
|
|
try {
|
|
const affectedBookmarks = await ctx.db.query.tagsOnBookmarks.findMany(
|
|
{
|
|
where: eq(tagsOnBookmarks.tagId, input.tagId),
|
|
columns: {
|
|
bookmarkId: true,
|
|
},
|
|
},
|
|
);
|
|
await Promise.all(
|
|
affectedBookmarks
|
|
.map((b) => b.bookmarkId)
|
|
.map((id) => triggerSearchReindex(id)),
|
|
);
|
|
} catch (e) {
|
|
console.error("Something ELSE Went Wrong", e);
|
|
}
|
|
|
|
return res[0];
|
|
} catch (e) {
|
|
if (e instanceof SqliteError) {
|
|
if (e.code == "SQLITE_CONSTRAINT_UNIQUE") {
|
|
throw new TRPCError({
|
|
code: "BAD_REQUEST",
|
|
message:
|
|
"Label name already exists.",
|
|
});
|
|
}
|
|
}
|
|
throw e;
|
|
}
|
|
}),
|
|
}); |