@vibeorm/dsl 0.3.0 → 2.0.0-alpha.1

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.
Files changed (46) hide show
  1. package/README.md +62 -471
  2. package/dist/column.d.ts +150 -0
  3. package/dist/column.d.ts.map +1 -0
  4. package/dist/enum.d.ts +27 -0
  5. package/dist/enum.d.ts.map +1 -0
  6. package/dist/generator/index.d.ts +5 -0
  7. package/dist/generator/index.d.ts.map +1 -0
  8. package/dist/generator/prisma.d.ts +19 -0
  9. package/dist/generator/prisma.d.ts.map +1 -0
  10. package/dist/index.d.ts +116 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +1546 -0
  13. package/dist/index.js.map +22 -0
  14. package/dist/model.d.ts +44 -0
  15. package/dist/model.d.ts.map +1 -0
  16. package/dist/naming.d.ts +23 -0
  17. package/dist/naming.d.ts.map +1 -0
  18. package/dist/relation-plan.d.ts +101 -0
  19. package/dist/relation-plan.d.ts.map +1 -0
  20. package/dist/relation.d.ts +23 -0
  21. package/dist/relation.d.ts.map +1 -0
  22. package/dist/relations.d.ts +29 -0
  23. package/dist/relations.d.ts.map +1 -0
  24. package/dist/schema.d.ts +38 -0
  25. package/dist/schema.d.ts.map +1 -0
  26. package/dist/templates.d.ts +79 -0
  27. package/dist/templates.d.ts.map +1 -0
  28. package/dist/to-ir.d.ts +41 -0
  29. package/dist/to-ir.d.ts.map +1 -0
  30. package/dist/types.d.ts +286 -0
  31. package/dist/types.d.ts.map +1 -0
  32. package/dist/validate.d.ts +22 -0
  33. package/dist/validate.d.ts.map +1 -0
  34. package/package.json +29 -26
  35. package/src/column.ts +0 -389
  36. package/src/enum.ts +0 -71
  37. package/src/generator/index.ts +0 -5
  38. package/src/generator/prisma.ts +0 -728
  39. package/src/index.ts +0 -247
  40. package/src/model.ts +0 -330
  41. package/src/relation.ts +0 -75
  42. package/src/relations.ts +0 -293
  43. package/src/schema.ts +0 -184
  44. package/src/templates.ts +0 -134
  45. package/src/types.ts +0 -381
  46. package/src/validate.ts +0 -141
