tina4-nodejs 3.13.85 → 3.13.87
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 +38 -32
- package/package.json +22 -5
- package/packages/cli/dist/bin.js +245 -103
- package/packages/core/dist/index.js +244 -102
- package/packages/core/public/js/tina4-dev-admin.min.js +90 -87
- package/packages/core/src/metrics.ts +11 -2
- package/packages/core/src/session.ts +2 -2
- package/packages/core/src/sessionHandlers/databaseHandler.ts +5 -6
- package/packages/frond/dist/index.js +115 -10
- package/packages/frond/src/engine.ts +186 -11
- package/packages/orm/dist/index.js +244 -102
- package/packages/orm/src/adapters/firebird.ts +39 -13
- package/packages/orm/src/adapters/mongodb.ts +13 -13
- package/packages/orm/src/adapters/mssql.ts +14 -14
- package/packages/orm/src/adapters/mysql.ts +14 -14
- package/packages/orm/src/adapters/odbc.ts +15 -15
- package/packages/orm/src/adapters/postgres.ts +28 -17
- package/packages/orm/src/adapters/sqlite.ts +14 -14
- package/packages/orm/src/autoCrud.ts +1 -1
- package/packages/orm/src/cachedDatabase.ts +1 -1
- package/packages/orm/src/database.ts +17 -5
- package/packages/orm/src/types.ts +4 -4
|
@@ -115,7 +115,7 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
115
115
|
return result;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
executeMany(sql: string, paramsList: unknown[][]): { totalAffected: number;
|
|
118
|
+
executeMany(sql: string, paramsList: unknown[][]): { totalAffected: number; lastId?: number | bigint } {
|
|
119
119
|
const stmt = this.db.prepare(sql);
|
|
120
120
|
let totalAffected = 0;
|
|
121
121
|
let lastId: number | bigint | undefined;
|
|
@@ -136,7 +136,7 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
136
136
|
throw e;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
return { totalAffected,
|
|
139
|
+
return { totalAffected, lastId: lastId };
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): T[] {
|
|
@@ -167,13 +167,13 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
167
167
|
|
|
168
168
|
insert(table: string, data: Record<string, unknown> | Record<string, unknown>[]): DatabaseResult {
|
|
169
169
|
if (Array.isArray(data)) {
|
|
170
|
-
if (data.length === 0) return { success: true,
|
|
170
|
+
if (data.length === 0) return { success: true, affectedRows: 0 };
|
|
171
171
|
const keys = Object.keys(data[0]);
|
|
172
172
|
const placeholders = keys.map(() => "?").join(", ");
|
|
173
173
|
const sql = `INSERT INTO "${table}" ("${keys.join('", "')}") VALUES (${placeholders})`;
|
|
174
174
|
const paramsList = data.map((row) => keys.map((k) => row[k]));
|
|
175
175
|
const result = this.executeMany(sql, paramsList);
|
|
176
|
-
return { success: true,
|
|
176
|
+
return { success: true, affectedRows: result.totalAffected, lastId: result.lastId };
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
const keys = Object.keys(data);
|
|
@@ -184,9 +184,9 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
184
184
|
try {
|
|
185
185
|
const result = this.db.prepare(sql).run(...toSqlParams(values));
|
|
186
186
|
this._lastInsertId = result.lastInsertRowid;
|
|
187
|
-
return { success: true,
|
|
187
|
+
return { success: true, affectedRows: Number(result.changes), lastId: result.lastInsertRowid };
|
|
188
188
|
} catch (e) {
|
|
189
|
-
return { success: false,
|
|
189
|
+
return { success: false, affectedRows: 0, error: (e as Error).message };
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
|
|
@@ -198,9 +198,9 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
198
198
|
|
|
199
199
|
try {
|
|
200
200
|
const result = this.db.prepare(sql).run(...toSqlParams(values));
|
|
201
|
-
return { success: true,
|
|
201
|
+
return { success: true, affectedRows: Number(result.changes) };
|
|
202
202
|
} catch (e) {
|
|
203
|
-
return { success: false,
|
|
203
|
+
return { success: false, affectedRows: 0, error: (e as Error).message };
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
|
|
@@ -209,18 +209,18 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
209
209
|
let totalAffected = 0;
|
|
210
210
|
for (const row of filter) {
|
|
211
211
|
const result = this.delete(table, row);
|
|
212
|
-
totalAffected += result.
|
|
212
|
+
totalAffected += result.affectedRows;
|
|
213
213
|
}
|
|
214
|
-
return { success: true,
|
|
214
|
+
return { success: true, affectedRows: totalAffected };
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
if (typeof filter === "string") {
|
|
218
218
|
const sql = filter ? `DELETE FROM "${table}" WHERE ${filter}` : `DELETE FROM "${table}"`;
|
|
219
219
|
try {
|
|
220
220
|
const result = this.db.prepare(sql).run(...toSqlParams(params ?? []));
|
|
221
|
-
return { success: true,
|
|
221
|
+
return { success: true, affectedRows: Number(result.changes) };
|
|
222
222
|
} catch (e) {
|
|
223
|
-
return { success: false,
|
|
223
|
+
return { success: false, affectedRows: 0, error: (e as Error).message };
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
226
|
|
|
@@ -230,9 +230,9 @@ export class SQLiteAdapter implements DatabaseAdapter {
|
|
|
230
230
|
|
|
231
231
|
try {
|
|
232
232
|
const result = this.db.prepare(sql).run(...toSqlParams(values));
|
|
233
|
-
return { success: true,
|
|
233
|
+
return { success: true, affectedRows: Number(result.changes) };
|
|
234
234
|
} catch (e) {
|
|
235
|
-
return { success: false,
|
|
235
|
+
return { success: false, affectedRows: 0, error: (e as Error).message };
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
238
|
|
|
@@ -233,7 +233,7 @@ export function generateCrudRoutes(models: DiscoveredModel[], options: AutoCrudO
|
|
|
233
233
|
|
|
234
234
|
// Non-SQLite engines can't read a plain INSERT's auto-id back via
|
|
235
235
|
// lastInsertId(); RETURNING the PK column lets us recover it. SQLite
|
|
236
|
-
// tolerates RETURNING but we still prefer its
|
|
236
|
+
// tolerates RETURNING but we still prefer its lastId below.
|
|
237
237
|
const isSqlite = adapter.constructor.name === "SQLiteAdapter";
|
|
238
238
|
const insertSql =
|
|
239
239
|
`INSERT INTO "${tableName}" (${columns.map((c) => `"${c}"`).join(", ")}) VALUES (${placeholders})` +
|
|
@@ -301,7 +301,7 @@ export class CachedDatabaseAdapter implements DatabaseAdapter {
|
|
|
301
301
|
return this.adapter.execute(sql, params);
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
-
executeMany(sql: string, paramsList: unknown[][]): { totalAffected: number;
|
|
304
|
+
executeMany(sql: string, paramsList: unknown[][]): { totalAffected: number; lastId?: number | bigint } {
|
|
305
305
|
if (this.enabled) this.invalidate();
|
|
306
306
|
return this.adapter.executeMany(sql, paramsList);
|
|
307
307
|
}
|
|
@@ -117,7 +117,7 @@ export async function adapterCreateTable(
|
|
|
117
117
|
*
|
|
118
118
|
* SQLite returns `{ lastInsertRowid }`. PostgreSQL (pg) returns a result whose
|
|
119
119
|
* `rows[0].id` holds the value when the statement had a `RETURNING` clause
|
|
120
|
-
* (insertAsync adds one). MySQL/MSSQL adapters set the adapter's
|
|
120
|
+
* (insertAsync adds one). MySQL/MSSQL adapters set the adapter's lastId,
|
|
121
121
|
* so callers fall back to `adapter.lastInsertId()` when the result has neither.
|
|
122
122
|
*/
|
|
123
123
|
export function extractLastInsertId(result: unknown): number | bigint | null {
|
|
@@ -125,7 +125,7 @@ export function extractLastInsertId(result: unknown): number | bigint | null {
|
|
|
125
125
|
const r = result as any;
|
|
126
126
|
if (r.lastInsertRowid !== undefined && r.lastInsertRowid !== null) return r.lastInsertRowid;
|
|
127
127
|
if (r.rows?.[0]?.id !== undefined && r.rows[0].id !== null) return r.rows[0].id;
|
|
128
|
-
if (r.
|
|
128
|
+
if (r.lastId !== undefined && r.lastId !== null) return r.lastId;
|
|
129
129
|
}
|
|
130
130
|
return null;
|
|
131
131
|
}
|
|
@@ -962,14 +962,26 @@ export class Database {
|
|
|
962
962
|
const adapter = this.getNextAdapter();
|
|
963
963
|
const results: unknown[] = [];
|
|
964
964
|
|
|
965
|
-
|
|
965
|
+
// Own the batch transaction ONLY when not already inside a caller's explicit
|
|
966
|
+
// transaction. inExplicitTransaction() is true when startTransaction() has
|
|
967
|
+
// pinned an adapter to this async context (getNextAdapter() returns that same
|
|
968
|
+
// pinned connection). If we owned a BEGIN/COMMIT here regardless, the inner
|
|
969
|
+
// COMMIT would commit the caller's OUTER transaction early and their later
|
|
970
|
+
// rollback() would undo nothing (the batch rows survive). So: standalone
|
|
971
|
+
// batch -> own BEGIN/COMMIT (atomic, all-or-nothing); nested batch -> join
|
|
972
|
+
// the caller's transaction and let their commit/rollback decide. Mirrors the
|
|
973
|
+
// sibling execute()/insert()/update()/delete() owns-guard, the PostgreSQL
|
|
974
|
+
// adapter's executeManyAsync owns-guard, and the Python master
|
|
975
|
+
// (Database.execute_many delegating to adapter.execute_many's owns_txn guard).
|
|
976
|
+
const owns = !this.inExplicitTransaction();
|
|
977
|
+
if (owns) await adapterStartTransaction(adapter);
|
|
966
978
|
try {
|
|
967
979
|
for (const params of paramSets) {
|
|
968
980
|
results.push(await adapterExecute(adapter, sql, params));
|
|
969
981
|
}
|
|
970
|
-
await adapterCommit(adapter);
|
|
982
|
+
if (owns) await adapterCommit(adapter);
|
|
971
983
|
} catch (e) {
|
|
972
|
-
await adapterRollback(adapter);
|
|
984
|
+
if (owns) await adapterRollback(adapter);
|
|
973
985
|
throw e;
|
|
974
986
|
}
|
|
975
987
|
|
|
@@ -51,10 +51,10 @@ export interface ColumnInfo {
|
|
|
51
51
|
|
|
52
52
|
export interface DatabaseResult {
|
|
53
53
|
success: boolean;
|
|
54
|
-
|
|
54
|
+
affectedRows: number;
|
|
55
55
|
// string covers a non-integer primary key (e.g. a PostgreSQL UUID PK returns
|
|
56
56
|
// its id as a string via RETURNING, not a SERIAL integer) — #256.
|
|
57
|
-
|
|
57
|
+
lastId?: number | bigint | string;
|
|
58
58
|
error?: string;
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -63,7 +63,7 @@ export interface DatabaseAdapter {
|
|
|
63
63
|
execute(sql: string, params?: unknown[]): unknown;
|
|
64
64
|
|
|
65
65
|
/** Execute a single SQL statement with multiple parameter sets (batch). */
|
|
66
|
-
executeMany(sql: string, paramsList: unknown[][]): { totalAffected: number;
|
|
66
|
+
executeMany(sql: string, paramsList: unknown[][]): { totalAffected: number; lastId?: number | bigint };
|
|
67
67
|
|
|
68
68
|
/** Query rows. */
|
|
69
69
|
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): T[];
|
|
@@ -74,7 +74,7 @@ export interface DatabaseAdapter {
|
|
|
74
74
|
/** Fetch a single row or null. */
|
|
75
75
|
fetchOne<T = Record<string, unknown>>(sql: string, params?: unknown[]): T | null;
|
|
76
76
|
|
|
77
|
-
/** Insert one or more rows into a table, returns result with
|
|
77
|
+
/** Insert one or more rows into a table, returns result with lastId. */
|
|
78
78
|
insert(table: string, data: Record<string, unknown> | Record<string, unknown>[]): DatabaseResult;
|
|
79
79
|
|
|
80
80
|
/** Update rows in a table matching filter, returns affected row count. */
|