@drzl/analyzer 1.12.0 → 1.13.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/index.cjs +51 -10
- package/dist/index.js +51 -10
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -215,6 +215,15 @@ function describeV1Column(column) {
|
|
|
215
215
|
if (typeof dims === "number" && dims >= 1) out.arrayDimensions = dims;
|
|
216
216
|
return out;
|
|
217
217
|
}
|
|
218
|
+
function unwrapArrayColumn(column) {
|
|
219
|
+
let element = column;
|
|
220
|
+
let dimensions = 0;
|
|
221
|
+
while (element?.baseColumn && String(element?.constructor?.name ?? "").endsWith("Array")) {
|
|
222
|
+
element = element.baseColumn;
|
|
223
|
+
dimensions++;
|
|
224
|
+
}
|
|
225
|
+
return { element, dimensions };
|
|
226
|
+
}
|
|
218
227
|
function declaredLength(column) {
|
|
219
228
|
const n = column?.length ?? column?.config?.length ?? column?.config?.dimensions;
|
|
220
229
|
return typeof n === "number" && Number.isFinite(n) && n > 0 ? n : void 0;
|
|
@@ -515,10 +524,23 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
515
524
|
return { tsType: "number", dbType: "REAL" };
|
|
516
525
|
case "SQLiteBlob":
|
|
517
526
|
return { tsType: "Uint8Array", dbType: "BLOB" };
|
|
527
|
+
// SQLite spells a mode as a distinct class rather than as config, so `text({mode:'json'})`
|
|
528
|
+
// is a `SQLiteTextJson` and matched no arm at all: the column came back UNKNOWN, which is
|
|
529
|
+
// wider than the `any` a json column at least used to get.
|
|
530
|
+
case "SQLiteTextJson":
|
|
531
|
+
case "SQLiteBlobJson":
|
|
532
|
+
return { tsType: "any", dbType: "JSON" };
|
|
533
|
+
case "SQLiteBigInt":
|
|
534
|
+
return { tsType: "bigint", dbType: "BIGINT" };
|
|
518
535
|
case "SQLiteNumeric":
|
|
519
536
|
return { tsType: "string", dbType: "NUMERIC" };
|
|
520
537
|
case "SQLiteBoolean":
|
|
521
538
|
return { tsType: "boolean", dbType: "INTEGER" };
|
|
539
|
+
// 0.4x gives an enum its own class, which had no arm here at all, so an enum column came
|
|
540
|
+
// back `unknown` and every generator emitted a schema that accepted anything. The values
|
|
541
|
+
// were on the column the whole time, in `enumValues`, waiting for a type to attach to.
|
|
542
|
+
case "PgEnumColumn":
|
|
543
|
+
return { tsType: "string", dbType: "TEXT" };
|
|
522
544
|
case "PgInteger":
|
|
523
545
|
case "PgSmallInt":
|
|
524
546
|
return { tsType: "number", dbType: "INTEGER" };
|
|
@@ -650,25 +672,26 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
650
672
|
const foreignKeys = [];
|
|
651
673
|
const pkCols = [];
|
|
652
674
|
const uniqueGroups = /* @__PURE__ */ new Map();
|
|
653
|
-
for (const [colName,
|
|
675
|
+
for (const [colName, outerCol] of Object.entries(columnsObj)) {
|
|
676
|
+
const { element: col, dimensions: arrayDims } = unwrapArrayColumn(outerCol);
|
|
654
677
|
let { tsType, dbType } = this.mapColumnType(col);
|
|
655
678
|
if (tsType === "unknown" && /At$/.test(colName)) {
|
|
656
679
|
tsType = "Date";
|
|
657
680
|
dbType = "INTEGER";
|
|
658
681
|
}
|
|
659
682
|
const ev = col?.enumValues;
|
|
660
|
-
const nullable = !
|
|
661
|
-
const rawDefault =
|
|
683
|
+
const nullable = !outerCol?.notNull && !outerCol?.config?.notNull;
|
|
684
|
+
const rawDefault = outerCol?.default;
|
|
662
685
|
const defaultValue = rawDefault !== void 0 && !(rawDefault && typeof rawDefault === "object" && "queryChunks" in rawDefault) ? rawDefault : void 0;
|
|
663
|
-
const generatedIdentity =
|
|
664
|
-
const isGenerated = !!(
|
|
665
|
-
const hasDefault =
|
|
686
|
+
const generatedIdentity = outerCol?.generatedIdentity;
|
|
687
|
+
const isGenerated = !!(outerCol?.generated || generatedIdentity?.type === "always" || outerCol?.isGenerated);
|
|
688
|
+
const hasDefault = outerCol?.hasDefault === true || outerCol?.default !== void 0 || outerCol?.config?.default !== void 0 || outerCol?.defaultFn !== void 0 || isGenerated;
|
|
666
689
|
const references = void 0;
|
|
667
|
-
const isUnique = !!(
|
|
668
|
-
const isPk = !!(
|
|
690
|
+
const isUnique = !!(outerCol?.isUnique || outerCol?.config?.isUnique);
|
|
691
|
+
const isPk = !!(outerCol?.primary || outerCol?.config?.primaryKey);
|
|
669
692
|
if (isPk) pkCols.push(colName);
|
|
670
693
|
if (isUnique) unique.push({ columns: [colName] });
|
|
671
|
-
const uName =
|
|
694
|
+
const uName = outerCol?.uniqueName || outerCol?.config?.uniqueName;
|
|
672
695
|
if (uName) {
|
|
673
696
|
const arr = uniqueGroups.get(uName) ?? [];
|
|
674
697
|
arr.push(colName);
|
|
@@ -677,6 +700,19 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
677
700
|
const v1 = describeV1Column(col);
|
|
678
701
|
const constraints = this.columnConstraints(col);
|
|
679
702
|
if (v1?.shape) delete constraints.maxLength;
|
|
703
|
+
const jsonShape = dbType === "JSON" || dbType === "JSONB" || col?.config?.mode === "json" ? { kind: "json" } : void 0;
|
|
704
|
+
const shape = (v1?.shape ?? jsonShape)?.kind;
|
|
705
|
+
const finalTs = v1?.tsType ?? tsType;
|
|
706
|
+
const wide = (finalTs === "unknown" || finalTs === "any") && (!shape || shape === "custom");
|
|
707
|
+
if (wide) {
|
|
708
|
+
const sqlType = typeof col?.getSQLType === "function" ? col.getSQLType() : void 0;
|
|
709
|
+
issues.push({
|
|
710
|
+
code: "DRZL_ANL_UNKNOWN_COLUMN",
|
|
711
|
+
level: "warn",
|
|
712
|
+
message: `Column "${colName}" on table "${tsName}" has no known type${sqlType ? ` (SQL type ${sqlType})` : ""}, so its validator will accept any value.`,
|
|
713
|
+
hint: shape === "custom" ? "A customType has no runtime shape to read. Declare it with .$type<T>() and turn on typedColumns to give the validator the type." : "Open an issue naming the column type so it can be modelled, or declare it with .$type<T>() and turn on typedColumns."
|
|
714
|
+
});
|
|
715
|
+
}
|
|
680
716
|
columns.push({
|
|
681
717
|
name: colName,
|
|
682
718
|
tsType,
|
|
@@ -689,7 +725,12 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
689
725
|
enumValues: Array.isArray(ev) ? ev : void 0,
|
|
690
726
|
...defaultValue !== void 0 ? { defaultValue } : {},
|
|
691
727
|
...constraints,
|
|
692
|
-
...v1 ?? {}
|
|
728
|
+
...v1 ?? {},
|
|
729
|
+
// After the v1 spread, which sets its own `arrayDimensions` from `dimensions`. On 0.4x
|
|
730
|
+
// that spread has nothing to say and this is the only source.
|
|
731
|
+
...arrayDims ? { arrayDimensions: arrayDims } : {},
|
|
732
|
+
// Only where v1 did not already describe the value, so a shaped column keeps its shape.
|
|
733
|
+
...jsonShape && !v1?.shape ? { shape: jsonShape } : {}
|
|
693
734
|
});
|
|
694
735
|
}
|
|
695
736
|
const name = this.getSymbol(tbl, "drizzle:Name") || tsName;
|
package/dist/index.js
CHANGED
|
@@ -175,6 +175,15 @@ function describeV1Column(column) {
|
|
|
175
175
|
if (typeof dims === "number" && dims >= 1) out.arrayDimensions = dims;
|
|
176
176
|
return out;
|
|
177
177
|
}
|
|
178
|
+
function unwrapArrayColumn(column) {
|
|
179
|
+
let element = column;
|
|
180
|
+
let dimensions = 0;
|
|
181
|
+
while (element?.baseColumn && String(element?.constructor?.name ?? "").endsWith("Array")) {
|
|
182
|
+
element = element.baseColumn;
|
|
183
|
+
dimensions++;
|
|
184
|
+
}
|
|
185
|
+
return { element, dimensions };
|
|
186
|
+
}
|
|
178
187
|
function declaredLength(column) {
|
|
179
188
|
const n = column?.length ?? column?.config?.length ?? column?.config?.dimensions;
|
|
180
189
|
return typeof n === "number" && Number.isFinite(n) && n > 0 ? n : void 0;
|
|
@@ -475,10 +484,23 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
475
484
|
return { tsType: "number", dbType: "REAL" };
|
|
476
485
|
case "SQLiteBlob":
|
|
477
486
|
return { tsType: "Uint8Array", dbType: "BLOB" };
|
|
487
|
+
// SQLite spells a mode as a distinct class rather than as config, so `text({mode:'json'})`
|
|
488
|
+
// is a `SQLiteTextJson` and matched no arm at all: the column came back UNKNOWN, which is
|
|
489
|
+
// wider than the `any` a json column at least used to get.
|
|
490
|
+
case "SQLiteTextJson":
|
|
491
|
+
case "SQLiteBlobJson":
|
|
492
|
+
return { tsType: "any", dbType: "JSON" };
|
|
493
|
+
case "SQLiteBigInt":
|
|
494
|
+
return { tsType: "bigint", dbType: "BIGINT" };
|
|
478
495
|
case "SQLiteNumeric":
|
|
479
496
|
return { tsType: "string", dbType: "NUMERIC" };
|
|
480
497
|
case "SQLiteBoolean":
|
|
481
498
|
return { tsType: "boolean", dbType: "INTEGER" };
|
|
499
|
+
// 0.4x gives an enum its own class, which had no arm here at all, so an enum column came
|
|
500
|
+
// back `unknown` and every generator emitted a schema that accepted anything. The values
|
|
501
|
+
// were on the column the whole time, in `enumValues`, waiting for a type to attach to.
|
|
502
|
+
case "PgEnumColumn":
|
|
503
|
+
return { tsType: "string", dbType: "TEXT" };
|
|
482
504
|
case "PgInteger":
|
|
483
505
|
case "PgSmallInt":
|
|
484
506
|
return { tsType: "number", dbType: "INTEGER" };
|
|
@@ -610,25 +632,26 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
610
632
|
const foreignKeys = [];
|
|
611
633
|
const pkCols = [];
|
|
612
634
|
const uniqueGroups = /* @__PURE__ */ new Map();
|
|
613
|
-
for (const [colName,
|
|
635
|
+
for (const [colName, outerCol] of Object.entries(columnsObj)) {
|
|
636
|
+
const { element: col, dimensions: arrayDims } = unwrapArrayColumn(outerCol);
|
|
614
637
|
let { tsType, dbType } = this.mapColumnType(col);
|
|
615
638
|
if (tsType === "unknown" && /At$/.test(colName)) {
|
|
616
639
|
tsType = "Date";
|
|
617
640
|
dbType = "INTEGER";
|
|
618
641
|
}
|
|
619
642
|
const ev = col?.enumValues;
|
|
620
|
-
const nullable = !
|
|
621
|
-
const rawDefault =
|
|
643
|
+
const nullable = !outerCol?.notNull && !outerCol?.config?.notNull;
|
|
644
|
+
const rawDefault = outerCol?.default;
|
|
622
645
|
const defaultValue = rawDefault !== void 0 && !(rawDefault && typeof rawDefault === "object" && "queryChunks" in rawDefault) ? rawDefault : void 0;
|
|
623
|
-
const generatedIdentity =
|
|
624
|
-
const isGenerated = !!(
|
|
625
|
-
const hasDefault =
|
|
646
|
+
const generatedIdentity = outerCol?.generatedIdentity;
|
|
647
|
+
const isGenerated = !!(outerCol?.generated || generatedIdentity?.type === "always" || outerCol?.isGenerated);
|
|
648
|
+
const hasDefault = outerCol?.hasDefault === true || outerCol?.default !== void 0 || outerCol?.config?.default !== void 0 || outerCol?.defaultFn !== void 0 || isGenerated;
|
|
626
649
|
const references = void 0;
|
|
627
|
-
const isUnique = !!(
|
|
628
|
-
const isPk = !!(
|
|
650
|
+
const isUnique = !!(outerCol?.isUnique || outerCol?.config?.isUnique);
|
|
651
|
+
const isPk = !!(outerCol?.primary || outerCol?.config?.primaryKey);
|
|
629
652
|
if (isPk) pkCols.push(colName);
|
|
630
653
|
if (isUnique) unique.push({ columns: [colName] });
|
|
631
|
-
const uName =
|
|
654
|
+
const uName = outerCol?.uniqueName || outerCol?.config?.uniqueName;
|
|
632
655
|
if (uName) {
|
|
633
656
|
const arr = uniqueGroups.get(uName) ?? [];
|
|
634
657
|
arr.push(colName);
|
|
@@ -637,6 +660,19 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
637
660
|
const v1 = describeV1Column(col);
|
|
638
661
|
const constraints = this.columnConstraints(col);
|
|
639
662
|
if (v1?.shape) delete constraints.maxLength;
|
|
663
|
+
const jsonShape = dbType === "JSON" || dbType === "JSONB" || col?.config?.mode === "json" ? { kind: "json" } : void 0;
|
|
664
|
+
const shape = (v1?.shape ?? jsonShape)?.kind;
|
|
665
|
+
const finalTs = v1?.tsType ?? tsType;
|
|
666
|
+
const wide = (finalTs === "unknown" || finalTs === "any") && (!shape || shape === "custom");
|
|
667
|
+
if (wide) {
|
|
668
|
+
const sqlType = typeof col?.getSQLType === "function" ? col.getSQLType() : void 0;
|
|
669
|
+
issues.push({
|
|
670
|
+
code: "DRZL_ANL_UNKNOWN_COLUMN",
|
|
671
|
+
level: "warn",
|
|
672
|
+
message: `Column "${colName}" on table "${tsName}" has no known type${sqlType ? ` (SQL type ${sqlType})` : ""}, so its validator will accept any value.`,
|
|
673
|
+
hint: shape === "custom" ? "A customType has no runtime shape to read. Declare it with .$type<T>() and turn on typedColumns to give the validator the type." : "Open an issue naming the column type so it can be modelled, or declare it with .$type<T>() and turn on typedColumns."
|
|
674
|
+
});
|
|
675
|
+
}
|
|
640
676
|
columns.push({
|
|
641
677
|
name: colName,
|
|
642
678
|
tsType,
|
|
@@ -649,7 +685,12 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
649
685
|
enumValues: Array.isArray(ev) ? ev : void 0,
|
|
650
686
|
...defaultValue !== void 0 ? { defaultValue } : {},
|
|
651
687
|
...constraints,
|
|
652
|
-
...v1 ?? {}
|
|
688
|
+
...v1 ?? {},
|
|
689
|
+
// After the v1 spread, which sets its own `arrayDimensions` from `dimensions`. On 0.4x
|
|
690
|
+
// that spread has nothing to say and this is the only source.
|
|
691
|
+
...arrayDims ? { arrayDimensions: arrayDims } : {},
|
|
692
|
+
// Only where v1 did not already describe the value, so a shaped column keeps its shape.
|
|
693
|
+
...jsonShape && !v1?.shape ? { shape: jsonShape } : {}
|
|
653
694
|
});
|
|
654
695
|
}
|
|
655
696
|
const name = this.getSymbol(tbl, "drizzle:Name") || tsName;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drzl/analyzer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -45,6 +45,6 @@
|
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "tsup src/index.ts --dts --format esm,cjs",
|
|
47
47
|
"lint": "eslint . --ext .ts",
|
|
48
|
-
"test": "vitest run"
|
|
48
|
+
"test": "vitest run --testTimeout=20000"
|
|
49
49
|
}
|
|
50
50
|
}
|