cogsbox-shape 0.5.23 → 0.5.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,11 +12,9 @@ A TypeScript library for creating type-safe database schemas with Zod validation
12
12
  - Type-safe schema definitions with TypeScript
13
13
  - Built-in Zod validation
14
14
  - Automatic type transformations between client and database
15
- - SQL migrations codegen from schemas
16
15
  - Relationship handling (hasMany, hasOne, belongsTo)
17
16
  - Schema serialization
18
17
  - Default value generation
19
- - CLI tool for SQL generation
20
18
 
21
19
  ## Installation
22
20
 
@@ -29,70 +27,38 @@ npm install cogsbox-shape
29
27
  ```typescript
30
28
  import { shape, hasMany, createSchema } from "cogsbox-shape";
31
29
 
32
- // Define your schemas with type safety
33
- const userSchema = {
34
- _tableName: "users",
30
+ const productSchema = {
31
+ _tableName: "products",
35
32
  id: shape.sql({ type: "int", pk: true }),
36
- firstname: shape
37
- .sql({ type: "varchar", length: 255 })
38
- .db(({ zod }) => zod.min(1)),
39
- surname: shape
40
- .sql({ type: "varchar", length: 255 })
41
- .db(({ zod }) => zod.min(1)),
42
- email: shape
43
- .sql({ type: "varchar", length: 255 })
44
- .db(({ zod }) => zod.email()),
45
- pets: hasMany({
33
+ sku: shape
34
+ .sql({ type: "varchar", length: 50 })
35
+ .initialState(
36
+ z.string(),
37
+ () => "PRD-" + Math.random().toString(36).slice(2)
38
+ )
39
+ .validation(({ sql }) => sql.min(5).max(50)),
40
+ price: shape
41
+ .sql({ type: "int" })
42
+ .client(({ sql }) => z.number().multipleOf(0.01))
43
+ .transform({
44
+ toClient: (dbValue) => dbValue / 100,
45
+ toDb: (clientValue) => Math.round(clientValue * 100),
46
+ }),
47
+ inStock: shape
48
+ .sql({ type: "boolean" })
49
+ .client(({ sql }) => z.boolean())
50
+ .initialState(z.boolean(), () => true),
51
+ categories: hasMany({
46
52
  fromKey: "id",
47
- toKey: () => petSchema.userId,
48
- schema: () => petSchema,
49
- defaultCount: 1,
53
+ toKey: () => categorySchema.productId,
54
+ schema: () => categorySchema,
50
55
  }),
51
56
  };
52
57
 
53
- // Create your schema and get typed utilities
54
- const { dbSchema, clientSchema, initialValues, serialized } =
55
- createSchema(userSchema);
56
- ```
57
-
58
- ## Schema Export and SQL Generation
59
-
60
- ### Exporting Schemas
61
-
62
- You can export your schemas for use with the CLI tool:
63
-
64
- ```typescript
65
- // schemas.ts
66
- import { petSchema, userSchema } from "./schemas";
67
-
68
- const schemas = {
69
- user: userSchema,
70
- pet: petSchema,
71
- };
72
-
73
- export { schemas };
74
- ```
75
-
76
- ### Using the CLI
77
-
78
- The package includes a CLI tool for generating SQL from your schemas. After installation, you can use it with:
79
-
80
- ```bash
81
- npx cogsbox-shape generate-sql <file>
58
+ const { sqlSchema, clientSchema, validationSchema, defaultValues } =
59
+ createSchema(productSchema);
82
60
  ```
83
61
 
84
- The CLI supports both TypeScript and JavaScript files:
85
-
86
- ```bash
87
- # For TypeScript files
88
- npx cogsbox-shape generate-sql schemas.ts
89
-
90
- # For JavaScript files
91
- npx cogsbox-shape generate-sql schemas.js
92
- ```
93
-
94
- This will generate a SQL file (`cogsbox-shape-sql.sql`) containing the table definitions for all your schemas.
95
-
96
62
  ## Advanced Features
97
63
 
98
64
  ### Type Transformations
@@ -100,21 +66,35 @@ This will generate a SQL file (`cogsbox-shape-sql.sql`) containing the table def
100
66
  Transform data between client and database representations:
101
67
 
