masterrecord 0.3.49 → 0.3.51
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/settings.local.json +2 -1
- package/QueryLanguage/queryMethods.js +23 -13
- package/context.js +174 -8
- package/package.json +1 -1
- package/test/ensure-ready-test.js +251 -0
- package/test/pool-registry-test.js +303 -0
- package/test/multiContextCacheSimple.test.js +0 -185
- package/test/simple-id-test.js +0 -61
- package/test/single-user-id-test.js +0 -70
- package/test/verifyFindById.js +0 -169
- package/test/verifyNewMethod.js +0 -191
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test: Global Pool Registry — One Pool Per Database
|
|
3
|
+
*
|
|
4
|
+
* Verifies that multiple context instances share the same connection pool
|
|
5
|
+
* instead of creating a new pool per instance (the bug this fixes).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const context = require('../context');
|
|
9
|
+
|
|
10
|
+
console.log("╔════════════════════════════════════════════════════════════════╗");
|
|
11
|
+
console.log("║ Pool Registry Test — One Pool Per Database ║");
|
|
12
|
+
console.log("╚════════════════════════════════════════════════════════════════╝\n");
|
|
13
|
+
|
|
14
|
+
let passed = 0;
|
|
15
|
+
let failed = 0;
|
|
16
|
+
|
|
17
|
+
function assert(condition, passMsg, failMsg) {
|
|
18
|
+
if (condition) {
|
|
19
|
+
console.log(` ✓ ${passMsg}`);
|
|
20
|
+
passed++;
|
|
21
|
+
} else {
|
|
22
|
+
console.log(` ✗ ${failMsg}`);
|
|
23
|
+
failed++;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Test 1: _pools global registry exists
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
console.log("📝 Test 1: Global pool registry exists");
|
|
31
|
+
console.log("──────────────────────────────────────────────────");
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const pools = global.__MR_POOLS__;
|
|
35
|
+
assert(
|
|
36
|
+
pools instanceof Map,
|
|
37
|
+
"global.__MR_POOLS__ is a Map",
|
|
38
|
+
`global.__MR_POOLS__ is not a Map (got: ${typeof pools})`
|
|
39
|
+
);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
42
|
+
failed++;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Test 2: closeAll() is a static method
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
console.log("\n📝 Test 2: context.closeAll() is a static method");
|
|
49
|
+
console.log("──────────────────────────────────────────────────");
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
assert(
|
|
53
|
+
typeof context.closeAll === 'function',
|
|
54
|
+
"context.closeAll exists and is a function",
|
|
55
|
+
`context.closeAll is not a function (got: ${typeof context.closeAll})`
|
|
56
|
+
);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
59
|
+
failed++;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// Test 3: getPoolStats() is a static method
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
console.log("\n📝 Test 3: context.getPoolStats() is a static method");
|
|
66
|
+
console.log("──────────────────────────────────────────────────");
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
assert(
|
|
70
|
+
typeof context.getPoolStats === 'function',
|
|
71
|
+
"context.getPoolStats exists and is a function",
|
|
72
|
+
`context.getPoolStats is not a function (got: ${typeof context.getPoolStats})`
|
|
73
|
+
);
|
|
74
|
+
} catch (err) {
|
|
75
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
76
|
+
failed++;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Test 4: getPoolStats() returns an array
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
console.log("\n📝 Test 4: getPoolStats() returns an array");
|
|
83
|
+
console.log("──────────────────────────────────────────────────");
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const stats = context.getPoolStats();
|
|
87
|
+
assert(
|
|
88
|
+
Array.isArray(stats),
|
|
89
|
+
`getPoolStats() returned array with ${stats.length} entries`,
|
|
90
|
+
`Expected array, got: ${typeof stats}`
|
|
91
|
+
);
|
|
92
|
+
} catch (err) {
|
|
93
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
94
|
+
failed++;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Async tests wrapped in IIFE
|
|
98
|
+
(async function runAsyncTests() {
|
|
99
|
+
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// Test 5: closeAll() clears the registry
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
console.log("\n📝 Test 5: closeAll() clears the registry");
|
|
104
|
+
console.log("──────────────────────────────────────────────────");
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const pools = global.__MR_POOLS__;
|
|
108
|
+
pools.set('test:fake@localhost:5432/testdb', {
|
|
109
|
+
engine: { close: function() {} },
|
|
110
|
+
refCount: 1,
|
|
111
|
+
dbType: 'test'
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const beforeSize = pools.size;
|
|
115
|
+
await context.closeAll();
|
|
116
|
+
const afterSize = pools.size;
|
|
117
|
+
|
|
118
|
+
assert(
|
|
119
|
+
beforeSize > 0 && afterSize === 0,
|
|
120
|
+
`Registry had ${beforeSize} entry, now has ${afterSize} after closeAll()`,
|
|
121
|
+
`Expected registry to be cleared (before: ${beforeSize}, after: ${afterSize})`
|
|
122
|
+
);
|
|
123
|
+
} catch (err) {
|
|
124
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
125
|
+
failed++;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// Test 6: close() on instance decrements refCount
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
console.log("\n📝 Test 6: close() decrements refCount");
|
|
132
|
+
console.log("──────────────────────────────────────────────────");
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
const pools = global.__MR_POOLS__;
|
|
136
|
+
const fakeEngine = { close: function() { return Promise.resolve(); } };
|
|
137
|
+
|
|
138
|
+
pools.set('test:ref-count-test', {
|
|
139
|
+
engine: fakeEngine,
|
|
140
|
+
refCount: 2,
|
|
141
|
+
dbType: 'test'
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
class TestCtx extends context {
|
|
145
|
+
constructor() { super(); }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const db = new TestCtx();
|
|
149
|
+
db._SQLEngine = fakeEngine;
|
|
150
|
+
|
|
151
|
+
await db.close();
|
|
152
|
+
|
|
153
|
+
const entry = pools.get('test:ref-count-test');
|
|
154
|
+
|
|
155
|
+
assert(
|
|
156
|
+
entry && entry.refCount === 1,
|
|
157
|
+
"refCount decremented from 2 to 1 — pool NOT closed (still has references)",
|
|
158
|
+
entry ? `Expected refCount 1, got ${entry.refCount}` : "Entry was deleted (should still exist with refCount 1)"
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
pools.delete('test:ref-count-test');
|
|
162
|
+
} catch (err) {
|
|
163
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
164
|
+
failed++;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
// Test 7: close() removes pool when refCount reaches 0
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
console.log("\n📝 Test 7: close() removes pool when refCount reaches 0");
|
|
171
|
+
console.log("──────────────────────────────────────────────────");
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
const pools = global.__MR_POOLS__;
|
|
175
|
+
let closeCalled = false;
|
|
176
|
+
const fakeEngine = { close: function() { closeCalled = true; return Promise.resolve(); } };
|
|
177
|
+
|
|
178
|
+
pools.set('test:last-ref-test', {
|
|
179
|
+
engine: fakeEngine,
|
|
180
|
+
refCount: 1,
|
|
181
|
+
dbType: 'test'
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
class TestCtx2 extends context {
|
|
185
|
+
constructor() { super(); }
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const db = new TestCtx2();
|
|
189
|
+
db._SQLEngine = fakeEngine;
|
|
190
|
+
|
|
191
|
+
await db.close();
|
|
192
|
+
|
|
193
|
+
const entry = pools.get('test:last-ref-test');
|
|
194
|
+
|
|
195
|
+
assert(
|
|
196
|
+
!entry && closeCalled,
|
|
197
|
+
"Pool removed from registry when refCount reached 0, engine.close() called",
|
|
198
|
+
entry ? `Entry still exists with refCount ${entry.refCount}` : "Entry removed but engine.close() was not called"
|
|
199
|
+
);
|
|
200
|
+
} catch (err) {
|
|
201
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
202
|
+
failed++;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// ---------------------------------------------------------------------------
|
|
206
|
+
// Test 8: getPoolStats() returns correct shape
|
|
207
|
+
// ---------------------------------------------------------------------------
|
|
208
|
+
console.log("\n📝 Test 8: Pool registry entries have correct shape");
|
|
209
|
+
console.log("──────────────────────────────────────────────────");
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
const pools = global.__MR_POOLS__;
|
|
213
|
+
const fakeEngine = { close: function() {} };
|
|
214
|
+
|
|
215
|
+
pools.set('mysql:testuser@localhost:3306/testdb', {
|
|
216
|
+
client: {},
|
|
217
|
+
engine: fakeEngine,
|
|
218
|
+
refCount: 3,
|
|
219
|
+
dbType: 'mysql'
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const stats = context.getPoolStats();
|
|
223
|
+
const mysqlStat = stats.find(function(s) { return s.key === 'mysql:testuser@localhost:3306/testdb'; });
|
|
224
|
+
|
|
225
|
+
assert(
|
|
226
|
+
mysqlStat && mysqlStat.dbType === 'mysql' && mysqlStat.refCount === 3,
|
|
227
|
+
`getPoolStats() correct: ${mysqlStat.key} (type: ${mysqlStat.dbType}, refs: ${mysqlStat.refCount})`,
|
|
228
|
+
`Expected mysql entry with refCount 3, got: ${JSON.stringify(mysqlStat)}`
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
pools.delete('mysql:testuser@localhost:3306/testdb');
|
|
232
|
+
} catch (err) {
|
|
233
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
234
|
+
failed++;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
// Test 9: Two context instances with same fake engine share one pool entry
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
console.log("\n📝 Test 9: Two instances sharing a pool both decrement correctly");
|
|
241
|
+
console.log("──────────────────────────────────────────────────");
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
const pools = global.__MR_POOLS__;
|
|
245
|
+
let closeCalled = false;
|
|
246
|
+
const sharedEngine = { close: function() { closeCalled = true; return Promise.resolve(); } };
|
|
247
|
+
|
|
248
|
+
pools.set('test:shared-engine', {
|
|
249
|
+
engine: sharedEngine,
|
|
250
|
+
refCount: 2,
|
|
251
|
+
dbType: 'test'
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
class TestCtx3 extends context {
|
|
255
|
+
constructor() { super(); }
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const db1 = new TestCtx3();
|
|
259
|
+
db1._SQLEngine = sharedEngine;
|
|
260
|
+
|
|
261
|
+
const db2 = new TestCtx3();
|
|
262
|
+
db2._SQLEngine = sharedEngine;
|
|
263
|
+
|
|
264
|
+
// First close: refCount 2 -> 1
|
|
265
|
+
await db1.close();
|
|
266
|
+
let entry = pools.get('test:shared-engine');
|
|
267
|
+
const afterFirst = entry ? entry.refCount : -1;
|
|
268
|
+
|
|
269
|
+
// Second close: refCount 1 -> 0, pool removed
|
|
270
|
+
await db2.close();
|
|
271
|
+
entry = pools.get('test:shared-engine');
|
|
272
|
+
|
|
273
|
+
assert(
|
|
274
|
+
afterFirst === 1 && !entry && closeCalled,
|
|
275
|
+
"First close: refs 2->1. Second close: refs 1->0, pool destroyed, engine.close() called",
|
|
276
|
+
`afterFirst=${afterFirst}, entryGone=${!entry}, closeCalled=${closeCalled}`
|
|
277
|
+
);
|
|
278
|
+
} catch (err) {
|
|
279
|
+
console.log(` ✗ Error: ${err.message}`);
|
|
280
|
+
failed++;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// ---------------------------------------------------------------------------
|
|
284
|
+
// Summary
|
|
285
|
+
// ---------------------------------------------------------------------------
|
|
286
|
+
console.log("\n╔════════════════════════════════════════════════════════════════╗");
|
|
287
|
+
console.log("║ Test Summary ║");
|
|
288
|
+
console.log("╚════════════════════════════════════════════════════════════════╝");
|
|
289
|
+
console.log(`\n ✓ Passed: ${passed}`);
|
|
290
|
+
console.log(` ✗ Failed: ${failed}`);
|
|
291
|
+
console.log(` 📊 Total: ${passed + failed}\n`);
|
|
292
|
+
|
|
293
|
+
if (failed === 0) {
|
|
294
|
+
console.log(" 🎉 All tests passed!\n");
|
|
295
|
+
console.log(" ✅ Global pool registry is working correctly");
|
|
296
|
+
console.log(" ✅ One pool per database — no more connection exhaustion\n");
|
|
297
|
+
process.exit(0);
|
|
298
|
+
} else {
|
|
299
|
+
console.log(" ❌ Some tests failed\n");
|
|
300
|
+
process.exit(1);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
})();
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test: Static Cache Sharing
|
|
3
|
-
* Verifies the cache is static/shared as designed
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const QueryCache = require('../Cache/QueryCache');
|
|
7
|
-
|
|
8
|
-
console.log("╔════════════════════════════════════════════════════════════════╗");
|
|
9
|
-
console.log("║ Static Cache Test ║");
|
|
10
|
-
console.log("╚════════════════════════════════════════════════════════════════╝\n");
|
|
11
|
-
|
|
12
|
-
let passed = 0;
|
|
13
|
-
let failed = 0;
|
|
14
|
-
|
|
15
|
-
// Simulate context class with static shared cache
|
|
16
|
-
class SimulatedContext {
|
|
17
|
-
static _sharedQueryCache = null;
|
|
18
|
-
|
|
19
|
-
constructor() {
|
|
20
|
-
// Initialize shared query cache (only once across all instances)
|
|
21
|
-
if (!SimulatedContext._sharedQueryCache) {
|
|
22
|
-
SimulatedContext._sharedQueryCache = new QueryCache({
|
|
23
|
-
ttl: 5 * 60 * 1000,
|
|
24
|
-
maxSize: 1000,
|
|
25
|
-
enabled: true
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Reference the shared cache
|
|
30
|
-
this._queryCache = SimulatedContext._sharedQueryCache;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
getCacheStats() {
|
|
34
|
-
return this._queryCache.getStats();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
clearQueryCache() {
|
|
38
|
-
this._queryCache.clear();
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Test 1: Multiple instances share the same cache
|
|
43
|
-
console.log("📝 Test 1: Multiple instances share same cache");
|
|
44
|
-
console.log("──────────────────────────────────────────────────");
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
const ctx1 = new SimulatedContext();
|
|
48
|
-
const ctx2 = new SimulatedContext();
|
|
49
|
-
|
|
50
|
-
const areSame = ctx1._queryCache === ctx2._queryCache;
|
|
51
|
-
const isStatic = ctx1._queryCache === SimulatedContext._sharedQueryCache;
|
|
52
|
-
|
|
53
|
-
if(areSame && isStatic) {
|
|
54
|
-
console.log(" ✓ Both instances share the same cache");
|
|
55
|
-
console.log(" ✓ Cache is stored in static property");
|
|
56
|
-
passed++;
|
|
57
|
-
} else {
|
|
58
|
-
console.log(` ✗ Instances have separate caches`);
|
|
59
|
-
failed++;
|
|
60
|
-
}
|
|
61
|
-
} catch(err) {
|
|
62
|
-
console.log(` ✗ Error: ${err.message}`);
|
|
63
|
-
failed++;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Test 2: Cache SET in one instance visible in another
|
|
67
|
-
console.log("\n📝 Test 2: Cache operations are shared");
|
|
68
|
-
console.log("──────────────────────────────────────────────────");
|
|
69
|
-
|
|
70
|
-
try {
|
|
71
|
-
const ctx1 = new SimulatedContext();
|
|
72
|
-
const ctx2 = new SimulatedContext();
|
|
73
|
-
|
|
74
|
-
// Instance 1: Add to cache
|
|
75
|
-
const key = ctx1._queryCache.generateKey('SELECT * FROM users', [], 'users');
|
|
76
|
-
ctx1._queryCache.set(key, [{ id: 1, name: 'Alice' }], 'users');
|
|
77
|
-
|
|
78
|
-
// Instance 2: Should see the same cached data
|
|
79
|
-
const cached = ctx2._queryCache.get(key);
|
|
80
|
-
|
|
81
|
-
if(cached && cached[0].name === 'Alice') {
|
|
82
|
-
console.log(" ✓ Cache data visible across instances");
|
|
83
|
-
console.log(" ✓ Data written by ctx1, read by ctx2");
|
|
84
|
-
passed++;
|
|
85
|
-
} else {
|
|
86
|
-
console.log(` ✗ Cache data not shared`);
|
|
87
|
-
failed++;
|
|
88
|
-
}
|
|
89
|
-
} catch(err) {
|
|
90
|
-
console.log(` ✗ Error: ${err.message}`);
|
|
91
|
-
failed++;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Test 3: Cache invalidation in one instance affects another
|
|
95
|
-
console.log("\n📝 Test 3: Cache invalidation is shared");
|
|
96
|
-
console.log("──────────────────────────────────────────────────");
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
const ctx1 = new SimulatedContext();
|
|
100
|
-
const ctx2 = new SimulatedContext();
|
|
101
|
-
|
|
102
|
-
// Clear for clean test
|
|
103
|
-
ctx1._queryCache.clear();
|
|
104
|
-
|
|
105
|
-
// Instance 1: Add entries
|
|
106
|
-
const key1 = ctx1._queryCache.generateKey('query1', [], 'users');
|
|
107
|
-
const key2 = ctx1._queryCache.generateKey('query2', [], 'users');
|
|
108
|
-
ctx1._queryCache.set(key1, { id: 1 }, 'users');
|
|
109
|
-
ctx1._queryCache.set(key2, { id: 2 }, 'users');
|
|
110
|
-
|
|
111
|
-
// Verify both cached
|
|
112
|
-
const before1 = ctx1._queryCache.get(key1);
|
|
113
|
-
const before2 = ctx2._queryCache.get(key2);
|
|
114
|
-
|
|
115
|
-
// Instance 2: Invalidate
|
|
116
|
-
ctx2._queryCache.invalidateTable('users');
|
|
117
|
-
|
|
118
|
-
// Both instances should see empty cache
|
|
119
|
-
const after1 = ctx1._queryCache.get(key1);
|
|
120
|
-
const after2 = ctx2._queryCache.get(key2);
|
|
121
|
-
|
|
122
|
-
if(before1 !== null && before2 !== null && after1 === null && after2 === null) {
|
|
123
|
-
console.log(" ✓ Invalidation in ctx2 affected ctx1");
|
|
124
|
-
console.log(" ✓ Cache properly shared");
|
|
125
|
-
passed++;
|
|
126
|
-
} else {
|
|
127
|
-
console.log(` ✗ Invalidation not shared`);
|
|
128
|
-
failed++;
|
|
129
|
-
}
|
|
130
|
-
} catch(err) {
|
|
131
|
-
console.log(` ✗ Error: ${err.message}`);
|
|
132
|
-
failed++;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Test 4: Statistics are shared
|
|
136
|
-
console.log("\n📝 Test 4: Statistics are shared");
|
|
137
|
-
console.log("──────────────────────────────────────────────────");
|
|
138
|
-
|
|
139
|
-
try {
|
|
140
|
-
const ctx1 = new SimulatedContext();
|
|
141
|
-
const ctx2 = new SimulatedContext();
|
|
142
|
-
|
|
143
|
-
// Clear for clean test
|
|
144
|
-
ctx1.clearQueryCache();
|
|
145
|
-
|
|
146
|
-
// Instance 1: Generate activity
|
|
147
|
-
const key = ctx1._queryCache.generateKey('test', [], 'users');
|
|
148
|
-
ctx1._queryCache.set(key, 'data', 'users');
|
|
149
|
-
ctx1._queryCache.get(key); // Hit
|
|
150
|
-
ctx1._queryCache.get('nonexistent'); // Miss
|
|
151
|
-
|
|
152
|
-
// Both instances should see same stats
|
|
153
|
-
const stats1 = ctx1.getCacheStats();
|
|
154
|
-
const stats2 = ctx2.getCacheStats();
|
|
155
|
-
|
|
156
|
-
if(stats1.hits === 1 && stats2.hits === 1 && stats1.misses === 1 && stats2.misses === 1) {
|
|
157
|
-
console.log(" ✓ Statistics shared across instances");
|
|
158
|
-
console.log(` ✓ Both see: ${stats1.hits} hit, ${stats1.misses} miss`);
|
|
159
|
-
passed++;
|
|
160
|
-
} else {
|
|
161
|
-
console.log(` ✗ Statistics not shared`);
|
|
162
|
-
failed++;
|
|
163
|
-
}
|
|
164
|
-
} catch(err) {
|
|
165
|
-
console.log(` ✗ Error: ${err.message}`);
|
|
166
|
-
failed++;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Summary
|
|
170
|
-
console.log("\n╔════════════════════════════════════════════════════════════════╗");
|
|
171
|
-
console.log("║ Test Summary ║");
|
|
172
|
-
console.log("╚════════════════════════════════════════════════════════════════╝");
|
|
173
|
-
console.log(`\n ✓ Passed: ${passed}`);
|
|
174
|
-
console.log(` ✗ Failed: ${failed}`);
|
|
175
|
-
console.log(` 📊 Total: ${passed + failed}\n`);
|
|
176
|
-
|
|
177
|
-
if(failed === 0) {
|
|
178
|
-
console.log(" 🎉 All tests passed!\n");
|
|
179
|
-
console.log(" ✅ Static cache pattern verified");
|
|
180
|
-
console.log(" ✅ BUG FIX CONFIRMED: Multi-context cache sharing works!\n");
|
|
181
|
-
process.exit(0);
|
|
182
|
-
} else {
|
|
183
|
-
console.log(" ❌ Some tests failed\n");
|
|
184
|
-
process.exit(1);
|
|
185
|
-
}
|
package/test/simple-id-test.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Simple test to check if ID is set after save
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const masterrecord = require('../MasterRecord.js');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
|
|
9
|
-
class User {
|
|
10
|
-
id(db) {
|
|
11
|
-
db.integer().primary().auto();
|
|
12
|
-
}
|
|
13
|
-
name(db) {
|
|
14
|
-
db.string();
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
class TestContext extends masterrecord.context {
|
|
19
|
-
constructor() {
|
|
20
|
-
super();
|
|
21
|
-
this.database = path.join(__dirname, '..', 'database', 'simpleIdTest.db');
|
|
22
|
-
}
|
|
23
|
-
onConfig(db) {
|
|
24
|
-
this.dbset(User);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Clean
|
|
29
|
-
if (fs.existsSync(path.join(__dirname, '..', 'database', 'simpleIdTest.db'))) {
|
|
30
|
-
fs.unlinkSync(path.join(__dirname, '..', 'database', 'simpleIdTest.db'));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async function test() {
|
|
34
|
-
const db = new TestContext();
|
|
35
|
-
db.onConfig();
|
|
36
|
-
|
|
37
|
-
const user = db.User.new();
|
|
38
|
-
user.name = 'Test';
|
|
39
|
-
|
|
40
|
-
console.log('Before save - user.id:', user.id);
|
|
41
|
-
console.log('Before save - user.__proto__:', Object.keys(user.__proto__));
|
|
42
|
-
|
|
43
|
-
await user.save();
|
|
44
|
-
|
|
45
|
-
console.log('After save - user.id:', user.id);
|
|
46
|
-
console.log('After save - user.__proto__:', Object.keys(user.__proto__));
|
|
47
|
-
console.log('After save - user.__proto__._id:', user.__proto__._id);
|
|
48
|
-
|
|
49
|
-
// Try direct access
|
|
50
|
-
console.log('Direct access test:');
|
|
51
|
-
for (const key in user) {
|
|
52
|
-
if (key === 'id') {
|
|
53
|
-
console.log('Found id property via for-in');
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
console.log('Has own property id?', user.hasOwnProperty('id'));
|
|
58
|
-
console.log('Keys:', Object.keys(user));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
test().catch(console.error);
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Single user ID test
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const masterrecord = require('../MasterRecord.js');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
|
|
9
|
-
class User {
|
|
10
|
-
id(db) {
|
|
11
|
-
db.integer().primary().auto();
|
|
12
|
-
}
|
|
13
|
-
name(db) {
|
|
14
|
-
db.string();
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
class TestContext extends masterrecord.context {
|
|
19
|
-
constructor() {
|
|
20
|
-
super();
|
|
21
|
-
}
|
|
22
|
-
onConfig(db) {
|
|
23
|
-
this.dbset(User);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Clean
|
|
28
|
-
const dbPath = path.join(__dirname, '..', 'database', 'singleUserTest.db');
|
|
29
|
-
if (fs.existsSync(dbPath)) {
|
|
30
|
-
fs.unlinkSync(dbPath);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async function test() {
|
|
34
|
-
const db = new TestContext();
|
|
35
|
-
|
|
36
|
-
// Manually initialize SQLite for testing
|
|
37
|
-
const SQLLiteEngine = require('../SQLLiteEngine');
|
|
38
|
-
const sqlite3 = require('better-sqlite3');
|
|
39
|
-
|
|
40
|
-
db.isSQLite = true;
|
|
41
|
-
db.isMySQL = false;
|
|
42
|
-
db.isPostgres = false;
|
|
43
|
-
db._SQLEngine = new SQLLiteEngine();
|
|
44
|
-
db.db = new sqlite3(dbPath);
|
|
45
|
-
db._SQLEngine.setDB(db.db, 'better-sqlite3');
|
|
46
|
-
|
|
47
|
-
db.onConfig();
|
|
48
|
-
|
|
49
|
-
// Create table
|
|
50
|
-
db.db.exec('CREATE TABLE IF NOT EXISTS User (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)');
|
|
51
|
-
|
|
52
|
-
const user = db.User.new();
|
|
53
|
-
user.name = 'Test';
|
|
54
|
-
|
|
55
|
-
console.log('Before save - user.id:', user.id);
|
|
56
|
-
console.log('Before save - tracked:', db.__trackedEntities.length);
|
|
57
|
-
|
|
58
|
-
await user.save();
|
|
59
|
-
|
|
60
|
-
console.log('After save - user.id:', user.id);
|
|
61
|
-
console.log('After save - user.__proto__._id:', user.__proto__._id);
|
|
62
|
-
|
|
63
|
-
if (user.id) {
|
|
64
|
-
console.log('✓ SUCCESS - ID was set to:', user.id);
|
|
65
|
-
} else {
|
|
66
|
-
console.log('✗ FAIL - ID is still undefined');
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
test().catch(console.error);
|