@vibeorm/dsl 4.2.0 → 4.3.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/column.d.ts +72 -5
- package/dist/index.d.ts +13 -7
- package/dist/index.js +745 -101
- package/dist/index.js.map +13 -12
- package/dist/predicate.d.ts +59 -2
- package/dist/relation-plan.d.ts +3 -1
- package/dist/row-rules.d.ts +63 -0
- package/dist/to-ir.d.ts +11 -1
- package/dist/types.d.ts +212 -10
- package/package.json +3 -3
package/dist/predicate.d.ts
CHANGED
|
@@ -12,14 +12,38 @@
|
|
|
12
12
|
* one instance serves every model. The type parameters on
|
|
13
13
|
* {@link PredicateBuilder} are what bind it to a particular model's columns.
|
|
14
14
|
*/
|
|
15
|
-
import type { ExclusionIR, CheckIR, EnumIR, FieldIR, PredicateIR } from "@vibeorm/schema";
|
|
15
|
+
import type { ExclusionIR, CheckIR, EnumIR, FieldIR, PredicateExpression, PredicateIR } from "@vibeorm/schema";
|
|
16
16
|
import type { SqlDialect } from "@vibeorm/sql";
|
|
17
|
-
import type { ModelDef, ChecksCallback, ModelCheckConfig, PredicateBuilder, SchemaDefinition } from "./types.ts";
|
|
17
|
+
import type { ModelDef, ChecksBuilder, ChecksCallback, ModelCheckConfig, PredicateBuilder, SchemaDefinition } from "./types.ts";
|
|
18
|
+
/** Internal shared scalar lowering for index keys; preserves B's exact literal carriers. */
|
|
19
|
+
export declare function toPredicateExpression(params: {
|
|
20
|
+
readonly value: unknown;
|
|
21
|
+
readonly at: string;
|
|
22
|
+
}): PredicateExpression;
|
|
18
23
|
/**
|
|
19
24
|
* One predicate builder instance. Stateless and structural — the type
|
|
20
25
|
* parameters, not the value, bind it to a model.
|
|
21
26
|
*/
|
|
22
27
|
export declare function createPredicateBuilder<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition>(): PredicateBuilder<TColumns, TSchema>;
|
|
28
|
+
/** What the check rules need to know about the model they belong to. */
|
|
29
|
+
export type CheckModelContext = {
|
|
30
|
+
/** Logical model name, for messages. */
|
|
31
|
+
readonly model: string;
|
|
32
|
+
/** PHYSICAL table name: generated CHECK names start with it. */
|
|
33
|
+
readonly table: string;
|
|
34
|
+
/** The model's built fields: logical name, `@map`ped name, scalar type, optional, list. */
|
|
35
|
+
readonly fields: readonly FieldIR[];
|
|
36
|
+
/** Schema enums, for a presence table's members. */
|
|
37
|
+
readonly enums: readonly EnumIR[];
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* The `c` a model's `checks` callback receives: the predicate builder plus the
|
|
41
|
+
* named check rules, each validated against `context` and returned as a named
|
|
42
|
+
* CHECK.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createChecksBuilder<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition>(params: {
|
|
45
|
+
context: CheckModelContext;
|
|
46
|
+
}): ChecksBuilder<TColumns, TSchema>;
|
|
23
47
|
/** A model's CHECKs, still un-rendered: raw text stays raw, typed stays typed. */
|
|
24
48
|
export type EvaluatedCheck = {
|
|
25
49
|
readonly kind: "raw";
|
|
@@ -29,6 +53,10 @@ export type EvaluatedCheck = {
|
|
|
29
53
|
readonly kind: "typed";
|
|
30
54
|
readonly name: string;
|
|
31
55
|
readonly predicate: PredicateIR;
|
|
56
|
+
/** The check rule that produced it, when one did. */
|
|
57
|
+
readonly origin?: string;
|
|
58
|
+
/** True when the name was generated by the rule. */
|
|
59
|
+
readonly minted?: boolean;
|
|
32
60
|
};
|
|
33
61
|
/**
|
|
34
62
|
* Run a model's `checks` declaration, whichever form it took.
|
|
@@ -36,10 +64,14 @@ export type EvaluatedCheck = {
|
|
|
36
64
|
* The raw array form and the typed callback form produce the same shape of
|
|
37
65
|
* answer, so every consumer downstream handles ONE list — and raw text is
|
|
38
66
|
* carried through untouched rather than parsed into a predicate.
|
|
67
|
+
*
|
|
68
|
+
* The check rules (`c.order`, `c.allOrNone`, `c.presence`, …) need the model's
|
|
69
|
+
* fields: pass `context`. Without it they refuse with `check-rule-context`.
|
|
39
70
|
*/
|
|
40
71
|
export declare function evaluateChecks(params: {
|
|
41
72
|
checks: readonly ModelCheckConfig[] | ChecksCallback | undefined;
|
|
42
73
|
model: string;
|
|
74
|
+
context?: CheckModelContext;
|
|
43
75
|
}): readonly EvaluatedCheck[];
|
|
44
76
|
/** What a predicate needs to know about the model it belongs to. */
|
|
45
77
|
export type PredicateModel = {
|
|
@@ -62,11 +94,36 @@ export declare function compileExclusions(params: {
|
|
|
62
94
|
model: PredicateModel;
|
|
63
95
|
dialect: SqlDialect;
|
|
64
96
|
}): readonly ExclusionIR[];
|
|
97
|
+
/**
|
|
98
|
+
* A `checks` declaration as IR, for a caller that holds the built fields but
|
|
99
|
+
* not the model definition. Check rules generate their names from `table`;
|
|
100
|
+
* pass it when the model is `@@map`ped, because `PredicateModel` does not
|
|
101
|
+
* carry the table name. Without it the model name is the table name, as for
|
|
102
|
+
* an unmapped model. A generated name that collides or is too long for the
|
|
103
|
+
* dialect is refused, exactly as `compileModelChecks` refuses it.
|
|
104
|
+
*/
|
|
65
105
|
export declare function compileChecks(params: {
|
|
66
106
|
checks: readonly ModelCheckConfig[] | ChecksCallback | undefined;
|
|
67
107
|
model: PredicateModel;
|
|
68
108
|
dialect: SqlDialect;
|
|
69
109
|
enums: readonly EnumIR[];
|
|
110
|
+
/** PHYSICAL table name generated CHECK names start with; defaults to `model.name`. */
|
|
111
|
+
table?: string;
|
|
112
|
+
}): readonly CheckIR[];
|
|
113
|
+
/**
|
|
114
|
+
* A model's CHECKs as IR: the `checks` declaration (hand-written and check
|
|
115
|
+
* rules) first, in declaration order, then the column rules (`.nonNegative()`,
|
|
116
|
+
* …) in column order. Generated names use the PHYSICAL table and column names.
|
|
117
|
+
*
|
|
118
|
+
* The one compiler both `toIR` and the `.prisma` generator call, so a printed
|
|
119
|
+
* schema and a compiled one hold the same CHECKs.
|
|
120
|
+
*/
|
|
121
|
+
export declare function compileModelChecks(params: {
|
|
122
|
+
model: ModelDef;
|
|
123
|
+
/** The model's built fields, from the same `buildField` the IR uses. */
|
|
124
|
+
predicateModel: PredicateModel;
|
|
125
|
+
dialect: SqlDialect;
|
|
126
|
+
enums: readonly EnumIR[];
|
|
70
127
|
}): readonly CheckIR[];
|
|
71
128
|
/**
|
|
72
129
|
* An index's partial predicate as IR: the raw string verbatim, or a typed
|
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, PredicateIR, QualifiedSqlName, RelationType } from "@vibeorm/schema";
|
|
23
|
+
import type { CascadeAction, IndexKeyTermIR, PredicateIR, QualifiedSqlName, 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:
|
|
@@ -57,6 +57,8 @@ export type PlannedIndex = {
|
|
|
57
57
|
readonly map?: string;
|
|
58
58
|
readonly isUnique: boolean;
|
|
59
59
|
readonly columns: readonly string[];
|
|
60
|
+
/** Whole ordered key, lowered once by the index builder. */
|
|
61
|
+
readonly keys?: readonly IndexKeyTermIR[];
|
|
60
62
|
readonly indexType?: IndexType;
|
|
61
63
|
/** Qualified operator classes keyed by logical index column. */
|
|
62
64
|
readonly ops?: Readonly<Partial<Record<string, QualifiedSqlName>>>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { Dialect, ModelIR, RowRuleIR, SchemaIR } from "@vibeorm/schema";
|
|
2
|
+
import type { ModelDef } from "./types.ts";
|
|
3
|
+
/** Model-bound authoring declarations; only frozen uses the short creation gate spelling. */
|
|
4
|
+
export type RowRuleDeclaration<TColumn extends string = string> = {
|
|
5
|
+
readonly kind: "appendOnly";
|
|
6
|
+
readonly name?: string;
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: "fixed";
|
|
9
|
+
readonly name?: string;
|
|
10
|
+
readonly columns: readonly TColumn[];
|
|
11
|
+
readonly when: {
|
|
12
|
+
readonly fromCreation: true;
|
|
13
|
+
readonly onceSet?: never;
|
|
14
|
+
} | {
|
|
15
|
+
readonly onceSet: TColumn;
|
|
16
|
+
readonly fromCreation?: never;
|
|
17
|
+
};
|
|
18
|
+
} | {
|
|
19
|
+
readonly kind: "rowFixed";
|
|
20
|
+
readonly name?: string;
|
|
21
|
+
readonly except: readonly TColumn[];
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: "frozen";
|
|
24
|
+
readonly name?: string;
|
|
25
|
+
readonly from: "create" | TColumn;
|
|
26
|
+
readonly mutable: readonly TColumn[];
|
|
27
|
+
};
|
|
28
|
+
/** Immutable row-rule data builder, without client-side row-state inference. */
|
|
29
|
+
export type RowRuleBuilder<TColumn extends string = string> = {
|
|
30
|
+
appendOnly(options?: {
|
|
31
|
+
readonly name?: string;
|
|
32
|
+
}): RowRuleDeclaration<TColumn>;
|
|
33
|
+
fixed(options: {
|
|
34
|
+
readonly columns: readonly TColumn[];
|
|
35
|
+
readonly when: {
|
|
36
|
+
readonly fromCreation: true;
|
|
37
|
+
readonly onceSet?: never;
|
|
38
|
+
} | {
|
|
39
|
+
readonly onceSet: TColumn;
|
|
40
|
+
readonly fromCreation?: never;
|
|
41
|
+
};
|
|
42
|
+
readonly name?: string;
|
|
43
|
+
}): RowRuleDeclaration<TColumn>;
|
|
44
|
+
rowFixed(options: {
|
|
45
|
+
readonly except: readonly TColumn[];
|
|
46
|
+
readonly name?: string;
|
|
47
|
+
}): RowRuleDeclaration<TColumn>;
|
|
48
|
+
frozen(options: {
|
|
49
|
+
readonly from: "create" | TColumn;
|
|
50
|
+
readonly mutable: readonly TColumn[];
|
|
51
|
+
readonly name?: string;
|
|
52
|
+
}): RowRuleDeclaration<TColumn>;
|
|
53
|
+
};
|
|
54
|
+
/** Build model-bound row-rule declarations and copy every retained list and gate. */
|
|
55
|
+
export declare function createRowRuleBuilder<TColumn extends string = string>(): RowRuleBuilder<TColumn>;
|
|
56
|
+
/** Evaluate the callback against finalized fields and lower short frozen gates without guessing. */
|
|
57
|
+
export declare function compileRowRules(params: {
|
|
58
|
+
model: ModelDef;
|
|
59
|
+
irModel: ModelIR;
|
|
60
|
+
dialect: Dialect;
|
|
61
|
+
schema?: SchemaIR;
|
|
62
|
+
}): readonly RowRuleIR[];
|
|
63
|
+
//# sourceMappingURL=row-rules.d.ts.map
|
package/dist/to-ir.d.ts
CHANGED
|
@@ -27,7 +27,10 @@
|
|
|
27
27
|
* - `.collation()` / `{ collation }` → `FieldIR.collation`.
|
|
28
28
|
* - relation types are derived structurally by `resolveRelationType`.
|
|
29
29
|
*/
|
|
30
|
-
import type { DefaultValueIR, ExtensionRegistry, FieldIR, Provider, SchemaIR } from "@vibeorm/schema";
|
|
30
|
+
import type { DefaultValueIR, EnumIR, ExtensionRegistry, FieldIR, IndexIR, Provider, SchemaIR } from "@vibeorm/schema";
|
|
31
|
+
import type { SqlDialect } from "@vibeorm/sql";
|
|
32
|
+
import type { PredicateModel } from "./predicate.ts";
|
|
33
|
+
import type { PlannedIndex } from "./relation-plan.ts";
|
|
31
34
|
import type { ColumnDef, DatetimeColumnConfig, IdColumnConfig, SchemaDef, StringColumnConfig } from "./types.ts";
|
|
32
35
|
/** Compile a column default once for both DSL output paths. */
|
|
33
36
|
export declare function fieldDefault(params: {
|
|
@@ -70,6 +73,13 @@ export declare function buildField(params: {
|
|
|
70
73
|
/** Native type resolved by an extension field-type lowering, when present. */
|
|
71
74
|
extensionNativeType?: string;
|
|
72
75
|
}): FieldIR;
|
|
76
|
+
/** Shared planned-index lowering for IR and source spelling; not a package-root authoring API. */
|
|
77
|
+
export declare function buildIndex(params: {
|
|
78
|
+
index: PlannedIndex;
|
|
79
|
+
model: PredicateModel;
|
|
80
|
+
dialect: SqlDialect;
|
|
81
|
+
enums: readonly EnumIR[];
|
|
82
|
+
}): IndexIR;
|
|
73
83
|
/**
|
|
74
84
|
* Compiles a composed DSL schema to the canonical `SchemaIR`, then validates it.
|
|
75
85
|
*
|
package/dist/types.d.ts
CHANGED
|
@@ -5,14 +5,16 @@
|
|
|
5
5
|
* through `defineRelations` (Drizzle-style), which keeps column references
|
|
6
6
|
* type-safe without inference-heavy model types.
|
|
7
7
|
*/
|
|
8
|
-
import type { ExclusionSpec, ExclusionEndpoint, CascadeAction, EnumStorage, JsonSchemaRefIR, ExtensionAttributeValue, PredicateExpression, PredicateIR, Provider, QualifiedSqlName, RlsContextIR, RlsContextRefIR, RlsPolicyIR } from "@vibeorm/schema";
|
|
8
|
+
import type { ExclusionSpec, ExclusionEndpoint, CascadeAction, EnumStorage, GeneratedColumnOptions, IndexKeyTermIR, JsonSchemaRefIR, ValidatorRefIR, ExtensionAttributeValue, PredicateExpression, PredicateIR, PredicateNumericType, Provider, QualifiedSqlName, RlsContextIR, RlsContextRefIR, RlsPolicyIR } from "@vibeorm/schema";
|
|
9
9
|
import type { ChainableEnumColumn } from "./column.ts";
|
|
10
|
+
import type { RowRuleBuilder, RowRuleDeclaration } from "./row-rules.ts";
|
|
11
|
+
export type { RowRuleBuilder, RowRuleDeclaration } from "./row-rules.ts";
|
|
10
12
|
/** Referential actions, re-exported from the IR so both sources agree. */
|
|
11
13
|
export type { CascadeAction };
|
|
12
14
|
/** Enum storage strategies (`"database"` | `"string"`), re-exported from the IR. */
|
|
13
15
|
export type { EnumStorage };
|
|
14
16
|
/** Column kinds the DSL can declare. */
|
|
15
|
-
export type ColumnType = "string" | "int" | "bigint" | "float" | "decimal" | "boolean" | "datetime" | "json" | "id" | "bytes" | "enum" | "unsupported";
|
|
17
|
+
export type ColumnType = "string" | "localDate" | "int" | "bigint" | "float" | "decimal" | "boolean" | "datetime" | "json" | "id" | "bytes" | "enum" | "unsupported";
|
|
16
18
|
/** Primary-key generator strategies for `dsl.id()`. */
|
|
17
19
|
export type IdGeneratorType = "ulid" | "cuid" | "uuid" | "nanoid" | "autoincrement" | "none";
|
|
18
20
|
/** PostgreSQL index types Prisma can express via `@@index(..., type: X)`. */
|
|
@@ -25,12 +27,53 @@ export type BaseColumnConfig = {
|
|
|
25
27
|
array?: boolean;
|
|
26
28
|
/** `@map("column_name")` — database column name when it differs. */
|
|
27
29
|
map?: string;
|
|
30
|
+
/** Stored database expression; the declaration is copied and frozen. */
|
|
31
|
+
generated?: GeneratedColumnOptions;
|
|
28
32
|
/** `@default(dbgenerated("..."))` — database-native default expression. */
|
|
29
33
|
dbgenerated?: string;
|
|
30
34
|
/** Emitted as a `///` doc comment above the column (Zod generators, docs). */
|
|
31
35
|
comment?: string;
|
|
36
|
+
/**
|
|
37
|
+
* One-column CHECK rules (`.nonNegative()`, `.range()`, `.oneOf()`, …),
|
|
38
|
+
* each compiled to a named CHECK. Stored copy-on-write and frozen, so a
|
|
39
|
+
* template column never shares rules with another model.
|
|
40
|
+
*/
|
|
41
|
+
checks?: readonly ColumnCheckRule[];
|
|
42
|
+
/** Consumer-owned write-only scalar validator export; types remain unchanged. */
|
|
43
|
+
validator?: ValidatorRefIR;
|
|
32
44
|
[key: string]: unknown;
|
|
33
45
|
};
|
|
46
|
+
/** Options every check rule takes. */
|
|
47
|
+
export type CheckRuleOptions = {
|
|
48
|
+
/** Explicit CHECK name, replacing the generated `<Table>_<column>_<rule>_check`. */
|
|
49
|
+
readonly name?: string;
|
|
50
|
+
/** The rule word in the generated name (`range` in `Device_volume_range_check`). */
|
|
51
|
+
readonly rule?: string;
|
|
52
|
+
};
|
|
53
|
+
/** What a one-column rule asserts, as data; the column is the one it is declared on. */
|
|
54
|
+
export type ColumnCheckShape = {
|
|
55
|
+
readonly kind: "compare";
|
|
56
|
+
readonly op: "gt" | "gte" | "lt" | "lte";
|
|
57
|
+
readonly value: string | number;
|
|
58
|
+
} | {
|
|
59
|
+
readonly kind: "range";
|
|
60
|
+
readonly min: string | number;
|
|
61
|
+
readonly max: string | number;
|
|
62
|
+
} | {
|
|
63
|
+
readonly kind: "oneOf";
|
|
64
|
+
readonly values: readonly string[];
|
|
65
|
+
} | {
|
|
66
|
+
readonly kind: "lengthAtMost";
|
|
67
|
+
readonly max: number;
|
|
68
|
+
};
|
|
69
|
+
/** One one-column CHECK rule, as a column method records it. */
|
|
70
|
+
export type ColumnCheckRule = {
|
|
71
|
+
/** The rule word in the generated name. */
|
|
72
|
+
readonly rule: string;
|
|
73
|
+
readonly check: ColumnCheckShape;
|
|
74
|
+
/** Explicit CHECK name, replacing the generated one. */
|
|
75
|
+
readonly name?: string;
|
|
76
|
+
};
|
|
34
77
|
export type StringColumnConfig = BaseColumnConfig & {
|
|
35
78
|
default?: string | readonly string[];
|
|
36
79
|
/** `@db.VarChar(n)` */
|
|
@@ -49,6 +92,10 @@ export type StringColumnConfig = BaseColumnConfig & {
|
|
|
49
92
|
*/
|
|
50
93
|
collation?: string;
|
|
51
94
|
};
|
|
95
|
+
/** A calendar day stored as String @db.Date; only canonical literal defaults are admitted. */
|
|
96
|
+
export type LocalDateColumnConfig = BaseColumnConfig & {
|
|
97
|
+
default?: string;
|
|
98
|
+
};
|
|
52
99
|
export type IntColumnConfig = BaseColumnConfig & {
|
|
53
100
|
autoincrement?: boolean;
|
|
54
101
|
default?: number | readonly number[];
|
|
@@ -234,6 +281,10 @@ export type NamedCheckDef = {
|
|
|
234
281
|
readonly __type: "check";
|
|
235
282
|
readonly name: string;
|
|
236
283
|
readonly predicate: PredicateIR;
|
|
284
|
+
/** The check rule that produced it (`c.allOrNone(…)`, a presence table), for error messages. */
|
|
285
|
+
readonly __origin?: string;
|
|
286
|
+
/** True when the name was generated, not passed with `{ name }`. */
|
|
287
|
+
readonly __minted?: boolean;
|
|
237
288
|
};
|
|
238
289
|
/**
|
|
239
290
|
* The `c` handed to a model's `checks` callback, returning typed or raw named CHECKs.
|
|
@@ -243,7 +294,91 @@ export type NamedCheckDef = {
|
|
|
243
294
|
* c.named("dispatch_clock", c.gt(c.field("deadlineAt"), c.field("startedAt"))),
|
|
244
295
|
* ]
|
|
245
296
|
*/
|
|
246
|
-
export type ChecksCallback<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition> = (c:
|
|
297
|
+
export type ChecksCallback<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition> = (c: ChecksBuilder<TColumns, TSchema>) => (NamedCheckDef | ModelCheckConfig)[];
|
|
298
|
+
/** Options of `c.order()`. */
|
|
299
|
+
export type OrderCheckOptions<TColumn extends string = string> = CheckRuleOptions & {
|
|
300
|
+
/** `false` allows equal values (`>=`); default `true` (`>`). */
|
|
301
|
+
readonly strict?: boolean;
|
|
302
|
+
/**
|
|
303
|
+
* The column the generated name is built from and the CHECK reads first:
|
|
304
|
+
* the later column by default (`"endAt" > "startAt"`), or the earlier one
|
|
305
|
+
* (`"cancelledAt" < "startAt"`).
|
|
306
|
+
*/
|
|
307
|
+
readonly nameColumn?: TColumn;
|
|
308
|
+
};
|
|
309
|
+
/** One state of a presence table: the optional columns that must be set, and those that must be empty. */
|
|
310
|
+
export type PresenceState<TColumns extends string = string> = {
|
|
311
|
+
/** NOT NULL while the enum column holds this member. */
|
|
312
|
+
readonly set?: readonly TColumns[];
|
|
313
|
+
/** NULL while the enum column holds this member. */
|
|
314
|
+
readonly unset?: readonly TColumns[];
|
|
315
|
+
};
|
|
316
|
+
/**
|
|
317
|
+
* A presence table: per enum member, which optional columns are set and which
|
|
318
|
+
* are empty. A column listed in neither is free in that state. Every member
|
|
319
|
+
* must appear exactly once.
|
|
320
|
+
*/
|
|
321
|
+
export type PresenceCheckConfig<TColumns extends string = string, TMember extends string = string, TBy extends string = string> = {
|
|
322
|
+
/** A REQUIRED enum column of this model. */
|
|
323
|
+
readonly by: TBy;
|
|
324
|
+
/** The rule word in each generated name; defaults to the `by` column's name. */
|
|
325
|
+
readonly rule?: string;
|
|
326
|
+
/** Explicit CHECK names per column, replacing the generated ones. */
|
|
327
|
+
readonly names?: {
|
|
328
|
+
readonly [C in TColumns]?: string;
|
|
329
|
+
};
|
|
330
|
+
readonly states: {
|
|
331
|
+
readonly [S in TMember]: PresenceState<TColumns>;
|
|
332
|
+
};
|
|
333
|
+
};
|
|
334
|
+
/**
|
|
335
|
+
* The model's enum columns, as names. An unbound builder (`ChecksBuilder` with
|
|
336
|
+
* its default `string` columns) knows no column kinds, so any name is allowed
|
|
337
|
+
* and the schema build checks it.
|
|
338
|
+
*/
|
|
339
|
+
type EnumColumnNames<TColumns extends string, TSchema extends SchemaDefinition> = string extends TColumns ? TColumns : {
|
|
340
|
+
[C in TColumns]: C extends keyof TSchema ? (TSchema[C] extends ColumnDef<"enum"> ? C : never) : never;
|
|
341
|
+
}[TColumns];
|
|
342
|
+
/** The members of one enum column, read from its `__enumValues` tuple. */
|
|
343
|
+
type EnumMembersOf<TSchema extends SchemaDefinition, TColumn extends string> = TColumn extends keyof TSchema ? TSchema[TColumn] extends {
|
|
344
|
+
readonly __enumValues?: infer TValues extends readonly string[];
|
|
345
|
+
} ? TValues[number] : string : string;
|
|
346
|
+
/** Columns that can pair with another column through the shared scalar-family table. */
|
|
347
|
+
type PairableCheckColumns<TColumns extends string, TSchema extends SchemaDefinition, TColumn extends TColumns> = ColumnRefKind extends SchemaColumnRefKind<TSchema, TColumn> ? TColumns : {
|
|
348
|
+
[C in TColumns]: SchemaColumnRefKind<TSchema, C> extends PairableRefKind[SchemaColumnRefKind<TSchema, TColumn>] ? C : never;
|
|
349
|
+
}[TColumns];
|
|
350
|
+
/**
|
|
351
|
+
* The `c` handed to a model's `checks` callback: the predicate builder plus
|
|
352
|
+
* the named check rules, each returning ready, named CHECKs.
|
|
353
|
+
*
|
|
354
|
+
* Names are generated as `<Table>_<column>_<rule>_check` from the PHYSICAL
|
|
355
|
+
* table and column names; every rule takes `{ name }` to replace it.
|
|
356
|
+
*
|
|
357
|
+
* @example
|
|
358
|
+
* checks: (c) => [
|
|
359
|
+
* c.order("startAt", "endAt"),
|
|
360
|
+
* c.allOrNone("latitude", "longitude"),
|
|
361
|
+
* ...c.presence({ by: "state", states: { draft: { unset: ["sentAt"] }, sent: { set: ["sentAt"] } } }),
|
|
362
|
+
* ]
|
|
363
|
+
*/
|
|
364
|
+
export type ChecksBuilder<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition> = PredicateBuilder<TColumns, TSchema> & {
|
|
365
|
+
/** `later > earlier` (or `>=` with `strict: false`), named after the later column. NULL in either passes. */
|
|
366
|
+
order<TEarlier extends TColumns, TLater extends PairableCheckColumns<TColumns, TSchema, NoInfer<TEarlier>>>(earlier: TEarlier, later: TLater, options?: OrderCheckOptions<NoInfer<TEarlier | TLater>>): NamedCheckDef;
|
|
367
|
+
/** All of the columns set, or none of them. */
|
|
368
|
+
allOrNone<C extends TColumns>(...columns: C[]): NamedCheckDef;
|
|
369
|
+
allOrNone<C extends TColumns>(columns: readonly C[], options: CheckRuleOptions): NamedCheckDef;
|
|
370
|
+
/** Exactly one of the columns set. */
|
|
371
|
+
exactlyOne<C extends TColumns>(...columns: C[]): NamedCheckDef;
|
|
372
|
+
exactlyOne<C extends TColumns>(columns: readonly C[], options: CheckRuleOptions): NamedCheckDef;
|
|
373
|
+
/** At most one of the columns set. */
|
|
374
|
+
atMostOne<C extends TColumns>(...columns: C[]): NamedCheckDef;
|
|
375
|
+
atMostOne<C extends TColumns>(columns: readonly C[], options: CheckRuleOptions): NamedCheckDef;
|
|
376
|
+
/** At least one of the columns set. */
|
|
377
|
+
anySet<C extends TColumns>(...columns: C[]): NamedCheckDef;
|
|
378
|
+
anySet<C extends TColumns>(columns: readonly C[], options: CheckRuleOptions): NamedCheckDef;
|
|
379
|
+
/** One CHECK per column the presence table names; spread the result into the list. */
|
|
380
|
+
presence<TBy extends EnumColumnNames<TColumns, TSchema>>(config: PresenceCheckConfig<TColumns, EnumMembersOf<TSchema, TBy>, TBy>): NamedCheckDef[];
|
|
381
|
+
};
|
|
247
382
|
/**
|
|
248
383
|
* Application-level row-scoping policy — the DSL twin of
|
|
249
384
|
* `@@policy([field], context: "key")`. The runtime fails closed on policied
|
|
@@ -263,6 +398,8 @@ export type IndexDef = {
|
|
|
263
398
|
readonly __map?: string;
|
|
264
399
|
readonly __type: "index" | "unique";
|
|
265
400
|
readonly __columns: readonly string[];
|
|
401
|
+
/** Complete ordered authoring keys when computation or explicit direction is present. */
|
|
402
|
+
readonly __keys?: readonly IndexKeyTermIR[];
|
|
266
403
|
readonly __indexType?: IndexType;
|
|
267
404
|
/** Non-unique PostgreSQL operator classes, keyed by logical index field name. */
|
|
268
405
|
readonly __ops?: Readonly<Partial<Record<string, QualifiedSqlName>>>;
|
|
@@ -320,14 +457,44 @@ export type UniqueIndexOptions = {
|
|
|
320
457
|
export type PartialIndexDef<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition> = IndexDef & {
|
|
321
458
|
where(predicate: (c: PredicateBuilder<TColumns, TSchema>) => PredicateIR): IndexDef;
|
|
322
459
|
};
|
|
323
|
-
/**
|
|
324
|
-
export type
|
|
325
|
-
|
|
326
|
-
|
|
460
|
+
/** Dialect-authored trusted scalar SQL; always requires a physical index map. */
|
|
461
|
+
export type RawIndexExpression = {
|
|
462
|
+
readonly __type: "rawIndexExpression";
|
|
463
|
+
readonly text: string;
|
|
464
|
+
};
|
|
465
|
+
/** Scalar or named key before direction is applied. */
|
|
466
|
+
export type UnsortedIndexKey<TColumns extends string = string> = TColumns | PredicateExpr | RawIndexExpression;
|
|
467
|
+
/** Direction belongs to the key, not its scalar expression data. */
|
|
468
|
+
export type SortedIndexKey<TColumns extends string = string> = {
|
|
469
|
+
readonly __type: "sortedIndexKey";
|
|
470
|
+
readonly key: UnsortedIndexKey<TColumns>;
|
|
471
|
+
readonly sort: "asc" | "desc";
|
|
472
|
+
};
|
|
473
|
+
/** Ordered mixed key accepted by ordinary and unique BTree builders. */
|
|
474
|
+
export type IndexKey<TColumns extends string = string> = UnsortedIndexKey<TColumns> | SortedIndexKey<TColumns>;
|
|
475
|
+
type StringIndexColumns<TColumns extends string, TSchema extends SchemaDefinition> = {
|
|
476
|
+
[C in TColumns]: "String" extends SchemaColumnRefKind<TSchema, C> ? C : "Id" extends SchemaColumnRefKind<TSchema, C> ? C : never;
|
|
477
|
+
}[TColumns];
|
|
478
|
+
/** Index builder; scalar helpers are separate from the terminal where builder. */
|
|
479
|
+
export type IndexBuilder<TColumns extends string = string, TSchema extends SchemaDefinition = SchemaDefinition> = Pick<PredicateBuilder<TColumns, TSchema>, "field" | "add" | "sub" | "mul"> & {
|
|
480
|
+
lower<C extends StringIndexColumns<TColumns, TSchema>>(column: C): PredicateExpr<"String">;
|
|
481
|
+
lower(expression: PredicateExpr<"String" | "Id">): PredicateExpr<"String">;
|
|
482
|
+
upper<C extends StringIndexColumns<TColumns, TSchema>>(column: C): PredicateExpr<"String">;
|
|
483
|
+
upper(expression: PredicateExpr<"String" | "Id">): PredicateExpr<"String">;
|
|
484
|
+
asc(key: UnsortedIndexKey<TColumns>): SortedIndexKey<TColumns>;
|
|
485
|
+
desc(key: UnsortedIndexKey<TColumns>): SortedIndexKey<TColumns>;
|
|
486
|
+
sql(params: {
|
|
487
|
+
readonly text: string;
|
|
488
|
+
}): RawIndexExpression;
|
|
489
|
+
on(...keys: IndexKey<TColumns>[]): PartialIndexDef<TColumns, TSchema>;
|
|
490
|
+
on<C extends TColumns>(keys: C[], options: IndexOptions<NoInfer<C>>): PartialIndexDef<TColumns, TSchema>;
|
|
491
|
+
on(keys: IndexKey<TColumns>[], options: Omit<IndexOptions, "ops"> & {
|
|
492
|
+
readonly ops?: never;
|
|
493
|
+
}): PartialIndexDef<TColumns, TSchema>;
|
|
327
494
|
/** Alias of `on(...)` — reads better next to `unique(...)`. */
|
|
328
|
-
index
|
|
329
|
-
unique
|
|
330
|
-
unique<
|
|
495
|
+
index(...keys: IndexKey<TColumns>[]): PartialIndexDef<TColumns, TSchema>;
|
|
496
|
+
unique(...keys: IndexKey<TColumns>[]): PartialIndexDef<TColumns, TSchema>;
|
|
497
|
+
unique(keys: IndexKey<TColumns>[], options: UniqueIndexOptions): PartialIndexDef<TColumns, TSchema>;
|
|
331
498
|
gin<T extends TColumns>(...columns: T[]): PartialIndexDef<TColumns, TSchema>;
|
|
332
499
|
gist<T extends TColumns>(...columns: T[]): PartialIndexDef<TColumns, TSchema>;
|
|
333
500
|
hash<T extends TColumns>(...columns: T[]): PartialIndexDef<TColumns, TSchema>;
|
|
@@ -386,6 +553,17 @@ export type PredicateFieldExpr<TColumn extends string = string, TKind extends Co
|
|
|
386
553
|
export type PredicateExpr<TKind extends ColumnRefKind = ColumnRefKind> = PredicateExpression & {
|
|
387
554
|
readonly __kind: TKind;
|
|
388
555
|
};
|
|
556
|
+
/** Numeric scalar families accepted by arithmetic, without implicit promotion. */
|
|
557
|
+
export type PredicateNumericKind = PredicateNumericType;
|
|
558
|
+
/** Exact literal carriers for each numeric scalar family. */
|
|
559
|
+
export type PredicateNumericLiteral = {
|
|
560
|
+
readonly Int: number;
|
|
561
|
+
readonly BigInt: bigint | number;
|
|
562
|
+
readonly Float: number;
|
|
563
|
+
readonly Decimal: string;
|
|
564
|
+
};
|
|
565
|
+
/** An arithmetic operand in the same numeric family as its left expression. */
|
|
566
|
+
export type PredicateNumericOperand<TKind extends PredicateNumericKind> = PredicateExpr<TKind> | PredicateNumericLiteral[TKind];
|
|
389
567
|
type JsonPredicateColumns<TColumns extends string, TSchema extends SchemaDefinition> = {
|
|
390
568
|
[C in TColumns]: "Json" extends SchemaColumnRefKind<TSchema, C> ? C : never;
|
|
391
569
|
}[TColumns];
|
|
@@ -411,6 +589,25 @@ export type PredicateBuilder<TColumns extends string = string, TSchema extends S
|
|
|
411
589
|
gte<TKind extends ColumnRefKind>(left: PredicateExpr<TKind>, right: ComparisonOperand<NoInfer<TKind>>): PredicateIR;
|
|
412
590
|
lt<TKind extends ColumnRefKind>(left: PredicateExpr<TKind>, right: ComparisonOperand<NoInfer<TKind>>): PredicateIR;
|
|
413
591
|
lte<TKind extends ColumnRefKind>(left: PredicateExpr<TKind>, right: ComparisonOperand<NoInfer<TKind>>): PredicateIR;
|
|
592
|
+
/** Add same-family numeric operands. SQL NULL behavior is unchanged. */
|
|
593
|
+
add<TKind extends PredicateNumericKind>(params: {
|
|
594
|
+
left: PredicateExpr<TKind>;
|
|
595
|
+
right: PredicateNumericOperand<NoInfer<TKind>>;
|
|
596
|
+
}): PredicateExpr<TKind>;
|
|
597
|
+
/** Subtract same-family numeric operands, preserving the authored grouping. */
|
|
598
|
+
sub<TKind extends PredicateNumericKind>(params: {
|
|
599
|
+
left: PredicateExpr<TKind>;
|
|
600
|
+
right: PredicateNumericOperand<NoInfer<TKind>>;
|
|
601
|
+
}): PredicateExpr<TKind>;
|
|
602
|
+
/** Multiply same-family numeric operands. SQLite refuses Decimal arithmetic. */
|
|
603
|
+
mul<TKind extends PredicateNumericKind>(params: {
|
|
604
|
+
left: PredicateExpr<TKind>;
|
|
605
|
+
right: PredicateNumericOperand<NoInfer<TKind>>;
|
|
606
|
+
}): PredicateExpr<TKind>;
|
|
607
|
+
/** Fold text to lowercase using the database's locale/collation behavior. */
|
|
608
|
+
lower(expression: PredicateExpr<"String" | "Id">): PredicateExpr<"String">;
|
|
609
|
+
/** Fold text to uppercase. Local dates and non-text Id storage refuse at build. */
|
|
610
|
+
upper(expression: PredicateExpr<"String" | "Id">): PredicateExpr<"String">;
|
|
414
611
|
/** PostgreSQL/PGlite CHECK only. Extract text without asserting the JSON leaf's type. */
|
|
415
612
|
jsonText(params: {
|
|
416
613
|
field: JsonPredicateColumns<TColumns, TSchema>;
|
|
@@ -452,6 +649,8 @@ export type ModelDef<TSchema extends SchemaDefinition = SchemaDefinition> = {
|
|
|
452
649
|
*/
|
|
453
650
|
readonly __exclusions?: readonly ExclusionSpec[] | ExclusionsCallback;
|
|
454
651
|
readonly __checks?: readonly ModelCheckConfig[] | ChecksCallback;
|
|
652
|
+
/** Separate row-rule authoring callback, evaluated against finalized model fields. */
|
|
653
|
+
readonly __rowRules?: (r: RowRuleBuilder) => readonly RowRuleDeclaration[];
|
|
455
654
|
/** Extension attributes declared on the model (`@@search`-style). */
|
|
456
655
|
readonly __extensions?: readonly ExtensionAttributeUse[];
|
|
457
656
|
/** `@@policy([field], context: "key")` — application-level row scoping. */
|
|
@@ -486,6 +685,8 @@ export type CreateModelConfig<TSchema extends SchemaDefinition = SchemaDefinitio
|
|
|
486
685
|
*/
|
|
487
686
|
exclusions?: readonly ExclusionConfig<TSchema>[] | ((c: PredicateBuilder<SchemaColumnNames<TSchema>, TSchema>) => readonly ExclusionConfig<TSchema>[]);
|
|
488
687
|
checks?: readonly ModelCheckConfig[] | ChecksCallback<SchemaColumnNames<TSchema>, TSchema>;
|
|
688
|
+
/** Database-enforced row invariants; every field slot is bound to this model. */
|
|
689
|
+
rowRules?: (r: RowRuleBuilder<SchemaColumnNames<TSchema>>) => readonly RowRuleDeclaration<SchemaColumnNames<TSchema>>[];
|
|
489
690
|
/** Extension model attributes (`@@search`-style declarations). */
|
|
490
691
|
extensions?: readonly ExtensionAttributeUse[];
|
|
491
692
|
/**
|
|
@@ -510,6 +711,7 @@ export type ColumnRefKind = "String" | "Boolean" | "Int" | "BigInt" | "Float" |
|
|
|
510
711
|
/** `ColumnType` → `ColumnRefKind`, as a table: one indexed access, never a conditional chain. */
|
|
511
712
|
type RefKindByColumnType = {
|
|
512
713
|
readonly string: "String";
|
|
714
|
+
readonly localDate: "String";
|
|
513
715
|
readonly int: "Int";
|
|
514
716
|
readonly bigint: "BigInt";
|
|
515
717
|
readonly float: "Float";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeorm/dsl",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"description": "TypeScript schema DSL for VibeORM v2 — compiles to canonical SchemaIR, with .prisma generation for interop",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"orm",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"bun": ">=1.2.0"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@vibeorm/schema": "4.
|
|
47
|
-
"@vibeorm/sql": "4.
|
|
46
|
+
"@vibeorm/schema": "4.3.0",
|
|
47
|
+
"@vibeorm/sql": "4.3.0"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public"
|