102
68
  ```typescript
103
- const petSchema = {
104
- _tableName: "pets",
105
- fluffynessScale: shape
69
+ const orderSchema = {
70
+ _tableName: "orders",
71
+ id: shape
72
+ .sql({ type: "int", pk: true })
73
+ .initialState(z.string().uuid(), () => crypto.randomUUID())
74
+ .client(({ sql, initialState }) => z.union([sql, initialState])),
75
+ status: shape
76
+ .sql({ type: "varchar", length: 20 })
77
+ .client(({ sql }) =>
78
+ z.enum(["pending", "processing", "shipped", "delivered"])
79
+ )
80
+ .validation(({ sql }) =>
81
+ sql.refine((val) =>
82
+ ["pending", "processing", "shipped", "delivered"].includes(val)
83
+ )
84
+ ),
85
+ metadata: shape
106
86
  .sql({ type: "text" })
107
- .client(({ zod }) => z.array(z.enum(["bald", "fuzzy", "fluffy", "poof"])))
87
+ .client(({ sql }) => z.record(z.unknown()))
108
88
  .transform({
109
- toClient: (value) => value.split(",").filter(Boolean),
110
- toDb: (value) => value.join(","),
89
+ toClient: (value) => JSON.parse(value),
90
+ toDb: (value) => JSON.stringify(value),
111
91
  }),
112
- favourite: shape
113
- .sql({ type: "int" })
114
- .client(({ zod }) => z.boolean())
92
+ createdAt: shape
93
+ .sql({ type: "datetime" })
94
+ .client(({ sql }) => z.string().datetime())
115
95
  .transform({
116
- toClient: (dbValue) => dbValue === 1,
117
- toDb: (clientValue) => (clientValue ? 1 : 0),
96
+ toClient: (date) => date.toISOString(),
97
+ toDb: (isoString) => new Date(isoString),
118
98
  }),
119
99
  };
120
100
  ```
@@ -124,24 +104,28 @@ const petSchema = {
124
104
  Define relationships between schemas:
125
105
 
126
106
  ```typescript
127
- const userSchema = {
128
- // ... other fields
129
- pets: hasMany({
107
+ const customerSchema = {
108
+ _tableName: "customers",
109
+ id: shape.sql({ type: "int", pk: true }),
110
+ name: shape.sql({ type: "varchar", length: 100 }),
111
+ orders: hasMany({
112
+ fromKey: "id",
113
+ toKey: () => orderSchema.customerId,
114
+ schema: () => orderSchema,
115
+ }),
116
+ primaryAddress: hasOne({
130
117
  fromKey: "id",
131
- toKey: () => petSchema.userId,
132
- schema: () => petSchema,
133
- defaultCount: 1,
118
+ toKey: () => addressSchema.customerId,
119
+ schema: () => addressSchema,
120
+ }),
121
+ company: belongsTo({
122
+ fromKey: "companyId",
123
+ toKey: () => companySchema.id,
124
+ schema: () => companySchema,
134
125
  }),
135
126
  };
136
127
  ```
137
128
 
138
- Supported relationships:
139
-
140
- - `hasMany`
141
- - `hasOne`
142
- - `belongsTo`
143
- - `manyToMany`
144
-
145
129
  ### SQL Types
146
130
 
147
131
  Built-in SQL type definitions:
@@ -161,11 +145,22 @@ shape.longtext();
161
145
  Add Zod validation to your schemas:
162
146
 
163
147
  ```typescript
164
- const schema = {
148
+ const userSchema = {
149
+ _tableName: "users",
165
150
  email: shape
166
151
  .sql({ type: "varchar", length: 255 })
167
- .db(({ zod }) => zod.email()),
168
- age: shape.sql({ type: "int" }).db(({ zod }) => zod.min(0).max(120)),
152
+ .validation(({ sql }) => sql.email().toLowerCase()),
153
+ password: shape
154
+ .sql({ type: "varchar", length: 255 })
155
+ .validation(({ sql }) =>
156
+ sql
157
+ .min(8)
158
+ .regex(/[A-Z]/, "Must contain uppercase letter")
159
+ .regex(/[0-9]/, "Must contain number")
160
+ ),
161
+ birthDate: shape
162
+ .sql({ type: "date" })
163
+ .validation(({ sql }) => sql.min(new Date("1900-01-01")).max(new Date())),
169
164
  };
170
165
  ```
171
166
 
@@ -174,12 +169,14 @@ const schema = {
174
169
  The library provides full type inference:
175
170
 
176
171
  ```typescript
177
- const { dbSchema, clientSchema, initialValues } = createSchema(userSchema);
172
+ const { sqlSchema, clientSchema, validationSchema, defaultValues } =
173
+ createSchema(userSchema);
178
174
 
179
175
  // These are fully typed:
180
- type DBUser = z.infer<typeof dbSchema>;
176
+ type DBUser = z.infer<typeof sqlSchema>;
181
177
  type ClientUser = z.infer<typeof clientSchema>;
182
- const defaults: typeof initialValues = {
178
+ type ValidationUser = z.infer<typeof validationSchema>;
179
+ const defaults: typeof defaultValues = {
183
180
  // TypeScript will ensure this matches your schema
184
181
  };
185
182
  ```