tina4-nodejs 3.13.43 → 3.13.45
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 -1
- package/package.json +1 -1
- package/packages/core/src/graphql.ts +23 -14
- package/packages/core/src/mcp.ts +21 -2
- package/packages/core/src/queueBackends/kafkaBackend.ts +303 -167
- package/packages/core/src/queueBackends/rabbitmqBackend.ts +97 -31
- package/packages/core/src/server.ts +12 -5
- package/packages/core/src/session.ts +11 -95
- package/packages/core/src/sessionHandlers/mongoClient.ts +238 -0
- package/packages/core/src/sessionHandlers/mongoHandler.ts +25 -204
- package/packages/core/src/sessionHandlers/redisHandler.ts +69 -114
- package/packages/core/src/sessionHandlers/respClient.ts +171 -0
- package/packages/core/src/sessionHandlers/valkeyHandler.ts +11 -95
- package/packages/orm/src/adapters/firebird.ts +20 -2
- package/packages/orm/src/adapters/mssql.ts +24 -2
- package/packages/orm/src/adapters/mysql.ts +20 -2
- package/packages/orm/src/adapters/postgres.ts +40 -12
- package/packages/orm/src/adapters/sqlite.ts +16 -2
- package/packages/orm/src/autoCrud.ts +13 -0
- package/packages/orm/src/baseModel.ts +3 -1
- package/packages/orm/src/cachedDatabase.ts +1 -1
- package/packages/orm/src/database.ts +42 -11
- package/packages/orm/src/index.ts +1 -1
- package/packages/orm/src/migration.ts +124 -45
- package/packages/orm/src/types.ts +5 -3
|
@@ -28,15 +28,41 @@ const ALTER_ADD_RE =
|
|
|
28
28
|
/^\s*ALTER\s+TABLE\s+(?:"([^"]+)"|(\S+))\s+ADD\s+(?:"([^"]+)"|(\S+))/i;
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* Check if the adapter is a Firebird adapter
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* Check if the adapter is a Firebird adapter.
|
|
32
|
+
*
|
|
33
|
+
* Detection is by the adapter's class name (`constructor.name`) — the engine
|
|
34
|
+
* discriminator used throughout this package (see `engineOf`). A previous
|
|
35
|
+
* duck-type check (`queryAsync` + `translateSql`) was WRONG: every async
|
|
36
|
+
* adapter (Postgres/MySQL/MSSQL) exposes BOTH of those, so the Postgres
|
|
37
|
+
* adapter was mis-identified as Firebird. That routed the migration-tracking
|
|
38
|
+
* CREATE into the Firebird `CREATE GENERATOR` + no-default-id DDL and the
|
|
39
|
+
* record INSERT into the Firebird `GEN_ID()` path — both invalid on Postgres,
|
|
40
|
+
* so `migrate()` died on the FIRST migration with "syntax error" / aborted
|
|
41
|
+
* transaction. Class-name detection fixes the mis-route without altering the
|
|
42
|
+
* runner loop, transaction handling, or raise/return semantics.
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
45
|
+
* Unwrap a CachedDatabaseAdapter (what initDatabase() returns) to the concrete
|
|
46
|
+
* underlying adapter. Engine detection keys on constructor.name, which on the
|
|
47
|
+
* wrapper reads "CachedDatabaseAdapter" — so without unwrapping, every real app
|
|
48
|
+
* (all of which go through initDatabase) is mis-detected as SQLite and migrate()
|
|
49
|
+
* emits AUTOINCREMENT on Postgres/MySQL/MSSQL. Drills through any nesting; a raw
|
|
50
|
+
* adapter passes through unchanged.
|
|
34
51
|
*/
|
|
52
|
+
function unwrapAdapter(db: DatabaseAdapter): DatabaseAdapter {
|
|
53
|
+
let cur: unknown = db;
|
|
54
|
+
while (
|
|
55
|
+
cur &&
|
|
56
|
+
(cur as { constructor?: { name?: string } }).constructor?.name === "CachedDatabaseAdapter" &&
|
|
57
|
+
(cur as { adapter?: unknown }).adapter
|
|
58
|
+
) {
|
|
59
|
+
cur = (cur as { adapter: unknown }).adapter;
|
|
60
|
+
}
|
|
61
|
+
return cur as DatabaseAdapter;
|
|
62
|
+
}
|
|
63
|
+
|
|
35
64
|
function isFirebirdAdapter(db: DatabaseAdapter): boolean {
|
|
36
|
-
return (
|
|
37
|
-
typeof (db as any).queryAsync === "function" &&
|
|
38
|
-
typeof (db as any).translateSql === "function"
|
|
39
|
-
);
|
|
65
|
+
return unwrapAdapter(db).constructor.name === "FirebirdAdapter";
|
|
40
66
|
}
|
|
41
67
|
|
|
42
68
|
/**
|
|
@@ -87,12 +113,41 @@ const CREATE_TABLE_RE =
|
|
|
87
113
|
/**
|
|
88
114
|
* Identify the database engine via the adapter's class name.
|
|
89
115
|
* (constructor.name is the engine discriminator used throughout this package.)
|
|
116
|
+
*
|
|
117
|
+
* SQLite is the default for any unrecognized adapter (matches the rest of the
|
|
118
|
+
* package and Python's `db.get_database_type() or "sqlite"`).
|
|
90
119
|
*/
|
|
91
|
-
function engineOf(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
120
|
+
function engineOf(
|
|
121
|
+
db: DatabaseAdapter,
|
|
122
|
+
): "firebird" | "mssql" | "postgres" | "mysql" | "sqlite" {
|
|
123
|
+
switch (unwrapAdapter(db).constructor.name) {
|
|
124
|
+
case "FirebirdAdapter": return "firebird";
|
|
125
|
+
case "MssqlAdapter": return "mssql";
|
|
126
|
+
case "PostgresAdapter": return "postgres";
|
|
127
|
+
case "MysqlAdapter": return "mysql";
|
|
128
|
+
default: return "sqlite";
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Engine-aware auto-increment integer primary-key column for the
|
|
134
|
+
* `tina4_migration` tracking table.
|
|
135
|
+
*
|
|
136
|
+
* Each engine spells an auto-increment integer PK differently — SQLite uses
|
|
137
|
+
* AUTOINCREMENT, PostgreSQL SERIAL, MySQL AUTO_INCREMENT, MSSQL IDENTITY(1,1).
|
|
138
|
+
* Emitting raw `AUTOINCREMENT` on any non-SQLite engine fails with
|
|
139
|
+
* "syntax error at or near AUTOINCREMENT" — which is exactly why `migrate()`
|
|
140
|
+
* was unusable on PostgreSQL/MySQL/MSSQL. Mirrors the engine-aware id DDL in
|
|
141
|
+
* the adapters' createTableAsync and Python's `_create_v3_table`. (Firebird is
|
|
142
|
+
* handled by its own generator branch and never reaches here.)
|
|
143
|
+
*/
|
|
144
|
+
function migrationIdColumn(db: DatabaseAdapter): string {
|
|
145
|
+
switch (engineOf(db)) {
|
|
146
|
+
case "postgres": return "id SERIAL PRIMARY KEY";
|
|
147
|
+
case "mysql": return "id INTEGER PRIMARY KEY AUTO_INCREMENT";
|
|
148
|
+
case "mssql": return "id INTEGER IDENTITY(1,1) PRIMARY KEY";
|
|
149
|
+
default: return "id INTEGER PRIMARY KEY AUTOINCREMENT";
|
|
150
|
+
}
|
|
96
151
|
}
|
|
97
152
|
|
|
98
153
|
/**
|
|
@@ -192,7 +247,7 @@ function buildAddColumnSql(
|
|
|
192
247
|
colName: string,
|
|
193
248
|
def: FieldDefinition,
|
|
194
249
|
): string {
|
|
195
|
-
const engine = adapter.constructor.name;
|
|
250
|
+
const engine = unwrapAdapter(adapter).constructor.name;
|
|
196
251
|
const isPg = engine === "PostgresAdapter";
|
|
197
252
|
const typeMap: Record<string, string> = isPg
|
|
198
253
|
? { integer: "INTEGER", string: def.maxLength ? `VARCHAR(${def.maxLength})` : "VARCHAR(255)", text: "TEXT", number: "DOUBLE PRECISION", numeric: "DOUBLE PRECISION", boolean: "BOOLEAN", datetime: "TIMESTAMP" }
|
|
@@ -237,12 +292,24 @@ export async function ensureMigrationTable(): Promise<void> {
|
|
|
237
292
|
applied_at VARCHAR(50) NOT NULL
|
|
238
293
|
)`);
|
|
239
294
|
} else {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
295
|
+
// Engine-aware bookkeeping DDL (non-Firebird) — same per-engine id column
|
|
296
|
+
// and column types as the inline `migrate()` bootstrap. Raw AUTOINCREMENT
|
|
297
|
+
// is SQLite-only and a syntax error elsewhere; SERIAL/AUTO_INCREMENT/
|
|
298
|
+
// IDENTITY(1,1) are produced via migrationIdColumn(). VARCHAR name (UNIQUE-
|
|
299
|
+
// safe on MySQL) and DATETIME applied_at on MSSQL (TIMESTAMP is rowversion
|
|
300
|
+
// there). SQLite gives VARCHAR TEXT affinity, so SQLite stays unchanged.
|
|
301
|
+
// applied_at keeps a CURRENT_TIMESTAMP default so recordMigration() (which
|
|
302
|
+
// inserts only name+batch) still works — same as the prior createTable.
|
|
303
|
+
const idCol = migrationIdColumn(adapter);
|
|
304
|
+
const engine = engineOf(adapter);
|
|
305
|
+
const ifNotExists = engine === "mssql" ? "" : "IF NOT EXISTS ";
|
|
306
|
+
const appliedType = engine === "mssql" ? "DATETIME" : "TEXT";
|
|
307
|
+
await adapterExecute(adapter, `CREATE TABLE ${ifNotExists}"${MIGRATION_TABLE}" (
|
|
308
|
+
${idCol},
|
|
309
|
+
name VARCHAR(500) NOT NULL,
|
|
310
|
+
batch INTEGER NOT NULL DEFAULT 1,
|
|
311
|
+
applied_at ${appliedType} NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
312
|
+
)`);
|
|
246
313
|
}
|
|
247
314
|
} else {
|
|
248
315
|
// Ensure batch column exists on older tables that only had passed/description
|
|
@@ -360,7 +427,17 @@ export async function removeMigrationRecord(name: string): Promise<void> {
|
|
|
360
427
|
*
|
|
361
428
|
* @param migrationsDir - Directory containing migration files (default: "migrations")
|
|
362
429
|
* @param delimiter - SQL statement delimiter (default: ";")
|
|
363
|
-
* @returns Array of
|
|
430
|
+
* @returns Array of the down-migration files that were run, e.g.
|
|
431
|
+
* "000001_create_users.down.sql". (The legacy down-FUNCTION Map API returns the
|
|
432
|
+
* bare migration name instead, since no .down.sql file is involved there.)
|
|
433
|
+
*
|
|
434
|
+
* NOTE on return form (intentional, cross-framework): migration return values reflect
|
|
435
|
+
* WHAT each method acted on, so the forms differ by method and that is by design (not
|
|
436
|
+
* unified). migrate()/getApplied()/getPending() return the up-migration filename
|
|
437
|
+
* ("name.sql"); rollback() returns the DOWN-migration filename it executed
|
|
438
|
+
* ("name.down.sql") — matching the Python master. So a caller diffing rollback()
|
|
439
|
+
* against getApplied() compares ".down.sql" vs ".sql": strip the suffixes (or compare
|
|
440
|
+
* the bare "name" stem) to relate them.
|
|
364
441
|
*/
|
|
365
442
|
export async function rollback(
|
|
366
443
|
migrationsDir?: string | Map<string, () => void | Promise<void>>,
|
|
@@ -377,6 +454,8 @@ export async function rollback(
|
|
|
377
454
|
await down();
|
|
378
455
|
}
|
|
379
456
|
await removeMigrationRecord(migration.name);
|
|
457
|
+
// Legacy down-FUNCTION API: no .down.sql file is involved here, so return the
|
|
458
|
+
// bare migration name (the file-based path below returns "name.down.sql").
|
|
380
459
|
rolledBack.push(migration.name);
|
|
381
460
|
}
|
|
382
461
|
return rolledBack;
|
|
@@ -419,7 +498,9 @@ export async function rollback(
|
|
|
419
498
|
}
|
|
420
499
|
|
|
421
500
|
await removeMigrationRecord(migration.name);
|
|
422
|
-
|
|
501
|
+
// Return the down-migration file that was run (e.g. "name.down.sql"), matching
|
|
502
|
+
// the Python master's rollback return form.
|
|
503
|
+
rolledBack.push(`${migration.name}.down.sql`);
|
|
423
504
|
}
|
|
424
505
|
|
|
425
506
|
return rolledBack;
|
|
@@ -629,32 +710,30 @@ export async function migrate(
|
|
|
629
710
|
batch INTEGER NOT NULL DEFAULT 1,
|
|
630
711
|
applied_at VARCHAR(50) NOT NULL
|
|
631
712
|
)`);
|
|
632
|
-
} else if (db.constructor.name === "PostgresAdapter") {
|
|
633
|
-
// PostgreSQL: SERIAL + TIMESTAMP (not AUTOINCREMENT/TEXT).
|
|
634
|
-
await adapterExecute(db, `CREATE TABLE IF NOT EXISTS "${MIGRATION_TABLE}" (
|
|
635
|
-
id SERIAL PRIMARY KEY,
|
|
636
|
-
name TEXT NOT NULL,
|
|
637
|
-
batch INTEGER NOT NULL DEFAULT 1,
|
|
638
|
-
applied_at TEXT NOT NULL
|
|
639
|
-
)`);
|
|
640
|
-
} else if (engineOf(db) === "mssql") {
|
|
641
|
-
// MSSQL has no AUTOINCREMENT / IF NOT EXISTS — route the bootstrap
|
|
642
|
-
// through the adapter's engine-aware createTable (IDENTITY(1,1) etc.),
|
|
643
|
-
// exactly like ensureMigrationTable does. Emitting raw
|
|
644
|
-
// AUTOINCREMENT/IF NOT EXISTS here is invalid on SQL Server.
|
|
645
|
-
await adapterCreateTable(db, MIGRATION_TABLE, {
|
|
646
|
-
id: { type: "integer", primaryKey: true, autoIncrement: true },
|
|
647
|
-
name: { type: "string", required: true },
|
|
648
|
-
batch: { type: "integer", required: true },
|
|
649
|
-
applied_at: { type: "datetime", default: "now" },
|
|
650
|
-
});
|
|
651
713
|
} else {
|
|
652
|
-
//
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
714
|
+
// Engine-aware bookkeeping DDL (non-Firebird). Each engine spells an
|
|
715
|
+
// auto-increment integer PK differently — SQLite AUTOINCREMENT, Postgres
|
|
716
|
+
// SERIAL, MySQL AUTO_INCREMENT, MSSQL IDENTITY(1,1) — so the id column is
|
|
717
|
+
// built per engine (raw `AUTOINCREMENT` is a syntax error on every other
|
|
718
|
+
// engine; that is the bug that made `migrate()` unusable on
|
|
719
|
+
// Postgres/MySQL/MSSQL). The `name` column is VARCHAR (not TEXT) so it can
|
|
720
|
+
// carry a UNIQUE index on MySQL; `applied_at` is DATETIME on MSSQL
|
|
721
|
+
// (TIMESTAMP there is rowversion, not a real timestamp). SQLite gives
|
|
722
|
+
// VARCHAR TEXT affinity, so SQLite behaviour is byte-for-byte unchanged.
|
|
723
|
+
// MSSQL has no IF NOT EXISTS (already guarded by the tableExists check
|
|
724
|
+
// above), so it is omitted; the other engines tolerate it being absent.
|
|
725
|
+
// applied_at keeps a CURRENT_TIMESTAMP default so the recordMigration()
|
|
726
|
+
// path (which inserts only name+batch) still works — preserving the prior
|
|
727
|
+
// engine-aware createTable behaviour that supplied that default.
|
|
728
|
+
const idCol = migrationIdColumn(db);
|
|
729
|
+
const engine = engineOf(db);
|
|
730
|
+
const ifNotExists = engine === "mssql" ? "" : "IF NOT EXISTS ";
|
|
731
|
+
const appliedType = engine === "mssql" ? "DATETIME" : "TEXT";
|
|
732
|
+
await adapterExecute(db, `CREATE TABLE ${ifNotExists}"${MIGRATION_TABLE}" (
|
|
733
|
+
${idCol},
|
|
734
|
+
name VARCHAR(500) NOT NULL,
|
|
656
735
|
batch INTEGER NOT NULL DEFAULT 1,
|
|
657
|
-
applied_at
|
|
736
|
+
applied_at ${appliedType} NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
658
737
|
)`);
|
|
659
738
|
}
|
|
660
739
|
} else {
|
|
@@ -52,7 +52,9 @@ export interface ColumnInfo {
|
|
|
52
52
|
export interface DatabaseResult {
|
|
53
53
|
success: boolean;
|
|
54
54
|
rowsAffected: number;
|
|
55
|
-
|
|
55
|
+
// string covers a non-integer primary key (e.g. a PostgreSQL UUID PK returns
|
|
56
|
+
// its id as a string via RETURNING, not a SERIAL integer) — #256.
|
|
57
|
+
lastInsertId?: number | bigint | string;
|
|
56
58
|
error?: string;
|
|
57
59
|
}
|
|
58
60
|
|
|
@@ -96,8 +98,8 @@ export interface DatabaseAdapter {
|
|
|
96
98
|
/** List columns with types for a table. */
|
|
97
99
|
columns(table: string): ColumnInfo[];
|
|
98
100
|
|
|
99
|
-
/** Get the last auto-increment
|
|
100
|
-
lastInsertId(): number | bigint | null;
|
|
101
|
+
/** Get the last inserted id (auto-increment integer, or a UUID/string PK). */
|
|
102
|
+
lastInsertId(): number | bigint | string | null;
|
|
101
103
|
|
|
102
104
|
/** Close the connection. */
|
|
103
105
|
close(): void;
|