tina4-nodejs 3.13.25 → 3.13.26
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 +7 -4
- package/package.json +1 -1
- package/packages/orm/src/database.ts +25 -6
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.26)
|
|
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.26 — 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
|
|
|
@@ -575,7 +575,10 @@ db.delete(table, filter?, params?): DatabaseWriteResult
|
|
|
575
575
|
db.getLastId(): string | number | null
|
|
576
576
|
db.getError(): string | null
|
|
577
577
|
|
|
578
|
-
// Transactions — autoCommit defaults to
|
|
578
|
+
// Transactions — autoCommit defaults to ON: a standalone write commits on its
|
|
579
|
+
// own connection (durable + visible across the pool); inside startTransaction()
|
|
580
|
+
// the per-statement commit is suppressed so the transaction stays atomic. Set
|
|
581
|
+
// TINA4_AUTOCOMMIT=false for strict manual-commit mode.
|
|
579
582
|
db.startTransaction(): void
|
|
580
583
|
db.commit(): void
|
|
581
584
|
db.rollback(): void
|
|
@@ -1114,7 +1117,7 @@ When adding new features, add a corresponding `test/<feature>.test.ts` file.
|
|
|
1114
1117
|
## v3 Features Summary
|
|
1115
1118
|
|
|
1116
1119
|
- **45 built-in features**, zero third-party dependencies
|
|
1117
|
-
- **3,
|
|
1120
|
+
- **3,748 tests** passing across all modules
|
|
1118
1121
|
- **Race-safe `getNextId()`** with atomic sequence table (`tina4_sequences`) for SQLite/MySQL/MSSQL; PostgreSQL auto-creates sequences
|
|
1119
1122
|
- **Frond template engine optimizations**: pre-compiled regexes, lazy loop context (copy-on-write), filter chain caching, path split caching, inline common filters (11-15% speedup)
|
|
1120
1123
|
- **Production server auto-detect**: `npx tina4nodejs serve --production` auto-uses cluster mode
|
package/package.json
CHANGED
|
@@ -458,8 +458,17 @@ export class Database {
|
|
|
458
458
|
/** Factory for creating new adapters (used by pool) */
|
|
459
459
|
private adapterFactory: (() => Promise<DatabaseAdapter>) | null = null;
|
|
460
460
|
|
|
461
|
-
/**
|
|
462
|
-
|
|
461
|
+
/**
|
|
462
|
+
* Whether a standalone write auto-commits. ON by default — a write made
|
|
463
|
+
* outside an explicit transaction commits on its own connection before
|
|
464
|
+
* returning (so it's durable and visible across pooled connections). Inside
|
|
465
|
+
* startTransaction()/commit()/rollback() the per-statement commit is
|
|
466
|
+
* suppressed, so explicit transactions stay atomic. Set TINA4_AUTOCOMMIT=false
|
|
467
|
+
* for strict manual-commit mode.
|
|
468
|
+
*/
|
|
469
|
+
private autoCommit: boolean = ["true", "1", "yes"].includes(
|
|
470
|
+
(process.env.TINA4_AUTOCOMMIT ?? "true").toLowerCase(),
|
|
471
|
+
);
|
|
463
472
|
private lastError: string | null = null;
|
|
464
473
|
|
|
465
474
|
/** Database engine type (sqlite, postgres, mysql, mssql, firebird) */
|
|
@@ -675,7 +684,7 @@ export class Database {
|
|
|
675
684
|
try {
|
|
676
685
|
const adapter = this.getNextAdapter();
|
|
677
686
|
const result = await adapterExecute(adapter, sql, params);
|
|
678
|
-
if (this.autoCommit) {
|
|
687
|
+
if (this.autoCommit && !this.inExplicitTransaction()) {
|
|
679
688
|
try { await adapterCommit(adapter); } catch { /* no active transaction */ }
|
|
680
689
|
}
|
|
681
690
|
this.lastError = null;
|
|
@@ -697,7 +706,7 @@ export class Database {
|
|
|
697
706
|
const result = (adapter as any).insertAsync
|
|
698
707
|
? await (adapter as any).insertAsync(table, data)
|
|
699
708
|
: adapter.insert(table, data);
|
|
700
|
-
if (this.autoCommit) {
|
|
709
|
+
if (this.autoCommit && !this.inExplicitTransaction()) {
|
|
701
710
|
try { await adapterCommit(adapter); } catch { /* no active transaction */ }
|
|
702
711
|
}
|
|
703
712
|
return result;
|
|
@@ -709,7 +718,7 @@ export class Database {
|
|
|
709
718
|
const result = (adapter as any).updateAsync
|
|
710
719
|
? await (adapter as any).updateAsync(table, data, filter ?? {}, params)
|
|
711
720
|
: adapter.update(table, data, filter ?? {}, params);
|
|
712
|
-
if (this.autoCommit) {
|
|
721
|
+
if (this.autoCommit && !this.inExplicitTransaction()) {
|
|
713
722
|
try { await adapterCommit(adapter); } catch { /* no active transaction */ }
|
|
714
723
|
}
|
|
715
724
|
return result;
|
|
@@ -721,7 +730,7 @@ export class Database {
|
|
|
721
730
|
const result = (adapter as any).deleteAsync
|
|
722
731
|
? await (adapter as any).deleteAsync(table, filter ?? {}, params)
|
|
723
732
|
: adapter.delete(table, filter ?? {}, params);
|
|
724
|
-
if (this.autoCommit) {
|
|
733
|
+
if (this.autoCommit && !this.inExplicitTransaction()) {
|
|
725
734
|
try { await adapterCommit(adapter); } catch { /* no active transaction */ }
|
|
726
735
|
}
|
|
727
736
|
return result;
|
|
@@ -741,6 +750,16 @@ export class Database {
|
|
|
741
750
|
}
|
|
742
751
|
}
|
|
743
752
|
|
|
753
|
+
/**
|
|
754
|
+
* True while an explicit transaction is active on the current async context.
|
|
755
|
+
* startTransaction() pins an adapter into txStore; commit()/rollback() clear
|
|
756
|
+
* it. Standalone writes only auto-commit when this is false, so per-statement
|
|
757
|
+
* commits never break the atomicity of an explicit transaction.
|
|
758
|
+
*/
|
|
759
|
+
private inExplicitTransaction(): boolean {
|
|
760
|
+
return !!this.txStore.getStore()?.adapter;
|
|
761
|
+
}
|
|
762
|
+
|
|
744
763
|
/**
|
|
745
764
|
* Start a transaction. Pins the adapter to the current async context for
|
|
746
765
|
* the whole transaction so executes and the final commit/rollback all run
|