@belopash/typeorm-store 2.0.0-rc.7 → 2.0.0-rc.8
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/lib/utils/cacheMap.d.ts
CHANGED
|
@@ -25,8 +25,13 @@ export declare class CacheMap {
|
|
|
25
25
|
/**
|
|
26
26
|
* Store `entity` as the canonical instance for its id.
|
|
27
27
|
*
|
|
28
|
-
* `fromQuery` — the entity came from a TypeORM query
|
|
29
|
-
*
|
|
28
|
+
* `fromQuery` — the entity came from a TypeORM query. If no instance is cached yet,
|
|
29
|
+
* stores it and captures a baseline snapshot for dirty detection. If a different
|
|
30
|
+
* instance is already cached, the cached one is kept (it may be a reference already
|
|
31
|
+
* handed back to user code in a concurrent read); the baseline is only refreshed
|
|
32
|
+
* when that cached instance is still clean (no in-memory mutations vs. its baseline).
|
|
33
|
+
* This avoids silently dropping mutations made through one reference when a parallel
|
|
34
|
+
* `find()` re-loads the same row through a JOIN and traverses it through `persist`.
|
|
30
35
|
*
|
|
31
36
|
* `overwrite` — the caller explicitly requested upsert semantics (`replace: true`);
|
|
32
37
|
* replaces any existing instance without touching `loadedFromDb` / `baseline`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cacheMap.d.ts","sourceRoot":"","sources":["../../src/utils/cacheMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAA;AACtC,OAAO,EAAC,aAAa,EAAC,MAAM,QAAQ,CAAA;AACpC,OAAO,EAAC,MAAM,EAAC,MAAM,kBAAkB,CAAA;AAEvC,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,EAAE,CAEhG;AAQD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAM7G;AAED,qBAAa,YAAY,CAAC,CAAC,SAAS,aAAa,GAAG,aAAa;IAC7D,KAAK,EAAE,CAAC,GAAG,IAAI,CAAO;IACtB,YAAY,UAAQ;IACpB,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAAO;CACpC;AAED,qBAAa,QAAQ;IACjB,OAAO,CAAC,GAAG,CAA4D;IACvE,OAAO,CAAC,MAAM,CAAC,CAAQ;gBAEX,MAAM,CAAC,EAAE,MAAM;IAI3B,GAAG,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAInE,GAAG,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO;IAIlD,MAAM,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAQlD,MAAM,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAKlD,KAAK,IAAI,IAAI;IAKb;;;OAGG;IACH,sBAAsB,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI;IAO7E
|
|
1
|
+
{"version":3,"file":"cacheMap.d.ts","sourceRoot":"","sources":["../../src/utils/cacheMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAA;AACtC,OAAO,EAAC,aAAa,EAAC,MAAM,QAAQ,CAAA;AACpC,OAAO,EAAC,MAAM,EAAC,MAAM,kBAAkB,CAAA;AAEvC,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,EAAE,CAEhG;AAQD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAM7G;AAED,qBAAa,YAAY,CAAC,CAAC,SAAS,aAAa,GAAG,aAAa;IAC7D,KAAK,EAAE,CAAC,GAAG,IAAI,CAAO;IACtB,YAAY,UAAQ;IACpB,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAAO;CACpC;AAED,qBAAa,QAAQ;IACjB,OAAO,CAAC,GAAG,CAA4D;IACvE,OAAO,CAAC,MAAM,CAAC,CAAQ;gBAEX,MAAM,CAAC,EAAE,MAAM;IAI3B,GAAG,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAInE,GAAG,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO;IAIlD,MAAM,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAQlD,MAAM,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAKlD,KAAK,IAAI,IAAI;IAKb;;;OAGG;IACH,sBAAsB,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI;IAO7E;;;;;;;;;;;;;;;OAeG;IACH,GAAG,CAAC,CAAC,SAAS,aAAa,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE;QAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAC,GAAG,IAAI;IAuD1H,OAAO,CAAC,cAAc;CAQzB"}
|
package/lib/utils/cacheMap.js
CHANGED
|
@@ -69,8 +69,13 @@ class CacheMap {
|
|
|
69
69
|
/**
|
|
70
70
|
* Store `entity` as the canonical instance for its id.
|
|
71
71
|
*
|
|
72
|
-
* `fromQuery` — the entity came from a TypeORM query
|
|
73
|
-
*
|
|
72
|
+
* `fromQuery` — the entity came from a TypeORM query. If no instance is cached yet,
|
|
73
|
+
* stores it and captures a baseline snapshot for dirty detection. If a different
|
|
74
|
+
* instance is already cached, the cached one is kept (it may be a reference already
|
|
75
|
+
* handed back to user code in a concurrent read); the baseline is only refreshed
|
|
76
|
+
* when that cached instance is still clean (no in-memory mutations vs. its baseline).
|
|
77
|
+
* This avoids silently dropping mutations made through one reference when a parallel
|
|
78
|
+
* `find()` re-loads the same row through a JOIN and traverses it through `persist`.
|
|
74
79
|
*
|
|
75
80
|
* `overwrite` — the caller explicitly requested upsert semantics (`replace: true`);
|
|
76
81
|
* replaces any existing instance without touching `loadedFromDb` / `baseline`.
|
|
@@ -96,10 +101,22 @@ class CacheMap {
|
|
|
96
101
|
if (cached.value === entity)
|
|
97
102
|
return;
|
|
98
103
|
if (opts?.fromQuery) {
|
|
99
|
-
cached
|
|
104
|
+
// Preserve the canonical cached instance: a concurrent reader may already
|
|
105
|
+
// hold a reference to it and be about to mutate it. Replacing it here would
|
|
106
|
+
// silently drop those mutations and reset the baseline to the freshly-loaded
|
|
107
|
+
// (untouched) row, so dirty-detection at sync time would miss the change.
|
|
108
|
+
const cachedValue = cached.value;
|
|
109
|
+
const cachedClean = cached.loadedFromDb &&
|
|
110
|
+
cached.baseline != null &&
|
|
111
|
+
!isSnapshotDirty(metadata, cachedValue, cached.baseline);
|
|
112
|
+
if (cachedClean || !cached.loadedFromDb) {
|
|
113
|
+
// Cached instance has no pending in-memory mutations (or has never been
|
|
114
|
+
// associated with a DB baseline at all). Safe to align baseline to the
|
|
115
|
+
// latest DB read so future dirty detection works against fresh data.
|
|
116
|
+
cached.baseline = captureColumnSnapshot(metadata, cachedValue);
|
|
117
|
+
}
|
|
100
118
|
cached.loadedFromDb = true;
|
|
101
|
-
|
|
102
|
-
this.logger?.debug(`replaced entity from query ${metadata.name} ${entity.id}`);
|
|
119
|
+
this.logger?.debug(`refreshed entity from query ${metadata.name} ${entity.id}`);
|
|
103
120
|
return;
|
|
104
121
|
}
|
|
105
122
|
if (opts?.overwrite) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cacheMap.js","sourceRoot":"","sources":["../../src/utils/cacheMap.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"cacheMap.js","sourceRoot":"","sources":["../../src/utils/cacheMap.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/utils/cacheMap.ts
CHANGED
|
@@ -74,8 +74,13 @@ export class CacheMap {
|
|
|
74
74
|
/**
|
|
75
75
|
* Store `entity` as the canonical instance for its id.
|
|
76
76
|
*
|
|
77
|
-
* `fromQuery` — the entity came from a TypeORM query
|
|
78
|
-
*
|
|
77
|
+
* `fromQuery` — the entity came from a TypeORM query. If no instance is cached yet,
|
|
78
|
+
* stores it and captures a baseline snapshot for dirty detection. If a different
|
|
79
|
+
* instance is already cached, the cached one is kept (it may be a reference already
|
|
80
|
+
* handed back to user code in a concurrent read); the baseline is only refreshed
|
|
81
|
+
* when that cached instance is still clean (no in-memory mutations vs. its baseline).
|
|
82
|
+
* This avoids silently dropping mutations made through one reference when a parallel
|
|
83
|
+
* `find()` re-loads the same row through a JOIN and traverses it through `persist`.
|
|
79
84
|
*
|
|
80
85
|
* `overwrite` — the caller explicitly requested upsert semantics (`replace: true`);
|
|
81
86
|
* replaces any existing instance without touching `loadedFromDb` / `baseline`.
|
|
@@ -104,10 +109,23 @@ export class CacheMap {
|
|
|
104
109
|
if (cached.value === entity) return
|
|
105
110
|
|
|
106
111
|
if (opts?.fromQuery) {
|
|
107
|
-
cached
|
|
112
|
+
// Preserve the canonical cached instance: a concurrent reader may already
|
|
113
|
+
// hold a reference to it and be about to mutate it. Replacing it here would
|
|
114
|
+
// silently drop those mutations and reset the baseline to the freshly-loaded
|
|
115
|
+
// (untouched) row, so dirty-detection at sync time would miss the change.
|
|
116
|
+
const cachedValue = cached.value
|
|
117
|
+
const cachedClean =
|
|
118
|
+
cached.loadedFromDb &&
|
|
119
|
+
cached.baseline != null &&
|
|
120
|
+
!isSnapshotDirty(metadata, cachedValue, cached.baseline)
|
|
121
|
+
if (cachedClean || !cached.loadedFromDb) {
|
|
122
|
+
// Cached instance has no pending in-memory mutations (or has never been
|
|
123
|
+
// associated with a DB baseline at all). Safe to align baseline to the
|
|
124
|
+
// latest DB read so future dirty detection works against fresh data.
|
|
125
|
+
cached.baseline = captureColumnSnapshot(metadata, cachedValue)
|
|
126
|
+
}
|
|
108
127
|
cached.loadedFromDb = true
|
|
109
|
-
|
|
110
|
-
this.logger?.debug(`replaced entity from query ${metadata.name} ${entity.id}`)
|
|
128
|
+
this.logger?.debug(`refreshed entity from query ${metadata.name} ${entity.id}`)
|
|
111
129
|
return
|
|
112
130
|
}
|
|
113
131
|
|