@drzl/analyzer 1.17.1 → 1.17.3
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/README.md +1 -1
- package/dist/index.cjs +75 -8
- package/dist/index.d.cts +23 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +75 -8
- package/package.json +16 -7
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ Per column, beyond the type: `nullable`, `hasDefault`, `defaultValue` (literal d
|
|
|
51
51
|
`isGenerated`, `enumValues`, `maxLength` (characters), `maxBytes` (MySQL's TEXT family is a byte
|
|
52
52
|
budget, which is a different measurement on the same kind of column), `min`/`max`,
|
|
53
53
|
`arrayDimensions`, `format`, and `shape` for values that are not scalars (json, buffer, tuple,
|
|
54
|
-
vector, bitstring, customType).
|
|
54
|
+
numberObject, vector, bitstring, customType).
|
|
55
55
|
|
|
56
56
|
`DRZL_ANL_UNKNOWN_COLUMN` is reported for any column whose validator would accept anything, which
|
|
57
57
|
is the shape a missing type mapping takes: nothing throws, and every row passes.
|
package/dist/index.cjs
CHANGED
|
@@ -63,13 +63,24 @@ var PG_FLOAT4_INPUT_MAX = "340282356779733661637539395458142568448";
|
|
|
63
63
|
var PG_FLOAT4_RANGE = [`-${PG_FLOAT4_INPUT_MAX}`, PG_FLOAT4_INPUT_MAX];
|
|
64
64
|
var MYSQL_FLOAT_RANGE = [`-${FLOAT32_MAX}`, FLOAT32_MAX];
|
|
65
65
|
var JS_SAFE_INTEGER_BOUNDS = ["-9007199254740991", "9007199254740991"];
|
|
66
|
-
var
|
|
66
|
+
var GEOMETRIC_CLASS_SHAPES = {
|
|
67
67
|
// `line()` is the trap here: its `drizzle:entityKind` is `PgLine` while its constructor is
|
|
68
68
|
// `PgLineTuple`, and this path matches on the constructor.
|
|
69
69
|
PgPointTuple: { kind: "tuple", length: 2 },
|
|
70
|
-
PgLineTuple: { kind: "tuple", length: 3 }
|
|
70
|
+
PgLineTuple: { kind: "tuple", length: 3 },
|
|
71
|
+
// The object modes. `line({ mode: 'abc' })` is a `PgLineABC` and not a `PgLineObject`, and any
|
|
72
|
+
// mode but `'tuple'` builds the object class: `point({ mode: 'abc' })` is a `PgPointObject` too.
|
|
73
|
+
PgPointObject: { kind: "numberObject", fields: ["x", "y"] },
|
|
74
|
+
PgLineABC: { kind: "numberObject", fields: ["a", "b", "c"] },
|
|
75
|
+
// `geometry()` and `geometry({ mode: 'xy' })` are two classes, not one class with a flag, and
|
|
76
|
+
// the fuzzer found both unnamed on this path. Their driver mappers disagree the same way the
|
|
77
|
+
// point ones do: the default hands back `[1, 2]` and the xy mode hands back `{ x: 1, y: 2 }`.
|
|
78
|
+
PgGeometry: { kind: "tuple", length: 2 },
|
|
79
|
+
PgGeometryObject: { kind: "numberObject", fields: ["x", "y"] }
|
|
71
80
|
};
|
|
72
81
|
var V1_ONLY_ENTITY_KINDS = /^(?:MsSql|Cockroach)/;
|
|
82
|
+
var NUMBER_VECTOR_CLASSES = /* @__PURE__ */ new Set(["PgVector", "PgHalfVector", "SingleStoreVector"]);
|
|
83
|
+
var BIT_STRING_CLASSES = /* @__PURE__ */ new Set(["PgBinaryVector"]);
|
|
73
84
|
var BYTE_STRING_CLASSES = /* @__PURE__ */ new Set([
|
|
74
85
|
"MySqlBinary",
|
|
75
86
|
"MySqlVarBinary",
|
|
@@ -190,18 +201,38 @@ function describeV1Column(column) {
|
|
|
190
201
|
};
|
|
191
202
|
break;
|
|
192
203
|
}
|
|
204
|
+
// Two modes per builder, and v1 states which in the JS half of the dataType it already
|
|
205
|
+
// carries: the tuple modes say `array point` / `array line` / `array geometry` and the object
|
|
206
|
+
// modes say `object point` / `object line` / `object geometry`. Read off real 1.0.0-rc.4
|
|
207
|
+
// columns rather than assumed. Both used to reach these arms and be called tuples, so a select
|
|
208
|
+
// schema for `point({ mode: 'xy' })` rejected every row the driver returned, on the major that
|
|
209
|
+
// describes the column outright.
|
|
210
|
+
//
|
|
211
|
+
// `js` rather than the codec, which also distinguishes them here (`point:tuple` against
|
|
212
|
+
// `point`): three dialects state a semantic with no codec at all on this release, so the codec
|
|
213
|
+
// is the weaker of the two signals and this file already prefers `js` elsewhere for the same
|
|
214
|
+
// reason.
|
|
193
215
|
case "point":
|
|
194
216
|
case "geometry":
|
|
195
|
-
out.tsType = "[number, number]";
|
|
217
|
+
out.tsType = js === "object" ? "{ x: number; y: number }" : "[number, number]";
|
|
196
218
|
out.dbType = semantic.toUpperCase();
|
|
197
|
-
out.shape = { kind: "tuple", length: 2 };
|
|
219
|
+
out.shape = js === "object" ? { kind: "numberObject", fields: ["x", "y"] } : { kind: "tuple", length: 2 };
|
|
198
220
|
break;
|
|
199
221
|
case "line":
|
|
200
|
-
out.tsType = "[number, number, number]";
|
|
222
|
+
out.tsType = js === "object" ? "{ a: number; b: number; c: number }" : "[number, number, number]";
|
|
201
223
|
out.dbType = "LINE";
|
|
202
|
-
out.shape = { kind: "tuple", length: 3 };
|
|
224
|
+
out.shape = js === "object" ? { kind: "numberObject", fields: ["a", "b", "c"] } : { kind: "tuple", length: 3 };
|
|
203
225
|
break;
|
|
226
|
+
// `halfvec` beside `vector`, because they differ in storage width and in nothing a validator
|
|
227
|
+
// can see: `mapFromDriverValue` on both hands back `[1, 2, 3]`. It had no arm and came back
|
|
228
|
+
// `unknown` on this path too, which the fuzzer found.
|
|
229
|
+
//
|
|
230
|
+
// `sparsevec` is deliberately not here. Its name says vector and its value is the string
|
|
231
|
+
// `{1:1.5,3:2}/3`, so typing it `number[]` for symmetry would reject every row the database
|
|
232
|
+
// returns. Its codec already answers `string` on its own, which is the same conclusion reached
|
|
233
|
+
// without this arm.
|
|
204
234
|
case "vector":
|
|
235
|
+
case "halfvec":
|
|
205
236
|
out.tsType = "number[]";
|
|
206
237
|
out.dbType = "VECTOR";
|
|
207
238
|
out.shape = { kind: "numberVector", length: declaredLength(column) };
|
|
@@ -593,6 +624,34 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
593
624
|
case "MySqlEnumColumn":
|
|
594
625
|
case "SingleStoreEnumColumn":
|
|
595
626
|
return { tsType: "string", dbType: "TEXT" };
|
|
627
|
+
// The pgvector family, found by the analyzer fuzzer: all three came back `unknown` on this
|
|
628
|
+
// path, so their validators accepted anything. The answers are drizzle's own mappers rather
|
|
629
|
+
// than the type names, and the three do not agree with each other:
|
|
630
|
+
//
|
|
631
|
+
// vector(3) SELECT gives [1,2,3] INSERT sends "[1,2,3]"
|
|
632
|
+
// halfvec(3) SELECT gives [1,2,3] INSERT sends "[1,2,3]"
|
|
633
|
+
// sparsevec(3) SELECT gives "{1:1.5,3:2}/3" INSERT sends "{1:1.5,3:2}/3"
|
|
634
|
+
//
|
|
635
|
+
// So the two dense ones are number arrays and the sparse one is a string. Typing `sparsevec`
|
|
636
|
+
// as a vector for symmetry would reject every row the database returns, which is the defect
|
|
637
|
+
// this family was filed under to begin with. The `shape` carries the dimension count where
|
|
638
|
+
// one is declared, as the codec path already did for `vector`.
|
|
639
|
+
case "PgVector":
|
|
640
|
+
case "PgHalfVector":
|
|
641
|
+
case "SingleStoreVector":
|
|
642
|
+
return { tsType: "number[]", dbType: "VECTOR" };
|
|
643
|
+
// `BIT` rather than `TEXT`, which a first version of this arm returned. v1's codec says `BIT`
|
|
644
|
+
// for the same column, and the cross-major diff said so: naming the class made ten of its
|
|
645
|
+
// twelve entries go stale and left `c_bit.dbType` and its nullable twin standing, which is
|
|
646
|
+
// that check distinguishing a fix from a half fix.
|
|
647
|
+
case "PgBinaryVector":
|
|
648
|
+
return { tsType: "string", dbType: "BIT" };
|
|
649
|
+
case "PgGeometry":
|
|
650
|
+
return { tsType: "[number, number]", dbType: "GEOMETRY" };
|
|
651
|
+
case "PgGeometryObject":
|
|
652
|
+
return { tsType: "{ x: number; y: number }", dbType: "GEOMETRY" };
|
|
653
|
+
case "PgSparseVector":
|
|
654
|
+
return { tsType: "string", dbType: "TEXT" };
|
|
596
655
|
case "PgInteger":
|
|
597
656
|
case "PgSmallInt":
|
|
598
657
|
return { tsType: "number", dbType: "INTEGER" };
|
|
@@ -658,6 +717,15 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
658
717
|
return { tsType: "[number, number]", dbType: "POINT" };
|
|
659
718
|
case "PgLineTuple":
|
|
660
719
|
return { tsType: "[number, number, number]", dbType: "LINE" };
|
|
720
|
+
// The object modes, which the same regex answered `string` for and which are not tuples
|
|
721
|
+
// either. `point({ mode: 'xy' })` returns `{ x, y }` and `line({ mode: 'abc' })` returns
|
|
722
|
+
// `{ a, b, c }`, read back from PGlite through drizzle 0.45.2; the same column refuses
|
|
723
|
+
// `[1, 2]` and `'1,2'`, both of which `mapToDriverValue` renders `(undefined,undefined)`.
|
|
724
|
+
// v1 says the same thing about the same two columns through `dataType: 'object point'`.
|
|
725
|
+
case "PgPointObject":
|
|
726
|
+
return { tsType: "{ x: number; y: number }", dbType: "POINT" };
|
|
727
|
+
case "PgLineABC":
|
|
728
|
+
return { tsType: "{ a: number; b: number; c: number }", dbType: "LINE" };
|
|
661
729
|
case "PgJson":
|
|
662
730
|
case "PgJsonb":
|
|
663
731
|
return { tsType: "any", dbType: ctor === "PgJsonb" ? "JSONB" : "JSON" };
|
|
@@ -678,7 +746,6 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
678
746
|
if (/^Pg/.test(ctor)) {
|
|
679
747
|
if (/Text|Varchar|Char|Uuid/i.test(ctor)) return { tsType: "string", dbType: "TEXT" };
|
|
680
748
|
if (/Inet|Cidr|Macaddr8?|Uuid/i.test(ctor)) return { tsType: "string", dbType: "TEXT" };
|
|
681
|
-
if (/Point|Line/i.test(ctor)) return { tsType: "string", dbType: "TEXT" };
|
|
682
749
|
if (/TimestampString|DateString/i.test(ctor))
|
|
683
750
|
return { tsType: "string", dbType: "TIMESTAMP" };
|
|
684
751
|
if (/Timestamptz/i.test(ctor)) return { tsType: "Date", dbType: "TIMESTAMPTZ" };
|
|
@@ -800,7 +867,7 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
800
867
|
const sqlType = sqlKind.startsWith("MySql") && typeof col?.getSQLType === "function" ? String(col.getSQLType()).toLowerCase() : void 0;
|
|
801
868
|
const byteCap = sqlType ? MYSQL_TEXT_CAPS[sqlType] : void 0;
|
|
802
869
|
const ctorName = String(col?.constructor?.name ?? "");
|
|
803
|
-
const fallbackShape = dbType === "JSON" || dbType === "JSONB" || col?.config?.mode === "json" ? { kind: "json" } : BYTE_STRING_CLASSES.has(ctorName) ? { kind: "byteString", length: declaredLength(col) } :
|
|
870
|
+
const fallbackShape = dbType === "JSON" || dbType === "JSONB" || col?.config?.mode === "json" ? { kind: "json" } : BYTE_STRING_CLASSES.has(ctorName) ? { kind: "byteString", length: declaredLength(col) } : NUMBER_VECTOR_CLASSES.has(ctorName) ? { kind: "numberVector", length: declaredLength(col) } : BIT_STRING_CLASSES.has(ctorName) ? { kind: "bitstring", length: declaredLength(col), exact: true } : GEOMETRIC_CLASS_SHAPES[ctorName];
|
|
804
871
|
if (fallbackShape?.kind === "byteString") delete constraints.maxLength;
|
|
805
872
|
const shape = (v1?.shape ?? fallbackShape)?.kind;
|
|
806
873
|
const finalTs = v1?.tsType ?? tsType;
|
package/dist/index.d.cts
CHANGED
|
@@ -121,11 +121,33 @@ type ColumnShape =
|
|
|
121
121
|
| {
|
|
122
122
|
kind: 'json';
|
|
123
123
|
}
|
|
124
|
-
/** `point`, `line`, `geometry
|
|
124
|
+
/** `point`, `line`, `geometry` in their tuple modes: a fixed-length tuple of numbers. */
|
|
125
125
|
| {
|
|
126
126
|
kind: 'tuple';
|
|
127
127
|
length: number;
|
|
128
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* The same three columns in their object modes: an object of named number fields.
|
|
131
|
+
*
|
|
132
|
+
* `point({ mode: 'xy' })` hands back `{ x, y }`, `line({ mode: 'abc' })` hands back
|
|
133
|
+
* `{ a, b, c }`, and `geometry({ type: 'point', mode: 'xy' })` hands back `{ x, y }`. The names
|
|
134
|
+
* are carried rather than derived from a length, because the two arities have different keys and
|
|
135
|
+
* nothing else on the column states them.
|
|
136
|
+
*
|
|
137
|
+
* Not a tuple, on either major, and the difference is a value the database refuses. Asked of
|
|
138
|
+
* PGlite through drizzle 0.45.2 and again through 1.0.0-rc.4: `mapToDriverValue` reads `.x`/`.y`
|
|
139
|
+
* off whatever it is handed, so `[1, 2]` and `'1,2'` both become the literal
|
|
140
|
+
* `(undefined,undefined)` and Postgres answers `invalid input syntax for type point`, while
|
|
141
|
+
* `{ x: 1.5, y: -2.25 }` is stored as `(1.5,-2.25)` and read back unchanged.
|
|
142
|
+
*
|
|
143
|
+
* Every field is required and unlisted keys are ignored, both measured on the same server:
|
|
144
|
+
* `{ x: 1 }` renders `(1,undefined)` and is refused, and `{ x: 1, y: 2, z: 3 }` is accepted and
|
|
145
|
+
* stored as `(1,2)`.
|
|
146
|
+
*/
|
|
147
|
+
| {
|
|
148
|
+
kind: 'numberObject';
|
|
149
|
+
fields: string[];
|
|
150
|
+
}
|
|
129
151
|
/** `vector`, `halfvec`: a numeric vector, with a fixed length where one is declared. */
|
|
130
152
|
| {
|
|
131
153
|
kind: 'numberVector';
|
package/dist/index.d.ts
CHANGED
|
@@ -121,11 +121,33 @@ type ColumnShape =
|
|
|
121
121
|
| {
|
|
122
122
|
kind: 'json';
|
|
123
123
|
}
|
|
124
|
-
/** `point`, `line`, `geometry
|
|
124
|
+
/** `point`, `line`, `geometry` in their tuple modes: a fixed-length tuple of numbers. */
|
|
125
125
|
| {
|
|
126
126
|
kind: 'tuple';
|
|
127
127
|
length: number;
|
|
128
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* The same three columns in their object modes: an object of named number fields.
|
|
131
|
+
*
|
|
132
|
+
* `point({ mode: 'xy' })` hands back `{ x, y }`, `line({ mode: 'abc' })` hands back
|
|
133
|
+
* `{ a, b, c }`, and `geometry({ type: 'point', mode: 'xy' })` hands back `{ x, y }`. The names
|
|
134
|
+
* are carried rather than derived from a length, because the two arities have different keys and
|
|
135
|
+
* nothing else on the column states them.
|
|
136
|
+
*
|
|
137
|
+
* Not a tuple, on either major, and the difference is a value the database refuses. Asked of
|
|
138
|
+
* PGlite through drizzle 0.45.2 and again through 1.0.0-rc.4: `mapToDriverValue` reads `.x`/`.y`
|
|
139
|
+
* off whatever it is handed, so `[1, 2]` and `'1,2'` both become the literal
|
|
140
|
+
* `(undefined,undefined)` and Postgres answers `invalid input syntax for type point`, while
|
|
141
|
+
* `{ x: 1.5, y: -2.25 }` is stored as `(1.5,-2.25)` and read back unchanged.
|
|
142
|
+
*
|
|
143
|
+
* Every field is required and unlisted keys are ignored, both measured on the same server:
|
|
144
|
+
* `{ x: 1 }` renders `(1,undefined)` and is refused, and `{ x: 1, y: 2, z: 3 }` is accepted and
|
|
145
|
+
* stored as `(1,2)`.
|
|
146
|
+
*/
|
|
147
|
+
| {
|
|
148
|
+
kind: 'numberObject';
|
|
149
|
+
fields: string[];
|
|
150
|
+
}
|
|
129
151
|
/** `vector`, `halfvec`: a numeric vector, with a fixed length where one is declared. */
|
|
130
152
|
| {
|
|
131
153
|
kind: 'numberVector';
|
package/dist/index.js
CHANGED
|
@@ -22,13 +22,24 @@ var PG_FLOAT4_INPUT_MAX = "340282356779733661637539395458142568448";
|
|
|
22
22
|
var PG_FLOAT4_RANGE = [`-${PG_FLOAT4_INPUT_MAX}`, PG_FLOAT4_INPUT_MAX];
|
|
23
23
|
var MYSQL_FLOAT_RANGE = [`-${FLOAT32_MAX}`, FLOAT32_MAX];
|
|
24
24
|
var JS_SAFE_INTEGER_BOUNDS = ["-9007199254740991", "9007199254740991"];
|
|
25
|
-
var
|
|
25
|
+
var GEOMETRIC_CLASS_SHAPES = {
|
|
26
26
|
// `line()` is the trap here: its `drizzle:entityKind` is `PgLine` while its constructor is
|
|
27
27
|
// `PgLineTuple`, and this path matches on the constructor.
|
|
28
28
|
PgPointTuple: { kind: "tuple", length: 2 },
|
|
29
|
-
PgLineTuple: { kind: "tuple", length: 3 }
|
|
29
|
+
PgLineTuple: { kind: "tuple", length: 3 },
|
|
30
|
+
// The object modes. `line({ mode: 'abc' })` is a `PgLineABC` and not a `PgLineObject`, and any
|
|
31
|
+
// mode but `'tuple'` builds the object class: `point({ mode: 'abc' })` is a `PgPointObject` too.
|
|
32
|
+
PgPointObject: { kind: "numberObject", fields: ["x", "y"] },
|
|
33
|
+
PgLineABC: { kind: "numberObject", fields: ["a", "b", "c"] },
|
|
34
|
+
// `geometry()` and `geometry({ mode: 'xy' })` are two classes, not one class with a flag, and
|
|
35
|
+
// the fuzzer found both unnamed on this path. Their driver mappers disagree the same way the
|
|
36
|
+
// point ones do: the default hands back `[1, 2]` and the xy mode hands back `{ x: 1, y: 2 }`.
|
|
37
|
+
PgGeometry: { kind: "tuple", length: 2 },
|
|
38
|
+
PgGeometryObject: { kind: "numberObject", fields: ["x", "y"] }
|
|
30
39
|
};
|
|
31
40
|
var V1_ONLY_ENTITY_KINDS = /^(?:MsSql|Cockroach)/;
|
|
41
|
+
var NUMBER_VECTOR_CLASSES = /* @__PURE__ */ new Set(["PgVector", "PgHalfVector", "SingleStoreVector"]);
|
|
42
|
+
var BIT_STRING_CLASSES = /* @__PURE__ */ new Set(["PgBinaryVector"]);
|
|
32
43
|
var BYTE_STRING_CLASSES = /* @__PURE__ */ new Set([
|
|
33
44
|
"MySqlBinary",
|
|
34
45
|
"MySqlVarBinary",
|
|
@@ -149,18 +160,38 @@ function describeV1Column(column) {
|
|
|
149
160
|
};
|
|
150
161
|
break;
|
|
151
162
|
}
|
|
163
|
+
// Two modes per builder, and v1 states which in the JS half of the dataType it already
|
|
164
|
+
// carries: the tuple modes say `array point` / `array line` / `array geometry` and the object
|
|
165
|
+
// modes say `object point` / `object line` / `object geometry`. Read off real 1.0.0-rc.4
|
|
166
|
+
// columns rather than assumed. Both used to reach these arms and be called tuples, so a select
|
|
167
|
+
// schema for `point({ mode: 'xy' })` rejected every row the driver returned, on the major that
|
|
168
|
+
// describes the column outright.
|
|
169
|
+
//
|
|
170
|
+
// `js` rather than the codec, which also distinguishes them here (`point:tuple` against
|
|
171
|
+
// `point`): three dialects state a semantic with no codec at all on this release, so the codec
|
|
172
|
+
// is the weaker of the two signals and this file already prefers `js` elsewhere for the same
|
|
173
|
+
// reason.
|
|
152
174
|
case "point":
|
|
153
175
|
case "geometry":
|
|
154
|
-
out.tsType = "[number, number]";
|
|
176
|
+
out.tsType = js === "object" ? "{ x: number; y: number }" : "[number, number]";
|
|
155
177
|
out.dbType = semantic.toUpperCase();
|
|
156
|
-
out.shape = { kind: "tuple", length: 2 };
|
|
178
|
+
out.shape = js === "object" ? { kind: "numberObject", fields: ["x", "y"] } : { kind: "tuple", length: 2 };
|
|
157
179
|
break;
|
|
158
180
|
case "line":
|
|
159
|
-
out.tsType = "[number, number, number]";
|
|
181
|
+
out.tsType = js === "object" ? "{ a: number; b: number; c: number }" : "[number, number, number]";
|
|
160
182
|
out.dbType = "LINE";
|
|
161
|
-
out.shape = { kind: "tuple", length: 3 };
|
|
183
|
+
out.shape = js === "object" ? { kind: "numberObject", fields: ["a", "b", "c"] } : { kind: "tuple", length: 3 };
|
|
162
184
|
break;
|
|
185
|
+
// `halfvec` beside `vector`, because they differ in storage width and in nothing a validator
|
|
186
|
+
// can see: `mapFromDriverValue` on both hands back `[1, 2, 3]`. It had no arm and came back
|
|
187
|
+
// `unknown` on this path too, which the fuzzer found.
|
|
188
|
+
//
|
|
189
|
+
// `sparsevec` is deliberately not here. Its name says vector and its value is the string
|
|
190
|
+
// `{1:1.5,3:2}/3`, so typing it `number[]` for symmetry would reject every row the database
|
|
191
|
+
// returns. Its codec already answers `string` on its own, which is the same conclusion reached
|
|
192
|
+
// without this arm.
|
|
163
193
|
case "vector":
|
|
194
|
+
case "halfvec":
|
|
164
195
|
out.tsType = "number[]";
|
|
165
196
|
out.dbType = "VECTOR";
|
|
166
197
|
out.shape = { kind: "numberVector", length: declaredLength(column) };
|
|
@@ -552,6 +583,34 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
552
583
|
case "MySqlEnumColumn":
|
|
553
584
|
case "SingleStoreEnumColumn":
|
|
554
585
|
return { tsType: "string", dbType: "TEXT" };
|
|
586
|
+
// The pgvector family, found by the analyzer fuzzer: all three came back `unknown` on this
|
|
587
|
+
// path, so their validators accepted anything. The answers are drizzle's own mappers rather
|
|
588
|
+
// than the type names, and the three do not agree with each other:
|
|
589
|
+
//
|
|
590
|
+
// vector(3) SELECT gives [1,2,3] INSERT sends "[1,2,3]"
|
|
591
|
+
// halfvec(3) SELECT gives [1,2,3] INSERT sends "[1,2,3]"
|
|
592
|
+
// sparsevec(3) SELECT gives "{1:1.5,3:2}/3" INSERT sends "{1:1.5,3:2}/3"
|
|
593
|
+
//
|
|
594
|
+
// So the two dense ones are number arrays and the sparse one is a string. Typing `sparsevec`
|
|
595
|
+
// as a vector for symmetry would reject every row the database returns, which is the defect
|
|
596
|
+
// this family was filed under to begin with. The `shape` carries the dimension count where
|
|
597
|
+
// one is declared, as the codec path already did for `vector`.
|
|
598
|
+
case "PgVector":
|
|
599
|
+
case "PgHalfVector":
|
|
600
|
+
case "SingleStoreVector":
|
|
601
|
+
return { tsType: "number[]", dbType: "VECTOR" };
|
|
602
|
+
// `BIT` rather than `TEXT`, which a first version of this arm returned. v1's codec says `BIT`
|
|
603
|
+
// for the same column, and the cross-major diff said so: naming the class made ten of its
|
|
604
|
+
// twelve entries go stale and left `c_bit.dbType` and its nullable twin standing, which is
|
|
605
|
+
// that check distinguishing a fix from a half fix.
|
|
606
|
+
case "PgBinaryVector":
|
|
607
|
+
return { tsType: "string", dbType: "BIT" };
|
|
608
|
+
case "PgGeometry":
|
|
609
|
+
return { tsType: "[number, number]", dbType: "GEOMETRY" };
|
|
610
|
+
case "PgGeometryObject":
|
|
611
|
+
return { tsType: "{ x: number; y: number }", dbType: "GEOMETRY" };
|
|
612
|
+
case "PgSparseVector":
|
|
613
|
+
return { tsType: "string", dbType: "TEXT" };
|
|
555
614
|
case "PgInteger":
|
|
556
615
|
case "PgSmallInt":
|
|
557
616
|
return { tsType: "number", dbType: "INTEGER" };
|
|
@@ -617,6 +676,15 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
617
676
|
return { tsType: "[number, number]", dbType: "POINT" };
|
|
618
677
|
case "PgLineTuple":
|
|
619
678
|
return { tsType: "[number, number, number]", dbType: "LINE" };
|
|
679
|
+
// The object modes, which the same regex answered `string` for and which are not tuples
|
|
680
|
+
// either. `point({ mode: 'xy' })` returns `{ x, y }` and `line({ mode: 'abc' })` returns
|
|
681
|
+
// `{ a, b, c }`, read back from PGlite through drizzle 0.45.2; the same column refuses
|
|
682
|
+
// `[1, 2]` and `'1,2'`, both of which `mapToDriverValue` renders `(undefined,undefined)`.
|
|
683
|
+
// v1 says the same thing about the same two columns through `dataType: 'object point'`.
|
|
684
|
+
case "PgPointObject":
|
|
685
|
+
return { tsType: "{ x: number; y: number }", dbType: "POINT" };
|
|
686
|
+
case "PgLineABC":
|
|
687
|
+
return { tsType: "{ a: number; b: number; c: number }", dbType: "LINE" };
|
|
620
688
|
case "PgJson":
|
|
621
689
|
case "PgJsonb":
|
|
622
690
|
return { tsType: "any", dbType: ctor === "PgJsonb" ? "JSONB" : "JSON" };
|
|
@@ -637,7 +705,6 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
637
705
|
if (/^Pg/.test(ctor)) {
|
|
638
706
|
if (/Text|Varchar|Char|Uuid/i.test(ctor)) return { tsType: "string", dbType: "TEXT" };
|
|
639
707
|
if (/Inet|Cidr|Macaddr8?|Uuid/i.test(ctor)) return { tsType: "string", dbType: "TEXT" };
|
|
640
|
-
if (/Point|Line/i.test(ctor)) return { tsType: "string", dbType: "TEXT" };
|
|
641
708
|
if (/TimestampString|DateString/i.test(ctor))
|
|
642
709
|
return { tsType: "string", dbType: "TIMESTAMP" };
|
|
643
710
|
if (/Timestamptz/i.test(ctor)) return { tsType: "Date", dbType: "TIMESTAMPTZ" };
|
|
@@ -759,7 +826,7 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
759
826
|
const sqlType = sqlKind.startsWith("MySql") && typeof col?.getSQLType === "function" ? String(col.getSQLType()).toLowerCase() : void 0;
|
|
760
827
|
const byteCap = sqlType ? MYSQL_TEXT_CAPS[sqlType] : void 0;
|
|
761
828
|
const ctorName = String(col?.constructor?.name ?? "");
|
|
762
|
-
const fallbackShape = dbType === "JSON" || dbType === "JSONB" || col?.config?.mode === "json" ? { kind: "json" } : BYTE_STRING_CLASSES.has(ctorName) ? { kind: "byteString", length: declaredLength(col) } :
|
|
829
|
+
const fallbackShape = dbType === "JSON" || dbType === "JSONB" || col?.config?.mode === "json" ? { kind: "json" } : BYTE_STRING_CLASSES.has(ctorName) ? { kind: "byteString", length: declaredLength(col) } : NUMBER_VECTOR_CLASSES.has(ctorName) ? { kind: "numberVector", length: declaredLength(col) } : BIT_STRING_CLASSES.has(ctorName) ? { kind: "bitstring", length: declaredLength(col), exact: true } : GEOMETRIC_CLASS_SHAPES[ctorName];
|
|
763
830
|
if (fallbackShape?.kind === "byteString") delete constraints.maxLength;
|
|
764
831
|
const shape = (v1?.shape ?? fallbackShape)?.kind;
|
|
765
832
|
const finalTs = v1?.tsType ?? tsType;
|
package/package.json
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drzl/analyzer",
|
|
3
|
-
"version": "1.17.
|
|
3
|
+
"version": "1.17.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"main": "dist/index.
|
|
8
|
-
"
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
9
10
|
"exports": {
|
|
10
11
|
".": {
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
"import": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"require": {
|
|
17
|
+
"types": "./dist/index.d.cts",
|
|
18
|
+
"default": "./dist/index.cjs"
|
|
19
|
+
}
|
|
14
20
|
}
|
|
15
21
|
},
|
|
16
22
|
"files": [
|
|
@@ -22,6 +28,7 @@
|
|
|
22
28
|
},
|
|
23
29
|
"devDependencies": {
|
|
24
30
|
"drizzle-orm": "^0.45.2",
|
|
31
|
+
"drizzle-orm-v1": "npm:drizzle-orm@1.0.0-rc.4",
|
|
25
32
|
"tsup": "^8.5.1",
|
|
26
33
|
"typescript": "^5.9.3"
|
|
27
34
|
},
|
|
@@ -45,6 +52,8 @@
|
|
|
45
52
|
"scripts": {
|
|
46
53
|
"build": "tsup src/index.ts --dts --format esm,cjs --clean",
|
|
47
54
|
"lint": "eslint . --ext .ts",
|
|
48
|
-
"test": "vitest run --testTimeout=20000"
|
|
55
|
+
"test": "vitest run --testTimeout=20000",
|
|
56
|
+
"fuzz": "node test/fuzz/run.mjs",
|
|
57
|
+
"fuzz:gate": "node test/fuzz/run.mjs --gate"
|
|
49
58
|
}
|
|
50
59
|
}
|