-
Notifications
You must be signed in to change notification settings - Fork 278
Open
Labels
enhancementNew feature or requestNew feature or request
Description
What is the feature you are proposing?
When I use drizzle to declare a table, then drizzle-zod to extract schemas as zod, and zod-openapi to show the zod schemas on my OpenAPI file, I'd like to be able to use the hono-openapi feature of using z.openapi("description")
for now the only hack I found is something like this in order to share my refinements in a typed way between createSchema/insertSchema/updateSchema etc
import { z } from "@hono/zod-openapi";
import { entitiesPgSchema, uuidIdColumn } from "@workspace/db/schema/shared";
import { boolean, text, timestamp } from "drizzle-orm/pg-core";
import {
createInsertSchema,
createSelectSchema,
createUpdateSchema,
} from "drizzle-zod";
import { ZodTypeAny } from "zod/v4";
// Battery config type enum
export const batteryConfigTypeEnum = entitiesPgSchema.enum(
"battery_config_type",
["bike_controller", "cell", "pack"],
);
export type BatteryConfigType =
(typeof batteryConfigTypeEnum.enumValues)[number];
// Battery configs table
export const batteryConfigsTable = entitiesPgSchema.table("battery_configs", {
id: uuidIdColumn,
name: text("name").notNull(),
type: batteryConfigTypeEnum("type").notNull(),
description: text("description"),
tags: text("tags"), // comma-separated string
payload: text("payload").notNull(), // configuration data
is_active: boolean("is_active").notNull().default(true),
created_at: timestamp("created_at", { withTimezone: true })
.defaultNow()
.notNull(),
updated_at: timestamp("updated_at", { withTimezone: true })
.defaultNow()
.notNull()
.$onUpdate(() => new Date()),
});
// Utility function to create refinements with better type inference
function createRefinements<T extends Record<string, any>>(
_table: T,
refinements: Partial<{ [K in keyof T]: (schema: T[K]) => T[K] }>,
): Partial<{ [K in keyof T]: (schema: T[K]) => T[K] }> {
return refinements;
}
const batteryConfigRefinements = createRefinements(
createSelectSchema(batteryConfigsTable).shape,
{
id: (schema) =>
schema.openapi({
description: "Unique identifier for the battery configuration",
}),
name: (schema) =>
schema.openapi({
description: "Name of the battery configuration",
}),
type: (schema) =>
schema.openapi({
description:
"Type of battery configuration (bike_controller, cell, pack)",
}),
description: (schema) =>
schema.openapi({
description: "Description of the battery configuration",
}),
tags: (schema) =>
schema.openapi({
description: "Comma-separated tags for the configuration",
}),
payload: (schema) =>
schema.openapi({
description: "Configuration data payload",
}),
is_active: (schema) =>
schema.openapi({
description: "Whether the configuration is currently active",
}),
created_at: (schema) =>
schema.openapi({
description: "Timestamp when the configuration was created",
}),
updated_at: (schema) =>
schema.openapi({
description: "Timestamp when the configuration was last updated",
}),
},
);
// Create Zod schemas
export const selectBatteryConfigSchema = createSelectSchema(
batteryConfigsTable,
batteryConfigRefinements as Partial<
Record<
keyof (typeof batteryConfigsTable)["_"]["columns"],
(schema: ZodTypeAny) => ZodTypeAny
>
>,
);
export const insertBatteryConfigSchema = createInsertSchema(
batteryConfigsTable,
batteryConfigRefinements as Partial<
Record<
keyof (typeof batteryConfigsTable)["_"]["columns"],
(schema: ZodTypeAny) => ZodTypeAny
>
>,
).omit({
id: true,
created_at: true,
updated_at: true,
});
export const patchBatteryConfigSchema = createUpdateSchema(
batteryConfigsTable,
batteryConfigRefinements as Partial<
Record<
keyof (typeof batteryConfigsTable)["_"]["columns"],
(schema: ZodTypeAny) => ZodTypeAny
>
>,
).omit({
id: true,
created_at: true,
updated_at: true,
});
// Export TypeScript types
export type BatteryConfig = z.infer<typeof selectBatteryConfigSchema>;
export type NewBatteryConfig = z.infer<typeof insertBatteryConfigSchema>;
export type PatchBatteryConfig = z.infer<typeof patchBatteryConfigSchema>;This seems to type correctly, but it feels like there should be an easier way to do the following:
- define a pgTable
- get the equivalent zod type of the table
- add openapi description for all the fields
- use those shared openapi descriptions for createInsertSchema/createUpdateSchema/createSelectSchema
all of this well-typed
mahyarmlk
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request