tina4-nodejs 3.13.75 → 3.13.76
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/orm/src/migration.ts +40 -9
package/CLAUDE.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# CLAUDE.md - AI Developer Guide for tina4-nodejs (v3.13.
|
|
1
|
+
# CLAUDE.md - AI Developer Guide for tina4-nodejs (v3.13.76)
|
|
2
2
|
|
|
3
3
|
> This file helps AI assistants (Claude, Copilot, Cursor, etc.) understand and work on this codebase effectively.
|
|
4
4
|
|
|
5
5
|
## What This Project Is
|
|
6
6
|
|
|
7
|
-
Tina4 for Node.js/TypeScript v3.13.
|
|
7
|
+
Tina4 for Node.js/TypeScript v3.13.76 - The Intelligent Native Application 4ramework. A convention-over-configuration structural paradigm. The developer writes TypeScript; Tina4 is invisible infrastructure.
|
|
8
8
|
|
|
9
9
|
The philosophy: zero ceremony, batteries included, file system as source of truth.
|
|
10
10
|
|
package/package.json
CHANGED
|
@@ -470,21 +470,52 @@ async function recordApplied(
|
|
|
470
470
|
`DELETE FROM "${MIGRATION_TABLE}" WHERE migration_name = ?`,
|
|
471
471
|
[name],
|
|
472
472
|
);
|
|
473
|
+
// Build the column list from the columns that ACTUALLY exist on the table, so
|
|
474
|
+
// a legacy column left behind by an in-place upgrade is populated rather than
|
|
475
|
+
// defaulted to NULL. Node never created a `migration_id` column, but a Node app
|
|
476
|
+
// can be pointed at a database whose tina4_migration table was created by
|
|
477
|
+
// tina4-python v3 <= 3.13.54 - there `migration_id` is NOT NULL, and an insert
|
|
478
|
+
// that omits it fails, wedging every migration on that database
|
|
479
|
+
// (tina4-python#93). Mirrors the PHP + Python masters.
|
|
480
|
+
const cols = await trackingColumns(db);
|
|
481
|
+
const insertCols = ["migration_name", "description", "batch", "executed_at", "passed"];
|
|
482
|
+
const values: unknown[] = [name, description, batch, now, passed];
|
|
483
|
+
|
|
484
|
+
if (cols.has("migration_id")) {
|
|
485
|
+
insertCols.push("migration_id");
|
|
486
|
+
values.push(name);
|
|
487
|
+
}
|
|
488
|
+
|
|
473
489
|
if (isFirebirdAdapter(db)) {
|
|
474
490
|
// Firebird: generate the id from the sequence.
|
|
475
491
|
const rows = await adapterQuery<{ NEXT_ID: number }>(db,
|
|
476
492
|
"SELECT GEN_ID(GEN_TINA4_MIGRATION_ID, 1) AS NEXT_ID FROM RDB$DATABASE",
|
|
477
493
|
);
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
494
|
+
insertCols.unshift("id");
|
|
495
|
+
values.unshift(rows[0]?.NEXT_ID ?? 1);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const placeholders = insertCols.map(() => "?").join(", ");
|
|
499
|
+
await adapterExecute(db,
|
|
500
|
+
`INSERT INTO "${MIGRATION_TABLE}" (${insertCols.join(", ")}) VALUES (${placeholders})`,
|
|
501
|
+
values,
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Lowercased column names on the tracking table. Returns an empty set on any
|
|
507
|
+
* failure so a missing/unreadable table falls back to the canonical columns.
|
|
508
|
+
*/
|
|
509
|
+
async function trackingColumns(db: DatabaseAdapter): Promise<Set<string>> {
|
|
510
|
+
try {
|
|
511
|
+
// The DatabaseAdapter contract exposes columns(), not getColumns().
|
|
512
|
+
const cols = await (db as any).columns?.(MIGRATION_TABLE);
|
|
513
|
+
if (!Array.isArray(cols)) return new Set();
|
|
514
|
+
return new Set(
|
|
515
|
+
cols.map((c: any) => String(c?.name ?? c ?? "").toLowerCase()).filter(Boolean),
|
|
487
516
|
);
|
|
517
|
+
} catch {
|
|
518
|
+
return new Set();
|
|
488
519
|
}
|
|
489
520
|
}
|
|
490
521
|
|