tina4-nodejs 3.10.6 → 3.10.10

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 CHANGED
@@ -1,10 +1,10 @@
1
- # CLAUDE.md — AI Developer Guide for tina4-nodejs (v3.10.6)
1
+ # CLAUDE.md — AI Developer Guide for tina4-nodejs (v3.10.10)
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.10.6 — a convention-over-configuration structural paradigm. **Not a framework.** The developer writes TypeScript; Tina4 is invisible infrastructure.
7
+ Tina4 for Node.js/TypeScript v3.10.10 — a convention-over-configuration structural paradigm. **Not a framework.** 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tina4-nodejs",
3
- "version": "3.10.6",
3
+ "version": "3.10.10",
4
4
  "type": "module",
5
5
  "description": "This is not a framework. Tina4 for Node.js/TypeScript — zero deps, 38 built-in features.",
6
6
  "keywords": ["tina4", "framework", "web", "api", "orm", "graphql", "websocket", "typescript"],
@@ -127,18 +127,34 @@ const MIGRATION_TABLE = "tina4_migration";
127
127
  * Ensure the migration tracking table exists with batch support.
128
128
  */
129
129
  export function ensureMigrationTable(): void {
130
- const adapter = getAdapter() as SQLiteAdapter;
130
+ const adapter = getAdapter();
131
131
  if (!adapter.tableExists(MIGRATION_TABLE)) {
132
- adapter.createTable(MIGRATION_TABLE, {
133
- id: { type: "integer", primaryKey: true, autoIncrement: true },
134
- name: { type: "string", required: true },
135
- batch: { type: "integer", required: true },
136
- applied_at: { type: "datetime", default: "now" },
137
- });
132
+ if (isFirebirdAdapter(adapter)) {
133
+ // Firebird: no AUTOINCREMENT, no TEXT type, use generator for IDs
134
+ try {
135
+ adapter.execute("CREATE GENERATOR GEN_TINA4_MIGRATION_ID");
136
+ try { adapter.execute("COMMIT"); } catch { /* ignore */ }
137
+ } catch {
138
+ // Generator may already exist
139
+ }
140
+ adapter.execute(`CREATE TABLE "${MIGRATION_TABLE}" (
141
+ id INTEGER NOT NULL PRIMARY KEY,
142
+ name VARCHAR(500) NOT NULL,
143
+ batch INTEGER NOT NULL DEFAULT 1,
144
+ applied_at VARCHAR(50) NOT NULL
145
+ )`);
146
+ } else {
147
+ (adapter as SQLiteAdapter).createTable(MIGRATION_TABLE, {
148
+ id: { type: "integer", primaryKey: true, autoIncrement: true },
149
+ name: { type: "string", required: true },
150
+ batch: { type: "integer", required: true },
151
+ applied_at: { type: "datetime", default: "now" },
152
+ });
153
+ }
138
154
  } else {
139
155
  // Ensure batch column exists on older tables that only had passed/description
140
156
  try {
141
- const cols = adapter.getTableColumns(MIGRATION_TABLE);
157
+ const cols = (adapter as SQLiteAdapter).getTableColumns(MIGRATION_TABLE);
142
158
  const colNames = new Set(cols.map((c) => c.name));
143
159
  if (!colNames.has("batch")) {
144
160
  adapter.execute(`ALTER TABLE "${MIGRATION_TABLE}" ADD COLUMN batch INTEGER NOT NULL DEFAULT 1`);
@@ -177,10 +193,22 @@ export function isMigrationApplied(name: string): boolean {
177
193
  */
178
194
  export function recordMigration(name: string, batch: number): void {
179
195
  const adapter = getAdapter();
180
- adapter.execute(
181
- `INSERT INTO "${MIGRATION_TABLE}" (name, batch) VALUES (?, ?)`,
182
- [name, batch],
183
- );
196
+ if (isFirebirdAdapter(adapter)) {
197
+ // Firebird: generate ID from sequence
198
+ const rows = adapter.query<{ NEXT_ID: number }>(
199
+ "SELECT GEN_ID(GEN_TINA4_MIGRATION_ID, 1) AS NEXT_ID FROM RDB$DATABASE",
200
+ );
201
+ const nextId = rows[0]?.NEXT_ID ?? 1;
202
+ adapter.execute(
203
+ `INSERT INTO "${MIGRATION_TABLE}" (id, name, batch) VALUES (?, ?, ?)`,
204
+ [nextId, name, batch],
205
+ );
206
+ } else {
207
+ adapter.execute(
208
+ `INSERT INTO "${MIGRATION_TABLE}" (name, batch) VALUES (?, ?)`,
209
+ [name, batch],
210
+ );
211
+ }
184
212
  }
185
213
 
186
214
  /**
@@ -438,12 +466,28 @@ export async function migrate(
438
466
 
439
467
  // Ensure tracking table with batch support
440
468
  if (!db.tableExists(MIGRATION_TABLE)) {
441
- db.execute(`CREATE TABLE IF NOT EXISTS "${MIGRATION_TABLE}" (
442
- id INTEGER PRIMARY KEY AUTOINCREMENT,
443
- name TEXT NOT NULL,
444
- batch INTEGER NOT NULL DEFAULT 1,
445
- applied_at TEXT NOT NULL
446
- )`);
469
+ if (isFirebirdAdapter(db)) {
470
+ // Firebird: no AUTOINCREMENT, no TEXT type, use generator for IDs
471
+ try {
472
+ db.execute("CREATE GENERATOR GEN_TINA4_MIGRATION_ID");
473
+ try { db.execute("COMMIT"); } catch { /* ignore */ }
474
+ } catch {
475
+ // Generator may already exist
476
+ }
477
+ db.execute(`CREATE TABLE "${MIGRATION_TABLE}" (
478
+ id INTEGER NOT NULL PRIMARY KEY,
479
+ name VARCHAR(500) NOT NULL,
480
+ batch INTEGER NOT NULL DEFAULT 1,
481
+ applied_at VARCHAR(50) NOT NULL
482
+ )`);
483
+ } else {
484
+ db.execute(`CREATE TABLE IF NOT EXISTS "${MIGRATION_TABLE}" (
485
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
486
+ name TEXT NOT NULL,
487
+ batch INTEGER NOT NULL DEFAULT 1,
488
+ applied_at TEXT NOT NULL
489
+ )`);
490
+ }
447
491
  } else {
448
492
  // Migrate old schema: if table has 'description' + 'passed' columns, migrate data
449
493
  try {
@@ -538,10 +582,22 @@ export async function migrate(
538
582
  // Record as applied with batch number
539
583
  const now = new Date().toISOString();
540
584
  try {
541
- db.execute(
542
- `INSERT INTO "${MIGRATION_TABLE}" (name, batch, applied_at) VALUES (?, ?, ?)`,
543
- [migrationId, currentBatch, now],
544
- );
585
+ if (isFirebirdAdapter(db)) {
586
+ // Firebird: generate ID from sequence
587
+ const idRows = db.query<{ NEXT_ID: number }>(
588
+ "SELECT GEN_ID(GEN_TINA4_MIGRATION_ID, 1) AS NEXT_ID FROM RDB$DATABASE",
589
+ );
590
+ const nextId = idRows[0]?.NEXT_ID ?? 1;
591
+ db.execute(
592
+ `INSERT INTO "${MIGRATION_TABLE}" (id, name, batch, applied_at) VALUES (?, ?, ?, ?)`,
593
+ [nextId, migrationId, currentBatch, now],
594
+ );
595
+ } else {
596
+ db.execute(
597
+ `INSERT INTO "${MIGRATION_TABLE}" (name, batch, applied_at) VALUES (?, ?, ?)`,
598
+ [migrationId, currentBatch, now],
599
+ );
600
+ }
545
601
  } catch {
546
602
  // Old schema fallback — try description/content/passed columns
547
603
  db.execute(