@vibeorm/schema 2.1.1 → 2.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/database-module.d.ts +19 -0
- package/dist/database-module.d.ts.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +228 -94
- package/dist/index.js.map +6 -6
- package/dist/ir.d.ts +5 -0
- package/dist/ir.d.ts.map +1 -1
- package/dist/migration-objects.d.ts +8 -2
- package/dist/migration-objects.d.ts.map +1 -1
- package/dist/reserved.d.ts.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Dialect, SchemaIR } from "./ir.ts";
|
|
2
|
+
/** Stable package identity and the schema revision expected by its runtime. */
|
|
3
|
+
export type DatabaseModuleOptions = {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly contract: string;
|
|
6
|
+
readonly revision: string;
|
|
7
|
+
};
|
|
8
|
+
/** Runtime artifact compatibility; schemaChecksum is not migration-history readiness. */
|
|
9
|
+
export type DatabaseModuleManifest = DatabaseModuleOptions & {
|
|
10
|
+
readonly protocol: 1;
|
|
11
|
+
readonly dialect: Dialect;
|
|
12
|
+
readonly schemaChecksum: string;
|
|
13
|
+
};
|
|
14
|
+
/** Data-only runtime artifact. Migration provenance is a separate contract. */
|
|
15
|
+
export type DatabaseModuleArtifact = {
|
|
16
|
+
readonly manifest: DatabaseModuleManifest;
|
|
17
|
+
readonly schema: SchemaIR;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=database-module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database-module.d.ts","sourceRoot":"","sources":["../src/database-module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEjD,+EAA+E;AAC/E,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,yFAAyF;AACzF,MAAM,MAAM,sBAAsB,GAAG,qBAAqB,GAAG;IAC3D,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC,CAAC;AAEF,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;CAC3B,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
* @vibeorm/schema — canonical Schema IR, validation, dialect/capability types,
|
|
3
3
|
* and the VibeError contract for VibeORM v2.
|
|
4
4
|
*/
|
|
5
|
+
export type { DatabaseModuleOptions, DatabaseModuleManifest, DatabaseModuleArtifact } from "./database-module.ts";
|
|
5
6
|
export type { ExclusionIR, ExclusionSpec, ExclusionKey, ExclusionEndpoint } from "./exclusion.ts";
|
|
6
7
|
export { DIALECTS, ENUM_STORAGES, enumStorageOf, fieldTypeIdentity, isEnumType, providerToDialect } from "./ir.ts";
|
|
7
8
|
export type { CascadeAction, DatasourceIR, DefaultValueIR, Dialect, EnumIR, EnumStorage, ExtensionDeclIR, FieldIR, FieldType, IndexFieldIR, CheckIR, IndexIR, IndexKind, ModelIR, Provider, RelationIR, RelationType, ScalarType, SchemaIR, } from "./ir.ts";
|
|
8
9
|
export { PREDICATE_COMPARISON_OPS, isPredicateFieldRef, predicateFieldNames, predicateKey } from "./predicate.ts";
|
|
9
10
|
export type { PredicateComparisonOp, PredicateFieldRef, PredicateIR, PredicateOperand, PredicateValue } from "./predicate.ts";
|
|
10
11
|
export { assertMigrationObjects, isSqlObjectDefinition, isSqlObjectIdentity, sqlObjectKey } from "./migration-objects.ts";
|
|
11
|
-
export type { MigrationObjectIR, QualifiedSqlName, SqlObjectDefinition, SqlObjectFacts, SqlObjectIdentity } from "./migration-objects.ts";
|
|
12
|
+
export type { MigrationObjectIR, QualifiedSqlName, SqlObjectDefinition, SqlObjectDefinitionFormat, SqlObjectFacts, SqlObjectIdentity } from "./migration-objects.ts";
|
|
12
13
|
export type { AdvisoryLockMode, DialectCapabilities, FullTextEngine, RowLockStrength, RowLockWaitPolicy, } from "./capabilities.ts";
|
|
13
14
|
export { READ_ONLY_REFUSAL_REASONS, ReadOnlyClientError, SCOPED_REFUSAL_REASONS, ScopedQueryError, VIBE_ERROR_CODES, VibeError, internalError, invalidStoredData, unsupportedCapability, } from "./errors.ts";
|
|
14
15
|
export type { ReadOnlyRefusalReason, ScopedRefusalReason, VibeErrorCode } from "./errors.ts";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAElG,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AACnH,YAAY,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,OAAO,EACP,MAAM,EACN,WAAW,EACX,eAAe,EACf,OAAO,EACP,SAAS,EACT,YAAY,EACZ,OAAO,EACP,OAAO,EACP,SAAS,EACT,OAAO,EACP,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,UAAU,EACV,QAAQ,GACT,MAAM,SAAS,CAAC;AAIjB,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAClH,YAAY,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE9H,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC1H,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,YAAY,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAElH,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAElG,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AACnH,YAAY,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,OAAO,EACP,MAAM,EACN,WAAW,EACX,eAAe,EACf,OAAO,EACP,SAAS,EACT,YAAY,EACZ,OAAO,EACP,OAAO,EACP,SAAS,EACT,OAAO,EACP,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,UAAU,EACV,QAAQ,GACT,MAAM,SAAS,CAAC;AAIjB,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAClH,YAAY,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE9H,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC1H,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAIrK,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,sBAAsB,EACtB,gBAAgB,EAChB,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAI7F,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAIlG,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAIvB,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,iBAAiB,EACjB,sBAAsB,EACtB,sBAAsB,EACtB,uBAAuB,EACvB,2BAA2B,EAC3B,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,EACtB,eAAe,EACf,eAAe,EACf,aAAa,GACd,MAAM,gBAAgB,CAAC;AAIxB,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC9E,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAI9F,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC3F,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAIrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAIlD,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC5H,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACzH,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnE,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAEnF,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -231,6 +231,7 @@ function sqlObjectKey(params) {
|
|
|
231
231
|
case "view":
|
|
232
232
|
case "sequence":
|
|
233
233
|
case "postgresExtension":
|
|
234
|
+
case "enum":
|
|
234
235
|
return JSON.stringify([object.kind, object.name.namespace, object.name.name]);
|
|
235
236
|
case "function":
|
|
236
237
|
return JSON.stringify([object.kind, object.name.namespace, object.name.name, object.argumentTypes.map((type) => [type.namespace, type.name])]);
|
|
@@ -259,6 +260,7 @@ function isSqlObjectIdentity(value) {
|
|
|
259
260
|
case "view":
|
|
260
261
|
case "sequence":
|
|
261
262
|
case "postgresExtension":
|
|
263
|
+
case "enum":
|
|
262
264
|
return name(value.name);
|
|
263
265
|
case "function":
|
|
264
266
|
return name(value.name) && Array.isArray(value.argumentTypes) && value.argumentTypes.every(name);
|
|
@@ -276,7 +278,7 @@ function isSqlObjectIdentity(value) {
|
|
|
276
278
|
}
|
|
277
279
|
}
|
|
278
280
|
function isSqlObjectDefinition(value) {
|
|
279
|
-
return record(value) && value.format === "catalog-v1" && isSqlObjectIdentity(value.identity) && record(value.facts) && Object.keys(value.facts).length > 0 && Object.values(value.facts).every((fact) => fact === null || typeof fact === "string" || typeof fact === "boolean" || typeof fact === "number" && Number.isFinite(fact) || Array.isArray(fact) && fact.every((entry) => typeof entry === "string")) && Array.isArray(value.dependencies) && value.dependencies.every(isSqlObjectIdentity);
|
|
281
|
+
return record(value) && (value.format === "catalog-v1" || value.format === "catalog-v2") && isSqlObjectIdentity(value.identity) && record(value.facts) && Object.keys(value.facts).length > 0 && Object.values(value.facts).every((fact) => fact === null || typeof fact === "string" || typeof fact === "boolean" || typeof fact === "number" && Number.isFinite(fact) || Array.isArray(fact) && fact.every((entry) => typeof entry === "string")) && Array.isArray(value.dependencies) && value.dependencies.every(isSqlObjectIdentity);
|
|
280
282
|
}
|
|
281
283
|
function assertMigrationObjects(params) {
|
|
282
284
|
if (!Array.isArray(params.objects))
|
|
@@ -401,6 +403,7 @@ var RESERVED_DELEGATE_NAMES = [
|
|
|
401
403
|
"updateMany",
|
|
402
404
|
"updateManyAndReturn",
|
|
403
405
|
"upsert",
|
|
406
|
+
"upsertMany",
|
|
404
407
|
"delete",
|
|
405
408
|
"deleteMany",
|
|
406
409
|
"count",
|
|
@@ -424,7 +427,11 @@ var RESERVED_CLIENT_NAMES = [
|
|
|
424
427
|
"$withPolicy",
|
|
425
428
|
"$bypassPolicy",
|
|
426
429
|
"$scoped",
|
|
427
|
-
"$readOnly"
|
|
430
|
+
"$readOnly",
|
|
431
|
+
"$models",
|
|
432
|
+
"$withContext",
|
|
433
|
+
"$advisoryLock",
|
|
434
|
+
"$tryAdvisoryLock"
|
|
428
435
|
];
|
|
429
436
|
var RESERVED_COLUMN_PREFIX = "__vibe_";
|
|
430
437
|
function isReservedDelegateName(params) {
|
|
@@ -462,26 +469,26 @@ function extensionManifestEntry(params) {
|
|
|
462
469
|
}
|
|
463
470
|
var EXTENSION_NAME_PATTERN = /^[a-z][a-zA-Z0-9]*$/;
|
|
464
471
|
function defineExtension(extension) {
|
|
465
|
-
const { name
|
|
466
|
-
if (!EXTENSION_NAME_PATTERN.test(
|
|
472
|
+
const { name } = extension;
|
|
473
|
+
if (!EXTENSION_NAME_PATTERN.test(name)) {
|
|
467
474
|
throw new VibeError({
|
|
468
475
|
code: "VIBE_CONFIG",
|
|
469
|
-
message: `extension name "${
|
|
470
|
-
meta: { name
|
|
476
|
+
message: `extension name "${name}" is invalid \u2014 must match ${EXTENSION_NAME_PATTERN} (it becomes a client identifier)`,
|
|
477
|
+
meta: { name }
|
|
471
478
|
});
|
|
472
479
|
}
|
|
473
|
-
if (RESERVED_DELEGATE_NAMES.includes(
|
|
480
|
+
if (RESERVED_DELEGATE_NAMES.includes(name)) {
|
|
474
481
|
throw new VibeError({
|
|
475
482
|
code: "VIBE_CONFIG",
|
|
476
|
-
message: `extension name "${
|
|
477
|
-
meta: { name
|
|
483
|
+
message: `extension name "${name}" collides with a core delegate method`,
|
|
484
|
+
meta: { name }
|
|
478
485
|
});
|
|
479
486
|
}
|
|
480
|
-
if (RESERVED_CLIENT_NAMES.includes(`$${
|
|
487
|
+
if (RESERVED_CLIENT_NAMES.includes(`$${name}`)) {
|
|
481
488
|
throw new VibeError({
|
|
482
489
|
code: "VIBE_CONFIG",
|
|
483
|
-
message: `extension name "${
|
|
484
|
-
meta: { name
|
|
490
|
+
message: `extension name "${name}" collides with the core client method "$${name}"`,
|
|
491
|
+
meta: { name }
|
|
485
492
|
});
|
|
486
493
|
}
|
|
487
494
|
return Object.freeze(extension);
|
|
@@ -817,6 +824,9 @@ var RESERVED_ENUM_NAMES = [
|
|
|
817
824
|
"schema",
|
|
818
825
|
"VibeClient",
|
|
819
826
|
"VibeClientInstance",
|
|
827
|
+
"VibeQueryPromise",
|
|
828
|
+
"vibeQuery",
|
|
829
|
+
"vibeTransaction",
|
|
820
830
|
"VibeClientOptions",
|
|
821
831
|
"VibeError",
|
|
822
832
|
"VibeErrorCode",
|
|
@@ -850,6 +860,8 @@ var RESERVED_ENUM_NAMES = [
|
|
|
850
860
|
"createClient",
|
|
851
861
|
"DatabaseAdapter",
|
|
852
862
|
"DbNow",
|
|
863
|
+
"ClientContext",
|
|
864
|
+
"QueryOperation",
|
|
853
865
|
"QueryEvent",
|
|
854
866
|
"Skip",
|
|
855
867
|
"TransactionOptions",
|
|
@@ -964,23 +976,98 @@ var GENERATED_TYPE_NAMES = {
|
|
|
964
976
|
"UpsertWithWhereUnique"
|
|
965
977
|
]
|
|
966
978
|
};
|
|
979
|
+
var INVALID_BINDING_NAMES = new Set([
|
|
980
|
+
"await",
|
|
981
|
+
"break",
|
|
982
|
+
"case",
|
|
983
|
+
"catch",
|
|
984
|
+
"class",
|
|
985
|
+
"const",
|
|
986
|
+
"continue",
|
|
987
|
+
"debugger",
|
|
988
|
+
"default",
|
|
989
|
+
"delete",
|
|
990
|
+
"do",
|
|
991
|
+
"else",
|
|
992
|
+
"enum",
|
|
993
|
+
"export",
|
|
994
|
+
"extends",
|
|
995
|
+
"false",
|
|
996
|
+
"finally",
|
|
997
|
+
"for",
|
|
998
|
+
"function",
|
|
999
|
+
"if",
|
|
1000
|
+
"import",
|
|
1001
|
+
"in",
|
|
1002
|
+
"instanceof",
|
|
1003
|
+
"new",
|
|
1004
|
+
"null",
|
|
1005
|
+
"return",
|
|
1006
|
+
"super",
|
|
1007
|
+
"switch",
|
|
1008
|
+
"this",
|
|
1009
|
+
"throw",
|
|
1010
|
+
"true",
|
|
1011
|
+
"try",
|
|
1012
|
+
"typeof",
|
|
1013
|
+
"var",
|
|
1014
|
+
"void",
|
|
1015
|
+
"while",
|
|
1016
|
+
"with",
|
|
1017
|
+
"yield",
|
|
1018
|
+
"implements",
|
|
1019
|
+
"interface",
|
|
1020
|
+
"let",
|
|
1021
|
+
"package",
|
|
1022
|
+
"private",
|
|
1023
|
+
"protected",
|
|
1024
|
+
"public",
|
|
1025
|
+
"static",
|
|
1026
|
+
"arguments",
|
|
1027
|
+
"eval",
|
|
1028
|
+
"any",
|
|
1029
|
+
"unknown",
|
|
1030
|
+
"never",
|
|
1031
|
+
"number",
|
|
1032
|
+
"bigint",
|
|
1033
|
+
"boolean",
|
|
1034
|
+
"string",
|
|
1035
|
+
"symbol",
|
|
1036
|
+
"object",
|
|
1037
|
+
"undefined"
|
|
1038
|
+
]);
|
|
967
1039
|
function validateGeneratedNames(params) {
|
|
968
1040
|
const { schema, issues } = params;
|
|
969
|
-
const owners = new Map(RESERVED_ENUM_NAMES.map((
|
|
1041
|
+
const owners = new Map(RESERVED_ENUM_NAMES.map((name) => [name, "generated client"]));
|
|
970
1042
|
if (schema.rls !== undefined) {
|
|
971
1043
|
owners.set("RlsContext", "native RLS client");
|
|
972
1044
|
owners.set("BoundVibeClientInstance", "native RLS client");
|
|
973
1045
|
owners.set("BoundVibeTransactionClientInstance", "native RLS client");
|
|
974
1046
|
}
|
|
975
|
-
const register = (
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1047
|
+
const register = (params) => {
|
|
1048
|
+
if (!/^[$_\p{ID_Start}][$_\u200c\u200d\p{ID_Continue}]*$/u.test(params.name) || INVALID_BINDING_NAMES.has(params.name)) {
|
|
1049
|
+
issues.push({ rule: "invalid-generated-identifier", message: `Generated name "${params.name}" from ${params.owner} is not a legal TypeScript identifier` });
|
|
1050
|
+
}
|
|
1051
|
+
const previous = owners.get(params.name);
|
|
1052
|
+
if (previous !== undefined && previous !== params.owner) {
|
|
1053
|
+
issues.push({ rule: "generated-name-collision", message: `Generated name "${params.name}" from ${params.owner} conflicts with ${previous}` });
|
|
979
1054
|
} else {
|
|
980
|
-
owners.set(
|
|
1055
|
+
owners.set(params.name, params.owner);
|
|
981
1056
|
}
|
|
982
1057
|
};
|
|
1058
|
+
const aliases = new Map;
|
|
983
1059
|
for (const model of schema.models) {
|
|
1060
|
+
const clientName = model.name.charAt(0).toLowerCase() + model.name.slice(1);
|
|
1061
|
+
for (const alias of new Set([model.name, clientName])) {
|
|
1062
|
+
const previous = aliases.get(alias);
|
|
1063
|
+
if (previous !== undefined && previous !== model.name) {
|
|
1064
|
+
issues.push({ rule: "model-client-alias-collision", message: `Model "${model.name}" alias "${alias}" conflicts with model "${previous}"`, model: model.name });
|
|
1065
|
+
}
|
|
1066
|
+
aliases.set(alias, model.name);
|
|
1067
|
+
}
|
|
1068
|
+
if (RESERVED_CLIENT_NAMES.includes(clientName)) {
|
|
1069
|
+
issues.push({ rule: "reserved-client-name", message: `Model "${model.name}" conflicts with client member "${clientName}"`, model: model.name });
|
|
1070
|
+
}
|
|
984
1071
|
const owner = `model "${model.name}"`;
|
|
985
1072
|
for (const suffix of GENERATED_TYPE_NAMES.modelSuffixes)
|
|
986
1073
|
register({ name: `${model.name}${suffix}`, owner });
|
|
@@ -1113,8 +1200,8 @@ function validateSchemaIR(params) {
|
|
|
1113
1200
|
}
|
|
1114
1201
|
}
|
|
1115
1202
|
const seenSelectorNames = new Set;
|
|
1116
|
-
const checkSelectorName = (
|
|
1117
|
-
const { clientName, fieldCount, where, isUnique, site } =
|
|
1203
|
+
const checkSelectorName = (params) => {
|
|
1204
|
+
const { clientName, fieldCount, where, isUnique, site } = params;
|
|
1118
1205
|
if (!isUnique) {
|
|
1119
1206
|
issues.push({
|
|
1120
1207
|
rule: "client-name-non-unique",
|
|
@@ -1186,6 +1273,53 @@ function validateModel(params) {
|
|
|
1186
1273
|
});
|
|
1187
1274
|
}
|
|
1188
1275
|
memberNames.add(field.name);
|
|
1276
|
+
const typeIdentity = field.nativeTypeIdentity;
|
|
1277
|
+
if (typeIdentity !== undefined && (typeIdentity === null || typeof typeIdentity !== "object" || field.isUnsupported !== true || typeof typeIdentity.source !== "string" || typeIdentity.source !== field.nativeType || typeof typeIdentity.namespace !== "string" || typeIdentity.namespace.length === 0 || typeIdentity.namespace.includes("\x00"))) {
|
|
1278
|
+
issues.push({ rule: "invalid-native-type-identity", message: `PostgreSQL type identity on "${model.name}.${field.name}" must be bound to its unsupported declaration`, model: model.name, field: field.name });
|
|
1279
|
+
}
|
|
1280
|
+
const defaultValue = field.default;
|
|
1281
|
+
if (defaultValue !== undefined && defaultValue.kind !== "dbgenerated" && defaultValue.kind !== "list") {
|
|
1282
|
+
let valid = !field.isList;
|
|
1283
|
+
if (defaultValue.kind === "now")
|
|
1284
|
+
valid &&= field.type === "DateTime";
|
|
1285
|
+
else if (defaultValue.kind === "autoincrement")
|
|
1286
|
+
valid &&= !field.isOptional && (field.type === "Int" || field.type === "BigInt");
|
|
1287
|
+
else if (defaultValue.kind === "uuid" || defaultValue.kind === "cuid" || defaultValue.kind === "ulid" || defaultValue.kind === "nanoid")
|
|
1288
|
+
valid &&= field.type === "String";
|
|
1289
|
+
else if (defaultValue.kind === "enumValue")
|
|
1290
|
+
valid &&= isEnumType(field.type);
|
|
1291
|
+
else if (defaultValue.kind === "literal") {
|
|
1292
|
+
const value = defaultValue.value;
|
|
1293
|
+
if (isEnumType(field.type))
|
|
1294
|
+
valid &&= typeof value === "string";
|
|
1295
|
+
else
|
|
1296
|
+
switch (field.type) {
|
|
1297
|
+
case "Int":
|
|
1298
|
+
valid &&= typeof value === "number" && Number.isInteger(value) && value >= -2147483648 && value <= 2147483647;
|
|
1299
|
+
break;
|
|
1300
|
+
case "BigInt":
|
|
1301
|
+
valid &&= typeof value === "number" && Number.isSafeInteger(value) || typeof value === "string" && /^-?\d+$/.test(value);
|
|
1302
|
+
break;
|
|
1303
|
+
case "Float":
|
|
1304
|
+
case "Decimal":
|
|
1305
|
+
valid &&= typeof value === "number" && Number.isFinite(value) || typeof value === "string" && /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i.test(value);
|
|
1306
|
+
break;
|
|
1307
|
+
case "Boolean":
|
|
1308
|
+
valid &&= typeof value === "boolean";
|
|
1309
|
+
break;
|
|
1310
|
+
case "DateTime":
|
|
1311
|
+
valid &&= typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
1312
|
+
break;
|
|
1313
|
+
case "String":
|
|
1314
|
+
case "Json":
|
|
1315
|
+
case "Bytes":
|
|
1316
|
+
valid &&= typeof value === "string";
|
|
1317
|
+
break;
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
if (!valid)
|
|
1321
|
+
issues.push({ rule: "invalid-scalar-default", message: `Default on "${model.name}.${field.name}" does not match its field type`, model: model.name, field: field.name });
|
|
1322
|
+
}
|
|
1189
1323
|
if (isEnumType(field.type)) {
|
|
1190
1324
|
const enumDef = enumByName.get(field.type.enum);
|
|
1191
1325
|
if (enumDef === undefined) {
|
|
@@ -1389,22 +1523,22 @@ function validateModel(params) {
|
|
|
1389
1523
|
}
|
|
1390
1524
|
function validatePredicateFields(params) {
|
|
1391
1525
|
const { predicate, model, fieldNames, site, issues } = params;
|
|
1392
|
-
for (const
|
|
1393
|
-
if (!fieldNames.has(
|
|
1526
|
+
for (const name of predicateFieldNames({ predicate })) {
|
|
1527
|
+
if (!fieldNames.has(name)) {
|
|
1394
1528
|
issues.push({
|
|
1395
1529
|
rule: "predicate-unknown-field",
|
|
1396
|
-
message: `${site} on "${model.name}" references unknown field "${
|
|
1530
|
+
message: `${site} on "${model.name}" references unknown field "${name}"`,
|
|
1397
1531
|
model: model.name,
|
|
1398
|
-
field:
|
|
1532
|
+
field: name
|
|
1399
1533
|
});
|
|
1400
1534
|
continue;
|
|
1401
1535
|
}
|
|
1402
|
-
if (model.fields.find((field) => field.name ===
|
|
1536
|
+
if (model.fields.find((field) => field.name === name)?.isList === true) {
|
|
1403
1537
|
issues.push({
|
|
1404
1538
|
rule: "predicate-list-field",
|
|
1405
|
-
message: `${site} on "${model.name}" compares scalar list "${
|
|
1539
|
+
message: `${site} on "${model.name}" compares scalar list "${name}" \u2014 use a raw expression for array operators`,
|
|
1406
1540
|
model: model.name,
|
|
1407
|
-
field:
|
|
1541
|
+
field: name
|
|
1408
1542
|
});
|
|
1409
1543
|
}
|
|
1410
1544
|
}
|
|
@@ -1426,10 +1560,10 @@ function assertValidSchemaIR(params) {
|
|
|
1426
1560
|
const source = exclusion.source;
|
|
1427
1561
|
if (source !== undefined) {
|
|
1428
1562
|
const references = [...source.keys.flatMap((key) => ("field" in key) ? [key.field] : key.fields), ...[source.range.lower, source.range.upper].flatMap((endpoint) => ("field" in endpoint) ? [endpoint.field] : []), ...source.where === undefined ? [] : predicateFieldNames({ predicate: source.where })];
|
|
1429
|
-
if (references.some((
|
|
1563
|
+
if (references.some((name) => !model.fields.some((field) => field.name === name && !field.isList)))
|
|
1430
1564
|
throw new VibeError({ code: "VIBE_SCHEMA_INVALID", message: "Exclusion references an unknown or list field", meta: { rule: "exclusion-field", model: model.name } });
|
|
1431
1565
|
}
|
|
1432
|
-
if (!exclusion.name || names.has(exclusion.name) || typeof exclusion.definition !== "string" || !exclusion.definition.startsWith("EXCLUDE USING ") || !Array.isArray(exclusion.requiredExtensions) || exclusion.requiredExtensions.some((
|
|
1566
|
+
if (!exclusion.name || names.has(exclusion.name) || typeof exclusion.definition !== "string" || !exclusion.definition.startsWith("EXCLUDE USING ") || !Array.isArray(exclusion.requiredExtensions) || exclusion.requiredExtensions.some((name) => name !== "btree_gist"))
|
|
1433
1567
|
throw new VibeError({ code: "VIBE_SCHEMA_INVALID", message: "Invalid exclusion declaration", meta: { rule: "exclusion-definition", model: model.name } });
|
|
1434
1568
|
names.add(exclusion.name);
|
|
1435
1569
|
}
|
|
@@ -1451,8 +1585,8 @@ function assertValidSchemaIR(params) {
|
|
|
1451
1585
|
throw new VibeError({ code: "VIBE_SCHEMA_INVALID", message: `List default on non-list field ${model.name}.${field.name}` });
|
|
1452
1586
|
scalarListDefault({ type: field.type, values: field.default.values });
|
|
1453
1587
|
if (isEnumType(field.type)) {
|
|
1454
|
-
const
|
|
1455
|
-
const members = params.schema.enums.find((entry) => entry.name ===
|
|
1588
|
+
const name = field.type.enum;
|
|
1589
|
+
const members = params.schema.enums.find((entry) => entry.name === name)?.values ?? [];
|
|
1456
1590
|
if (field.default.values.some((value) => typeof value !== "string" || !members.includes(value)))
|
|
1457
1591
|
throw new VibeError({ code: "VIBE_SCHEMA_INVALID", message: `Invalid enum-list default on ${model.name}.${field.name}` });
|
|
1458
1592
|
}
|
|
@@ -1543,8 +1677,8 @@ function validateNativeRls(params) {
|
|
|
1543
1677
|
const tables = new Set;
|
|
1544
1678
|
const throughTargets = new Map;
|
|
1545
1679
|
for (const model of schema.models) {
|
|
1546
|
-
const add = (
|
|
1547
|
-
issues.push({ ...
|
|
1680
|
+
const add = (params) => {
|
|
1681
|
+
issues.push({ ...params, model: model.name });
|
|
1548
1682
|
};
|
|
1549
1683
|
const table = model.dbName ?? model.name;
|
|
1550
1684
|
if (tables.has(table))
|
|
@@ -1552,10 +1686,10 @@ function validateNativeRls(params) {
|
|
|
1552
1686
|
tables.add(table);
|
|
1553
1687
|
const columns = new Set;
|
|
1554
1688
|
for (const field of model.fields) {
|
|
1555
|
-
const
|
|
1556
|
-
if (columns.has(
|
|
1557
|
-
add({ rule: "rls-duplicate-column", message: `RLS model ${model.name} repeats physical column ${
|
|
1558
|
-
columns.add(
|
|
1689
|
+
const name = field.dbName ?? field.name;
|
|
1690
|
+
if (columns.has(name))
|
|
1691
|
+
add({ rule: "rls-duplicate-column", message: `RLS model ${model.name} repeats physical column ${name}`, field: field.name });
|
|
1692
|
+
columns.add(name);
|
|
1559
1693
|
}
|
|
1560
1694
|
if (model.policy !== undefined)
|
|
1561
1695
|
add({ rule: "rls-policy-conflict", message: "Native RLS cannot combine with application-level ModelIR.policy" });
|
|
@@ -1608,7 +1742,7 @@ function validateNativeRls(params) {
|
|
|
1608
1742
|
add({ rule: "rls-invalid-through", message: "Native RLS through requires a to-one relation with an actual, complete foreign key on this model" });
|
|
1609
1743
|
continue;
|
|
1610
1744
|
}
|
|
1611
|
-
if (relation.isOptional || relation.fields?.some((
|
|
1745
|
+
if (relation.isOptional || relation.fields?.some((name) => model.fields.find((field) => field.name === name)?.isOptional)) {
|
|
1612
1746
|
add({ rule: "rls-nullable-through", message: "Native RLS through requires a non-nullable parent relation and foreign key; NULL parent links cannot satisfy WITH CHECK. Make the link required or use a direct ownership rule", field: relation.name });
|
|
1613
1747
|
continue;
|
|
1614
1748
|
}
|
|
@@ -1640,8 +1774,8 @@ function validRlsForeignKey(params) {
|
|
|
1640
1774
|
const refs = relation.references;
|
|
1641
1775
|
if (fields === undefined || refs === undefined || fields.length === 0 || fields.length !== refs.length || new Set(fields).size !== fields.length || new Set(refs).size !== refs.length)
|
|
1642
1776
|
return false;
|
|
1643
|
-
const validFields = fields.every((
|
|
1644
|
-
const field = model.fields.find((f) => f.name ===
|
|
1777
|
+
const validFields = fields.every((name, index) => {
|
|
1778
|
+
const field = model.fields.find((f) => f.name === name);
|
|
1645
1779
|
const ref = target.fields.find((f) => f.name === refs[index]);
|
|
1646
1780
|
return field !== undefined && ref !== undefined && !field.isList && !ref.isList && !field.isUnsupported && !ref.isUnsupported && (field.type === ref.type || isEnumType(field.type) && isEnumType(ref.type) && field.type.enum === ref.type.enum);
|
|
1647
1781
|
});
|
|
@@ -1650,7 +1784,7 @@ function validRlsForeignKey(params) {
|
|
|
1650
1784
|
...target.primaryKey === undefined ? [] : [target.primaryKey.fields],
|
|
1651
1785
|
...target.indexes.filter((index) => index.kind === "unique" && index.where === undefined).map((index) => index.fields.map((f) => f.name))
|
|
1652
1786
|
];
|
|
1653
|
-
return validFields && uniqueSets.some((set) => set.length === refs.length && set.every((
|
|
1787
|
+
return validFields && uniqueSets.some((set) => set.length === refs.length && set.every((name) => refs.includes(name)));
|
|
1654
1788
|
}
|
|
1655
1789
|
// packages/schema/src/m2m.ts
|
|
1656
1790
|
function implicitJoinTable(params) {
|
|
@@ -1667,59 +1801,59 @@ function implicitJoinTable(params) {
|
|
|
1667
1801
|
};
|
|
1668
1802
|
}
|
|
1669
1803
|
export {
|
|
1670
|
-
|
|
1671
|
-
validateRlsContextIR,
|
|
1672
|
-
validateComputedConfig,
|
|
1673
|
-
unsupportedCapability,
|
|
1674
|
-
sqlObjectKey,
|
|
1675
|
-
serializeJsonDefault,
|
|
1676
|
-
scalarListDefault,
|
|
1677
|
-
providerToDialect,
|
|
1678
|
-
predicateKey,
|
|
1679
|
-
predicateFieldNames,
|
|
1680
|
-
mergeExtensionDeclarations,
|
|
1681
|
-
isSqlObjectIdentity,
|
|
1682
|
-
isSqlObjectDefinition,
|
|
1683
|
-
isReservedDelegateName,
|
|
1684
|
-
isReservedClientName,
|
|
1685
|
-
isPredicateFieldRef,
|
|
1686
|
-
isImplicitManyToManyRelation,
|
|
1687
|
-
isEnumType,
|
|
1688
|
-
invalidStoredData,
|
|
1689
|
-
internalError,
|
|
1690
|
-
implicitJoinTable,
|
|
1691
|
-
fieldTypeIdentity,
|
|
1692
|
-
extensionOptionsHash,
|
|
1693
|
-
extensionManifestEntry,
|
|
1694
|
-
extensionDeclarations,
|
|
1695
|
-
exactIntegerLiteral,
|
|
1696
|
-
enumStorageOf,
|
|
1697
|
-
encodePrismaString,
|
|
1698
|
-
defineExtension,
|
|
1699
|
-
decodePrismaString,
|
|
1700
|
-
buildExtensionRegistry,
|
|
1701
|
-
buildComputedManifest,
|
|
1702
|
-
assertValidSchemaIR,
|
|
1703
|
-
assertMigrationObjects,
|
|
1704
|
-
VibeError,
|
|
1705
|
-
VIBE_ERROR_CODES,
|
|
1706
|
-
ScopedQueryError,
|
|
1707
|
-
SQLITE_CAPABILITIES,
|
|
1708
|
-
SCOPED_REFUSAL_REASONS,
|
|
1709
|
-
RlsContextError,
|
|
1710
|
-
ReadOnlyClientError,
|
|
1711
|
-
RLS_CONTEXT_REASONS,
|
|
1712
|
-
RESERVED_ENUM_NAMES,
|
|
1713
|
-
RESERVED_DELEGATE_NAMES,
|
|
1714
|
-
RESERVED_CLIENT_NAMES,
|
|
1715
|
-
READ_ONLY_REFUSAL_REASONS,
|
|
1716
|
-
PREDICATE_COMPARISON_OPS,
|
|
1717
|
-
POSTGRES_CAPABILITIES,
|
|
1718
|
-
MYSQL_CAPABILITIES,
|
|
1719
|
-
ENUM_STORAGES,
|
|
1720
|
-
EMPTY_EXTENSION_REGISTRY,
|
|
1804
|
+
DIALECTS,
|
|
1721
1805
|
DIALECT_CAPABILITIES,
|
|
1722
|
-
|
|
1806
|
+
EMPTY_EXTENSION_REGISTRY,
|
|
1807
|
+
ENUM_STORAGES,
|
|
1808
|
+
MYSQL_CAPABILITIES,
|
|
1809
|
+
POSTGRES_CAPABILITIES,
|
|
1810
|
+
PREDICATE_COMPARISON_OPS,
|
|
1811
|
+
READ_ONLY_REFUSAL_REASONS,
|
|
1812
|
+
RESERVED_CLIENT_NAMES,
|
|
1813
|
+
RESERVED_DELEGATE_NAMES,
|
|
1814
|
+
RESERVED_ENUM_NAMES,
|
|
1815
|
+
RLS_CONTEXT_REASONS,
|
|
1816
|
+
ReadOnlyClientError,
|
|
1817
|
+
RlsContextError,
|
|
1818
|
+
SCOPED_REFUSAL_REASONS,
|
|
1819
|
+
SQLITE_CAPABILITIES,
|
|
1820
|
+
ScopedQueryError,
|
|
1821
|
+
VIBE_ERROR_CODES,
|
|
1822
|
+
VibeError,
|
|
1823
|
+
assertMigrationObjects,
|
|
1824
|
+
assertValidSchemaIR,
|
|
1825
|
+
buildComputedManifest,
|
|
1826
|
+
buildExtensionRegistry,
|
|
1827
|
+
decodePrismaString,
|
|
1828
|
+
defineExtension,
|
|
1829
|
+
encodePrismaString,
|
|
1830
|
+
enumStorageOf,
|
|
1831
|
+
exactIntegerLiteral,
|
|
1832
|
+
extensionDeclarations,
|
|
1833
|
+
extensionManifestEntry,
|
|
1834
|
+
extensionOptionsHash,
|
|
1835
|
+
fieldTypeIdentity,
|
|
1836
|
+
implicitJoinTable,
|
|
1837
|
+
internalError,
|
|
1838
|
+
invalidStoredData,
|
|
1839
|
+
isEnumType,
|
|
1840
|
+
isImplicitManyToManyRelation,
|
|
1841
|
+
isPredicateFieldRef,
|
|
1842
|
+
isReservedClientName,
|
|
1843
|
+
isReservedDelegateName,
|
|
1844
|
+
isSqlObjectDefinition,
|
|
1845
|
+
isSqlObjectIdentity,
|
|
1846
|
+
mergeExtensionDeclarations,
|
|
1847
|
+
predicateFieldNames,
|
|
1848
|
+
predicateKey,
|
|
1849
|
+
providerToDialect,
|
|
1850
|
+
scalarListDefault,
|
|
1851
|
+
serializeJsonDefault,
|
|
1852
|
+
sqlObjectKey,
|
|
1853
|
+
unsupportedCapability,
|
|
1854
|
+
validateComputedConfig,
|
|
1855
|
+
validateRlsContextIR,
|
|
1856
|
+
validateSchemaIR
|
|
1723
1857
|
};
|
|
1724
1858
|
|
|
1725
|
-
//# debugId=
|
|
1859
|
+
//# debugId=5275C43BC09D1F0064756E2164756E21
|