tina4-nodejs 3.13.124 → 3.13.125
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/CLAUDE.md +2 -2
- package/package.json +1 -1
- package/packages/cli/dist/bin.js +42 -4
- package/packages/cli/src/commands/generate.ts +4 -4
- package/packages/core/dist/index.js +42 -4
- package/packages/orm/dist/index.js +42 -4
- package/packages/orm/src/adapters/firebird.ts +7 -0
- package/packages/orm/src/adapters/mssql.ts +6 -0
- package/packages/orm/src/adapters/mysql.ts +6 -0
- package/packages/orm/src/sqlTranslator.ts +45 -0
- package/types/orm/src/sqlTranslator.d.ts +19 -0
package/CLAUDE.md
CHANGED
|
@@ -13,13 +13,13 @@ Even if the skill text is not currently loaded, these are non-negotiable:
|
|
|
13
13
|
|
|
14
14
|
The full discipline lives in `.claude/skills/tina4-maintainer/SKILL.md`; this block is the always-on floor.
|
|
15
15
|
|
|
16
|
-
# CLAUDE.md - AI Developer Guide for tina4-nodejs (v3.13.
|
|
16
|
+
# CLAUDE.md - AI Developer Guide for tina4-nodejs (v3.13.125)
|
|
17
17
|
|
|
18
18
|
> This file helps AI assistants (Claude, Copilot, Cursor, etc.) understand and work on this codebase effectively.
|
|
19
19
|
|
|
20
20
|
## What This Project Is
|
|
21
21
|
|
|
22
|
-
Tina4 for Node.js/TypeScript v3.13.
|
|
22
|
+
Tina4 for Node.js/TypeScript v3.13.125 - The Intelligent Native Application 4ramework. A convention-over-configuration structural paradigm. The developer writes TypeScript; Tina4 is invisible infrastructure.
|
|
23
23
|
|
|
24
24
|
The philosophy: zero ceremony, batteries included, file system as source of truth.
|
|
25
25
|
|
package/package.json
CHANGED
package/packages/cli/dist/bin.js
CHANGED
|
@@ -6375,6 +6375,38 @@ var init_sqlTranslator = __esm({
|
|
|
6375
6375
|
return sql;
|
|
6376
6376
|
}
|
|
6377
6377
|
}
|
|
6378
|
+
/**
|
|
6379
|
+
* Translate SQLite-canonical DDL column TYPES + CREATE-TABLE options to the
|
|
6380
|
+
* target engine.
|
|
6381
|
+
*
|
|
6382
|
+
* ONLY acts on `CREATE TABLE` / `ALTER TABLE` statements, so a query or INSERT
|
|
6383
|
+
* that happens to contain the word `TEXT` (a column name, a string literal) is
|
|
6384
|
+
* never rewritten. Complements `autoIncrementSyntax` (which maps the id
|
|
6385
|
+
* keyword) so ONE portable migration — and every `Model.createTable()` DDL,
|
|
6386
|
+
* which is also SQLite-canonical — applies on every engine instead of failing
|
|
6387
|
+
* on Firebird/MSSQL.
|
|
6388
|
+
*
|
|
6389
|
+
* * Firebird has no `TEXT` (-607), no `REAL`, and no `CREATE TABLE IF NOT
|
|
6390
|
+
* EXISTS`.
|
|
6391
|
+
* * MSSQL has no `CREATE TABLE IF NOT EXISTS` and its `TIMESTAMP` is a
|
|
6392
|
+
* rowversion, not a datetime — a `created_at TIMESTAMP` there is wrong.
|
|
6393
|
+
* * MySQL's `TIMESTAMP` carries auto-update / 2038 surprises, so a datetime
|
|
6394
|
+
* column maps to `DATETIME` (matching the adapters' createTableAsync).
|
|
6395
|
+
*/
|
|
6396
|
+
static ddlTypes(sql, engine) {
|
|
6397
|
+
const head = sql.replace(/^(?:\s*--[^\n]*\n)+/, "");
|
|
6398
|
+
if (!/^\s*(?:CREATE\s+TABLE|ALTER\s+TABLE)\b/i.test(head)) return sql;
|
|
6399
|
+
switch ((engine ?? "").toLowerCase()) {
|
|
6400
|
+
case "firebird":
|
|
6401
|
+
return sql.replace(/\bIF\s+NOT\s+EXISTS\b/gi, "").replace(/\bBLOB\s+SUB_TYPE\s+TEXT\b/gi, "\0FBTEXT\0").replace(/\bTEXT\b/gi, "BLOB SUB_TYPE TEXT").replaceAll("\0FBTEXT\0", "BLOB SUB_TYPE TEXT").replace(/\bREAL\b/gi, "DOUBLE PRECISION");
|
|
6402
|
+
case "mssql":
|
|
6403
|
+
return sql.replace(/\bIF\s+NOT\s+EXISTS\b/gi, "").replace(/\bTIMESTAMP\b/gi, "DATETIME2");
|
|
6404
|
+
case "mysql":
|
|
6405
|
+
return sql.replace(/\bTIMESTAMP\b/gi, "DATETIME");
|
|
6406
|
+
default:
|
|
6407
|
+
return sql;
|
|
6408
|
+
}
|
|
6409
|
+
}
|
|
6378
6410
|
/**
|
|
6379
6411
|
* Convert ? placeholders to engine-specific style.
|
|
6380
6412
|
*
|
|
@@ -8416,6 +8448,8 @@ var init_mysql = __esm({
|
|
|
8416
8448
|
translateSql(sql) {
|
|
8417
8449
|
let translated = SQLTranslator.concatPipesToFunc(sql);
|
|
8418
8450
|
translated = SQLTranslator.ilikeToLike(translated);
|
|
8451
|
+
translated = SQLTranslator.autoIncrementSyntax(translated, "mysql");
|
|
8452
|
+
translated = SQLTranslator.ddlTypes(translated, "mysql");
|
|
8419
8453
|
return translated;
|
|
8420
8454
|
}
|
|
8421
8455
|
execute(sql, params) {
|
|
@@ -8837,6 +8871,8 @@ var init_mssql = __esm({
|
|
|
8837
8871
|
let translated = SQLTranslator.limitToTop(sql);
|
|
8838
8872
|
translated = SQLTranslator.concatPipesToFunc(translated);
|
|
8839
8873
|
translated = SQLTranslator.ilikeToLike(translated);
|
|
8874
|
+
translated = SQLTranslator.autoIncrementSyntax(translated, "mssql");
|
|
8875
|
+
translated = SQLTranslator.ddlTypes(translated, "mssql");
|
|
8840
8876
|
return translated;
|
|
8841
8877
|
}
|
|
8842
8878
|
execSqlPromise(sql, params) {
|
|
@@ -9467,6 +9503,8 @@ var init_firebird = __esm({
|
|
|
9467
9503
|
let translated = SQLTranslator.limitToRows(sql);
|
|
9468
9504
|
translated = SQLTranslator.booleanToInt(translated);
|
|
9469
9505
|
translated = SQLTranslator.ilikeToLike(translated);
|
|
9506
|
+
translated = SQLTranslator.autoIncrementSyntax(translated, "firebird");
|
|
9507
|
+
translated = SQLTranslator.ddlTypes(translated, "firebird");
|
|
9470
9508
|
return translated;
|
|
9471
9509
|
}
|
|
9472
9510
|
/**
|
|
@@ -25048,7 +25086,7 @@ function generateMigration(name, flags, fieldsOverride, tableOverride, emitTest
|
|
|
25048
25086
|
const defaultClause = info.defaultVal !== "NULL" ? ` DEFAULT ${info.defaultVal}` : "";
|
|
25049
25087
|
colLines.push(` ${fname} ${info.sql}${defaultClause}`);
|
|
25050
25088
|
}
|
|
25051
|
-
colLines.push(" created_at
|
|
25089
|
+
colLines.push(" created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP");
|
|
25052
25090
|
upSql = `CREATE TABLE IF NOT EXISTS ${table2} (
|
|
25053
25091
|
-- tina4:edit add columns beyond id + created_at
|
|
25054
25092
|
${colLines.join(",\n")}
|
|
@@ -26191,8 +26229,8 @@ var init_generate = __esm({
|
|
|
26191
26229
|
"src/commands/generate.ts"() {
|
|
26192
26230
|
"use strict";
|
|
26193
26231
|
FIELD_TYPE_MAP = {
|
|
26194
|
-
string: { orm: '"string"', sql: "
|
|
26195
|
-
str: { orm: '"string"', sql: "
|
|
26232
|
+
string: { orm: '"string"', sql: "VARCHAR(255)", defaultVal: "''" },
|
|
26233
|
+
str: { orm: '"string"', sql: "VARCHAR(255)", defaultVal: "''" },
|
|
26196
26234
|
int: { orm: '"integer"', sql: "INTEGER", defaultVal: "0" },
|
|
26197
26235
|
integer: { orm: '"integer"', sql: "INTEGER", defaultVal: "0" },
|
|
26198
26236
|
float: { orm: '"number"', sql: "REAL", defaultVal: "0" },
|
|
@@ -26202,7 +26240,7 @@ var init_generate = __esm({
|
|
|
26202
26240
|
bool: { orm: '"boolean"', sql: "INTEGER", defaultVal: "0" },
|
|
26203
26241
|
boolean: { orm: '"boolean"', sql: "INTEGER", defaultVal: "0" },
|
|
26204
26242
|
text: { orm: '"string"', sql: "TEXT", defaultVal: "''" },
|
|
26205
|
-
datetime: { orm: '"datetime"', sql: "
|
|
26243
|
+
datetime: { orm: '"datetime"', sql: "TIMESTAMP", defaultVal: "NULL" },
|
|
26206
26244
|
blob: { orm: '"string"', sql: "BLOB", defaultVal: "NULL" }
|
|
26207
26245
|
};
|
|
26208
26246
|
SQL_RESERVED_TABLE_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -37,8 +37,8 @@ import { join, relative, resolve, sep } from "node:path";
|
|
|
37
37
|
|
|
38
38
|
// ── Field type mapping ──────────────────────────────────────────────
|
|
39
39
|
const FIELD_TYPE_MAP: Record<string, { orm: string; sql: string; defaultVal: string }> = {
|
|
40
|
-
string: { orm: '"string"', sql: "
|
|
41
|
-
str: { orm: '"string"', sql: "
|
|
40
|
+
string: { orm: '"string"', sql: "VARCHAR(255)", defaultVal: "''" },
|
|
41
|
+
str: { orm: '"string"', sql: "VARCHAR(255)", defaultVal: "''" },
|
|
42
42
|
int: { orm: '"integer"', sql: "INTEGER", defaultVal: "0" },
|
|
43
43
|
integer: { orm: '"integer"', sql: "INTEGER", defaultVal: "0" },
|
|
44
44
|
float: { orm: '"number"', sql: "REAL", defaultVal: "0" },
|
|
@@ -48,7 +48,7 @@ const FIELD_TYPE_MAP: Record<string, { orm: string; sql: string; defaultVal: str
|
|
|
48
48
|
bool: { orm: '"boolean"', sql: "INTEGER", defaultVal: "0" },
|
|
49
49
|
boolean: { orm: '"boolean"', sql: "INTEGER", defaultVal: "0" },
|
|
50
50
|
text: { orm: '"string"', sql: "TEXT", defaultVal: "''" },
|
|
51
|
-
datetime: { orm: '"datetime"', sql: "
|
|
51
|
+
datetime: { orm: '"datetime"', sql: "TIMESTAMP", defaultVal: "NULL" },
|
|
52
52
|
blob: { orm: '"string"', sql: "BLOB", defaultVal: "NULL" },
|
|
53
53
|
};
|
|
54
54
|
|
|
@@ -1269,7 +1269,7 @@ export function generateMigration(
|
|
|
1269
1269
|
const defaultClause = info.defaultVal !== "NULL" ? ` DEFAULT ${info.defaultVal}` : "";
|
|
1270
1270
|
colLines.push(` ${fname} ${info.sql}${defaultClause}`);
|
|
1271
1271
|
}
|
|
1272
|
-
colLines.push(" created_at
|
|
1272
|
+
colLines.push(" created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP");
|
|
1273
1273
|
|
|
1274
1274
|
upSql =
|
|
1275
1275
|
`CREATE TABLE IF NOT EXISTS ${table} (\n` +
|
|
@@ -6374,6 +6374,38 @@ var init_sqlTranslator = __esm({
|
|
|
6374
6374
|
return sql;
|
|
6375
6375
|
}
|
|
6376
6376
|
}
|
|
6377
|
+
/**
|
|
6378
|
+
* Translate SQLite-canonical DDL column TYPES + CREATE-TABLE options to the
|
|
6379
|
+
* target engine.
|
|
6380
|
+
*
|
|
6381
|
+
* ONLY acts on `CREATE TABLE` / `ALTER TABLE` statements, so a query or INSERT
|
|
6382
|
+
* that happens to contain the word `TEXT` (a column name, a string literal) is
|
|
6383
|
+
* never rewritten. Complements `autoIncrementSyntax` (which maps the id
|
|
6384
|
+
* keyword) so ONE portable migration — and every `Model.createTable()` DDL,
|
|
6385
|
+
* which is also SQLite-canonical — applies on every engine instead of failing
|
|
6386
|
+
* on Firebird/MSSQL.
|
|
6387
|
+
*
|
|
6388
|
+
* * Firebird has no `TEXT` (-607), no `REAL`, and no `CREATE TABLE IF NOT
|
|
6389
|
+
* EXISTS`.
|
|
6390
|
+
* * MSSQL has no `CREATE TABLE IF NOT EXISTS` and its `TIMESTAMP` is a
|
|
6391
|
+
* rowversion, not a datetime — a `created_at TIMESTAMP` there is wrong.
|
|
6392
|
+
* * MySQL's `TIMESTAMP` carries auto-update / 2038 surprises, so a datetime
|
|
6393
|
+
* column maps to `DATETIME` (matching the adapters' createTableAsync).
|
|
6394
|
+
*/
|
|
6395
|
+
static ddlTypes(sql, engine) {
|
|
6396
|
+
const head = sql.replace(/^(?:\s*--[^\n]*\n)+/, "");
|
|
6397
|
+
if (!/^\s*(?:CREATE\s+TABLE|ALTER\s+TABLE)\b/i.test(head)) return sql;
|
|
6398
|
+
switch ((engine ?? "").toLowerCase()) {
|
|
6399
|
+
case "firebird":
|
|
6400
|
+
return sql.replace(/\bIF\s+NOT\s+EXISTS\b/gi, "").replace(/\bBLOB\s+SUB_TYPE\s+TEXT\b/gi, "\0FBTEXT\0").replace(/\bTEXT\b/gi, "BLOB SUB_TYPE TEXT").replaceAll("\0FBTEXT\0", "BLOB SUB_TYPE TEXT").replace(/\bREAL\b/gi, "DOUBLE PRECISION");
|
|
6401
|
+
case "mssql":
|
|
6402
|
+
return sql.replace(/\bIF\s+NOT\s+EXISTS\b/gi, "").replace(/\bTIMESTAMP\b/gi, "DATETIME2");
|
|
6403
|
+
case "mysql":
|
|
6404
|
+
return sql.replace(/\bTIMESTAMP\b/gi, "DATETIME");
|
|
6405
|
+
default:
|
|
6406
|
+
return sql;
|
|
6407
|
+
}
|
|
6408
|
+
}
|
|
6377
6409
|
/**
|
|
6378
6410
|
* Convert ? placeholders to engine-specific style.
|
|
6379
6411
|
*
|
|
@@ -8415,6 +8447,8 @@ var init_mysql = __esm({
|
|
|
8415
8447
|
translateSql(sql) {
|
|
8416
8448
|
let translated = SQLTranslator.concatPipesToFunc(sql);
|
|
8417
8449
|
translated = SQLTranslator.ilikeToLike(translated);
|
|
8450
|
+
translated = SQLTranslator.autoIncrementSyntax(translated, "mysql");
|
|
8451
|
+
translated = SQLTranslator.ddlTypes(translated, "mysql");
|
|
8418
8452
|
return translated;
|
|
8419
8453
|
}
|
|
8420
8454
|
execute(sql, params) {
|
|
@@ -8836,6 +8870,8 @@ var init_mssql = __esm({
|
|
|
8836
8870
|
let translated = SQLTranslator.limitToTop(sql);
|
|
8837
8871
|
translated = SQLTranslator.concatPipesToFunc(translated);
|
|
8838
8872
|
translated = SQLTranslator.ilikeToLike(translated);
|
|
8873
|
+
translated = SQLTranslator.autoIncrementSyntax(translated, "mssql");
|
|
8874
|
+
translated = SQLTranslator.ddlTypes(translated, "mssql");
|
|
8839
8875
|
return translated;
|
|
8840
8876
|
}
|
|
8841
8877
|
execSqlPromise(sql, params) {
|
|
@@ -9466,6 +9502,8 @@ var init_firebird = __esm({
|
|
|
9466
9502
|
let translated = SQLTranslator.limitToRows(sql);
|
|
9467
9503
|
translated = SQLTranslator.booleanToInt(translated);
|
|
9468
9504
|
translated = SQLTranslator.ilikeToLike(translated);
|
|
9505
|
+
translated = SQLTranslator.autoIncrementSyntax(translated, "firebird");
|
|
9506
|
+
translated = SQLTranslator.ddlTypes(translated, "firebird");
|
|
9469
9507
|
return translated;
|
|
9470
9508
|
}
|
|
9471
9509
|
/**
|
|
@@ -25027,7 +25065,7 @@ function generateMigration(name, flags, fieldsOverride, tableOverride, emitTest
|
|
|
25027
25065
|
const defaultClause = info.defaultVal !== "NULL" ? ` DEFAULT ${info.defaultVal}` : "";
|
|
25028
25066
|
colLines.push(` ${fname} ${info.sql}${defaultClause}`);
|
|
25029
25067
|
}
|
|
25030
|
-
colLines.push(" created_at
|
|
25068
|
+
colLines.push(" created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP");
|
|
25031
25069
|
upSql = `CREATE TABLE IF NOT EXISTS ${table2} (
|
|
25032
25070
|
-- tina4:edit add columns beyond id + created_at
|
|
25033
25071
|
${colLines.join(",\n")}
|
|
@@ -26170,8 +26208,8 @@ var init_generate = __esm({
|
|
|
26170
26208
|
"../cli/src/commands/generate.ts"() {
|
|
26171
26209
|
"use strict";
|
|
26172
26210
|
FIELD_TYPE_MAP = {
|
|
26173
|
-
string: { orm: '"string"', sql: "
|
|
26174
|
-
str: { orm: '"string"', sql: "
|
|
26211
|
+
string: { orm: '"string"', sql: "VARCHAR(255)", defaultVal: "''" },
|
|
26212
|
+
str: { orm: '"string"', sql: "VARCHAR(255)", defaultVal: "''" },
|
|
26175
26213
|
int: { orm: '"integer"', sql: "INTEGER", defaultVal: "0" },
|
|
26176
26214
|
integer: { orm: '"integer"', sql: "INTEGER", defaultVal: "0" },
|
|
26177
26215
|
float: { orm: '"number"', sql: "REAL", defaultVal: "0" },
|
|
@@ -26181,7 +26219,7 @@ var init_generate = __esm({
|
|
|
26181
26219
|
bool: { orm: '"boolean"', sql: "INTEGER", defaultVal: "0" },
|
|
26182
26220
|
boolean: { orm: '"boolean"', sql: "INTEGER", defaultVal: "0" },
|
|
26183
26221
|
text: { orm: '"string"', sql: "TEXT", defaultVal: "''" },
|
|
26184
|
-
datetime: { orm: '"datetime"', sql: "
|
|
26222
|
+
datetime: { orm: '"datetime"', sql: "TIMESTAMP", defaultVal: "NULL" },
|
|
26185
26223
|
blob: { orm: '"string"', sql: "BLOB", defaultVal: "NULL" }
|
|
26186
26224
|
};
|
|
26187
26225
|
SQL_RESERVED_TABLE_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -915,6 +915,38 @@ var init_sqlTranslator = __esm({
|
|
|
915
915
|
return sql;
|
|
916
916
|
}
|
|
917
917
|
}
|
|
918
|
+
/**
|
|
919
|
+
* Translate SQLite-canonical DDL column TYPES + CREATE-TABLE options to the
|
|
920
|
+
* target engine.
|
|
921
|
+
*
|
|
922
|
+
* ONLY acts on `CREATE TABLE` / `ALTER TABLE` statements, so a query or INSERT
|
|
923
|
+
* that happens to contain the word `TEXT` (a column name, a string literal) is
|
|
924
|
+
* never rewritten. Complements `autoIncrementSyntax` (which maps the id
|
|
925
|
+
* keyword) so ONE portable migration — and every `Model.createTable()` DDL,
|
|
926
|
+
* which is also SQLite-canonical — applies on every engine instead of failing
|
|
927
|
+
* on Firebird/MSSQL.
|
|
928
|
+
*
|
|
929
|
+
* * Firebird has no `TEXT` (-607), no `REAL`, and no `CREATE TABLE IF NOT
|
|
930
|
+
* EXISTS`.
|
|
931
|
+
* * MSSQL has no `CREATE TABLE IF NOT EXISTS` and its `TIMESTAMP` is a
|
|
932
|
+
* rowversion, not a datetime — a `created_at TIMESTAMP` there is wrong.
|
|
933
|
+
* * MySQL's `TIMESTAMP` carries auto-update / 2038 surprises, so a datetime
|
|
934
|
+
* column maps to `DATETIME` (matching the adapters' createTableAsync).
|
|
935
|
+
*/
|
|
936
|
+
static ddlTypes(sql, engine) {
|
|
937
|
+
const head = sql.replace(/^(?:\s*--[^\n]*\n)+/, "");
|
|
938
|
+
if (!/^\s*(?:CREATE\s+TABLE|ALTER\s+TABLE)\b/i.test(head)) return sql;
|
|
939
|
+
switch ((engine ?? "").toLowerCase()) {
|
|
940
|
+
case "firebird":
|
|
941
|
+
return sql.replace(/\bIF\s+NOT\s+EXISTS\b/gi, "").replace(/\bBLOB\s+SUB_TYPE\s+TEXT\b/gi, "\0FBTEXT\0").replace(/\bTEXT\b/gi, "BLOB SUB_TYPE TEXT").replaceAll("\0FBTEXT\0", "BLOB SUB_TYPE TEXT").replace(/\bREAL\b/gi, "DOUBLE PRECISION");
|
|
942
|
+
case "mssql":
|
|
943
|
+
return sql.replace(/\bIF\s+NOT\s+EXISTS\b/gi, "").replace(/\bTIMESTAMP\b/gi, "DATETIME2");
|
|
944
|
+
case "mysql":
|
|
945
|
+
return sql.replace(/\bTIMESTAMP\b/gi, "DATETIME");
|
|
946
|
+
default:
|
|
947
|
+
return sql;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
918
950
|
/**
|
|
919
951
|
* Convert ? placeholders to engine-specific style.
|
|
920
952
|
*
|
|
@@ -13386,7 +13418,7 @@ function generateMigration(name, flags, fieldsOverride, tableOverride, emitTest
|
|
|
13386
13418
|
const defaultClause = info.defaultVal !== "NULL" ? ` DEFAULT ${info.defaultVal}` : "";
|
|
13387
13419
|
colLines.push(` ${fname} ${info.sql}${defaultClause}`);
|
|
13388
13420
|
}
|
|
13389
|
-
colLines.push(" created_at
|
|
13421
|
+
colLines.push(" created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP");
|
|
13390
13422
|
upSql = `CREATE TABLE IF NOT EXISTS ${table2} (
|
|
13391
13423
|
-- tina4:edit add columns beyond id + created_at
|
|
13392
13424
|
${colLines.join(",\n")}
|
|
@@ -14529,8 +14561,8 @@ var init_generate = __esm({
|
|
|
14529
14561
|
"../cli/src/commands/generate.ts"() {
|
|
14530
14562
|
"use strict";
|
|
14531
14563
|
FIELD_TYPE_MAP = {
|
|
14532
|
-
string: { orm: '"string"', sql: "
|
|
14533
|
-
str: { orm: '"string"', sql: "
|
|
14564
|
+
string: { orm: '"string"', sql: "VARCHAR(255)", defaultVal: "''" },
|
|
14565
|
+
str: { orm: '"string"', sql: "VARCHAR(255)", defaultVal: "''" },
|
|
14534
14566
|
int: { orm: '"integer"', sql: "INTEGER", defaultVal: "0" },
|
|
14535
14567
|
integer: { orm: '"integer"', sql: "INTEGER", defaultVal: "0" },
|
|
14536
14568
|
float: { orm: '"number"', sql: "REAL", defaultVal: "0" },
|
|
@@ -14540,7 +14572,7 @@ var init_generate = __esm({
|
|
|
14540
14572
|
bool: { orm: '"boolean"', sql: "INTEGER", defaultVal: "0" },
|
|
14541
14573
|
boolean: { orm: '"boolean"', sql: "INTEGER", defaultVal: "0" },
|
|
14542
14574
|
text: { orm: '"string"', sql: "TEXT", defaultVal: "''" },
|
|
14543
|
-
datetime: { orm: '"datetime"', sql: "
|
|
14575
|
+
datetime: { orm: '"datetime"', sql: "TIMESTAMP", defaultVal: "NULL" },
|
|
14544
14576
|
blob: { orm: '"string"', sql: "BLOB", defaultVal: "NULL" }
|
|
14545
14577
|
};
|
|
14546
14578
|
SQL_RESERVED_TABLE_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -37310,6 +37342,8 @@ var init_mysql = __esm({
|
|
|
37310
37342
|
translateSql(sql) {
|
|
37311
37343
|
let translated = SQLTranslator.concatPipesToFunc(sql);
|
|
37312
37344
|
translated = SQLTranslator.ilikeToLike(translated);
|
|
37345
|
+
translated = SQLTranslator.autoIncrementSyntax(translated, "mysql");
|
|
37346
|
+
translated = SQLTranslator.ddlTypes(translated, "mysql");
|
|
37313
37347
|
return translated;
|
|
37314
37348
|
}
|
|
37315
37349
|
execute(sql, params) {
|
|
@@ -37731,6 +37765,8 @@ var init_mssql = __esm({
|
|
|
37731
37765
|
let translated = SQLTranslator.limitToTop(sql);
|
|
37732
37766
|
translated = SQLTranslator.concatPipesToFunc(translated);
|
|
37733
37767
|
translated = SQLTranslator.ilikeToLike(translated);
|
|
37768
|
+
translated = SQLTranslator.autoIncrementSyntax(translated, "mssql");
|
|
37769
|
+
translated = SQLTranslator.ddlTypes(translated, "mssql");
|
|
37734
37770
|
return translated;
|
|
37735
37771
|
}
|
|
37736
37772
|
execSqlPromise(sql, params) {
|
|
@@ -38361,6 +38397,8 @@ var init_firebird = __esm({
|
|
|
38361
38397
|
let translated = SQLTranslator.limitToRows(sql);
|
|
38362
38398
|
translated = SQLTranslator.booleanToInt(translated);
|
|
38363
38399
|
translated = SQLTranslator.ilikeToLike(translated);
|
|
38400
|
+
translated = SQLTranslator.autoIncrementSyntax(translated, "firebird");
|
|
38401
|
+
translated = SQLTranslator.ddlTypes(translated, "firebird");
|
|
38364
38402
|
return translated;
|
|
38365
38403
|
}
|
|
38366
38404
|
/**
|
|
@@ -395,6 +395,13 @@ export class FirebirdAdapter implements DatabaseAdapter {
|
|
|
395
395
|
let translated = SQLTranslator.limitToRows(sql);
|
|
396
396
|
translated = SQLTranslator.booleanToInt(translated);
|
|
397
397
|
translated = SQLTranslator.ilikeToLike(translated);
|
|
398
|
+
// DDL: strip AUTOINCREMENT (Firebird uses generators) and rewrite the
|
|
399
|
+
// SQLite-canonical column TYPES so ONE portable migration applies here —
|
|
400
|
+
// TEXT -> BLOB SUB_TYPE TEXT, REAL -> DOUBLE PRECISION, IF NOT EXISTS
|
|
401
|
+
// dropped. Both are DDL-only, so DML is untouched. Mirrors the Python
|
|
402
|
+
// master's firebird.py::_translate_sql.
|
|
403
|
+
translated = SQLTranslator.autoIncrementSyntax(translated, "firebird");
|
|
404
|
+
translated = SQLTranslator.ddlTypes(translated, "firebird");
|
|
398
405
|
return translated;
|
|
399
406
|
}
|
|
400
407
|
|
|
@@ -172,6 +172,12 @@ export class MssqlAdapter implements DatabaseAdapter {
|
|
|
172
172
|
let translated = SQLTranslator.limitToTop(sql);
|
|
173
173
|
translated = SQLTranslator.concatPipesToFunc(translated);
|
|
174
174
|
translated = SQLTranslator.ilikeToLike(translated);
|
|
175
|
+
// DDL: AUTOINCREMENT -> IDENTITY(1,1), drop IF NOT EXISTS (unsupported), and
|
|
176
|
+
// TIMESTAMP -> DATETIME2 (MSSQL's TIMESTAMP is a rowversion, not a datetime)
|
|
177
|
+
// so ONE portable migration applies here. Both are DDL-only, so DML is
|
|
178
|
+
// untouched. Mirrors the Python master's mssql.py::_translate_sql.
|
|
179
|
+
translated = SQLTranslator.autoIncrementSyntax(translated, "mssql");
|
|
180
|
+
translated = SQLTranslator.ddlTypes(translated, "mssql");
|
|
175
181
|
return translated;
|
|
176
182
|
}
|
|
177
183
|
|
|
@@ -148,6 +148,12 @@ export class MysqlAdapter implements DatabaseAdapter {
|
|
|
148
148
|
let translated = SQLTranslator.concatPipesToFunc(sql);
|
|
149
149
|
// MySQL uses LOWER() LIKE instead of ILIKE
|
|
150
150
|
translated = SQLTranslator.ilikeToLike(translated);
|
|
151
|
+
// DDL: AUTOINCREMENT -> AUTO_INCREMENT and TIMESTAMP -> DATETIME (MySQL's
|
|
152
|
+
// TIMESTAMP carries auto-update / 2038 surprises) so ONE portable migration
|
|
153
|
+
// applies here. Both are DDL-only, so DML is untouched. Mirrors the Python
|
|
154
|
+
// master's mysql.py::_translate_sql.
|
|
155
|
+
translated = SQLTranslator.autoIncrementSyntax(translated, "mysql");
|
|
156
|
+
translated = SQLTranslator.ddlTypes(translated, "mysql");
|
|
151
157
|
return translated;
|
|
152
158
|
}
|
|
153
159
|
|
|
@@ -269,6 +269,51 @@ export class SQLTranslator {
|
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Translate SQLite-canonical DDL column TYPES + CREATE-TABLE options to the
|
|
274
|
+
* target engine.
|
|
275
|
+
*
|
|
276
|
+
* ONLY acts on `CREATE TABLE` / `ALTER TABLE` statements, so a query or INSERT
|
|
277
|
+
* that happens to contain the word `TEXT` (a column name, a string literal) is
|
|
278
|
+
* never rewritten. Complements `autoIncrementSyntax` (which maps the id
|
|
279
|
+
* keyword) so ONE portable migration — and every `Model.createTable()` DDL,
|
|
280
|
+
* which is also SQLite-canonical — applies on every engine instead of failing
|
|
281
|
+
* on Firebird/MSSQL.
|
|
282
|
+
*
|
|
283
|
+
* * Firebird has no `TEXT` (-607), no `REAL`, and no `CREATE TABLE IF NOT
|
|
284
|
+
* EXISTS`.
|
|
285
|
+
* * MSSQL has no `CREATE TABLE IF NOT EXISTS` and its `TIMESTAMP` is a
|
|
286
|
+
* rowversion, not a datetime — a `created_at TIMESTAMP` there is wrong.
|
|
287
|
+
* * MySQL's `TIMESTAMP` carries auto-update / 2038 surprises, so a datetime
|
|
288
|
+
* column maps to `DATETIME` (matching the adapters' createTableAsync).
|
|
289
|
+
*/
|
|
290
|
+
static ddlTypes(sql: string, engine: string): string {
|
|
291
|
+
// Gate to DDL only, tolerating leading `-- ...` comment lines / blank lines
|
|
292
|
+
// that a migration file carries before its CREATE TABLE. A SELECT or INSERT
|
|
293
|
+
// that merely mentions a type keyword is never rewritten.
|
|
294
|
+
const head = sql.replace(/^(?:\s*--[^\n]*\n)+/, "");
|
|
295
|
+
if (!/^\s*(?:CREATE\s+TABLE|ALTER\s+TABLE)\b/i.test(head)) return sql;
|
|
296
|
+
switch ((engine ?? "").toLowerCase()) {
|
|
297
|
+
case "firebird":
|
|
298
|
+
return sql
|
|
299
|
+
.replace(/\bIF\s+NOT\s+EXISTS\b/gi, "")
|
|
300
|
+
// Map bare TEXT -> BLOB SUB_TYPE TEXT, but leave an existing
|
|
301
|
+
// "BLOB SUB_TYPE TEXT" intact (it already contains the word TEXT).
|
|
302
|
+
.replace(/\bBLOB\s+SUB_TYPE\s+TEXT\b/gi, "\x00FBTEXT\x00")
|
|
303
|
+
.replace(/\bTEXT\b/gi, "BLOB SUB_TYPE TEXT")
|
|
304
|
+
.replaceAll("\x00FBTEXT\x00", "BLOB SUB_TYPE TEXT")
|
|
305
|
+
.replace(/\bREAL\b/gi, "DOUBLE PRECISION");
|
|
306
|
+
case "mssql":
|
|
307
|
+
return sql
|
|
308
|
+
.replace(/\bIF\s+NOT\s+EXISTS\b/gi, "")
|
|
309
|
+
.replace(/\bTIMESTAMP\b/gi, "DATETIME2");
|
|
310
|
+
case "mysql":
|
|
311
|
+
return sql.replace(/\bTIMESTAMP\b/gi, "DATETIME");
|
|
312
|
+
default:
|
|
313
|
+
return sql;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
272
317
|
/**
|
|
273
318
|
* Convert ? placeholders to engine-specific style.
|
|
274
319
|
*
|
|
@@ -75,6 +75,25 @@ export declare class SQLTranslator {
|
|
|
75
75
|
* Translate AUTOINCREMENT across engines in DDL.
|
|
76
76
|
*/
|
|
77
77
|
static autoIncrementSyntax(sql: string, engine: string): string;
|
|
78
|
+
/**
|
|
79
|
+
* Translate SQLite-canonical DDL column TYPES + CREATE-TABLE options to the
|
|
80
|
+
* target engine.
|
|
81
|
+
*
|
|
82
|
+
* ONLY acts on `CREATE TABLE` / `ALTER TABLE` statements, so a query or INSERT
|
|
83
|
+
* that happens to contain the word `TEXT` (a column name, a string literal) is
|
|
84
|
+
* never rewritten. Complements `autoIncrementSyntax` (which maps the id
|
|
85
|
+
* keyword) so ONE portable migration — and every `Model.createTable()` DDL,
|
|
86
|
+
* which is also SQLite-canonical — applies on every engine instead of failing
|
|
87
|
+
* on Firebird/MSSQL.
|
|
88
|
+
*
|
|
89
|
+
* * Firebird has no `TEXT` (-607), no `REAL`, and no `CREATE TABLE IF NOT
|
|
90
|
+
* EXISTS`.
|
|
91
|
+
* * MSSQL has no `CREATE TABLE IF NOT EXISTS` and its `TIMESTAMP` is a
|
|
92
|
+
* rowversion, not a datetime — a `created_at TIMESTAMP` there is wrong.
|
|
93
|
+
* * MySQL's `TIMESTAMP` carries auto-update / 2038 surprises, so a datetime
|
|
94
|
+
* column maps to `DATETIME` (matching the adapters' createTableAsync).
|
|
95
|
+
*/
|
|
96
|
+
static ddlTypes(sql: string, engine: string): string;
|
|
78
97
|
/**
|
|
79
98
|
* Convert ? placeholders to engine-specific style.
|
|
80
99
|
*
|