tina4-nodejs 3.13.9 → 3.13.11

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.13.9)
1
+ # CLAUDE.md — AI Developer Guide for tina4-nodejs (v3.13.11)
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.9 — The Intelligent Native Application 4ramework. A convention-over-configuration structural paradigm. The developer writes TypeScript; Tina4 is invisible infrastructure.
7
+ Tina4 for Node.js/TypeScript v3.13.11 — 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
@@ -3,7 +3,7 @@
3
3
 
4
4
 
5
5
 
6
- "version": "3.13.9",
6
+ "version": "3.13.11",
7
7
 
8
8
  "type": "module",
9
9
  "description": "Tina4 for Node.js/TypeScript \u2014 54 built-in features, zero dependencies",
@@ -481,11 +481,36 @@ export class BaseModel {
481
481
  const pk = ModelClass.getPkField();
482
482
  const pkCol = ModelClass.getPkColumn();
483
483
  const pkValue = this[pk];
484
+ const pkField = (ModelClass.fields as Record<string, FieldDefinition>)[pk];
484
485
  this._relCache = {}; // Clear relationship cache on save
485
486
 
487
+ // v3.13.11 (issue #50.2): for non-auto-increment PKs (user-supplied
488
+ // string IDs like "GC-100"), decide INSERT vs UPDATE on row
489
+ // existence, not on whether the PK is set. Pre-v3.13.11 a
490
+ // natural-key save() always chose UPDATE → matched zero rows →
491
+ // silently returned success without inserting anything.
492
+ //
493
+ // Auto-increment behaviour is unchanged: pkValue is null/undefined
494
+ // → INSERT, pkValue is set → UPDATE.
495
+ let isUpdate = false;
496
+ if (pkValue !== undefined && pkValue !== null) {
497
+ if (pkField?.autoIncrement) {
498
+ isUpdate = true;
499
+ } else {
500
+ try {
501
+ isUpdate = ModelClass.exists(pkValue);
502
+ } catch {
503
+ // If we can't tell (e.g. table doesn't exist yet), fall back
504
+ // to INSERT so the user sees the real driver error rather
505
+ // than a silent no-op.
506
+ isUpdate = false;
507
+ }
508
+ }
509
+ }
510
+
486
511
  db.startTransaction();
487
512
  try {
488
- if (pkValue !== undefined && pkValue !== null) {
513
+ if (isUpdate) {
489
514
  // Update
490
515
  const updateFields = Object.entries(ModelClass.fields).filter(
491
516
  ([name, def]) => !def.primaryKey && this[name] !== undefined,
@@ -511,7 +536,12 @@ export class BaseModel {
511
536
  values,
512
537
  ) as { lastInsertRowid?: number };
513
538
 
514
- if (result.lastInsertRowid) {
539
+ // v3.13.11 (issue #50.2): only adopt the engine-assigned ID
540
+ // for auto-increment PKs. A natural-key PK was already set by
541
+ // the caller; don't overwrite it with the driver's last_id
542
+ // (which on PG would be a sequence value that doesn't apply
543
+ // to this row).
544
+ if (result.lastInsertRowid && pkField?.autoIncrement) {
515
545
  this[pk] = result.lastInsertRowid;
516
546
  }
517
547
  }