lifetracker/packages/trpc/routers/days.ts

132 lines
4.2 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 { categories, days, hours, } from "@lifetracker/db/schema";
import {
zDaySchema, ZDay
} from "@lifetracker/shared/types/days";
import type { Context } from "../index";
import { authedProcedure, router } from "../index";
import { dateFromInput } from "@lifetracker/shared/utils/days";
async function createDay(date: string, ctx: Context) {
return await ctx.db.transaction(async (trx) => {
try {
// Create the Day object
const dayRes = await trx
.insert(days)
.values({
userId: ctx.user!.id,
date: date,
})
.returning({
id: days.id,
date: days.date,
mood: days.mood,
comment: days.comment,
});
const dayId = dayRes[0].id;
// Generate 24 "hour" objects
const hoursData = Array.from({ length: 24 }, (_, hour) => ({
userId: ctx.user!.id,
dayId: dayId,
time: hour
}));
// Insert the "hour" objects
await trx.insert(hours).values(hoursData);
return dayRes;
} catch (e) {
console.log(e);
if (e instanceof SqliteError) {
if (e.code == "SQLITE_CONSTRAINT_UNIQUE") {
throw new TRPCError({
code: "BAD_REQUEST",
message: "This day already exists",
});
}
}
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Something went wrong",
});
}
});
}
export const daysAppRouter = router({
get: authedProcedure
.input(z.object({
dateQuery: z.string(),
}))
.output(zDaySchema)
.query(async ({ input, ctx }) => {
const date = dateFromInput(input);
// Fetch the day data
let dayRes;
dayRes = await ctx.db
.select({
id: days.id,
date: days.date,
mood: days.mood,
comment: days.comment,
})
.from(days)
.where(eq(days.date, date));
if (dayRes.length === 0) {
dayRes = await createDay(date, ctx);
}
const day = dayRes[0];
// Fetch the hours data for the corresponding dayId
const hoursRes = await ctx.db
.select({
id: hours.id,
dayId: hours.dayId,
time: hours.time,
categoryId: hours.categoryId,
categoryCode: categories.code,
comment: hours.comment,
})
.from(hours)
.where(eq(hours.dayId, day.id))
.leftJoin(categories, eq(categories.id, hours.categoryId))
// Combine the day and hours data
const result = {
...day,
hours: hoursRes,
};
return result;
}),
update: authedProcedure
.input(
z.object({
mood: z.string().optional().or(z.number()),
comment: z.string().optional(),
dateQuery: z.string(),
}),
)
.mutation(async ({ input, ctx }) => {
const { dateQuery, ...updatedProps } = input;
// Convert mood to number, if it exists
if (updatedProps.mood) {
updatedProps.mood = parseInt(updatedProps.mood);
}
console.log(dateQuery, "::", dateFromInput({ dateQuery: dateQuery }));
await ctx.db
.update(days)
.set(updatedProps)
.where(eq(days.date, dateFromInput({ dateQuery: dateQuery })));
}),
});