gel-zod is a code generator for Zod schemas from your EdgeDB database schema.
2 types of schemas will be generated:
Create: All properties excluding link propertiesUpdate: All properties excluding link and readonly properties
To run the CLI: npx gel-zod [options] or pnpm exec gel-zod
Currently the supported options are:
--outputDir: The output directory relative from yourgel.toml--target ts|mts: If set tomtswill include.jsin import statements
| Feature | Status |
|---|---|
| Scalars | See table |
| Ranges | 🔴 |
| Arrays, tuples | 🟢 |
| Union types | 🔴 |
| Abstract objects | 🟢 |
| Overloaded properties | 🟢 |
| Regex constraints | 🟢 |
| Min, max constraints | 🔴 |
| Custom validators | 🔴 |
| Property annotations | 🔴 |
| EdgeDB Type | Supported | Zod Type | Constraints |
|---|---|---|---|
std::str |
🟢 | z.string() |
- |
std::bool |
🟢 | z.boolean() |
- |
std::json |
🟢 | z.unknown() |
- |
std::uuid |
🟢 | z.string().uuid() |
- |
std::enum |
🟢 | z.enum() |
- |
std::int16 |
🟢 | z.number().int().min(-32768).max(32768) |
16-bit unsigned integer |
std::int32 |
🟢 | z.number().int().min(-2147483647).max(2147483647) |
32-bit unsigned integer |
std::int64 |
🟢 | z.bigint().min(-9223372036854775808n).max(9223372036854775807n) |
64-bit unsigned integer |
std::bigint |
🟢 | z.bigint() |
- |
std::float32 |
🟢 | z.number().min(-3.40282347e38).max(3.40282347e38) |
32-bit float |
std::float64 |
🟢 | z.number() |
64-bit float |
std::datetime |
🟢 | z.string().datetime({ offset: true }) |
ISO datetime with timezone |
std::duration |
🟢 | z.string().duration() |
ISO duration format |
cal::local_datetime |
🟢 | z.string().datetime({ local: true }) |
Local datetime without timezone |
cal::local_date |
🔴 | - | - |
cal::local_time |
🟢 | z.string().time() |
Local time format |
cal::relative_duration |
🔴 | - | - |
cal::date_duration |
🔴 | - | - |
std::bytes |
🔴 | - | - |
std::sequence |
🔴 | - | - |
Are we missing any? Please open an issue or PR.
Partial output of /dbschema/zod/modules/default.ts:
// #region default::User
export const CreateUserSchema = z.
object({ // default::HasTimestamps
createdAt: z.iso.datetime().optional(), // std::datetime
updatedAt: z.iso.datetime().optional(), // std::datetime
})
.extend({ // default::User
name: z.string(), // std::str
emailAddress: z.string().regex(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/), // std::str
password: z.string(), // std::str
});
export const UpdateUserSchema = z.
object({ // default::HasTimestamps
updatedAt: z.iso.datetime().optional(), // std::datetime
})
.extend({ // default::User
name: z.string(), // std::str
emailAddress: z.string().regex(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/), // std::str
password: z.string(), // std::str
});
// #endregion