47 lines
1.3 KiB
TypeScript
47 lines
1.3 KiB
TypeScript
|
|
import { TRPCError } from "@trpc/server";
|
||
|
|
import { and, eq } from "drizzle-orm";
|
||
|
|
import {
|
||
|
|
objects,
|
||
|
|
forms,
|
||
|
|
propertyDefinitions,
|
||
|
|
templates,
|
||
|
|
objectTypeDefs,
|
||
|
|
} from "@tasks/database/schema";
|
||
|
|
import type { db as defaultDb } from "@tasks/database";
|
||
|
|
|
||
|
|
type Db = typeof defaultDb;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Generic "this row belongs to this workspace" guard used by tenant-scoped
|
||
|
|
* routers when a mutation targets a specific row by id. Throws NOT_FOUND if the
|
||
|
|
* row either doesn't exist or lives in a different workspace, so callers can't
|
||
|
|
* use the error code to probe IDs across tenants.
|
||
|
|
*/
|
||
|
|
export async function assertRowInWorkspace<
|
||
|
|
T extends { id: typeof objects.id; workspaceId: typeof objects.workspaceId },
|
||
|
|
>(args: {
|
||
|
|
db: Db;
|
||
|
|
table: T;
|
||
|
|
rowId: string;
|
||
|
|
workspaceId: string;
|
||
|
|
notFoundMessage?: string;
|
||
|
|
}): Promise<void> {
|
||
|
|
const [row] = await args.db
|
||
|
|
.select({ id: args.table.id })
|
||
|
|
.from(args.table as any)
|
||
|
|
.where(and(eq(args.table.id, args.rowId), eq(args.table.workspaceId, args.workspaceId)))
|
||
|
|
.limit(1);
|
||
|
|
if (!row) {
|
||
|
|
throw new TRPCError({
|
||
|
|
code: "NOT_FOUND",
|
||
|
|
message: args.notFoundMessage ?? "Resource not found",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export const tableForms = forms;
|
||
|
|
export const tablePropertyDefs = propertyDefinitions;
|
||
|
|
export const tableTemplates = templates;
|
||
|
|
export const tableObjectTypeDefs = objectTypeDefs;
|
||
|
|
export const tableObjects = objects;
|