@vibeorm/dsl 2.0.0 → 2.1.0
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/dist/field-type.d.ts +30 -0
- package/dist/field-type.d.ts.map +1 -0
- package/dist/generator/prisma.d.ts +1 -1
- package/dist/generator/prisma.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +531 -118
- package/dist/index.js.map +12 -10
- package/dist/model.d.ts +1 -1
- package/dist/model.d.ts.map +1 -1
- package/dist/predicate.d.ts +86 -0
- package/dist/predicate.d.ts.map +1 -0
- package/dist/relation-plan.d.ts +9 -1
- package/dist/relation-plan.d.ts.map +1 -1
- package/dist/relations.d.ts.map +1 -1
- package/dist/to-ir.d.ts +14 -1
- package/dist/to-ir.d.ts.map +1 -1
- package/dist/types.d.ts +289 -30
- package/dist/types.d.ts.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/package.json +3 -2
package/dist/model.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ import type { CreateModelConfig, IndexBuilder, IndexDef, ModelDef, SchemaDefinit
|
|
|
27
27
|
* i.on(["content"], { type: "Gist" }),
|
|
28
28
|
* ]
|
|
29
29
|
*/
|
|
30
|
-
export declare function createIndexBuilder<T extends string = string>(): IndexBuilder<T>;
|
|
30
|
+
export declare function createIndexBuilder<T extends string = string, TSchema extends SchemaDefinition = SchemaDefinition>(): IndexBuilder<T, TSchema>;
|
|
31
31
|
/**
|
|
32
32
|
* Creates a model definition. `indexes` and `primaryKey` are constrained to
|
|
33
33
|
* the model's own column names.
|
package/dist/model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAQH,OAAO,KAAK,EAKV,iBAAiB,EAEjB,YAAY,EAEZ,QAAQ,EAGR,QAAQ,EAIR,gBAAgB,EAEjB,MAAM,YAAY,CAAC;AAkBpB;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,CAAC,SAAS,MAAM,GAAG,MAAM,EACzB,OAAO,SAAS,gBAAgB,GAAG,gBAAgB,KAChD,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAkG5B;AAyCD;;;GAGG;AACH,wBAAgB,MAAM,CAAC,KAAK,CAAC,OAAO,SAAS,gBAAgB,EAC3D,MAAM,EAAE,iBAAiB,CAAC,OAAO,CAAC,GACjC,QAAQ,CAAC,OAAO,CAAC,CAwBnB;AAID,yDAAyD;AACzD,wBAAgB,cAAc,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,GAAG,MAAM,EAAE,CAEpE;AAED,6DAA6D;AAC7D,wBAAgB,eAAe,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,GAAG,QAAQ,EAAE,CAMvE"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The typed predicate builder — the `c` handed to a model's `checks` callback
|
|
3
|
+
* and to an index's `.where()`.
|
|
4
|
+
*
|
|
5
|
+
* Every combinator returns plain {@link PredicateIR}: serializable data, never
|
|
6
|
+
* a JavaScript callback. Nothing downstream evaluates a function, and a
|
|
7
|
+
* predicate survives JSON unchanged. The SQL text is produced exactly once, by
|
|
8
|
+
* `renderPredicate` in @vibeorm/sql, when the schema is compiled and the
|
|
9
|
+
* dialect is finally known.
|
|
10
|
+
*
|
|
11
|
+
* The builder is structural at RUNTIME — it only records names and values — so
|
|
12
|
+
* one instance serves every model. The type parameters on
|
|
13
|
+
* {@link PredicateBuilder} are what bind it to a particular model's columns.
|
|
14
|
+
*/
|
|
15
|
+
import type { ExclusionIR, CheckIR, EnumIR, FieldIR, PredicateIR } from "@vibeorm/schema";
|
|
16
|
+
import type { SqlDialect } from "@vibeorm/sql";
|
|
17
|
+
import type { ModelDef, ChecksCallback, ModelCheckConfig, PredicateBuilder, SchemaDefinition } from "./types.ts";
|
|
18
|
+
/**
|
|
19
|
+
* One predicate builder instance. Stateless and structural — the type
|
|
20
|
+
* parameters, not the value, bind it to a model.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createPredicateBuilder<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition>(): PredicateBuilder<TColumns, TSchema>;
|
|
23
|
+
/** A model's CHECKs, still un-rendered: raw text stays raw, typed stays typed. */
|
|
24
|
+
export type EvaluatedCheck = {
|
|
25
|
+
readonly kind: "raw";
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly expression: string;
|
|
28
|
+
} | {
|
|
29
|
+
readonly kind: "typed";
|
|
30
|
+
readonly name: string;
|
|
31
|
+
readonly predicate: PredicateIR;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Run a model's `checks` declaration, whichever form it took.
|
|
35
|
+
*
|
|
36
|
+
* The raw array form and the typed callback form produce the same shape of
|
|
37
|
+
* answer, so every consumer downstream handles ONE list — and raw text is
|
|
38
|
+
* carried through untouched rather than parsed into a predicate.
|
|
39
|
+
*/
|
|
40
|
+
export declare function evaluateChecks(params: {
|
|
41
|
+
checks: readonly ModelCheckConfig[] | ChecksCallback | undefined;
|
|
42
|
+
model: string;
|
|
43
|
+
}): readonly EvaluatedCheck[];
|
|
44
|
+
/** What a predicate needs to know about the model it belongs to. */
|
|
45
|
+
export type PredicateModel = {
|
|
46
|
+
readonly name: string;
|
|
47
|
+
readonly fields: readonly FieldIR[];
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* A model's CHECKs as IR, with every typed expression compiled to SQL ONCE.
|
|
51
|
+
*
|
|
52
|
+
* `CheckIR.expression` always carries the AUTHORED text — what the schema says,
|
|
53
|
+
* not what a database deparsed back — because that is the currency EPIC 1's
|
|
54
|
+
* differ, desired-state records and DDL renderers all read. The predicate rides
|
|
55
|
+
* alongside as the structured source, so editing a typed expression changes the
|
|
56
|
+
* text and produces a real migration, while re-rendering an unchanged one
|
|
57
|
+
* produces byte-identical text and cannot churn.
|
|
58
|
+
*/
|
|
59
|
+
/** Compile exclusions beside CHECKs and index predicates at the schema boundary. */
|
|
60
|
+
export declare function compileExclusions(params: {
|
|
61
|
+
exclusions: ModelDef["__exclusions"];
|
|
62
|
+
model: PredicateModel;
|
|
63
|
+
dialect: SqlDialect;
|
|
64
|
+
}): readonly ExclusionIR[];
|
|
65
|
+
export declare function compileChecks(params: {
|
|
66
|
+
checks: readonly ModelCheckConfig[] | ChecksCallback | undefined;
|
|
67
|
+
model: PredicateModel;
|
|
68
|
+
dialect: SqlDialect;
|
|
69
|
+
enums: readonly EnumIR[];
|
|
70
|
+
}): readonly CheckIR[];
|
|
71
|
+
/**
|
|
72
|
+
* An index's partial predicate as IR: the raw string verbatim, or a typed
|
|
73
|
+
* expression compiled to SQL text plus its structured source.
|
|
74
|
+
*/
|
|
75
|
+
export declare function compileIndexPredicate(params: {
|
|
76
|
+
where: string | undefined;
|
|
77
|
+
wherePredicate: PredicateIR | undefined;
|
|
78
|
+
columns: readonly string[];
|
|
79
|
+
model: PredicateModel;
|
|
80
|
+
dialect: SqlDialect;
|
|
81
|
+
enums: readonly EnumIR[];
|
|
82
|
+
}): {
|
|
83
|
+
readonly where: string;
|
|
84
|
+
readonly wherePredicate?: PredicateIR;
|
|
85
|
+
} | undefined;
|
|
86
|
+
//# sourceMappingURL=predicate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predicate.d.ts","sourceRoot":"","sources":["../src/predicate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAkB,MAAM,iBAAiB,CAAC;AAE1G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EACd,gBAAgB,EAEhB,gBAAgB,EAEhB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAyEpB;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,SAAS,MAAM,GAAG,MAAM,EAChC,OAAO,SAAS,gBAAgB,GAAG,gBAAgB,KAChD,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CA8DvC;AAID,kFAAkF;AAClF,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC5E;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAA;CAAE,CAAC;AAEvF;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE;IACrC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,cAAc,GAAG,SAAS,CAAC;IACjE,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,SAAS,cAAc,EAAE,CAmB5B;AAID,oEAAoE;AACpE,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;CACrC,CAAC;AAEF;;;;;;;;;GASG;AACH,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IAAE,UAAU,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAE,GAAG,SAAS,WAAW,EAAE,CAGtJ;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE;IACpC,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAAG,cAAc,GAAG,SAAS,CAAC;IACjE,KAAK,EAAE,cAAc,CAAC;IACtB,OAAO,EAAE,UAAU,CAAC;IACpB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B,GAAG,SAAS,OAAO,EAAE,CAkBrB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,cAAc,EAAE,WAAW,GAAG,SAAS,CAAC;IACxC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,KAAK,EAAE,cAAc,CAAC;IACtB,OAAO,EAAE,UAAU,CAAC;IACpB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,WAAW,CAAA;CAAE,GAAG,SAAS,CAwBhF"}
|
package/dist/relation-plan.d.ts
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* parent) use the `@relation` alias when there is one, else the source model
|
|
21
21
|
* name, suffixed on collision.
|
|
22
22
|
*/
|
|
23
|
-
import type { CascadeAction, RelationType } from "@vibeorm/schema";
|
|
23
|
+
import type { CascadeAction, PredicateIR, RelationType } from "@vibeorm/schema";
|
|
24
24
|
import type { IndexType, ModelDef, RelationsMap, SchemaDef } from "./types.ts";
|
|
25
25
|
/**
|
|
26
26
|
* Structural role of a planned relation field:
|
|
@@ -43,7 +43,11 @@ export type PlannedRelation = {
|
|
|
43
43
|
readonly isOptional: boolean;
|
|
44
44
|
/** `@relation("Name")` — the DSL's `alias`. */
|
|
45
45
|
readonly relationName?: string;
|
|
46
|
+
/** Physical FOREIGN KEY name — the DSL's `constraintName`, never the alias. */
|
|
47
|
+
readonly constraintName?: string;
|
|
48
|
+
/** FK columns on this model, in declared order; member `i` pairs with `references[i]`. */
|
|
46
49
|
readonly fields?: readonly string[];
|
|
50
|
+
/** Referenced columns on the target model, in declared order. */
|
|
47
51
|
readonly references?: readonly string[];
|
|
48
52
|
readonly onDelete?: CascadeAction;
|
|
49
53
|
readonly onUpdate?: CascadeAction;
|
|
@@ -56,6 +60,8 @@ export type PlannedIndex = {
|
|
|
56
60
|
readonly indexType?: IndexType;
|
|
57
61
|
/** Partial-index predicate (raw SQL) — postgres/pglite/sqlite only. */
|
|
58
62
|
readonly where?: string;
|
|
63
|
+
/** Partial-index predicate as a typed expression, rendered when the dialect is known. */
|
|
64
|
+
readonly wherePredicate?: PredicateIR;
|
|
59
65
|
/** `UNIQUE NULLS NOT DISTINCT` — unique indexes on postgres/pglite (15+) only. */
|
|
60
66
|
readonly nullsNotDistinct?: boolean;
|
|
61
67
|
/** Client selector name for a compound unique (Prisma `@@unique(..., name:)`). */
|
|
@@ -74,6 +80,8 @@ export type MergedOneToOneSide = {
|
|
|
74
80
|
/** Merged referential actions — the FK owner's win. */
|
|
75
81
|
readonly onDelete?: CascadeAction;
|
|
76
82
|
readonly onUpdate?: CascadeAction;
|
|
83
|
+
/** Merged physical FK name — the FK owner's wins; either side may declare it. */
|
|
84
|
+
readonly constraintName?: string;
|
|
77
85
|
};
|
|
78
86
|
/**
|
|
79
87
|
* Finds pairs of `r.one` relations that describe the same 1:1 relationship
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relation-plan.d.ts","sourceRoot":"","sources":["../src/relation-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"relation-plan.d.ts","sourceRoot":"","sources":["../src/relation-plan.ts"],"names":[],"mappings":"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"}
|
package/dist/relations.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relations.d.ts","sourceRoot":"","sources":["../src/relations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"relations.d.ts","sourceRoot":"","sources":["../src/relations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAKV,QAAQ,EACR,eAAe,EAGf,gBAAgB,EAChB,YAAY,EACZ,eAAe,EAGhB,MAAM,YAAY,CAAC;AAmMpB;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,OAAO,SAAS,YAAY,EAC1G,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,CAAC,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,KAAK,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,GAC7E,OAAO,CAGT;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,OAAO,SAAS,YAAY,EAC9G,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,CAAC,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,KAAK,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,GACtF,OAAO,CAGT;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,KAAK,CAAC,MAAM,SAAS,SAAS,YAAY,EAAE,EAAE,GAAG,KAAK,EAAE,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAWtH"}
|
package/dist/to-ir.d.ts
CHANGED
|
@@ -26,12 +26,25 @@
|
|
|
26
26
|
* - `.collation()` / `{ collation }` → `FieldIR.collation`.
|
|
27
27
|
* - relation types are derived structurally by `resolveRelationType`.
|
|
28
28
|
*/
|
|
29
|
-
import type { DefaultValueIR, ExtensionRegistry, Provider, SchemaIR } from "@vibeorm/schema";
|
|
29
|
+
import type { DefaultValueIR, ExtensionRegistry, FieldIR, Provider, SchemaIR } from "@vibeorm/schema";
|
|
30
30
|
import type { ColumnDef, SchemaDef } from "./types.ts";
|
|
31
31
|
/** Compile a column default once for both DSL output paths. */
|
|
32
32
|
export declare function fieldDefault(params: {
|
|
33
33
|
column: ColumnDef;
|
|
34
34
|
}): DefaultValueIR | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* One column as `FieldIR`.
|
|
37
|
+
*
|
|
38
|
+
* Exported so the `.prisma` printer compiles typed CHECK and partial-index
|
|
39
|
+
* expressions against exactly the same physical names and scalar types the IR
|
|
40
|
+
* path uses — a second mapping is how the two would drift apart.
|
|
41
|
+
*/
|
|
42
|
+
export declare function buildField(params: {
|
|
43
|
+
name: string;
|
|
44
|
+
column: ColumnDef;
|
|
45
|
+
/** Native type resolved by an extension field-type lowering, when present. */
|
|
46
|
+
extensionNativeType?: string;
|
|
47
|
+
}): FieldIR;
|
|
35
48
|
/**
|
|
36
49
|
* Compiles a composed DSL schema to the canonical `SchemaIR`, then validates it.
|
|
37
50
|
*
|
package/dist/to-ir.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"to-ir.d.ts","sourceRoot":"","sources":["../src/to-ir.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;
|
|
1
|
+
{"version":3,"file":"to-ir.d.ts","sourceRoot":"","sources":["../src/to-ir.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAYH,OAAO,KAAK,EACV,cAAc,EAGd,iBAAiB,EACjB,OAAO,EAKP,QAAQ,EAER,QAAQ,EAET,MAAM,iBAAiB,CAAC;AAQzB,OAAO,KAAK,EACV,SAAS,EAKT,SAAS,EAEV,MAAM,YAAY,CAAC;AA6BpB,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GAAG,cAAc,GAAG,SAAS,CAyCtF;AA6CD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;IAClB,8EAA8E;IAC9E,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,GAAG,OAAO,CA8BV;AA0OD;;;;;;;;;GASG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE;IAC3B,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC,GAAG,QAAQ,CAmDX"}
|
package/dist/types.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* through `defineRelations` (Drizzle-style), which keeps column references
|
|
6
6
|
* type-safe without inference-heavy model types.
|
|
7
7
|
*/
|
|
8
|
-
import type { CascadeAction, EnumStorage, ExtensionAttributeValue, RlsContextIR, RlsContextRefIR, RlsPolicyIR } from "@vibeorm/schema";
|
|
8
|
+
import type { ExclusionSpec, ExclusionEndpoint, CascadeAction, EnumStorage, ExtensionAttributeValue, PredicateIR, Provider, RlsContextIR, RlsContextRefIR, RlsPolicyIR } from "@vibeorm/schema";
|
|
9
9
|
import type { ChainableEnumColumn } from "./column.ts";
|
|
10
10
|
/** Referential actions, re-exported from the IR so both sources agree. */
|
|
11
11
|
export type { CascadeAction };
|
|
@@ -175,11 +175,59 @@ export type ChildrenDef = {
|
|
|
175
175
|
export type ChildrenBuilder = {
|
|
176
176
|
children(config: ChildrenRelationConfig): ChildrenDef;
|
|
177
177
|
};
|
|
178
|
-
/**
|
|
178
|
+
/**
|
|
179
|
+
* A named CHECK constraint written as a RAW SQL expression.
|
|
180
|
+
*
|
|
181
|
+
* This is the documented escape hatch for anything the typed expression
|
|
182
|
+
* language cannot say (database-specific functions, operators VibeORM does not
|
|
183
|
+
* model). The text is carried through VERBATIM: never parsed, never
|
|
184
|
+
* re-rendered, never checked against the model — so physical column names and
|
|
185
|
+
* dialect-specific syntax are the author's responsibility here.
|
|
186
|
+
*/
|
|
187
|
+
/** Range operands are restricted to the schema's matching scalar columns. */
|
|
188
|
+
export type ExclusionConfig<TSchema extends SchemaDefinition> = Omit<ExclusionSpec<SchemaColumnNames<TSchema>>, "range"> & {
|
|
189
|
+
readonly range: ({
|
|
190
|
+
readonly type: "int8range";
|
|
191
|
+
readonly lower: ExclusionEndpoint<ExclusionColumns<TSchema, "bigint">>;
|
|
192
|
+
readonly upper: ExclusionEndpoint<ExclusionColumns<TSchema, "bigint">>;
|
|
193
|
+
} | {
|
|
194
|
+
readonly type: "tsrange" | "tstzrange";
|
|
195
|
+
readonly lower: ExclusionEndpoint<ExclusionColumns<TSchema, "datetime">>;
|
|
196
|
+
readonly upper: ExclusionEndpoint<ExclusionColumns<TSchema, "datetime">>;
|
|
197
|
+
}) & {
|
|
198
|
+
readonly bounds: "[)" | "[]" | "()" | "(]";
|
|
199
|
+
};
|
|
200
|
+
};
|
|
201
|
+
type ExclusionColumns<TSchema extends SchemaDefinition, TType extends ColumnType> = {
|
|
202
|
+
[K in keyof TSchema]: TSchema[K] extends ColumnDef<TType> ? K : never;
|
|
203
|
+
}[keyof TSchema] & string;
|
|
204
|
+
/** Predicate callback for a model's exclusion declarations. */
|
|
205
|
+
export type ExclusionsCallback<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition> = (c: PredicateBuilder<TColumns, TSchema>) => readonly ExclusionSpec<TColumns>[];
|
|
179
206
|
export type ModelCheckConfig = {
|
|
180
207
|
readonly name: string;
|
|
181
208
|
readonly expression: string;
|
|
182
209
|
};
|
|
210
|
+
/**
|
|
211
|
+
* A named CHECK constraint built from a TYPED expression (`c.named(...)`).
|
|
212
|
+
*
|
|
213
|
+
* The predicate is serializable data compiled to SQL once, when the schema
|
|
214
|
+
* becomes IR or `.prisma` text — never a JavaScript callback carried
|
|
215
|
+
* downstream.
|
|
216
|
+
*/
|
|
217
|
+
export type NamedCheckDef = {
|
|
218
|
+
readonly __type: "check";
|
|
219
|
+
readonly name: string;
|
|
220
|
+
readonly predicate: PredicateIR;
|
|
221
|
+
};
|
|
222
|
+
/**
|
|
223
|
+
* The `c` handed to a model's `checks` callback, returning named typed CHECKs.
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* checks: (c) => [
|
|
227
|
+
* c.named("dispatch_clock", c.gt(c.field("deadlineAt"), c.field("startedAt"))),
|
|
228
|
+
* ]
|
|
229
|
+
*/
|
|
230
|
+
export type ChecksCallback<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition> = (c: PredicateBuilder<TColumns, TSchema>) => NamedCheckDef[];
|
|
183
231
|
/**
|
|
184
232
|
* Application-level row-scoping policy — the DSL twin of
|
|
185
233
|
* `@@policy([field], context: "key")`. The runtime fails closed on policied
|
|
@@ -200,8 +248,18 @@ export type IndexDef = {
|
|
|
200
248
|
readonly __type: "index" | "unique";
|
|
201
249
|
readonly __columns: readonly string[];
|
|
202
250
|
readonly __indexType?: IndexType;
|
|
203
|
-
/**
|
|
251
|
+
/**
|
|
252
|
+
* Partial-index predicate as RAW SQL — postgres/pglite/sqlite only. Carried
|
|
253
|
+
* verbatim, exactly like a raw CHECK: the escape hatch for predicates the
|
|
254
|
+
* typed expression language cannot say.
|
|
255
|
+
*/
|
|
204
256
|
readonly __where?: string;
|
|
257
|
+
/**
|
|
258
|
+
* Partial-index predicate as a TYPED expression (`.where((c) => …)`),
|
|
259
|
+
* compiled to SQL once when the schema becomes IR or `.prisma` text. Refused
|
|
260
|
+
* alongside `__where` — one index has one predicate.
|
|
261
|
+
*/
|
|
262
|
+
readonly __wherePredicate?: PredicateIR;
|
|
205
263
|
/** `UNIQUE NULLS NOT DISTINCT` — unique indexes on postgres/pglite (15+) only. */
|
|
206
264
|
readonly __nullsNotDistinct?: boolean;
|
|
207
265
|
/** Client selector name for a compound unique (Prisma `@@unique(..., name:)`). */
|
|
@@ -230,20 +288,116 @@ export type UniqueIndexOptions = {
|
|
|
230
288
|
*/
|
|
231
289
|
name?: string;
|
|
232
290
|
};
|
|
291
|
+
/**
|
|
292
|
+
* An index that can still be narrowed by a TYPED partial predicate.
|
|
293
|
+
*
|
|
294
|
+
* `.where()` is terminal — it returns the plain {@link IndexDef} — so an index
|
|
295
|
+
* carries at most one predicate and the chain cannot be reopened.
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* i.index("deadlineAt").where((c) => c.isNull("cancelledAt"))
|
|
299
|
+
*/
|
|
300
|
+
export type PartialIndexDef<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition> = IndexDef & {
|
|
301
|
+
where(predicate: (c: PredicateBuilder<TColumns, TSchema>) => PredicateIR): IndexDef;
|
|
302
|
+
};
|
|
233
303
|
/** Index builder; column names are constrained to the model's own columns. */
|
|
234
|
-
export type IndexBuilder<TColumns extends string = string> = {
|
|
235
|
-
on<T extends TColumns>(...columns: T[]):
|
|
236
|
-
on<T extends TColumns>(columns: T[], options: IndexOptions):
|
|
304
|
+
export type IndexBuilder<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition> = {
|
|
305
|
+
on<T extends TColumns>(...columns: T[]): PartialIndexDef<TColumns, TSchema>;
|
|
306
|
+
on<T extends TColumns>(columns: T[], options: IndexOptions): PartialIndexDef<TColumns, TSchema>;
|
|
237
307
|
/** Alias of `on(...)` — reads better next to `unique(...)`. */
|
|
238
|
-
index<T extends TColumns>(...columns: T[]):
|
|
239
|
-
unique<T extends TColumns>(...columns: T[]):
|
|
240
|
-
unique<T extends TColumns>(columns: T[], options: UniqueIndexOptions):
|
|
241
|
-
gin<T extends TColumns>(...columns: T[]):
|
|
242
|
-
gist<T extends TColumns>(...columns: T[]):
|
|
243
|
-
hash<T extends TColumns>(...columns: T[]):
|
|
244
|
-
brin<T extends TColumns>(...columns: T[]):
|
|
245
|
-
};
|
|
246
|
-
export type IndexCallback<TColumns extends string = string> = (i: IndexBuilder<TColumns>) => IndexDef[];
|
|
308
|
+
index<T extends TColumns>(...columns: T[]): PartialIndexDef<TColumns, TSchema>;
|
|
309
|
+
unique<T extends TColumns>(...columns: T[]): PartialIndexDef<TColumns, TSchema>;
|
|
310
|
+
unique<T extends TColumns>(columns: T[], options: UniqueIndexOptions): PartialIndexDef<TColumns, TSchema>;
|
|
311
|
+
gin<T extends TColumns>(...columns: T[]): PartialIndexDef<TColumns, TSchema>;
|
|
312
|
+
gist<T extends TColumns>(...columns: T[]): PartialIndexDef<TColumns, TSchema>;
|
|
313
|
+
hash<T extends TColumns>(...columns: T[]): PartialIndexDef<TColumns, TSchema>;
|
|
314
|
+
brin<T extends TColumns>(...columns: T[]): PartialIndexDef<TColumns, TSchema>;
|
|
315
|
+
};
|
|
316
|
+
export type IndexCallback<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition> = (i: IndexBuilder<TColumns, TSchema>) => IndexDef[];
|
|
317
|
+
/**
|
|
318
|
+
* The JavaScript literal a column of each pairing tag admits.
|
|
319
|
+
*
|
|
320
|
+
* `DateTime` is deliberately `never`: the same instant is spelled three
|
|
321
|
+
* different ways across postgres, mysql and sqlite, and guessing wrong is a
|
|
322
|
+
* silent data bug rather than an error — so a fixed instant goes through the
|
|
323
|
+
* raw-expression escape hatch, while "end after start" is a column-to-column
|
|
324
|
+
* comparison that needs no literal at all. `Json`, `Bytes` and `Unsupported`
|
|
325
|
+
* are `never` because VibeORM does not model their operators.
|
|
326
|
+
*
|
|
327
|
+
* `Decimal` takes exact decimal TEXT (`"19.99"`) for the reason column defaults
|
|
328
|
+
* do: a JS number cannot carry an exact decimal.
|
|
329
|
+
*/
|
|
330
|
+
type PredicateLiteralByRefKind = {
|
|
331
|
+
readonly String: string;
|
|
332
|
+
readonly Boolean: boolean;
|
|
333
|
+
readonly Int: number;
|
|
334
|
+
readonly BigInt: bigint | number;
|
|
335
|
+
readonly Float: number;
|
|
336
|
+
readonly Decimal: string;
|
|
337
|
+
readonly DateTime: never;
|
|
338
|
+
readonly Json: never;
|
|
339
|
+
readonly Bytes: never;
|
|
340
|
+
readonly Enum: string;
|
|
341
|
+
readonly Id: string | number;
|
|
342
|
+
readonly Unsupported: never;
|
|
343
|
+
};
|
|
344
|
+
/**
|
|
345
|
+
* A reference to one of the model's own fields inside a predicate.
|
|
346
|
+
*
|
|
347
|
+
* Structurally a `PredicateFieldRef` (`{ kind: "field", name }`) plus the
|
|
348
|
+
* pairing tag comparisons are checked against. The tag carries no value and is
|
|
349
|
+
* stripped when the builder writes the IR, so nothing `__kind`-shaped is ever
|
|
350
|
+
* serialized.
|
|
351
|
+
*/
|
|
352
|
+
export type PredicateFieldExpr<TColumn extends string = string, TKind extends ColumnRefKind = ColumnRefKind> = {
|
|
353
|
+
readonly kind: "field";
|
|
354
|
+
readonly name: TColumn;
|
|
355
|
+
readonly __kind: TKind;
|
|
356
|
+
};
|
|
357
|
+
/**
|
|
358
|
+
* What may sit opposite a field of a given tag: a literal of its own scalar, or
|
|
359
|
+
* another field whose scalar can be compared with it.
|
|
360
|
+
*
|
|
361
|
+
* Column pairing reads {@link PairableRefKind} — the SAME table foreign keys
|
|
362
|
+
* use — because a foreign key and a comparison ask one question: are these two
|
|
363
|
+
* columns the same scalar family?
|
|
364
|
+
*/
|
|
365
|
+
type ComparisonOperand<TKind extends ColumnRefKind> = PredicateLiteralByRefKind[TKind] | PredicateFieldExpr<string, PairableRefKind[TKind]>;
|
|
366
|
+
/**
|
|
367
|
+
* The `c` handed to `checks` and to an index's `.where()`.
|
|
368
|
+
*
|
|
369
|
+
* Every combinator returns serializable {@link PredicateIR} — never a callback
|
|
370
|
+
* — and the SQL text is produced once, when the schema is compiled and the
|
|
371
|
+
* dialect is known.
|
|
372
|
+
*
|
|
373
|
+
* SQL three-valued logic applies unchanged: a comparison against NULL is
|
|
374
|
+
* UNKNOWN, and a CHECK passes on TRUE **or** UNKNOWN, so a comparison alone
|
|
375
|
+
* never rejects a NULL row. Nothing here adds a hidden null guard — write
|
|
376
|
+
* all-or-none out with {@link PredicateBuilder.isNull} / `isNotNull`.
|
|
377
|
+
*/
|
|
378
|
+
export type PredicateBuilder<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition> = {
|
|
379
|
+
/** Reference one of the model's own fields, by LOGICAL name. */
|
|
380
|
+
field<C extends TColumns>(name: C): PredicateFieldExpr<C, SchemaColumnRefKind<TSchema, C>>;
|
|
381
|
+
eq<TKind extends ColumnRefKind>(left: PredicateFieldExpr<string, TKind>, right: ComparisonOperand<TKind>): PredicateIR;
|
|
382
|
+
ne<TKind extends ColumnRefKind>(left: PredicateFieldExpr<string, TKind>, right: ComparisonOperand<TKind>): PredicateIR;
|
|
383
|
+
gt<TKind extends ColumnRefKind>(left: PredicateFieldExpr<string, TKind>, right: ComparisonOperand<TKind>): PredicateIR;
|
|
384
|
+
gte<TKind extends ColumnRefKind>(left: PredicateFieldExpr<string, TKind>, right: ComparisonOperand<TKind>): PredicateIR;
|
|
385
|
+
lt<TKind extends ColumnRefKind>(left: PredicateFieldExpr<string, TKind>, right: ComparisonOperand<TKind>): PredicateIR;
|
|
386
|
+
lte<TKind extends ColumnRefKind>(left: PredicateFieldExpr<string, TKind>, right: ComparisonOperand<TKind>): PredicateIR;
|
|
387
|
+
/** `col IN (…)`. Membership, not a set operation — every value is a literal. */
|
|
388
|
+
inList<TKind extends ColumnRefKind>(field: PredicateFieldExpr<string, TKind>, values: readonly PredicateLiteralByRefKind[TKind][]): PredicateIR;
|
|
389
|
+
/** `col NOT IN (…)`. NULL in the column stays UNKNOWN, as SQL defines it. */
|
|
390
|
+
notInList<TKind extends ColumnRefKind>(field: PredicateFieldExpr<string, TKind>, values: readonly PredicateLiteralByRefKind[TKind][]): PredicateIR;
|
|
391
|
+
/** `col IS NULL` — the EXPLICIT null test; a comparison never implies one. */
|
|
392
|
+
isNull<C extends TColumns>(name: C): PredicateIR;
|
|
393
|
+
/** `col IS NOT NULL`. */
|
|
394
|
+
isNotNull<C extends TColumns>(name: C): PredicateIR;
|
|
395
|
+
and(...operands: PredicateIR[]): PredicateIR;
|
|
396
|
+
or(...operands: PredicateIR[]): PredicateIR;
|
|
397
|
+
not(operand: PredicateIR): PredicateIR;
|
|
398
|
+
/** Name a predicate as a CHECK constraint. The name keys the migration diff. */
|
|
399
|
+
named(name: string, predicate: PredicateIR): NamedCheckDef;
|
|
400
|
+
};
|
|
247
401
|
/** A model. `TSchema` is preserved so relations can reference real columns. */
|
|
248
402
|
export type ModelDef<TSchema extends SchemaDefinition = SchemaDefinition> = {
|
|
249
403
|
readonly __type: "model";
|
|
@@ -256,8 +410,12 @@ export type ModelDef<TSchema extends SchemaDefinition = SchemaDefinition> = {
|
|
|
256
410
|
readonly __map?: string;
|
|
257
411
|
/** `@@id([...])` — compound primary key. */
|
|
258
412
|
readonly __primaryKey?: readonly string[];
|
|
259
|
-
/**
|
|
260
|
-
|
|
413
|
+
/**
|
|
414
|
+
* Named CHECK constraints (`@@check`-equivalent): the raw-SQL array form, or
|
|
415
|
+
* the typed-expression callback. Evaluated once, where the dialect is known.
|
|
416
|
+
*/
|
|
417
|
+
readonly __exclusions?: readonly ExclusionSpec[] | ExclusionsCallback;
|
|
418
|
+
readonly __checks?: readonly ModelCheckConfig[] | ChecksCallback;
|
|
261
419
|
/** Extension attributes declared on the model (`@@search`-style). */
|
|
262
420
|
readonly __extensions?: readonly ExtensionAttributeUse[];
|
|
263
421
|
/** `@@policy([field], context: "key")` — application-level row scoping. */
|
|
@@ -275,13 +433,23 @@ export type SchemaColumnNames<T> = Extract<ColumnKeys<T>, string>;
|
|
|
275
433
|
export type CreateModelConfig<TSchema extends SchemaDefinition = SchemaDefinition> = {
|
|
276
434
|
name: string;
|
|
277
435
|
schema: TSchema | ((s: ChildrenBuilder) => TSchema);
|
|
278
|
-
indexes?: IndexCallback<SchemaColumnNames<TSchema
|
|
436
|
+
indexes?: IndexCallback<SchemaColumnNames<TSchema>, TSchema>;
|
|
279
437
|
/** `@@map("table_name")` — database table name when it differs. */
|
|
280
438
|
map?: string;
|
|
281
439
|
/** `@@id([...])` — compound primary key columns. */
|
|
282
440
|
primaryKey?: SchemaColumnNames<TSchema>[];
|
|
283
|
-
/**
|
|
284
|
-
|
|
441
|
+
/**
|
|
442
|
+
* Named CHECK constraints, name-keyed in migrations. Either the TYPED
|
|
443
|
+
* expression callback (checked against this model's fields) or the raw-SQL
|
|
444
|
+
* array form, which is carried verbatim as the escape hatch.
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* checks: (c) => [c.named("qty_nonnegative", c.gte(c.field("qty"), 0))]
|
|
448
|
+
* @example
|
|
449
|
+
* checks: [{ name: "qty_nonnegative", expression: '"qty" >= 0' }]
|
|
450
|
+
*/
|
|
451
|
+
exclusions?: readonly ExclusionConfig<TSchema>[] | ((c: PredicateBuilder<SchemaColumnNames<TSchema>, TSchema>) => readonly ExclusionConfig<TSchema>[]);
|
|
452
|
+
checks?: readonly ModelCheckConfig[] | ChecksCallback<SchemaColumnNames<TSchema>, TSchema>;
|
|
285
453
|
/** Extension model attributes (`@@search`-style declarations). */
|
|
286
454
|
extensions?: readonly ExtensionAttributeUse[];
|
|
287
455
|
/**
|
|
@@ -292,11 +460,61 @@ export type CreateModelConfig<TSchema extends SchemaDefinition = SchemaDefinitio
|
|
|
292
460
|
/** Model doc comment — emitted as `///` lines above the model, kept as `ModelIR.documentation`. */
|
|
293
461
|
comment?: string;
|
|
294
462
|
};
|
|
463
|
+
/**
|
|
464
|
+
* The scalar identity relation pairing compares.
|
|
465
|
+
*
|
|
466
|
+
* Deliberately coarser than `FieldType`: `dsl.id()` carries the single tag
|
|
467
|
+
* `"Id"` because the DSL type does not record whether an id is String-backed or
|
|
468
|
+
* `autoincrement`, and an enum column carries `"Enum"` without its name. The
|
|
469
|
+
* type level rejects the pairs no id strategy and no enum could ever make legal
|
|
470
|
+
* (String↔Int, DateTime↔String); relation planning compares the real
|
|
471
|
+
* `FieldType` — id strategy and enum name included — when it builds the IR.
|
|
472
|
+
*/
|
|
473
|
+
export type ColumnRefKind = "String" | "Boolean" | "Int" | "BigInt" | "Float" | "Decimal" | "DateTime" | "Json" | "Bytes" | "Enum" | "Id" | "Unsupported";
|
|
474
|
+
/** `ColumnType` → `ColumnRefKind`, as a table: one indexed access, never a conditional chain. */
|
|
475
|
+
type RefKindByColumnType = {
|
|
476
|
+
readonly string: "String";
|
|
477
|
+
readonly int: "Int";
|
|
478
|
+
readonly bigint: "BigInt";
|
|
479
|
+
readonly float: "Float";
|
|
480
|
+
readonly decimal: "Decimal";
|
|
481
|
+
readonly boolean: "Boolean";
|
|
482
|
+
readonly datetime: "DateTime";
|
|
483
|
+
readonly json: "Json";
|
|
484
|
+
readonly bytes: "Bytes";
|
|
485
|
+
readonly id: "Id";
|
|
486
|
+
readonly enum: "Enum";
|
|
487
|
+
readonly unsupported: "Unsupported";
|
|
488
|
+
};
|
|
489
|
+
/** The pairing tag of a column kind. */
|
|
490
|
+
export type ColumnRefKindOf<TColumn extends ColumnType> = RefKindByColumnType[TColumn];
|
|
491
|
+
/**
|
|
492
|
+
* Which tags may sit OPPOSITE a given tag in a relation pair. Symmetric, and
|
|
493
|
+
* `"Id"` pairs with both scalars an id column can be backed by. `Json` and an
|
|
494
|
+
* `Unsupported` column can never be a foreign key on any dialect here, so they
|
|
495
|
+
* pair with nothing.
|
|
496
|
+
*/
|
|
497
|
+
type PairableRefKind = {
|
|
498
|
+
readonly String: "String" | "Id";
|
|
499
|
+
readonly Boolean: "Boolean";
|
|
500
|
+
readonly Int: "Int" | "Id";
|
|
501
|
+
readonly BigInt: "BigInt";
|
|
502
|
+
readonly Float: "Float";
|
|
503
|
+
readonly Decimal: "Decimal";
|
|
504
|
+
readonly DateTime: "DateTime";
|
|
505
|
+
readonly Json: never;
|
|
506
|
+
readonly Bytes: "Bytes";
|
|
507
|
+
readonly Enum: "Enum";
|
|
508
|
+
readonly Id: "Id" | "String" | "Int";
|
|
509
|
+
readonly Unsupported: never;
|
|
510
|
+
};
|
|
295
511
|
/** A reference to `Model.column`, used for relation `from` / `to`. */
|
|
296
|
-
export type ColumnRef<TModel extends string = string, TColumn extends string = string> = {
|
|
512
|
+
export type ColumnRef<TModel extends string = string, TColumn extends string = string, TKind extends ColumnRefKind = ColumnRefKind> = {
|
|
297
513
|
readonly __type: "columnRef";
|
|
298
514
|
readonly __model: TModel;
|
|
299
515
|
readonly __column: TColumn;
|
|
516
|
+
/** Pairing tag; carries no value, only the scalar identity `to` is checked against. */
|
|
517
|
+
readonly __kind: TKind;
|
|
300
518
|
through<TJunction extends string, TJunctionCol extends string>(junction: ColumnRef<TJunction, TJunctionCol>): ThroughRef<TModel, TColumn, TJunction, TJunctionCol>;
|
|
301
519
|
};
|
|
302
520
|
/** A column reference routed through a junction model (many-to-many). */
|
|
@@ -307,24 +525,48 @@ export type ThroughRef<TModel extends string = string, TColumn extends string =
|
|
|
307
525
|
readonly __junction: TJunction;
|
|
308
526
|
readonly __junctionColumn: TJunctionCol;
|
|
309
527
|
};
|
|
528
|
+
/**
|
|
529
|
+
* One end of a relation reference: a single column (today's syntax) or an
|
|
530
|
+
* ordered tuple of columns from ONE model (a composite key).
|
|
531
|
+
*/
|
|
532
|
+
export type RelationRefInput = ColumnRef | ThroughRef | readonly ColumnRef[];
|
|
533
|
+
/** The `to` partner a single `from` column admits. */
|
|
534
|
+
type PairedColumnRef<TRef> = TRef extends ColumnRef<string, string, infer TKind extends ColumnRefKind> ? ColumnRef<string, string, PairableRefKind[TKind]> : never;
|
|
535
|
+
/**
|
|
536
|
+
* The `to` a given `from` admits: the same arity, each position restricted to
|
|
537
|
+
* the scalar tags its partner can pair with. Mapping over a tuple keeps its
|
|
538
|
+
* length, so a `to` of the wrong size is a type error at the `to:` property.
|
|
539
|
+
*/
|
|
540
|
+
export type RelationTarget<TFrom extends RelationRefInput> = TFrom extends readonly ColumnRef[] ? {
|
|
541
|
+
readonly [TIndex in keyof TFrom]: PairedColumnRef<TFrom[TIndex]>;
|
|
542
|
+
} : TFrom extends ColumnRef ? PairedColumnRef<TFrom> | ThroughRef : ColumnRef | ThroughRef;
|
|
310
543
|
/** Config for `r.one.Model({ from, to })`. */
|
|
311
|
-
export type OneRelationDefConfig<TFrom extends
|
|
544
|
+
export type OneRelationDefConfig<TFrom extends RelationRefInput = ColumnRef> = {
|
|
312
545
|
/** Explicitly identifies the foreign-key side of a one-to-one pair. */
|
|
313
546
|
ownsForeignKey?: boolean;
|
|
314
547
|
from: TFrom;
|
|
315
|
-
to:
|
|
548
|
+
to: RelationTarget<TFrom>;
|
|
316
549
|
optional?: boolean;
|
|
317
550
|
/** `@relation("Name")` — disambiguates multiple relations between a pair. */
|
|
318
551
|
alias?: string;
|
|
552
|
+
/**
|
|
553
|
+
* Physical FOREIGN KEY constraint name (`@relation(map: "…")` in .prisma).
|
|
554
|
+
* Independent of `alias` and of the relation key: those name the client
|
|
555
|
+
* field, this names the database object. Set it to adopt an existing
|
|
556
|
+
* constraint under the name the database already gave it.
|
|
557
|
+
*/
|
|
558
|
+
constraintName?: string;
|
|
319
559
|
onDelete?: CascadeAction;
|
|
320
560
|
onUpdate?: CascadeAction;
|
|
321
561
|
};
|
|
322
562
|
/** Config for `r.many.Model({ from, to })`. */
|
|
323
|
-
export type ManyRelationDefConfig<TFrom extends
|
|
563
|
+
export type ManyRelationDefConfig<TFrom extends RelationRefInput = ColumnRef | ThroughRef> = {
|
|
324
564
|
from: TFrom;
|
|
325
|
-
to:
|
|
565
|
+
to: RelationTarget<TFrom>;
|
|
326
566
|
optional?: boolean;
|
|
327
567
|
alias?: string;
|
|
568
|
+
/** Physical FOREIGN KEY constraint name; see `OneRelationDefConfig.constraintName`. */
|
|
569
|
+
constraintName?: string;
|
|
328
570
|
onDelete?: CascadeAction;
|
|
329
571
|
onUpdate?: CascadeAction;
|
|
330
572
|
};
|
|
@@ -334,14 +576,22 @@ export type StoredRelationDef<TKind extends "one" | "many" = "one" | "many", TTa
|
|
|
334
576
|
readonly __relationType: TKind;
|
|
335
577
|
readonly __targetModel: TTarget;
|
|
336
578
|
readonly __fromModel: string;
|
|
579
|
+
/** First `from` member — `__fromColumns[0]`. The tuple is authoritative. */
|
|
337
580
|
readonly __fromColumn: string;
|
|
581
|
+
/** Every `from` member, in declared order. Length 1 for a single-column relation. */
|
|
582
|
+
readonly __fromColumns: readonly string[];
|
|
338
583
|
readonly __toModel: string;
|
|
584
|
+
/** First `to` member — `__toColumns[0]`. The tuple is authoritative. */
|
|
339
585
|
readonly __toColumn: string;
|
|
586
|
+
/** Every `to` member, in declared order; member `i` pairs with `__fromColumns[i]`. */
|
|
587
|
+
readonly __toColumns: readonly string[];
|
|
340
588
|
readonly __throughJunction?: string;
|
|
341
589
|
readonly __throughFromCol?: string;
|
|
342
590
|
readonly __throughToCol?: string;
|
|
343
591
|
readonly __optional: boolean;
|
|
344
592
|
readonly __alias?: string;
|
|
593
|
+
/** Physical FOREIGN KEY constraint name, independent of `__alias`. */
|
|
594
|
+
readonly __constraintName?: string;
|
|
345
595
|
readonly __ownsForeignKey?: boolean;
|
|
346
596
|
readonly __onDelete?: CascadeAction;
|
|
347
597
|
readonly __onUpdate?: CascadeAction;
|
|
@@ -350,17 +600,19 @@ export type StoredRelationDef<TKind extends "one" | "many" = "one" | "many", TTa
|
|
|
350
600
|
export type RelationsMap = Record<string, Record<string, StoredRelationDef>>;
|
|
351
601
|
/** Column names of a `ModelDef`, extracted from its schema type. */
|
|
352
602
|
export type ExtractModelColumns<T> = T extends ModelDef<infer TSchema> ? Extract<keyof TSchema, string> : never;
|
|
603
|
+
/** The pairing tag of one column of a model schema. */
|
|
604
|
+
type SchemaColumnRefKind<TSchema, TColumn extends PropertyKey> = TColumn extends keyof TSchema ? (TSchema[TColumn] extends ColumnDef<infer TColumnType> ? ColumnRefKindOf<TColumnType> : ColumnRefKind) : ColumnRefKind;
|
|
353
605
|
/** `r.User.id`, `r.User.email`, … */
|
|
354
|
-
export type ModelColumnRefs<TModelName extends string, TModel extends ModelDef> = {
|
|
355
|
-
[C in
|
|
356
|
-
}
|
|
606
|
+
export type ModelColumnRefs<TModelName extends string, TModel extends ModelDef> = TModel extends ModelDef<infer TSchema> ? {
|
|
607
|
+
[C in Extract<keyof TSchema, string>]: ColumnRef<TModelName, C, SchemaColumnRefKind<TSchema, C>>;
|
|
608
|
+
} : Record<string, ColumnRef<TModelName>>;
|
|
357
609
|
/** The `r` handed to a `defineRelations` callback. */
|
|
358
610
|
export type RelationsBuilder<TSchema extends Record<string, ModelDef>> = {
|
|
359
611
|
one: {
|
|
360
|
-
[K in keyof TSchema & string]: <TFrom extends
|
|
612
|
+
[K in keyof TSchema & string]: <const TFrom extends RelationRefInput>(config: OneRelationDefConfig<TFrom>) => StoredRelationDef<"one", K>;
|
|
361
613
|
};
|
|
362
614
|
many: {
|
|
363
|
-
[K in keyof TSchema & string]: <TFrom extends
|
|
615
|
+
[K in keyof TSchema & string]: <const TFrom extends RelationRefInput>(config: ManyRelationDefConfig<TFrom>) => StoredRelationDef<"many", K>;
|
|
364
616
|
};
|
|
365
617
|
} & {
|
|
366
618
|
[K in keyof TSchema & string]: ModelColumnRefs<K, TSchema[K]>;
|
|
@@ -432,6 +684,13 @@ export type SchemaDef = {
|
|
|
432
684
|
};
|
|
433
685
|
export type PrismaGeneratorConfig = {
|
|
434
686
|
output?: string;
|
|
687
|
+
/**
|
|
688
|
+
* Datasource provider the printed schema targets. Only typed CHECK and
|
|
689
|
+
* partial-index expressions read it — they become SQL text while printing,
|
|
690
|
+
* and identifier quoting and literal spelling are dialect decisions. Defaults
|
|
691
|
+
* to `"postgresql"`, matching `toIR`.
|
|
692
|
+
*/
|
|
693
|
+
provider?: Provider;
|
|
435
694
|
};
|
|
436
695
|
export type GeneratorOutput = {
|
|
437
696
|
prisma?: string;
|