Derive Elysia request validators from Drizzle tables via drizzle-typebox
This commit is contained in:
@@ -15,7 +15,10 @@ bun run dev
|
|||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
- `src/db/` — Drizzle schema (`printers`, `farms`, `print_jobs`, `frame_embeddings`)
|
- `src/db/` — Drizzle schema (`printers`, `farms`, `print_jobs`, `frame_embeddings`)
|
||||||
and client, pointed at pgCat.
|
and client, pointed at pgCat. `src/db/validators.ts` derives Elysia/TypeBox
|
||||||
|
request validators straight from the Drizzle tables via `drizzle-typebox`,
|
||||||
|
so the Postgres schema and the API validators come from one definition
|
||||||
|
instead of two hand-synced ones.
|
||||||
- `src/s3/` — R2 presigned URL helpers (`PUT` for client uploads, `GET` for the
|
- `src/s3/` — R2 presigned URL helpers (`PUT` for client uploads, `GET` for the
|
||||||
edge proxy).
|
edge proxy).
|
||||||
- `src/queue/` — Redis client + `XADD` helper pushing onto `stream:camera_frames`
|
- `src/queue/` — Redis client + `XADD` helper pushing onto `stream:camera_frames`
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
"@aws-sdk/client-s3": "^3.658.1",
|
"@aws-sdk/client-s3": "^3.658.1",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.658.1",
|
"@aws-sdk/s3-request-presigner": "^3.658.1",
|
||||||
"drizzle-orm": "^0.33.0",
|
"drizzle-orm": "^0.33.0",
|
||||||
|
"drizzle-typebox": "^0.2.1",
|
||||||
|
"@sinclair/typebox": "^0.33.12",
|
||||||
"postgres": "^3.4.4",
|
"postgres": "^3.4.4",
|
||||||
"ioredis": "^5.4.1"
|
"ioredis": "^5.4.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { createInsertSchema, createSelectSchema } from "drizzle-typebox";
|
||||||
|
import { t } from "elysia";
|
||||||
|
import { printers, printJobs } from "./schema";
|
||||||
|
|
||||||
|
// Generated straight from the Drizzle table definitions in `./schema` — this
|
||||||
|
// is the *only* place these shapes are defined. The Postgres column and the
|
||||||
|
// Elysia request/response validator can no longer drift apart: change a
|
||||||
|
// column in `./schema/printers.ts` and both the DB migration and the API
|
||||||
|
// validator below pick it up automatically.
|
||||||
|
//
|
||||||
|
// The second argument overrides fields Drizzle can't infer correctly for an
|
||||||
|
// insert — `id` is DB-generated (defaultRandom()) so it must be optional on
|
||||||
|
// the way in, even though it's required on the way out.
|
||||||
|
export const PrinterInsertSchema = createInsertSchema(printers, {
|
||||||
|
id: t.Optional(t.String({ format: "uuid" })),
|
||||||
|
});
|
||||||
|
export const PrinterSelectSchema = createSelectSchema(printers);
|
||||||
|
|
||||||
|
export const PrintJobInsertSchema = createInsertSchema(printJobs, {
|
||||||
|
id: t.Optional(t.String({ format: "uuid" })),
|
||||||
|
});
|
||||||
|
export const PrintJobSelectSchema = createSelectSchema(printJobs);
|
||||||
+8
-21
@@ -2,6 +2,7 @@ import { Elysia, t } from "elysia";
|
|||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "../db";
|
import { db } from "../db";
|
||||||
import { printers } from "../db/schema";
|
import { printers } from "../db/schema";
|
||||||
|
import { PrinterInsertSchema } from "../db/validators";
|
||||||
|
|
||||||
export const printerRoutes = new Elysia({ prefix: "/printers" })
|
export const printerRoutes = new Elysia({ prefix: "/printers" })
|
||||||
.get("/", async ({ query }) => {
|
.get("/", async ({ query }) => {
|
||||||
@@ -21,28 +22,14 @@ export const printerRoutes = new Elysia({ prefix: "/printers" })
|
|||||||
.post(
|
.post(
|
||||||
"/",
|
"/",
|
||||||
async ({ body, set }) => {
|
async ({ body, set }) => {
|
||||||
const [printer] = await db
|
// `body` is already validated + shaped against the Drizzle table by
|
||||||
.insert(printers)
|
// PrinterInsertSchema, so it can go straight into `.values()` with no
|
||||||
.values({
|
// hand-mapping of individual fields.
|
||||||
farmId: body.farmId,
|
const [printer] = await db.insert(printers).values(body).returning();
|
||||||
name: body.name,
|
|
||||||
vendor: body.vendor,
|
|
||||||
lanAddress: body.lanAddress,
|
|
||||||
serialNumber: body.serialNumber,
|
|
||||||
accessCode: body.accessCode,
|
|
||||||
})
|
|
||||||
.returning();
|
|
||||||
set.status = 201;
|
set.status = 201;
|
||||||
return printer;
|
return printer;
|
||||||
},
|
},
|
||||||
{
|
// Derived from `printers` via drizzle-typebox — see src/db/validators.ts.
|
||||||
body: t.Object({
|
// Add or rename a column in the schema and this validator updates itself.
|
||||||
farmId: t.String({ format: "uuid" }),
|
{ body: PrinterInsertSchema },
|
||||||
name: t.String({ minLength: 1 }),
|
|
||||||
vendor: t.Union([t.Literal("bambu"), t.Literal("prusa"), t.Literal("klipper")]),
|
|
||||||
lanAddress: t.Optional(t.String()),
|
|
||||||
serialNumber: t.Optional(t.String()),
|
|
||||||
accessCode: t.Optional(t.String()),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user