@drzl/analyzer 1.7.0 → 1.8.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 CHANGED
@@ -44,6 +44,16 @@ function renderSqlLiteral(v) {
44
44
  if (Array.isArray(v)) return `(${v.map(renderSqlLiteral).join(", ")})`;
45
45
  return `'${String(v).replace(/'/g, "''")}'`;
46
46
  }
47
+ var MYSQL_TEXT_CAPS = {
48
+ tinytext: 255,
49
+ text: 65535,
50
+ mediumtext: 16777215,
51
+ longtext: 4294967295,
52
+ tinyblob: 255,
53
+ blob: 65535,
54
+ mediumblob: 16777215,
55
+ longblob: 4294967295
56
+ };
47
57
  var V1_FLOAT_BOUNDS = {
48
58
  float: ["-8388608", "8388607"],
49
59
  // real / float4, 2^23
@@ -53,26 +63,49 @@ var V1_FLOAT_BOUNDS = {
53
63
  function describeV1Column(column) {
54
64
  const codec = column?.codec;
55
65
  const dataType = column?.dataType;
56
- if (typeof codec !== "string" || typeof dataType !== "string") return null;
66
+ if (typeof dataType !== "string") return null;
67
+ if (dataType === "custom") {
68
+ const sqlType = typeof column?.getSQLType === "function" ? column.getSQLType() : void 0;
69
+ return {
70
+ tsType: "unknown",
71
+ dbType: typeof sqlType === "string" && sqlType ? sqlType.toUpperCase() : "UNKNOWN",
72
+ shape: { kind: "custom", sqlType: typeof sqlType === "string" ? sqlType : void 0 }
73
+ };
74
+ }
57
75
  const [js, semantic = ""] = dataType.split(" ");
76
+ if (typeof codec !== "string" && !semantic) return null;
58
77
  const out = {};
59
78
  switch (semantic) {
79
+ case "int8":
60
80
  case "int16":
81
+ case "int24":
61
82
  case "int32":
62
83
  case "int53":
84
+ case "uint53":
63
85
  case "int64": {
64
86
  const range = {
87
+ int8: ["-128", "127"],
65
88
  int16: ["-32768", "32767"],
89
+ int24: ["-8388608", "8388607"],
66
90
  int32: ["-2147483648", "2147483647"],
67
91
  int53: ["-9007199254740991", "9007199254740991"],
92
+ // MySQL `serial` is `bigint unsigned auto_increment`, so it starts at 0 rather than
93
+ // spanning the signed range.
94
+ uint53: ["0", "9007199254740991"],
68
95
  int64: ["-9223372036854775808", "9223372036854775807"]
69
96
  }[semantic];
70
97
  [out.min, out.max] = range;
71
98
  out.integer = true;
72
99
  out.tsType = js === "bigint" ? "bigint" : "number";
73
- out.dbType = semantic === "int16" ? "SMALLINT" : semantic === "int32" ? "INTEGER" : "BIGINT";
100
+ out.dbType = semantic === "int8" ? "TINYINT" : semantic === "int16" ? "SMALLINT" : semantic === "int24" ? "MEDIUMINT" : semantic === "int32" ? "INTEGER" : "BIGINT";
74
101
  break;
75
102
  }
103
+ case "year":
104
+ out.tsType = "number";
105
+ out.dbType = "YEAR";
106
+ out.integer = true;
107
+ [out.min, out.max] = ["1901", "2155"];
108
+ break;
76
109
  case "float":
77
110
  case "double": {
78
111
  [out.min, out.max] = V1_FLOAT_BOUNDS[semantic];
@@ -102,7 +135,7 @@ function describeV1Column(column) {
102
135
  break;
103
136
  case "date":
104
137
  out.tsType = js === "string" ? "string" : "Date";
105
- out.dbType = codec.startsWith("timestamp") ? "TIMESTAMP" : "DATE";
138
+ out.dbType = codec?.startsWith("timestamp") ? "TIMESTAMP" : "DATE";
106
139
  break;
107
140
  case "timestamp":
108
141
  out.tsType = js === "string" ? "string" : "Date";
@@ -124,8 +157,14 @@ function describeV1Column(column) {
124
157
  break;
125
158
  case "binary":
126
159
  out.tsType = "string";
127
- out.dbType = "BIT";
128
- out.shape = { kind: "bitstring", length: declaredLength(column) };
160
+ out.dbType = codec === "bit" ? "BIT" : "BINARY";
161
+ out.shape = {
162
+ kind: "bitstring",
163
+ length: declaredLength(column),
164
+ // A Postgres `bit(3)` holds exactly three digits; a MySQL `binary(4)`/`varbinary(16)`
165
+ // holds at most that many, which is why `''` is valid there and not here.
166
+ exact: codec === "bit"
167
+ };
129
168
  break;
130
169
  case "point":
131
170
  case "geometry":
@@ -159,6 +198,9 @@ function describeV1Column(column) {
159
198
  } else if (js === "string") {
160
199
  out.tsType = "string";
161
200
  out.dbType = codec === "varchar" ? "VARCHAR" : codec === "char" ? "CHAR" : "TEXT";
201
+ const kind = String(column?.constructor?.[/* @__PURE__ */ Symbol.for("drizzle:entityKind")] ?? "");
202
+ const cap = codec && kind.startsWith("MySql") ? MYSQL_TEXT_CAPS[codec] : void 0;
203
+ if (cap) out.maxLength = cap;
162
204
  } else {
163
205
  return null;
164
206
  }
@@ -563,7 +605,8 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
563
605
  }
564
606
  const ev = col?.enumValues;
565
607
  const nullable = !col?.notNull && !col?.config?.notNull;
566
- const isGenerated = !!(col?.autoIncrement || col?.isGenerated);
608
+ const generatedIdentity = col?.generatedIdentity;
609
+ const isGenerated = !!(col?.generated || generatedIdentity?.type === "always" || col?.isGenerated);
567
610
  const hasDefault = col?.hasDefault === true || col?.default !== void 0 || col?.config?.default !== void 0 || col?.defaultFn !== void 0 || isGenerated;
568
611
  const references = void 0;
569
612
  const isUnique = !!(col?.isUnique || col?.config?.isUnique);
package/dist/index.d.cts CHANGED
@@ -104,10 +104,29 @@ type ColumnShape =
104
104
  kind: 'numberVector';
105
105
  length?: number;
106
106
  }
107
- /** `bit`: a string of `0`/`1`, with a fixed length where one is declared. */
107
+ /**
108
+ * A `customType` column, whose JavaScript type exists only at compile time.
109
+ *
110
+ * `getSQLType()` gives the declared SQL type, but that is the *database* side: `fromDriver` may
111
+ * map it to anything, so a `numeric(12,2)` custom column can perfectly well hand back a number
112
+ * where a plain numeric hands back a string. Guessing from the SQL type would reject the real
113
+ * value, so the type is taken from Drizzle's own inference or not at all.
114
+ */
115
+ | {
116
+ kind: 'custom';
117
+ sqlType?: string;
118
+ }
119
+ /**
120
+ * A string of `0`/`1`: Postgres `bit(n)`, MySQL `binary(n)`/`varbinary(n)`.
121
+ *
122
+ * `exact` separates the two. A Postgres `bit(3)` is always three digits, while a MySQL
123
+ * `varbinary(16)` is at most sixteen, so treating both as exact rejected the empty string on
124
+ * every MySQL binary column.
125
+ */
108
126
  | {
109
127
  kind: 'bitstring';
110
128
  length?: number;
129
+ exact?: boolean;
111
130
  };
112
131
  interface Key {
113
132
  name?: string;
package/dist/index.d.ts CHANGED
@@ -104,10 +104,29 @@ type ColumnShape =
104
104
  kind: 'numberVector';
105
105
  length?: number;
106
106
  }
107
- /** `bit`: a string of `0`/`1`, with a fixed length where one is declared. */
107
+ /**
108
+ * A `customType` column, whose JavaScript type exists only at compile time.
109
+ *
110
+ * `getSQLType()` gives the declared SQL type, but that is the *database* side: `fromDriver` may
111
+ * map it to anything, so a `numeric(12,2)` custom column can perfectly well hand back a number
112
+ * where a plain numeric hands back a string. Guessing from the SQL type would reject the real
113
+ * value, so the type is taken from Drizzle's own inference or not at all.
114
+ */
115
+ | {
116
+ kind: 'custom';
117
+ sqlType?: string;
118
+ }
119
+ /**
120
+ * A string of `0`/`1`: Postgres `bit(n)`, MySQL `binary(n)`/`varbinary(n)`.
121
+ *
122
+ * `exact` separates the two. A Postgres `bit(3)` is always three digits, while a MySQL
123
+ * `varbinary(16)` is at most sixteen, so treating both as exact rejected the empty string on
124
+ * every MySQL binary column.
125
+ */
108
126
  | {
109
127
  kind: 'bitstring';
110
128
  length?: number;
129
+ exact?: boolean;
111
130
  };
112
131
  interface Key {
113
132
  name?: string;
package/dist/index.js CHANGED
@@ -7,6 +7,16 @@ function renderSqlLiteral(v) {
7
7
  if (Array.isArray(v)) return `(${v.map(renderSqlLiteral).join(", ")})`;
8
8
  return `'${String(v).replace(/'/g, "''")}'`;
9
9
  }
10
+ var MYSQL_TEXT_CAPS = {
11
+ tinytext: 255,
12
+ text: 65535,
13
+ mediumtext: 16777215,
14
+ longtext: 4294967295,
15
+ tinyblob: 255,
16
+ blob: 65535,
17
+ mediumblob: 16777215,
18
+ longblob: 4294967295
19
+ };
10
20
  var V1_FLOAT_BOUNDS = {
11
21
  float: ["-8388608", "8388607"],
12
22
  // real / float4, 2^23
@@ -16,26 +26,49 @@ var V1_FLOAT_BOUNDS = {
16
26
  function describeV1Column(column) {
17
27
  const codec = column?.codec;
18
28
  const dataType = column?.dataType;
19
- if (typeof codec !== "string" || typeof dataType !== "string") return null;
29
+ if (typeof dataType !== "string") return null;
30
+ if (dataType === "custom") {
31
+ const sqlType = typeof column?.getSQLType === "function" ? column.getSQLType() : void 0;
32
+ return {
33
+ tsType: "unknown",
34
+ dbType: typeof sqlType === "string" && sqlType ? sqlType.toUpperCase() : "UNKNOWN",
35
+ shape: { kind: "custom", sqlType: typeof sqlType === "string" ? sqlType : void 0 }
36
+ };
37
+ }
20
38
  const [js, semantic = ""] = dataType.split(" ");
39
+ if (typeof codec !== "string" && !semantic) return null;
21
40
  const out = {};
22
41
  switch (semantic) {
42
+ case "int8":
23
43
  case "int16":
44
+ case "int24":
24
45
  case "int32":
25
46
  case "int53":
47
+ case "uint53":
26
48
  case "int64": {
27
49
  const range = {
50
+ int8: ["-128", "127"],
28
51
  int16: ["-32768", "32767"],
52
+ int24: ["-8388608", "8388607"],
29
53
  int32: ["-2147483648", "2147483647"],
30
54
  int53: ["-9007199254740991", "9007199254740991"],
55
+ // MySQL `serial` is `bigint unsigned auto_increment`, so it starts at 0 rather than
56
+ // spanning the signed range.
57
+ uint53: ["0", "9007199254740991"],
31
58
  int64: ["-9223372036854775808", "9223372036854775807"]
32
59
  }[semantic];
33
60
  [out.min, out.max] = range;
34
61
  out.integer = true;
35
62
  out.tsType = js === "bigint" ? "bigint" : "number";
36
- out.dbType = semantic === "int16" ? "SMALLINT" : semantic === "int32" ? "INTEGER" : "BIGINT";
63
+ out.dbType = semantic === "int8" ? "TINYINT" : semantic === "int16" ? "SMALLINT" : semantic === "int24" ? "MEDIUMINT" : semantic === "int32" ? "INTEGER" : "BIGINT";
37
64
  break;
38
65
  }
66
+ case "year":
67
+ out.tsType = "number";
68
+ out.dbType = "YEAR";
69
+ out.integer = true;
70
+ [out.min, out.max] = ["1901", "2155"];
71
+ break;
39
72
  case "float":
40
73
  case "double": {
41
74
  [out.min, out.max] = V1_FLOAT_BOUNDS[semantic];
@@ -65,7 +98,7 @@ function describeV1Column(column) {
65
98
  break;
66
99
  case "date":
67
100
  out.tsType = js === "string" ? "string" : "Date";
68
- out.dbType = codec.startsWith("timestamp") ? "TIMESTAMP" : "DATE";
101
+ out.dbType = codec?.startsWith("timestamp") ? "TIMESTAMP" : "DATE";
69
102
  break;
70
103
  case "timestamp":
71
104
  out.tsType = js === "string" ? "string" : "Date";
@@ -87,8 +120,14 @@ function describeV1Column(column) {
87
120
  break;
88
121
  case "binary":
89
122
  out.tsType = "string";
90
- out.dbType = "BIT";
91
- out.shape = { kind: "bitstring", length: declaredLength(column) };
123
+ out.dbType = codec === "bit" ? "BIT" : "BINARY";
124
+ out.shape = {
125
+ kind: "bitstring",
126
+ length: declaredLength(column),
127
+ // A Postgres `bit(3)` holds exactly three digits; a MySQL `binary(4)`/`varbinary(16)`
128
+ // holds at most that many, which is why `''` is valid there and not here.
129
+ exact: codec === "bit"
130
+ };
92
131
  break;
93
132
  case "point":
94
133
  case "geometry":
@@ -122,6 +161,9 @@ function describeV1Column(column) {
122
161
  } else if (js === "string") {
123
162
  out.tsType = "string";
124
163
  out.dbType = codec === "varchar" ? "VARCHAR" : codec === "char" ? "CHAR" : "TEXT";
164
+ const kind = String(column?.constructor?.[/* @__PURE__ */ Symbol.for("drizzle:entityKind")] ?? "");
165
+ const cap = codec && kind.startsWith("MySql") ? MYSQL_TEXT_CAPS[codec] : void 0;
166
+ if (cap) out.maxLength = cap;
125
167
  } else {
126
168
  return null;
127
169
  }
@@ -526,7 +568,8 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
526
568
  }
527
569
  const ev = col?.enumValues;
528
570
  const nullable = !col?.notNull && !col?.config?.notNull;
529
- const isGenerated = !!(col?.autoIncrement || col?.isGenerated);
571
+ const generatedIdentity = col?.generatedIdentity;
572
+ const isGenerated = !!(col?.generated || generatedIdentity?.type === "always" || col?.isGenerated);
530
573
  const hasDefault = col?.hasDefault === true || col?.default !== void 0 || col?.config?.default !== void 0 || col?.defaultFn !== void 0 || isGenerated;
531
574
  const references = void 0;
532
575
  const isUnique = !!(col?.isUnique || col?.config?.isUnique);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drzl/analyzer",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "private": false,
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",