@drzl/analyzer 1.17.5 → 1.17.6
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 +86 -13
- package/dist/index.d.cts +36 -13
- package/dist/index.d.ts +36 -13
- package/dist/index.js +86 -13
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -112,6 +112,14 @@ function describeV1Column(column) {
|
|
|
112
112
|
case "int53":
|
|
113
113
|
case "uint53":
|
|
114
114
|
case "int64": {
|
|
115
|
+
if (DECIMAL_BIGINT_MODE.test(entityKind)) {
|
|
116
|
+
out.tsType = "bigint";
|
|
117
|
+
out.dbType = "NUMERIC";
|
|
118
|
+
out.integer = true;
|
|
119
|
+
const range2 = decimalModeRange(column, entityKind, "bigint");
|
|
120
|
+
if (range2) [out.min, out.max] = range2;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
115
123
|
const range = {
|
|
116
124
|
int8: ["-128", "127"],
|
|
117
125
|
int16: ["-32768", "32767"],
|
|
@@ -254,10 +262,11 @@ function describeV1Column(column) {
|
|
|
254
262
|
out.tsType = "number";
|
|
255
263
|
out.dbType = "NUMERIC";
|
|
256
264
|
out.integer = false;
|
|
257
|
-
|
|
265
|
+
const range = decimalModeRange(column, entityKind, "number");
|
|
266
|
+
if (range) [out.min, out.max] = range;
|
|
258
267
|
if (codec === "numeric:number") {
|
|
259
268
|
out.allowsNaN = true;
|
|
260
|
-
out.allowsInfinity =
|
|
269
|
+
out.allowsInfinity = !declaredDecimalRange(column);
|
|
261
270
|
}
|
|
262
271
|
} else if (js === "string") {
|
|
263
272
|
out.tsType = "string";
|
|
@@ -286,6 +295,28 @@ function declaredLength(column) {
|
|
|
286
295
|
const n = column?.length ?? column?.config?.length ?? column?.config?.dimensions;
|
|
287
296
|
return typeof n === "number" && Number.isFinite(n) && n > 0 ? n : void 0;
|
|
288
297
|
}
|
|
298
|
+
function declaredDecimalRange(column) {
|
|
299
|
+
const cfg = column?.config ?? {};
|
|
300
|
+
const precision = column?.precision ?? cfg.precision;
|
|
301
|
+
const scale = column?.scale ?? cfg.scale ?? 0;
|
|
302
|
+
if (typeof precision !== "number" || !Number.isInteger(precision) || precision < 1)
|
|
303
|
+
return void 0;
|
|
304
|
+
if (typeof scale !== "number" || !Number.isInteger(scale) || scale < 0) return void 0;
|
|
305
|
+
const nines = "9".repeat(precision);
|
|
306
|
+
const max = scale === 0 ? nines : scale < precision ? `${nines.slice(0, precision - scale)}.${nines.slice(precision - scale)}` : `0.${"0".repeat(scale - precision)}${nines}`;
|
|
307
|
+
return [`-${max}`, max];
|
|
308
|
+
}
|
|
309
|
+
var DECIMAL_NUMBER_MODE = /(?:Numeric|Decimal)Number$/;
|
|
310
|
+
var DECIMAL_BIGINT_MODE = /(?:Numeric|Decimal)BigInt$/;
|
|
311
|
+
var MYSQL_IMPLICIT_DECIMAL_RANGE = ["-9999999999", "9999999999"];
|
|
312
|
+
function decimalModeRange(column, kind, mode) {
|
|
313
|
+
const declared = declaredDecimalRange(column);
|
|
314
|
+
if (declared) return declared;
|
|
315
|
+
if (kind.startsWith("MySql") || kind.startsWith("SingleStore"))
|
|
316
|
+
return MYSQL_IMPLICIT_DECIMAL_RANGE;
|
|
317
|
+
if (kind.startsWith("SQLite")) return void 0;
|
|
318
|
+
return mode === "number" ? JS_SAFE_INTEGER_BOUNDS : void 0;
|
|
319
|
+
}
|
|
289
320
|
var VIEW_CONFIG_FIELDS = {
|
|
290
321
|
"drizzle:Columns": "selectedFields",
|
|
291
322
|
"drizzle:Name": "name",
|
|
@@ -583,6 +614,19 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
583
614
|
out.allowsNaN = nonFinite.nan;
|
|
584
615
|
out.allowsInfinity = nonFinite.infinity;
|
|
585
616
|
}
|
|
617
|
+
if (DECIMAL_NUMBER_MODE.test(ctor)) {
|
|
618
|
+
const range2 = decimalModeRange(column, ctor, "number");
|
|
619
|
+
if (range2) [out.min, out.max] = range2;
|
|
620
|
+
out.integer = false;
|
|
621
|
+
if (ctor === "PgNumericNumber") {
|
|
622
|
+
out.allowsNaN = true;
|
|
623
|
+
out.allowsInfinity = !declaredDecimalRange(column);
|
|
624
|
+
}
|
|
625
|
+
} else if (DECIMAL_BIGINT_MODE.test(ctor)) {
|
|
626
|
+
const range2 = decimalModeRange(column, ctor, "bigint");
|
|
627
|
+
if (range2) [out.min, out.max] = range2;
|
|
628
|
+
out.integer = true;
|
|
629
|
+
}
|
|
586
630
|
if (/^(Pg)?UUID$/i.test(ctor) || /Uuid$/i.test(ctor)) out.format = "uuid";
|
|
587
631
|
return out;
|
|
588
632
|
}
|
|
@@ -850,7 +894,8 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
850
894
|
if (/^Gel/i.test(ctor)) {
|
|
851
895
|
if (/BigInt64/i.test(ctor)) return { tsType: "bigint", dbType: "BIGINT" };
|
|
852
896
|
if (/Int53|Integer|SmallInt/i.test(ctor)) return { tsType: "number", dbType: "INTEGER" };
|
|
853
|
-
if (/
|
|
897
|
+
if (/DoublePrecision/i.test(ctor)) return { tsType: "number", dbType: "DOUBLE" };
|
|
898
|
+
if (/Real/i.test(ctor)) return { tsType: "number", dbType: "REAL" };
|
|
854
899
|
if (/Decimal/i.test(ctor)) return { tsType: "string", dbType: "NUMERIC" };
|
|
855
900
|
if (/UUID/i.test(ctor)) return { tsType: "string", dbType: "UUID" };
|
|
856
901
|
if (/Json/i.test(ctor)) return { tsType: "any", dbType: "JSON" };
|
|
@@ -901,7 +946,9 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
901
946
|
const v1 = describeV1Column(col);
|
|
902
947
|
const constraints = this.columnConstraints(col);
|
|
903
948
|
if (v1?.shape) delete constraints.maxLength;
|
|
904
|
-
const sqlKind = String(
|
|
949
|
+
const sqlKind = String(
|
|
950
|
+
outerCol?.constructor?.[/* @__PURE__ */ Symbol.for("drizzle:entityKind")] ?? ""
|
|
951
|
+
);
|
|
905
952
|
const sqlType = sqlKind.startsWith("MySql") && typeof col?.getSQLType === "function" ? String(col.getSQLType()).toLowerCase() : void 0;
|
|
906
953
|
const byteCap = sqlType ? MYSQL_TEXT_CAPS[sqlType] : void 0;
|
|
907
954
|
const ctorName = String(col?.constructor?.name ?? "");
|
|
@@ -1268,11 +1315,29 @@ _SchemaAnalyzer.INEXACT_RANGES = {
|
|
|
1268
1315
|
SQLiteReal: null,
|
|
1269
1316
|
SingleStoreDouble: null,
|
|
1270
1317
|
SingleStoreReal: null,
|
|
1271
|
-
// `
|
|
1272
|
-
//
|
|
1273
|
-
//
|
|
1274
|
-
|
|
1318
|
+
// Gel, whose `real` is a `std::float32` and whose `doublePrecision` is a `std::float64`. Both
|
|
1319
|
+
// used to be answered by a `/Real|DoublePrecision/i` arm that said NUMERIC and stated nothing
|
|
1320
|
+
// else at all, so a `real` column accepted 1e300 and the server refused it.
|
|
1321
|
+
//
|
|
1322
|
+
// Measured on a live Gel 7.1 (`geldata/gel:7`, sys::get_version_as_str() -> 7.1+08db576)
|
|
1323
|
+
// through the `gel` client, casting each literal so the server parses it, and again through a
|
|
1324
|
+
// stored property on a real object type. The float32 edge is Postgres's exactly, to the double:
|
|
1325
|
+
//
|
|
1326
|
+
// 3.4028234663852886e38 accepted, returned unchanged
|
|
1327
|
+
// 3.4028235677973366e38 accepted, and stored as 3.4028234663852886e38
|
|
1328
|
+
// 3.402823567797337e38 refused, "is out of range for type std::float32"
|
|
1329
|
+
// 1e300 refused, the same way
|
|
1330
|
+
//
|
|
1331
|
+
// The same value accepted, the same next double up refused, and the same rounding down of the
|
|
1332
|
+
// midpoint, so it takes the constant already here rather than a second name for one number.
|
|
1333
|
+
// float64 took 1e300 and Number.MAX_VALUE faithfully, for the reason no 8 byte float has a
|
|
1334
|
+
// truthful finite bound.
|
|
1335
|
+
GelReal: PG_FLOAT4_RANGE,
|
|
1336
|
+
GelDoublePrecision: null
|
|
1275
1337
|
};
|
|
1338
|
+
// `numeric`/`decimal` in either of its two numeric modes is deliberately not in the table above.
|
|
1339
|
+
// Its bound is not a fixed magnitude per class but the precision each column declares for itself,
|
|
1340
|
+
// which no table keyed on a class name can hold; see `declaredDecimalRange`.
|
|
1276
1341
|
/**
|
|
1277
1342
|
* The Postgres number columns that hold a non-finite double, and which of the three each holds.
|
|
1278
1343
|
*
|
|
@@ -1283,17 +1348,25 @@ _SchemaAnalyzer.INEXACT_RANGES = {
|
|
|
1283
1348
|
* table also answers for a v1 column and the two answers are identical rather than merely
|
|
1284
1349
|
* compatible. non-finite-numbers.spec.ts asserts that agreement through the real analyzer.
|
|
1285
1350
|
*
|
|
1286
|
-
*
|
|
1287
|
-
* `
|
|
1288
|
-
*
|
|
1351
|
+
* No MySQL, SingleStore or SQLite class belongs here: MySQL refuses all three on a `float`/
|
|
1352
|
+
* `double` and stores `0.00` for a `decimal`, and SQLite returns both infinities while silently
|
|
1353
|
+
* turning `NaN` into NULL, which is a different answer that has to arrive whole.
|
|
1354
|
+
*
|
|
1355
|
+
* Gel does belong, and is the fourth and fifth entries. Measured on a live Gel 7.1 rather than
|
|
1356
|
+
* inferred from it being Postgres-backed: both `std::float32` and `std::float64` stored `nan`,
|
|
1357
|
+
* `inf` and `-inf` and handed all three back as `NaN`, `Infinity` and `-Infinity`, through a cast
|
|
1358
|
+
* and again through a stored property. Without them every row of such a column failed validation.
|
|
1289
1359
|
*
|
|
1290
1360
|
* `PgNumeric` is absent because its value is a string, and its pattern already accepts `NaN` and
|
|
1291
|
-
* `Infinity`. `PgNumericNumber`
|
|
1361
|
+
* `Infinity`. `PgNumericNumber` is absent because its answer is no longer flat: it takes `NaN` at
|
|
1362
|
+
* any width and an infinity only where no precision is declared, which is a per-column question
|
|
1363
|
+
* this table cannot ask. `columnConstraints` answers it beside the bound that decides it.
|
|
1292
1364
|
*/
|
|
1293
1365
|
_SchemaAnalyzer.PG_NON_FINITE = {
|
|
1294
1366
|
PgReal: { nan: true, infinity: true },
|
|
1295
1367
|
PgDoublePrecision: { nan: true, infinity: true },
|
|
1296
|
-
|
|
1368
|
+
GelReal: { nan: true, infinity: true },
|
|
1369
|
+
GelDoublePrecision: { nan: true, infinity: true }
|
|
1297
1370
|
};
|
|
1298
1371
|
var SchemaAnalyzer = _SchemaAnalyzer;
|
|
1299
1372
|
var index_default = SchemaAnalyzer;
|
package/dist/index.d.cts
CHANGED
|
@@ -48,8 +48,16 @@ interface Column {
|
|
|
48
48
|
*
|
|
49
49
|
* Strings rather than numbers because a 64 bit bound is not representable as a JS number:
|
|
50
50
|
* `9223372036854775807` rounds to `9223372036854775808` the moment it becomes one, so a
|
|
51
|
-
* numeric field here would silently emit a wrong bound.
|
|
52
|
-
*
|
|
51
|
+
* numeric field here would silently emit a wrong bound. A 20 digit `numeric(20,0)` bound is
|
|
52
|
+
* further past that again.
|
|
53
|
+
*
|
|
54
|
+
* Not an integer range, despite the name this field used to be described by. An inexact column
|
|
55
|
+
* carries one too: a `real` is bounded by the magnitude the database refuses past, and a
|
|
56
|
+
* `numeric(10,2)` by the width its own declaration states. `integer` says which kind it is, and
|
|
57
|
+
* saying it is what stops a bounded float schema refusing 1.5.
|
|
58
|
+
*
|
|
59
|
+
* Absent where nothing declares a bound: an 8 byte float holds every finite JS number, and a
|
|
60
|
+
* `numeric` with no precision holds arbitrary precision.
|
|
53
61
|
*/
|
|
54
62
|
min?: string;
|
|
55
63
|
max?: string;
|
|
@@ -76,14 +84,22 @@ interface Column {
|
|
|
76
84
|
* does too, but a `numeric(10,2)` refuses either infinity with `22003 numeric field overflow`
|
|
77
85
|
* while still taking `NaN`, and `integer`/`bigint` refuse all three.
|
|
78
86
|
*
|
|
79
|
-
* So `numeric` in `{ mode: 'number' }`
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
87
|
+
* So `numeric` in `{ mode: 'number' }` answers each of the two separately: `allowsNaN` at any
|
|
88
|
+
* width, and `allowsInfinity` only where the declaration carries no precision. That used to be a
|
|
89
|
+
* flat `false`, and the recorded reason was that nothing here read a column's precision or scale,
|
|
90
|
+
* so the two declarations were indistinguishable and the narrower answer was the safer one.
|
|
91
|
+
* `declaredDecimalRange` reads both numbers now, the two are distinguishable, and each says what
|
|
92
|
+
* its own server does.
|
|
83
93
|
*
|
|
84
|
-
* Postgres
|
|
85
|
-
*
|
|
86
|
-
*
|
|
94
|
+
* Postgres and Gel. MySQL refuses all three on a `float`/`double`, and on a `decimal` refuses
|
|
95
|
+
* them outright rather than storing `0.00`: measured on MySQL 8.4.11 in `STRICT_TRANS_TABLES`,
|
|
96
|
+
* all three answer `Incorrect decimal value`. SQLite returns both infinities and silently turns
|
|
97
|
+
* `NaN` into NULL, which is real and is filed on its own: a column needs both halves of that
|
|
98
|
+
* answer or none.
|
|
99
|
+
*
|
|
100
|
+
* Gel joined on a measurement of its own rather than on being Postgres-backed: a live Gel 7.1
|
|
101
|
+
* stored `nan`, `inf` and `-inf` in both `std::float32` and `std::float64` and handed all three
|
|
102
|
+
* back unchanged, through a cast and through a stored property.
|
|
87
103
|
*
|
|
88
104
|
* Absent on every other column, including the string mode of `numeric`, which already carries the
|
|
89
105
|
* same fact as a pattern; see `COLUMN_FORMATS.numeric` in `@drzl/validation-core`.
|
|
@@ -489,12 +505,19 @@ declare class SchemaAnalyzer {
|
|
|
489
505
|
* table also answers for a v1 column and the two answers are identical rather than merely
|
|
490
506
|
* compatible. non-finite-numbers.spec.ts asserts that agreement through the real analyzer.
|
|
491
507
|
*
|
|
492
|
-
*
|
|
493
|
-
* `
|
|
494
|
-
*
|
|
508
|
+
* No MySQL, SingleStore or SQLite class belongs here: MySQL refuses all three on a `float`/
|
|
509
|
+
* `double` and stores `0.00` for a `decimal`, and SQLite returns both infinities while silently
|
|
510
|
+
* turning `NaN` into NULL, which is a different answer that has to arrive whole.
|
|
511
|
+
*
|
|
512
|
+
* Gel does belong, and is the fourth and fifth entries. Measured on a live Gel 7.1 rather than
|
|
513
|
+
* inferred from it being Postgres-backed: both `std::float32` and `std::float64` stored `nan`,
|
|
514
|
+
* `inf` and `-inf` and handed all three back as `NaN`, `Infinity` and `-Infinity`, through a cast
|
|
515
|
+
* and again through a stored property. Without them every row of such a column failed validation.
|
|
495
516
|
*
|
|
496
517
|
* `PgNumeric` is absent because its value is a string, and its pattern already accepts `NaN` and
|
|
497
|
-
* `Infinity`. `PgNumericNumber`
|
|
518
|
+
* `Infinity`. `PgNumericNumber` is absent because its answer is no longer flat: it takes `NaN` at
|
|
519
|
+
* any width and an infinity only where no precision is declared, which is a per-column question
|
|
520
|
+
* this table cannot ask. `columnConstraints` answers it beside the bound that decides it.
|
|
498
521
|
*/
|
|
499
522
|
private static readonly PG_NON_FINITE;
|
|
500
523
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -48,8 +48,16 @@ interface Column {
|
|
|
48
48
|
*
|
|
49
49
|
* Strings rather than numbers because a 64 bit bound is not representable as a JS number:
|
|
50
50
|
* `9223372036854775807` rounds to `9223372036854775808` the moment it becomes one, so a
|
|
51
|
-
* numeric field here would silently emit a wrong bound.
|
|
52
|
-
*
|
|
51
|
+
* numeric field here would silently emit a wrong bound. A 20 digit `numeric(20,0)` bound is
|
|
52
|
+
* further past that again.
|
|
53
|
+
*
|
|
54
|
+
* Not an integer range, despite the name this field used to be described by. An inexact column
|
|
55
|
+
* carries one too: a `real` is bounded by the magnitude the database refuses past, and a
|
|
56
|
+
* `numeric(10,2)` by the width its own declaration states. `integer` says which kind it is, and
|
|
57
|
+
* saying it is what stops a bounded float schema refusing 1.5.
|
|
58
|
+
*
|
|
59
|
+
* Absent where nothing declares a bound: an 8 byte float holds every finite JS number, and a
|
|
60
|
+
* `numeric` with no precision holds arbitrary precision.
|
|
53
61
|
*/
|
|
54
62
|
min?: string;
|
|
55
63
|
max?: string;
|
|
@@ -76,14 +84,22 @@ interface Column {
|
|
|
76
84
|
* does too, but a `numeric(10,2)` refuses either infinity with `22003 numeric field overflow`
|
|
77
85
|
* while still taking `NaN`, and `integer`/`bigint` refuse all three.
|
|
78
86
|
*
|
|
79
|
-
* So `numeric` in `{ mode: 'number' }`
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
87
|
+
* So `numeric` in `{ mode: 'number' }` answers each of the two separately: `allowsNaN` at any
|
|
88
|
+
* width, and `allowsInfinity` only where the declaration carries no precision. That used to be a
|
|
89
|
+
* flat `false`, and the recorded reason was that nothing here read a column's precision or scale,
|
|
90
|
+
* so the two declarations were indistinguishable and the narrower answer was the safer one.
|
|
91
|
+
* `declaredDecimalRange` reads both numbers now, the two are distinguishable, and each says what
|
|
92
|
+
* its own server does.
|
|
83
93
|
*
|
|
84
|
-
* Postgres
|
|
85
|
-
*
|
|
86
|
-
*
|
|
94
|
+
* Postgres and Gel. MySQL refuses all three on a `float`/`double`, and on a `decimal` refuses
|
|
95
|
+
* them outright rather than storing `0.00`: measured on MySQL 8.4.11 in `STRICT_TRANS_TABLES`,
|
|
96
|
+
* all three answer `Incorrect decimal value`. SQLite returns both infinities and silently turns
|
|
97
|
+
* `NaN` into NULL, which is real and is filed on its own: a column needs both halves of that
|
|
98
|
+
* answer or none.
|
|
99
|
+
*
|
|
100
|
+
* Gel joined on a measurement of its own rather than on being Postgres-backed: a live Gel 7.1
|
|
101
|
+
* stored `nan`, `inf` and `-inf` in both `std::float32` and `std::float64` and handed all three
|
|
102
|
+
* back unchanged, through a cast and through a stored property.
|
|
87
103
|
*
|
|
88
104
|
* Absent on every other column, including the string mode of `numeric`, which already carries the
|
|
89
105
|
* same fact as a pattern; see `COLUMN_FORMATS.numeric` in `@drzl/validation-core`.
|
|
@@ -489,12 +505,19 @@ declare class SchemaAnalyzer {
|
|
|
489
505
|
* table also answers for a v1 column and the two answers are identical rather than merely
|
|
490
506
|
* compatible. non-finite-numbers.spec.ts asserts that agreement through the real analyzer.
|
|
491
507
|
*
|
|
492
|
-
*
|
|
493
|
-
* `
|
|
494
|
-
*
|
|
508
|
+
* No MySQL, SingleStore or SQLite class belongs here: MySQL refuses all three on a `float`/
|
|
509
|
+
* `double` and stores `0.00` for a `decimal`, and SQLite returns both infinities while silently
|
|
510
|
+
* turning `NaN` into NULL, which is a different answer that has to arrive whole.
|
|
511
|
+
*
|
|
512
|
+
* Gel does belong, and is the fourth and fifth entries. Measured on a live Gel 7.1 rather than
|
|
513
|
+
* inferred from it being Postgres-backed: both `std::float32` and `std::float64` stored `nan`,
|
|
514
|
+
* `inf` and `-inf` and handed all three back as `NaN`, `Infinity` and `-Infinity`, through a cast
|
|
515
|
+
* and again through a stored property. Without them every row of such a column failed validation.
|
|
495
516
|
*
|
|
496
517
|
* `PgNumeric` is absent because its value is a string, and its pattern already accepts `NaN` and
|
|
497
|
-
* `Infinity`. `PgNumericNumber`
|
|
518
|
+
* `Infinity`. `PgNumericNumber` is absent because its answer is no longer flat: it takes `NaN` at
|
|
519
|
+
* any width and an infinity only where no precision is declared, which is a per-column question
|
|
520
|
+
* this table cannot ask. `columnConstraints` answers it beside the bound that decides it.
|
|
498
521
|
*/
|
|
499
522
|
private static readonly PG_NON_FINITE;
|
|
500
523
|
/**
|
package/dist/index.js
CHANGED
|
@@ -71,6 +71,14 @@ function describeV1Column(column) {
|
|
|
71
71
|
case "int53":
|
|
72
72
|
case "uint53":
|
|
73
73
|
case "int64": {
|
|
74
|
+
if (DECIMAL_BIGINT_MODE.test(entityKind)) {
|
|
75
|
+
out.tsType = "bigint";
|
|
76
|
+
out.dbType = "NUMERIC";
|
|
77
|
+
out.integer = true;
|
|
78
|
+
const range2 = decimalModeRange(column, entityKind, "bigint");
|
|
79
|
+
if (range2) [out.min, out.max] = range2;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
74
82
|
const range = {
|
|
75
83
|
int8: ["-128", "127"],
|
|
76
84
|
int16: ["-32768", "32767"],
|
|
@@ -213,10 +221,11 @@ function describeV1Column(column) {
|
|
|
213
221
|
out.tsType = "number";
|
|
214
222
|
out.dbType = "NUMERIC";
|
|
215
223
|
out.integer = false;
|
|
216
|
-
|
|
224
|
+
const range = decimalModeRange(column, entityKind, "number");
|
|
225
|
+
if (range) [out.min, out.max] = range;
|
|
217
226
|
if (codec === "numeric:number") {
|
|
218
227
|
out.allowsNaN = true;
|
|
219
|
-
out.allowsInfinity =
|
|
228
|
+
out.allowsInfinity = !declaredDecimalRange(column);
|
|
220
229
|
}
|
|
221
230
|
} else if (js === "string") {
|
|
222
231
|
out.tsType = "string";
|
|
@@ -245,6 +254,28 @@ function declaredLength(column) {
|
|
|
245
254
|
const n = column?.length ?? column?.config?.length ?? column?.config?.dimensions;
|
|
246
255
|
return typeof n === "number" && Number.isFinite(n) && n > 0 ? n : void 0;
|
|
247
256
|
}
|
|
257
|
+
function declaredDecimalRange(column) {
|
|
258
|
+
const cfg = column?.config ?? {};
|
|
259
|
+
const precision = column?.precision ?? cfg.precision;
|
|
260
|
+
const scale = column?.scale ?? cfg.scale ?? 0;
|
|
261
|
+
if (typeof precision !== "number" || !Number.isInteger(precision) || precision < 1)
|
|
262
|
+
return void 0;
|
|
263
|
+
if (typeof scale !== "number" || !Number.isInteger(scale) || scale < 0) return void 0;
|
|
264
|
+
const nines = "9".repeat(precision);
|
|
265
|
+
const max = scale === 0 ? nines : scale < precision ? `${nines.slice(0, precision - scale)}.${nines.slice(precision - scale)}` : `0.${"0".repeat(scale - precision)}${nines}`;
|
|
266
|
+
return [`-${max}`, max];
|
|
267
|
+
}
|
|
268
|
+
var DECIMAL_NUMBER_MODE = /(?:Numeric|Decimal)Number$/;
|
|
269
|
+
var DECIMAL_BIGINT_MODE = /(?:Numeric|Decimal)BigInt$/;
|
|
270
|
+
var MYSQL_IMPLICIT_DECIMAL_RANGE = ["-9999999999", "9999999999"];
|
|
271
|
+
function decimalModeRange(column, kind, mode) {
|
|
272
|
+
const declared = declaredDecimalRange(column);
|
|
273
|
+
if (declared) return declared;
|
|
274
|
+
if (kind.startsWith("MySql") || kind.startsWith("SingleStore"))
|
|
275
|
+
return MYSQL_IMPLICIT_DECIMAL_RANGE;
|
|
276
|
+
if (kind.startsWith("SQLite")) return void 0;
|
|
277
|
+
return mode === "number" ? JS_SAFE_INTEGER_BOUNDS : void 0;
|
|
278
|
+
}
|
|
248
279
|
var VIEW_CONFIG_FIELDS = {
|
|
249
280
|
"drizzle:Columns": "selectedFields",
|
|
250
281
|
"drizzle:Name": "name",
|
|
@@ -542,6 +573,19 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
542
573
|
out.allowsNaN = nonFinite.nan;
|
|
543
574
|
out.allowsInfinity = nonFinite.infinity;
|
|
544
575
|
}
|
|
576
|
+
if (DECIMAL_NUMBER_MODE.test(ctor)) {
|
|
577
|
+
const range2 = decimalModeRange(column, ctor, "number");
|
|
578
|
+
if (range2) [out.min, out.max] = range2;
|
|
579
|
+
out.integer = false;
|
|
580
|
+
if (ctor === "PgNumericNumber") {
|
|
581
|
+
out.allowsNaN = true;
|
|
582
|
+
out.allowsInfinity = !declaredDecimalRange(column);
|
|
583
|
+
}
|
|
584
|
+
} else if (DECIMAL_BIGINT_MODE.test(ctor)) {
|
|
585
|
+
const range2 = decimalModeRange(column, ctor, "bigint");
|
|
586
|
+
if (range2) [out.min, out.max] = range2;
|
|
587
|
+
out.integer = true;
|
|
588
|
+
}
|
|
545
589
|
if (/^(Pg)?UUID$/i.test(ctor) || /Uuid$/i.test(ctor)) out.format = "uuid";
|
|
546
590
|
return out;
|
|
547
591
|
}
|
|
@@ -809,7 +853,8 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
809
853
|
if (/^Gel/i.test(ctor)) {
|
|
810
854
|
if (/BigInt64/i.test(ctor)) return { tsType: "bigint", dbType: "BIGINT" };
|
|
811
855
|
if (/Int53|Integer|SmallInt/i.test(ctor)) return { tsType: "number", dbType: "INTEGER" };
|
|
812
|
-
if (/
|
|
856
|
+
if (/DoublePrecision/i.test(ctor)) return { tsType: "number", dbType: "DOUBLE" };
|
|
857
|
+
if (/Real/i.test(ctor)) return { tsType: "number", dbType: "REAL" };
|
|
813
858
|
if (/Decimal/i.test(ctor)) return { tsType: "string", dbType: "NUMERIC" };
|
|
814
859
|
if (/UUID/i.test(ctor)) return { tsType: "string", dbType: "UUID" };
|
|
815
860
|
if (/Json/i.test(ctor)) return { tsType: "any", dbType: "JSON" };
|
|
@@ -860,7 +905,9 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
860
905
|
const v1 = describeV1Column(col);
|
|
861
906
|
const constraints = this.columnConstraints(col);
|
|
862
907
|
if (v1?.shape) delete constraints.maxLength;
|
|
863
|
-
const sqlKind = String(
|
|
908
|
+
const sqlKind = String(
|
|
909
|
+
outerCol?.constructor?.[/* @__PURE__ */ Symbol.for("drizzle:entityKind")] ?? ""
|
|
910
|
+
);
|
|
864
911
|
const sqlType = sqlKind.startsWith("MySql") && typeof col?.getSQLType === "function" ? String(col.getSQLType()).toLowerCase() : void 0;
|
|
865
912
|
const byteCap = sqlType ? MYSQL_TEXT_CAPS[sqlType] : void 0;
|
|
866
913
|
const ctorName = String(col?.constructor?.name ?? "");
|
|
@@ -1227,11 +1274,29 @@ _SchemaAnalyzer.INEXACT_RANGES = {
|
|
|
1227
1274
|
SQLiteReal: null,
|
|
1228
1275
|
SingleStoreDouble: null,
|
|
1229
1276
|
SingleStoreReal: null,
|
|
1230
|
-
// `
|
|
1231
|
-
//
|
|
1232
|
-
//
|
|
1233
|
-
|
|
1277
|
+
// Gel, whose `real` is a `std::float32` and whose `doublePrecision` is a `std::float64`. Both
|
|
1278
|
+
// used to be answered by a `/Real|DoublePrecision/i` arm that said NUMERIC and stated nothing
|
|
1279
|
+
// else at all, so a `real` column accepted 1e300 and the server refused it.
|
|
1280
|
+
//
|
|
1281
|
+
// Measured on a live Gel 7.1 (`geldata/gel:7`, sys::get_version_as_str() -> 7.1+08db576)
|
|
1282
|
+
// through the `gel` client, casting each literal so the server parses it, and again through a
|
|
1283
|
+
// stored property on a real object type. The float32 edge is Postgres's exactly, to the double:
|
|
1284
|
+
//
|
|
1285
|
+
// 3.4028234663852886e38 accepted, returned unchanged
|
|
1286
|
+
// 3.4028235677973366e38 accepted, and stored as 3.4028234663852886e38
|
|
1287
|
+
// 3.402823567797337e38 refused, "is out of range for type std::float32"
|
|
1288
|
+
// 1e300 refused, the same way
|
|
1289
|
+
//
|
|
1290
|
+
// The same value accepted, the same next double up refused, and the same rounding down of the
|
|
1291
|
+
// midpoint, so it takes the constant already here rather than a second name for one number.
|
|
1292
|
+
// float64 took 1e300 and Number.MAX_VALUE faithfully, for the reason no 8 byte float has a
|
|
1293
|
+
// truthful finite bound.
|
|
1294
|
+
GelReal: PG_FLOAT4_RANGE,
|
|
1295
|
+
GelDoublePrecision: null
|
|
1234
1296
|
};
|
|
1297
|
+
// `numeric`/`decimal` in either of its two numeric modes is deliberately not in the table above.
|
|
1298
|
+
// Its bound is not a fixed magnitude per class but the precision each column declares for itself,
|
|
1299
|
+
// which no table keyed on a class name can hold; see `declaredDecimalRange`.
|
|
1235
1300
|
/**
|
|
1236
1301
|
* The Postgres number columns that hold a non-finite double, and which of the three each holds.
|
|
1237
1302
|
*
|
|
@@ -1242,17 +1307,25 @@ _SchemaAnalyzer.INEXACT_RANGES = {
|
|
|
1242
1307
|
* table also answers for a v1 column and the two answers are identical rather than merely
|
|
1243
1308
|
* compatible. non-finite-numbers.spec.ts asserts that agreement through the real analyzer.
|
|
1244
1309
|
*
|
|
1245
|
-
*
|
|
1246
|
-
* `
|
|
1247
|
-
*
|
|
1310
|
+
* No MySQL, SingleStore or SQLite class belongs here: MySQL refuses all three on a `float`/
|
|
1311
|
+
* `double` and stores `0.00` for a `decimal`, and SQLite returns both infinities while silently
|
|
1312
|
+
* turning `NaN` into NULL, which is a different answer that has to arrive whole.
|
|
1313
|
+
*
|
|
1314
|
+
* Gel does belong, and is the fourth and fifth entries. Measured on a live Gel 7.1 rather than
|
|
1315
|
+
* inferred from it being Postgres-backed: both `std::float32` and `std::float64` stored `nan`,
|
|
1316
|
+
* `inf` and `-inf` and handed all three back as `NaN`, `Infinity` and `-Infinity`, through a cast
|
|
1317
|
+
* and again through a stored property. Without them every row of such a column failed validation.
|
|
1248
1318
|
*
|
|
1249
1319
|
* `PgNumeric` is absent because its value is a string, and its pattern already accepts `NaN` and
|
|
1250
|
-
* `Infinity`. `PgNumericNumber`
|
|
1320
|
+
* `Infinity`. `PgNumericNumber` is absent because its answer is no longer flat: it takes `NaN` at
|
|
1321
|
+
* any width and an infinity only where no precision is declared, which is a per-column question
|
|
1322
|
+
* this table cannot ask. `columnConstraints` answers it beside the bound that decides it.
|
|
1251
1323
|
*/
|
|
1252
1324
|
_SchemaAnalyzer.PG_NON_FINITE = {
|
|
1253
1325
|
PgReal: { nan: true, infinity: true },
|
|
1254
1326
|
PgDoublePrecision: { nan: true, infinity: true },
|
|
1255
|
-
|
|
1327
|
+
GelReal: { nan: true, infinity: true },
|
|
1328
|
+
GelDoublePrecision: { nan: true, infinity: true }
|
|
1256
1329
|
};
|
|
1257
1330
|
var SchemaAnalyzer = _SchemaAnalyzer;
|
|
1258
1331
|
var index_default = SchemaAnalyzer;
|