package/src/index.ts DELETED
@@ -1,247 +0,0 @@
1
- /**
2
- * @vibeorm/dsl - TypeScript DSL for database schema management
3
- *
4
- * Relations are defined separately via dsl.defineRelations()
5
- *
6
- * @example
7
- * import { dsl } from "@vibeorm/dsl";
8
- *
9
- * // Models - just columns (FK columns declared explicitly)
10
- * const Workspace = dsl.create({
11
- * name: "Workspace",
12
- * schema: {
13
- * ...dsl.templates.base,
14
- * name: dsl.string(),
15
- * },
16
- * });
17
- *
18
- * const User = dsl.create({
19
- * name: "User",
20
- * schema: {
21
- * ...dsl.templates.base,
22
- * email: dsl.string({ unique: true }),
23
- * workspaceId: dsl.string({ index: true }),
24
- * },
25
- * indexes: (i) => [
26
- * i.unique("workspaceId", "email"),
27
- * ],
28
- * });
29
- *
30
- * // Relations - centralized and type-safe
31
- * const relations = dsl.defineRelations({ Workspace, User }, (r) => ({
32
- * Workspace: {
33
- * users: r.many.User({
34
- * from: r.Workspace.id,
35
- * to: r.User.workspaceId,
36
- * }),
37
- * },
38
- * User: {
39
- * workspace: r.one.Workspace({
40
- * from: r.User.workspaceId,
41
- * to: r.Workspace.id,
42
- * }),
43
- * },
44
- * }));
45
- *
46
- * // Schema with relations
47
- * const schema = dsl.schema({ User, Workspace }, { relations });
48
- * const prisma = dsl.generate.prisma(schema);
49
- */
50
-
51
- // ─── Column Imports ─────────────────────────────────
52
-
53
- import {
54
- bigint,
55
- boolean,
56
- bytes,
57
- ChainableColumn,
58
- datetime,
59
- decimal,
60
- enumCol,
61
- float,
62
- id,
63
- int,
64
- json,
65
- string,
66
- unsupported,
67
- } from "./column.ts";
68
-
69
- // ─── Enum Imports ─────────────────────────────────
70
-
71
- import { createEnum } from "./enum.ts";
72
- import type { StandaloneEnumConfig } from "./enum.ts";
73
-
74
- // ─── Model Imports ─────────────────────────────────
75
-
76
- import { create } from "./model.ts";
77
-
78
- // ─── Relations Imports ─────────────────────────────────
79
-
80
- import { defineRelations, defineRelationsPart, mergeRelations } from "./relations.ts";
81
-
82
- // ─── Schema Imports ─────────────────────────────────
83
-
84
- import { domain, schema } from "./schema.ts";
85
-
86
- // ─── Generator Imports ─────────────────────────────────
87
-
88
- import { generatePrisma } from "./generator/prisma.ts";
89
-
90
- // ─── Validation Imports ─────────────────────────────────
91
-
92
- import { validateSchema } from "./validate.ts";
93
-
94
- // ─── Template Imports ─────────────────────────────────
95
-
96
- import {
97
- base,
98
- baseWithWorkspace,
99
- fields,
100
- templates,
101
- withActive,
102
- withAudit,
103
- withExternalId,
104
- withMetadata,
105
- withNameDescription,
106
- } from "./templates.ts";
107
-
108
- // ─── Type Imports ─────────────────────────────────
109
-
110
- import type {
111
- ColumnDef,
112
- EnumDef,
113
- InlineEnumConfig,
114
- SchemaDef,
115
- } from "./types.ts";
116
-
117
- // ─── Type Exports ─────────────────────────────────
118
-
119
- export type {
120
- // Cascade action types
121
- CascadeAction,
122
- // Children types
123
- ChildrenBuilder,
124
- ChildrenDef,
125
- ChildrenRelationConfig,
126
- // Column types
127
- ColumnDef,
128
- ColumnRef,
129
- // Enum types
130
- EnumDef,
131
- EnumFieldConfig,
132
- // Generator types
133
- GeneratorConfig,
134
- GeneratorOutput,
135
- // Index types
136
- IndexBuilder,
137
- IndexCallback,
138
- IndexDef,
139
- IndexOptions,
140
- IndexType,
141
- InlineEnumConfig,
142
- // Model types
143
- ModelDef,
144
- // Prisma types
145
- PrismaGeneratorConfig,
146
- // Relations types
147
- ManyRelationDefConfig,
148
- OneRelationDefConfig,
149
- RelationsBuilder,
150
- RelationsMap,
151
- RelationsOutput,
152
- StoredRelationDef,
153
- ThroughRef,
154
- // Schema types
155
- SchemaDef,
156
- SchemaInput,
157
- } from "./types.ts";
158
-
159
- export type { ValidationError } from "./validate.ts";
160
-
161
- // ─── Enum Factory ─────────────────────────────────
162
-
163
- /**
164
- * Creates an enum - either standalone (reusable) or inline (one-off)
165
- *
166
- * @example
167
- * // Standalone enum (reusable across models)
168
- * const Status = dsl.enum({ name: "Status", options: ["active", "inactive"] });
169
- * // Use in model: status: Status.field({ default: "active" })
170
- *
171
- * // Inline enum (one-off use)
172
- * priority: dsl.enum({ options: ["low", "medium", "high"], default: "medium" })
173
- */
174
- function enumFactory<const T extends readonly string[]>(
175
- config: StandaloneEnumConfig<T>
176
- ): EnumDef<T>;
177
- function enumFactory<const T extends readonly string[]>(config: InlineEnumConfig<T>): ChainableColumn<"enum">;
178
- function enumFactory<const T extends readonly string[]>(
179
- config: StandaloneEnumConfig<T> | InlineEnumConfig<T>
180
- ): EnumDef<T> | ChainableColumn<"enum"> {
181
- // Standalone enum has 'name' property
182
- if ("name" in config && typeof config.name === "string") {
183
- return createEnum(config as StandaloneEnumConfig<T>);
184
- }
185
- // Inline enum
186
- return enumCol(config as InlineEnumConfig<T>);
187
- }
188
-
189
- // ─── Main DSL Namespace ─────────────────────────────────
190
-
191
- /**
192
- * Main database schema DSL namespace
193
- */
194
- export const dsl = {
195
- // Column types
196
- string,
197
- int,
198
- bigint,
199
- float,
200
- decimal,
201
- boolean,
202
- datetime,
203
- json,
204
- id,
205
- bytes,
206
- unsupported,
207
- enum: enumFactory,
208
-
209
- // Model creation
210
- create,
211
-
212
- // Relations
213
- defineRelations,
214
- defineRelationsPart,
215
- mergeRelations,
216
-
217
- // Schema composition
218
- schema,
219
- domain,
220
-
221
- // Validation
222
- validateSchema,
223
-
224
- // Generators
225
- generate: Object.assign(
226
- function generate(schemaDef: SchemaDef): { prisma?: string } {
227
- return {
228
- prisma: generatePrisma(schemaDef),
229
- };
230
- },
231
- {
232
- prisma: generatePrisma,
233
- }
234
- ),
235
-
236
- // Templates
237
- templates: {
238
- base,
239
- baseWithWorkspace,
240
- withMetadata,
241
- withActive,
242
- withAudit,
243
- withExternalId,
244
- withNameDescription,
245
- fields,
246
- },
247
- };
package/src/model.ts DELETED
@@ -1,330 +0,0 @@
1
- /**
2
- * Model builder using dsl.create({ name, schema, indexes })
3
- *
4
- * v3: Models define ONLY columns (no inline relations)
5
- * Relations are defined separately via dsl.defineRelations()
6
- * Children (inline nested models) are still supported via schema callback
7
- *
8
- * @example
9
- * // Simple model - just columns
10
- * const Workspace = dsl.create({
11
- * name: "Workspace",
12
- * schema: {
13
- * ...dsl.base,
14
- * name: dsl.string(),
15
- * slug: dsl.string({ unique: true }),
16
- * },
17
- * });
18
- *
19
- * // Model with FK column (explicit) and type-safe indexes
20
- * const Printer = dsl.create({
21
- * name: "Printer",
22
- * schema: {
23
- * ...dsl.base,
24
- * name: dsl.string(),
25
- * workspaceId: dsl.string({ index: true }), // FK declared explicitly
26
- * },
27
- * // TypeScript suggests valid column names
28
- * indexes: (i) => [
29
- * i.unique("workspaceId", "name"),
30
- * ],
31
- * });
32
- *
33
- * // Model with children (inline nested models)
34
- * const Order = dsl.create({
35
- * name: "Order",
36
- * schema: (s) => ({
37
- * ...dsl.base,
38
- * total: dsl.int(),
39
- * Items: s.children({
40
- * name: "OrderItem",
41
- * schema: { id: dsl.id(), quantity: dsl.int() },
42
- * }),
43
- * }),
44
- * });
45
- */
46
-
47
- import type {
48
- ChildrenBuilder,
49
- ChildrenDef,
50
- ChildrenSchemaCallback,
51
- ColumnDef,
52
- IndexBuilder,
53
- IndexCallback,
54
- IndexDef,
55
- IndexOptions,
56
- IndexType,
57
- ModelDef,
58
- SchemaDefinition,
59
- } from "./types.ts";
60
- import { cloneColumnDef } from "./column.ts";
61
- import { createChildrenBuilder } from "./relation.ts";
62
-
63
- // ─── Type Guards ─────────────────────────
64
-
65
- /**
66
- * Checks if a value is a ColumnDef
67
- */
68
- function isColumnDef(value: unknown): value is ColumnDef {
69
- return (
70
- typeof value === "object" &&
71
- value !== null &&
72
- "__type" in value &&
73
- value.__type === "column"
74
- );
75
- }
76
-
77
- /**
78
- * Checks if a value is a ChildrenDef
79
- */
80
- function isChildrenDef(value: unknown): value is ChildrenDef {
81
- return (
82
- typeof value === "object" &&
83
- value !== null &&
84
- "__type" in value &&
85
- value.__type === "children"
86
- );
87
- }
88
-
89
- // ─── Helpers ─────────────────────────────
90
-
91
- /**
92
- * Converts a model name to a FK column name
93
- * e.g., "Order" -> "orderId"
94
- */
95
- function toFkColumnName(modelName: string): string {
96
- return modelName.charAt(0).toLowerCase() + modelName.slice(1) + "Id";
97
- }
98
-
99
- // ─── Index Builder ───────────────────────
100
-
101
- /**
102
- * Creates an IndexBuilder with type-safe column references
103
- *
104
- * @example
105
- * indexes: (i) => [
106
- * i.on("workspaceId", "name"), // Composite index
107
- * i.unique("workspaceId", "email"), // Unique constraint
108
- * i.on("status"), // Single column index
109
- * i.gin("tags"), // GIN index for JSON/arrays
110
- * i.on(["content"], { type: "Gist" }), // Index with type option
111
- * ]
112
- */
113
- export function createIndexBuilder<T extends string>(): IndexBuilder<T> {
114
- // Helper to create index with optional type
115
- const createIndex = (columns: string[], type?: IndexType): IndexDef => ({
116
- __type: "index",
117
- __columns: columns,
118
- __indexType: type,
119
- });
120
-
121
- return {
122
- /**
123
- * Creates a composite index on the specified columns
124
- * Optionally accepts an options object with index type
125
- */
126
- on<C extends T>(...args: C[] | [C[], IndexOptions]): IndexDef {
127
- // Check if last arg is options object
128
- if (args.length === 2 && Array.isArray(args[0]) && typeof args[1] === "object" && !Array.isArray(args[1])) {
129
- const [columns, options] = args as [C[], IndexOptions];
130
- return createIndex(columns, options.type);
131
- }
132
- // Normal variadic columns
133
- return createIndex(args as string[]);
134
- },
135
-
136
- /**
137
- * Creates a unique constraint on the specified columns
138
- */
139
- unique<C extends T>(...columns: C[]): IndexDef {
140
- return {
141
- __type: "unique",
142
- __columns: columns,
143
- };
144
- },
145
-
146
- /**
147
- * Creates a GIN index (PostgreSQL) - good for JSON, arrays, full-text search
148
- */
149
- gin<C extends T>(...columns: C[]): IndexDef {
150
- return createIndex(columns, "Gin");
151
- },
152
-
153
- /**
154
- * Creates a GiST index (PostgreSQL) - good for geometric, range, and full-text data
155
- */
156
- gist<C extends T>(...columns: C[]): IndexDef {
157
- return createIndex(columns, "Gist");
158
- },
159
-
160
- /**
161
- * Creates a Hash index (PostgreSQL) - good for equality comparisons
162
- */
163
- hash<C extends T>(...columns: C[]): IndexDef {
164
- return createIndex(columns, "Hash");
165
- },
166
-
167
- /**
168
- * Creates a BRIN index (PostgreSQL) - good for large tables with naturally ordered data
169
- */
170
- brin<C extends T>(...columns: C[]): IndexDef {
171
- return createIndex(columns, "Brin");
172
- },
173
- };
174
- }
175
-
176
- // ─── Schema Processing ───────────────────
177
-
178
- /**
179
- * Processes a schema definition and extracts columns and children
180
- * Note: Relations are no longer processed here - use defineRelations() instead
181
- */
182
- function processSchema(
183
- modelName: string,
184
- schema: SchemaDefinition | ChildrenSchemaCallback
185
- ): {
186
- columns: Map<string, ColumnDef>;
187
- children: Map<string, ModelDef>;
188
- resolvedSchema: SchemaDefinition;
189
- } {
190
- // Resolve schema if it's a callback (for children support)
191
- const resolvedSchema =
192
- typeof schema === "function" ? schema(createChildrenBuilder()) : schema;
193
-
194
- const columns = new Map<string, ColumnDef>();
195
- const children = new Map<string, ModelDef>();
196
-
197
- for (const [key, value] of Object.entries(resolvedSchema)) {
198
- if (isColumnDef(value)) {
199
- // Clone to avoid mutating shared instances (e.g., from templates)
200
- const cloned = cloneColumnDef(value);
201
- cloned.__name = key;
202
- columns.set(key, cloned);
203
- } else if (isChildrenDef(value)) {
204
- // Create child model from children definition
205
- const childModel = create({
206
- name: value.__name,
207
- schema: value.__schema,
208
- });
209
-
210
- // Add parent FK to child model
211
- const parentFkName = toFkColumnName(modelName);
212
- childModel.__columns.set(parentFkName, {
213
- __type: "column",
214
- __columnType: "string",
215
- __name: parentFkName,
216
- __config: {
217
- index: true,
218
- },
219
- });
220
-
221
- children.set(key, childModel);
222
- }
223
- }
224
-
225
- return { columns, children, resolvedSchema };
226
- }
227
-
228
- // ─── Type Helpers ────────────────────────
229
-
230
- /**
231
- * Extract keys from schema where value is a ColumnDef (excludes ChildrenDef)
232
- */
233
- export type ColumnKeys<T> = {
234
- [K in keyof T]: T[K] extends ColumnDef ? K : never;
235
- }[keyof T];
236
-
237
- /**
238
- * All valid column names for indexes
239
- */
240
- export type SchemaColumnNames<T> = Extract<ColumnKeys<T>, string>;
241
-
242
- // ─── Model Config ────────────────────────
243
-
244
- /**
245
- * Config for dsl.create() with type-safe indexes
246
- */
247
- export type CreateModelConfig<
248
- TSchema extends SchemaDefinition,
249
- TColumns extends string = SchemaColumnNames<TSchema>,
250
- > = {
251
- name: string;
252
- schema: TSchema | ((s: ChildrenBuilder) => TSchema);
253
- indexes?: IndexCallback<TColumns>;
254
- /** Map to a different database table name - generates @@map("table_name") */
255
- map?: string;
256
- /** Compound primary key columns - generates @@id([col1, col2]) */
257
- primaryKey?: TColumns[];
258
- };
259
-
260
- // ─── Model Factory ───────────────────────
261
-
262
- /**
263
- * Creates a model definition with type-safe indexes
264
- *
265
- * v3: Models only contain columns and children.
266
- * Relations are defined separately via dsl.defineRelations()
267
- *
268
- * @example
269
- * // Simple model
270
- * const User = dsl.create({
271
- * name: "User",
272
- * schema: {
273
- * ...dsl.base,
274
- * email: dsl.string({ unique: true }),
275
- * workspaceId: dsl.string({ index: true }), // FK declared explicitly
276
- * },
277
- * });
278
- *
279
- * // Model with children
280
- * const Order = dsl.create({
281
- * name: "Order",
282
- * schema: (s) => ({
283
- * ...dsl.base,
284
- * Items: s.children({
285
- * name: "OrderItem",
286
- * schema: { id: dsl.id(), qty: dsl.int() },
287
- * }),
288
- * }),
289
- * });
290
- */
291
- export function create<
292
- const TSchema extends SchemaDefinition,
293
- TColumns extends string = SchemaColumnNames<TSchema>,
294
- >(config: CreateModelConfig<TSchema, TColumns>): ModelDef<TSchema> {
295
- const { columns, children } = processSchema(config.name, config.schema);
296
-
297
- const model: ModelDef<TSchema> = {
298
- __type: "model",
299
- __name: config.name,
300
- __schema: config.schema,
301
- __indexes: config.indexes as IndexCallback | undefined,
302
- __columns: columns,
303
- __children: children,
304
- __map: config.map,
305
- __primaryKey: config.primaryKey as string[] | undefined,
306
- };
307
-
308
- return model;
309
- }
310
-
311
- // ─── Model Utilities ─────────────────────
312
-
313
- /**
314
- * Gets all column names from a model (for index builder)
315
- */
316
- export function getColumnNames(model: ModelDef): string[] {
317
- return Array.from(model.__columns.keys());
318
- }
319
-
320
- /**
321
- * Evaluates index definitions for a model
322
- */
323
- export function evaluateIndexes(model: ModelDef): IndexDef[] {
324
- if (!model.__indexes) {
325
- return [];
326
- }
327
-
328
- const indexBuilder = createIndexBuilder<string>();
329
- return model.__indexes(indexBuilder);
330
- }
package/src/relation.ts DELETED
@@ -1,75 +0,0 @@
1
- /**
2
- * Children builder for inline nested models
3
- *
4
- * v3: Relations are now defined separately via dsl.defineRelations()
5
- * This module only provides the children() builder for inline nested models
6
- *
7
- * @example
8
- * const Order = dsl.create({
9
- * name: "Order",
10
- * schema: (s) => ({
11
- * ...dsl.base,
12
- * total: dsl.int(),
13
- * Items: s.children({
14
- * name: "OrderItem",
15
- * schema: {
16
- * ...dsl.base,
17
- * productId: dsl.string(),
18
- * quantity: dsl.int(),
19
- * },
20
- * }),
21
- * }),
22
- * });
23
- */
24
-
25
- import type {
26
- ChildrenBuilder,
27
- ChildrenDef,
28
- ChildrenRelationConfig,
29
- } from "./types.ts";
30
-
31
- // ─── Children Builder ─────────────────────
32
-
33
- /**
34
- * Creates an inline child model
35
- * Generates a separate model with automatic FK back to parent
36
- *
37
- * @example
38
- * Files: s.children({
39
- * name: "PrintJobFile",
40
- * schema: {
41
- * ...dsl.base,
42
- * fileUrl: dsl.string(),
43
- * fileName: dsl.string(),
44
- * },
45
- * })
46
- *
47
- * // Or with nested children:
48
- * Activities: s.children({
49
- * name: "PrintJobActivity",
50
- * schema: (s2) => ({
51
- * ...dsl.base,
52
- * type: dsl.string(),
53
- * Logs: s2.children({
54
- * name: "ActivityLog",
55
- * schema: { id: dsl.id(), message: dsl.string() },
56
- * }),
57
- * }),
58
- * })
59
- */
60
- export function children(config: ChildrenRelationConfig): ChildrenDef {
61
- return {
62
- __type: "children",
63
- __name: config.name,
64
- __schema: config.schema,
65
- };
66
- }
67
-
68
- /**
69
- * Creates a ChildrenBuilder for use in schema callbacks
70
- */
71
- export function createChildrenBuilder(): ChildrenBuilder {
72
- return {
73
- children,
74
- };
75
- }