UNPKG

cogsbox-shape

Version:

A TypeScript library for creating type-safe database schemas with Zod validation, SQL type definitions, and automatic client/server transformations. Unifies client, server, and database types through a single schema definition, with built-in support for r

187 lines (156 loc) 4.98 kB
# Unified Schema > ⚠️ **Warning**: This package is currently a work in progress and not ready for production use. The API is unstable and subject to breaking changes. Please do not use in production environments. --- A TypeScript library for creating type-safe database schemas with Zod validation, SQL type definitions, and automatic client/server transformations. Unifies client, server, and database types through a single schema definition, with built-in support for relationships and serialization. ## Features - Single source of truth for database, server, and client types - Type-safe schema definitions with TypeScript - Built-in Zod validation - Automatic type transformations between client and database - Relationship handling (hasMany, hasOne, belongsTo) - Schema serialization - Default value generation ## Installation ```bash npm install cogsbox-shape ``` ## Basic Usage ```typescript import { shape, hasMany, createSchema } from "cogsbox-shape"; const productSchema = { _tableName: "products", id: shape.sql({ type: "int", pk: true }), sku: shape .sql({ type: "varchar", length: 50 }) .initialState( z.string(), () => "PRD-" + Math.random().toString(36).slice(2) ) .validation(({ sql }) => sql.min(5).max(50)), price: shape .sql({ type: "int" }) .client(({ sql }) => z.number().multipleOf(0.01)) .transform({ toClient: (dbValue) => dbValue / 100, toDb: (clientValue) => Math.round(clientValue * 100), }), inStock: shape .sql({ type: "boolean" }) .client(({ sql }) => z.boolean()) .initialState(z.boolean(), () => true), categories: hasMany({ fromKey: "id", toKey: () => categorySchema.productId, schema: () => categorySchema, }), }; const { sqlSchema, clientSchema, validationSchema, defaultValues } = createSchema(productSchema); ``` ## Advanced Features ### Type Transformations Transform data between client and database representations: ```typescript const orderSchema = { _tableName: "orders", id: shape .sql({ type: "int", pk: true }) .initialState(z.string().uuid(), () => crypto.randomUUID()) .client(({ sql, initialState }) => z.union([sql, initialState])), status: shape .sql({ type: "varchar", length: 20 }) .client(({ sql }) => z.enum(["pending", "processing", "shipped", "delivered"]) ) .validation(({ sql }) => sql.refine((val) => ["pending", "processing", "shipped", "delivered"].includes(val) ) ), metadata: shape .sql({ type: "text" }) .client(({ sql }) => z.record(z.unknown())) .transform({ toClient: (value) => JSON.parse(value), toDb: (value) => JSON.stringify(value), }), createdAt: shape .sql({ type: "datetime" }) .client(({ sql }) => z.string().datetime()) .transform({ toClient: (date) => date.toISOString(), toDb: (isoString) => new Date(isoString), }), }; ``` ### Relationships Define relationships between schemas: ```typescript const customerSchema = { _tableName: "customers", id: shape.sql({ type: "int", pk: true }), name: shape.sql({ type: "varchar", length: 100 }), orders: hasMany({ fromKey: "id", toKey: () => orderSchema.customerId, schema: () => orderSchema, }), primaryAddress: hasOne({ fromKey: "id", toKey: () => addressSchema.customerId, schema: () => addressSchema, }), company: belongsTo({ fromKey: "companyId", toKey: () => companySchema.id, schema: () => companySchema, }), }; ``` ### SQL Types Built-in SQL type definitions: ```typescript shape.int({ nullable: true }); shape.varchar({ length: 255 }); shape.boolean(); shape.date(); shape.datetime(); shape.text(); shape.longtext(); ``` ### Validation Add Zod validation to your schemas: ```typescript const userSchema = { _tableName: "users", email: shape .sql({ type: "varchar", length: 255 }) .validation(({ sql }) => sql.email().toLowerCase()), password: shape .sql({ type: "varchar", length: 255 }) .validation(({ sql }) => sql .min(8) .regex(/[A-Z]/, "Must contain uppercase letter") .regex(/[0-9]/, "Must contain number") ), birthDate: shape .sql({ type: "date" }) .validation(({ sql }) => sql.min(new Date("1900-01-01")).max(new Date())), }; ``` ## Type Safety The library provides full type inference: ```typescript const { sqlSchema, clientSchema, validationSchema, defaultValues } = createSchema(userSchema); // These are fully typed: type DBUser = z.infer<typeof sqlSchema>; type ClientUser = z.infer<typeof clientSchema>; type ValidationUser = z.infer<typeof validationSchema>; const defaults: typeof defaultValues = { // TypeScript will ensure this matches your schema }; ``` ## License MIT