cogsbox-shape 0.5.2
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 +189 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +47 -0
- package/dist/example/schema.d.ts +1104 -0
- package/dist/example/schema.js +6 -0
- package/dist/example/user.d.ts +1384 -0
- package/dist/example/user.js +42 -0
- package/dist/generateSQL.d.ts +6 -0
- package/dist/generateSQL.js +65 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/schema.d.ts +1442 -0
- package/dist/schema.js +452 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Unified Schema
|
|
2
|
+
|
|
3
|
+
> ⚠️ **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.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
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.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Single source of truth for database, server, and client types
|
|
12
|
+
- Type-safe schema definitions with TypeScript
|
|
13
|
+
- Built-in Zod validation
|
|
14
|
+
- Automatic type transformations between client and database
|
|
15
|
+
- SQL migrations codegen from schemas
|
|
16
|
+
- Relationship handling (hasMany, hasOne, belongsTo)
|
|
17
|
+
- Schema serialization
|
|
18
|
+
- Default value generation
|
|
19
|
+
- CLI tool for SQL generation
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install cogsbox-shape
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Basic Usage
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { shape, hasMany, createSchema } from "cogsbox-shape";
|
|
31
|
+
|
|
32
|
+
// Define your schemas with type safety
|
|
33
|
+
const userSchema = {
|
|
34
|
+
_tableName: "users",
|
|
35
|
+
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({
|
|
46
|
+
fromKey: "id",
|
|
47
|
+
toKey: () => petSchema.userId,
|
|
48
|
+
schema: () => petSchema,
|
|
49
|
+
defaultCount: 1,
|
|
50
|
+
}),
|
|
51
|
+
};
|
|
52
|
+
|
|
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>
|
|
82
|
+
```
|
|
83
|
+
|
|
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
|
+
## Advanced Features
|
|
97
|
+
|
|
98
|
+
### Type Transformations
|
|
99
|
+
|
|
100
|
+
Transform data between client and database representations:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
const petSchema = {
|
|
104
|
+
_tableName: "pets",
|
|
105
|
+
fluffynessScale: shape
|
|
106
|
+
.sql({ type: "text" })
|
|
107
|
+
.client(({ zod }) => z.array(z.enum(["bald", "fuzzy", "fluffy", "poof"])))
|
|
108
|
+
.transform({
|
|
109
|
+
toClient: (value) => value.split(",").filter(Boolean),
|
|
110
|
+
toDb: (value) => value.join(","),
|
|
111
|
+
}),
|
|
112
|
+
favourite: shape
|
|
113
|
+
.sql({ type: "int" })
|
|
114
|
+
.client(({ zod }) => z.boolean())
|
|
115
|
+
.transform({
|
|
116
|
+
toClient: (dbValue) => dbValue === 1,
|
|
117
|
+
toDb: (clientValue) => (clientValue ? 1 : 0),
|
|
118
|
+
}),
|
|
119
|
+
};
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Relationships
|
|
123
|
+
|
|
124
|
+
Define relationships between schemas:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const userSchema = {
|
|
128
|
+
// ... other fields
|
|
129
|
+
pets: hasMany({
|
|
130
|
+
fromKey: "id",
|
|
131
|
+
toKey: () => petSchema.userId,
|
|
132
|
+
schema: () => petSchema,
|
|
133
|
+
defaultCount: 1,
|
|
134
|
+
}),
|
|
135
|
+
};
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Supported relationships:
|
|
139
|
+
|
|
140
|
+
- `hasMany`
|
|
141
|
+
- `hasOne`
|
|
142
|
+
- `belongsTo`
|
|
143
|
+
- `manyToMany`
|
|
144
|
+
|
|
145
|
+
### SQL Types
|
|
146
|
+
|
|
147
|
+
Built-in SQL type definitions:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
shape.int({ nullable: true });
|
|
151
|
+
shape.varchar({ length: 255 });
|
|
152
|
+
shape.boolean();
|
|
153
|
+
shape.date();
|
|
154
|
+
shape.datetime();
|
|
155
|
+
shape.text();
|
|
156
|
+
shape.longtext();
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Validation
|
|
160
|
+
|
|
161
|
+
Add Zod validation to your schemas:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
const schema = {
|
|
165
|
+
email: shape
|
|
166
|
+
.sql({ type: "varchar", length: 255 })
|
|
167
|
+
.db(({ zod }) => zod.email()),
|
|
168
|
+
age: shape.sql({ type: "int" }).db(({ zod }) => zod.min(0).max(120)),
|
|
169
|
+
};
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Type Safety
|
|
173
|
+
|
|
174
|
+
The library provides full type inference:
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
const { dbSchema, clientSchema, initialValues } = createSchema(userSchema);
|
|
178
|
+
|
|
179
|
+
// These are fully typed:
|
|
180
|
+
type DBUser = z.infer<typeof dbSchema>;
|
|
181
|
+
type ClientUser = z.infer<typeof clientSchema>;
|
|
182
|
+
const defaults: typeof initialValues = {
|
|
183
|
+
// TypeScript will ensure this matches your schema
|
|
184
|
+
};
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
MIT
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { pathToFileURL } from "url";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { generateSQL } from "./generateSQL.js";
|
|
6
|
+
import { unlink, writeFile } from "fs/promises";
|
|
7
|
+
import { spawnSync } from "child_process";
|
|
8
|
+
const program = new Command();
|
|
9
|
+
program.command("generate-sql <file>").action(async (file) => {
|
|
10
|
+
try {
|
|
11
|
+
const fullPath = path.resolve(process.cwd(), file);
|
|
12
|
+
if (file.endsWith(".ts")) {
|
|
13
|
+
// Create a virtual module that imports and outputs the schema
|
|
14
|
+
const virtualModule = `
|
|
15
|
+
import { schemas } from '${pathToFileURL(fullPath).href}';
|
|
16
|
+
console.log(JSON.stringify(schemas));
|
|
17
|
+
`;
|
|
18
|
+
// Write this to a temporary file
|
|
19
|
+
const tmpFile = path.join(path.dirname(fullPath), ".tmp-schema-loader.ts");
|
|
20
|
+
await writeFile(tmpFile, virtualModule, "utf8");
|
|
21
|
+
const result = spawnSync("npx", ["tsx", tmpFile], {
|
|
22
|
+
encoding: "utf8",
|
|
23
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
24
|
+
});
|
|
25
|
+
// Clean up temp file
|
|
26
|
+
await unlink(tmpFile).catch(() => { });
|
|
27
|
+
if (result.error) {
|
|
28
|
+
throw result.error;
|
|
29
|
+
}
|
|
30
|
+
if (result.stderr) {
|
|
31
|
+
console.error("stderr:", result.stderr);
|
|
32
|
+
}
|
|
33
|
+
const schema = JSON.parse(result.stdout);
|
|
34
|
+
await generateSQL(schema);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
const schema = await import(pathToFileURL(fullPath).href);
|
|
38
|
+
await generateSQL(schema.schemas);
|
|
39
|
+
}
|
|
40
|
+
console.log("Generated SQL successfully");
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
console.error("Error:", error);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
program.parse();
|