serializable-bptree 5.1.4 → 5.2.0
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/dist/cjs/index.cjs +177 -288
- package/dist/esm/index.mjs +177 -288
- package/dist/types/BPTreeAsync.d.ts +1 -1
- package/dist/types/BPTreeSync.d.ts +1 -1
- package/dist/types/base/BPTree.d.ts +5 -8
- package/dist/types/index.d.ts +1 -1
- package/package.json +9 -9
package/dist/cjs/index.cjs
CHANGED
|
@@ -62,253 +62,132 @@ var StringComparator = class extends ValueComparator {
|
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
// node_modules/cache-entanglement/dist/esm/index.mjs
|
|
65
|
-
var
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
65
|
+
var LRUMap = class {
|
|
66
|
+
capacity;
|
|
67
|
+
map;
|
|
68
|
+
head = null;
|
|
69
|
+
tail = null;
|
|
70
|
+
constructor(capacity) {
|
|
71
|
+
this.capacity = capacity;
|
|
72
|
+
this.map = /* @__PURE__ */ new Map();
|
|
73
|
+
}
|
|
74
|
+
// 내부 유틸리티: 노드를 헤드로 이동 (가장 최근 사용됨 표시)
|
|
75
|
+
promote(node) {
|
|
76
|
+
this.extract(node);
|
|
77
|
+
this.prepend(node);
|
|
78
|
+
}
|
|
79
|
+
// 내부 유틸리티: 리스트에서 노드 연결 끊기
|
|
80
|
+
extract(node) {
|
|
81
|
+
if (node.prev) node.prev.next = node.next;
|
|
82
|
+
else this.head = node.next;
|
|
83
|
+
if (node.next) node.next.prev = node.prev;
|
|
84
|
+
else this.tail = node.prev;
|
|
85
|
+
node.prev = null;
|
|
86
|
+
node.next = null;
|
|
87
|
+
}
|
|
88
|
+
// 내부 유틸리티: 리스트 맨 앞에 노드 삽입
|
|
89
|
+
prepend(node) {
|
|
90
|
+
node.next = this.head;
|
|
91
|
+
if (this.head) this.head.prev = node;
|
|
92
|
+
this.head = node;
|
|
93
|
+
if (!this.tail) this.tail = node;
|
|
79
94
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
var require_ms = __commonJS({
|
|
91
|
-
"node_modules/ms/index.js"(exports, module2) {
|
|
92
|
-
var s = 1e3;
|
|
93
|
-
var m = s * 60;
|
|
94
|
-
var h = m * 60;
|
|
95
|
-
var d = h * 24;
|
|
96
|
-
var w = d * 7;
|
|
97
|
-
var y = d * 365.25;
|
|
98
|
-
module2.exports = function(val, options) {
|
|
99
|
-
options = options || {};
|
|
100
|
-
var type = typeof val;
|
|
101
|
-
if (type === "string" && val.length > 0) {
|
|
102
|
-
return parse(val);
|
|
103
|
-
} else if (type === "number" && isFinite(val)) {
|
|
104
|
-
return options.long ? fmtLong(val) : fmtShort(val);
|
|
105
|
-
}
|
|
106
|
-
throw new Error(
|
|
107
|
-
"val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
|
|
108
|
-
);
|
|
109
|
-
};
|
|
110
|
-
function parse(str) {
|
|
111
|
-
str = String(str);
|
|
112
|
-
if (str.length > 100) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
|
|
116
|
-
str
|
|
117
|
-
);
|
|
118
|
-
if (!match) {
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
var n = parseFloat(match[1]);
|
|
122
|
-
var type = (match[2] || "ms").toLowerCase();
|
|
123
|
-
switch (type) {
|
|
124
|
-
case "years":
|
|
125
|
-
case "year":
|
|
126
|
-
case "yrs":
|
|
127
|
-
case "yr":
|
|
128
|
-
case "y":
|
|
129
|
-
return n * y;
|
|
130
|
-
case "weeks":
|
|
131
|
-
case "week":
|
|
132
|
-
case "w":
|
|
133
|
-
return n * w;
|
|
134
|
-
case "days":
|
|
135
|
-
case "day":
|
|
136
|
-
case "d":
|
|
137
|
-
return n * d;
|
|
138
|
-
case "hours":
|
|
139
|
-
case "hour":
|
|
140
|
-
case "hrs":
|
|
141
|
-
case "hr":
|
|
142
|
-
case "h":
|
|
143
|
-
return n * h;
|
|
144
|
-
case "minutes":
|
|
145
|
-
case "minute":
|
|
146
|
-
case "mins":
|
|
147
|
-
case "min":
|
|
148
|
-
case "m":
|
|
149
|
-
return n * m;
|
|
150
|
-
case "seconds":
|
|
151
|
-
case "second":
|
|
152
|
-
case "secs":
|
|
153
|
-
case "sec":
|
|
154
|
-
case "s":
|
|
155
|
-
return n * s;
|
|
156
|
-
case "milliseconds":
|
|
157
|
-
case "millisecond":
|
|
158
|
-
case "msecs":
|
|
159
|
-
case "msec":
|
|
160
|
-
case "ms":
|
|
161
|
-
return n;
|
|
162
|
-
default:
|
|
163
|
-
return void 0;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
function fmtShort(ms2) {
|
|
167
|
-
var msAbs = Math.abs(ms2);
|
|
168
|
-
if (msAbs >= d) {
|
|
169
|
-
return Math.round(ms2 / d) + "d";
|
|
170
|
-
}
|
|
171
|
-
if (msAbs >= h) {
|
|
172
|
-
return Math.round(ms2 / h) + "h";
|
|
173
|
-
}
|
|
174
|
-
if (msAbs >= m) {
|
|
175
|
-
return Math.round(ms2 / m) + "m";
|
|
176
|
-
}
|
|
177
|
-
if (msAbs >= s) {
|
|
178
|
-
return Math.round(ms2 / s) + "s";
|
|
179
|
-
}
|
|
180
|
-
return ms2 + "ms";
|
|
181
|
-
}
|
|
182
|
-
function fmtLong(ms2) {
|
|
183
|
-
var msAbs = Math.abs(ms2);
|
|
184
|
-
if (msAbs >= d) {
|
|
185
|
-
return plural(ms2, msAbs, d, "day");
|
|
186
|
-
}
|
|
187
|
-
if (msAbs >= h) {
|
|
188
|
-
return plural(ms2, msAbs, h, "hour");
|
|
189
|
-
}
|
|
190
|
-
if (msAbs >= m) {
|
|
191
|
-
return plural(ms2, msAbs, m, "minute");
|
|
192
|
-
}
|
|
193
|
-
if (msAbs >= s) {
|
|
194
|
-
return plural(ms2, msAbs, s, "second");
|
|
195
|
-
}
|
|
196
|
-
return ms2 + " ms";
|
|
197
|
-
}
|
|
198
|
-
function plural(ms2, msAbs, n, name) {
|
|
199
|
-
var isPlural = msAbs >= n * 1.5;
|
|
200
|
-
return Math.round(ms2 / n) + " " + name + (isPlural ? "s" : "");
|
|
95
|
+
/**
|
|
96
|
+
* 데이터를 저장하거나 업데이트합니다.
|
|
97
|
+
* 용량 초과 시 가장 오래된 항목(tail)을 제거합니다.
|
|
98
|
+
*/
|
|
99
|
+
set(key, value) {
|
|
100
|
+
const existing = this.map.get(key);
|
|
101
|
+
if (existing) {
|
|
102
|
+
existing.value = value;
|
|
103
|
+
this.promote(existing);
|
|
104
|
+
return;
|
|
201
105
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
_timeouts;
|
|
209
|
-
_registry;
|
|
210
|
-
_lifespan;
|
|
211
|
-
constructor(option) {
|
|
212
|
-
const { lifespan } = option;
|
|
213
|
-
this._lifespan = lifespan;
|
|
214
|
-
this._map = /* @__PURE__ */ new Map();
|
|
215
|
-
this._keepAlive = /* @__PURE__ */ new Map();
|
|
216
|
-
this._timeouts = /* @__PURE__ */ new Map();
|
|
217
|
-
this._registry = new FinalizationRegistry((key) => {
|
|
218
|
-
this._stopExpire(key, true);
|
|
219
|
-
this._map.delete(key);
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
clear() {
|
|
223
|
-
this._keepAlive.clear();
|
|
224
|
-
this._map.clear();
|
|
225
|
-
}
|
|
226
|
-
delete(key) {
|
|
227
|
-
const ref = this._map.get(key);
|
|
228
|
-
if (ref) {
|
|
229
|
-
const raw = ref.deref();
|
|
230
|
-
if (raw !== void 0) {
|
|
231
|
-
this._registry.unregister(raw);
|
|
232
|
-
}
|
|
106
|
+
const newNode = { key, value, prev: null, next: null };
|
|
107
|
+
this.map.set(key, newNode);
|
|
108
|
+
this.prepend(newNode);
|
|
109
|
+
if (this.map.size > this.capacity && this.tail) {
|
|
110
|
+
this.map.delete(this.tail.key);
|
|
111
|
+
this.extract(this.tail);
|
|
233
112
|
}
|
|
234
|
-
this._stopExpire(key, true);
|
|
235
|
-
this._keepAlive.delete(key);
|
|
236
|
-
return this._map.delete(key);
|
|
237
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* 데이터를 가져옵니다. 접근한 데이터는 "최근 사용됨"으로 갱신됩니다.
|
|
116
|
+
*/
|
|
238
117
|
get(key) {
|
|
239
|
-
|
|
118
|
+
const node = this.map.get(key);
|
|
119
|
+
if (!node) return void 0;
|
|
120
|
+
this.promote(node);
|
|
121
|
+
return node.value;
|
|
240
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* 키의 존재 여부를 확인합니다. (순서는 변경하지 않는 것이 일반적입니다)
|
|
125
|
+
*/
|
|
241
126
|
has(key) {
|
|
242
|
-
return this.
|
|
243
|
-
}
|
|
244
|
-
set(key, value) {
|
|
245
|
-
this._map.set(key, new WeakRef(value));
|
|
246
|
-
this._registry.register(value, key);
|
|
247
|
-
if (this._lifespan > 0) {
|
|
248
|
-
this._stopExpire(key, true);
|
|
249
|
-
this._startExpire(key, value);
|
|
250
|
-
}
|
|
251
|
-
return this;
|
|
252
|
-
}
|
|
253
|
-
extendExpire(key) {
|
|
254
|
-
if (!(this._lifespan > 0)) {
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
if (!this._keepAlive.has(key)) {
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
this._stopExpire(key, false);
|
|
261
|
-
this._startExpire(key, this._keepAlive.get(key));
|
|
127
|
+
return this.map.has(key);
|
|
262
128
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
129
|
+
/**
|
|
130
|
+
* 특정 키와 데이터를 캐시에서 완전히 제거합니다.
|
|
131
|
+
*/
|
|
132
|
+
delete(key) {
|
|
133
|
+
const node = this.map.get(key);
|
|
134
|
+
if (!node) return false;
|
|
135
|
+
this.extract(node);
|
|
136
|
+
this.map.delete(key);
|
|
137
|
+
return true;
|
|
268
138
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
this._keepAlive.delete(key);
|
|
139
|
+
/**
|
|
140
|
+
* 현재 캐시된 키들을 최근 사용된 순서대로 반환합니다.
|
|
141
|
+
*/
|
|
142
|
+
*keys() {
|
|
143
|
+
let current = this.head;
|
|
144
|
+
while (current) {
|
|
145
|
+
yield current.key;
|
|
146
|
+
current = current.next;
|
|
278
147
|
}
|
|
279
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* 현재 캐시된 아이템의 개수를 반환합니다.
|
|
151
|
+
*/
|
|
280
152
|
get size() {
|
|
281
|
-
return this.
|
|
153
|
+
return this.map.size;
|
|
282
154
|
}
|
|
283
|
-
|
|
284
|
-
|
|
155
|
+
/**
|
|
156
|
+
* 캐시를 완전히 비웁니다.
|
|
157
|
+
*/
|
|
158
|
+
clear() {
|
|
159
|
+
this.map.clear();
|
|
160
|
+
this.head = null;
|
|
161
|
+
this.tail = null;
|
|
285
162
|
}
|
|
286
163
|
};
|
|
287
164
|
var CacheEntanglement = class {
|
|
288
165
|
creation;
|
|
289
166
|
beforeUpdateHook;
|
|
290
|
-
|
|
167
|
+
capacity;
|
|
291
168
|
dependencies;
|
|
292
169
|
caches;
|
|
293
|
-
assignments;
|
|
294
170
|
parameters;
|
|
171
|
+
assignments;
|
|
295
172
|
dependencyProperties;
|
|
173
|
+
updateRequirements;
|
|
296
174
|
constructor(creation, option) {
|
|
297
175
|
option = option ?? {};
|
|
298
176
|
const {
|
|
299
177
|
dependencies,
|
|
300
|
-
|
|
178
|
+
capacity,
|
|
301
179
|
beforeUpdateHook
|
|
302
180
|
} = option;
|
|
303
181
|
this.creation = creation;
|
|
304
182
|
this.beforeUpdateHook = beforeUpdateHook ?? (() => {
|
|
305
183
|
});
|
|
306
|
-
this.
|
|
184
|
+
this.capacity = capacity ?? 100;
|
|
307
185
|
this.assignments = [];
|
|
308
|
-
this.caches = new
|
|
186
|
+
this.caches = new LRUMap(this.capacity);
|
|
187
|
+
this.parameters = /* @__PURE__ */ new Map();
|
|
309
188
|
this.dependencies = dependencies ?? {};
|
|
310
189
|
this.dependencyProperties = Object.keys(this.dependencies);
|
|
311
|
-
this.
|
|
190
|
+
this.updateRequirements = /* @__PURE__ */ new Set();
|
|
312
191
|
for (const name in this.dependencies) {
|
|
313
192
|
const dependency = this.dependencies[name];
|
|
314
193
|
if (!dependency.assignments.includes(this)) {
|
|
@@ -316,22 +195,30 @@ var CacheEntanglement = class {
|
|
|
316
195
|
}
|
|
317
196
|
}
|
|
318
197
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
198
|
+
bubbleUpdateSignal(key) {
|
|
199
|
+
this.updateRequirements.add(key);
|
|
200
|
+
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
201
|
+
const t = this.assignments[i];
|
|
202
|
+
const instance = t;
|
|
203
|
+
for (const cacheKey of instance.caches.keys()) {
|
|
204
|
+
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
205
|
+
instance.bubbleUpdateSignal(cacheKey);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
322
208
|
}
|
|
323
|
-
return time;
|
|
324
209
|
}
|
|
325
210
|
dependencyKey(key) {
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
211
|
+
const i = key.lastIndexOf("/");
|
|
212
|
+
if (i === -1) {
|
|
213
|
+
return key;
|
|
214
|
+
}
|
|
215
|
+
return key.substring(0, i);
|
|
329
216
|
}
|
|
330
217
|
/**
|
|
331
218
|
* Returns all keys stored in the instance.
|
|
332
219
|
*/
|
|
333
220
|
keys() {
|
|
334
|
-
return this.
|
|
221
|
+
return this.parameters.keys();
|
|
335
222
|
}
|
|
336
223
|
/**
|
|
337
224
|
* Deletes all cache values stored in the instance.
|
|
@@ -346,17 +233,33 @@ var CacheEntanglement = class {
|
|
|
346
233
|
* @param key The key to search.
|
|
347
234
|
*/
|
|
348
235
|
exists(key) {
|
|
349
|
-
return this.
|
|
236
|
+
return this.parameters.has(key);
|
|
350
237
|
}
|
|
351
238
|
/**
|
|
352
|
-
*
|
|
239
|
+
* Checks if there is a cache value stored in the key within the instance.
|
|
240
|
+
* This method is an alias for `exists`.
|
|
353
241
|
* @param key The key to search.
|
|
354
242
|
*/
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
243
|
+
has(key) {
|
|
244
|
+
return this.exists(key);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Deletes the cache value stored in the key within the instance.
|
|
248
|
+
* @param key The key to delete.
|
|
249
|
+
*/
|
|
250
|
+
delete(key) {
|
|
251
|
+
this.caches.delete(key);
|
|
252
|
+
this.parameters.delete(key);
|
|
253
|
+
this.updateRequirements.delete(key);
|
|
254
|
+
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
255
|
+
const t = this.assignments[i];
|
|
256
|
+
const instance = t;
|
|
257
|
+
for (const cacheKey of instance.keys()) {
|
|
258
|
+
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
259
|
+
instance.delete(cacheKey);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
358
262
|
}
|
|
359
|
-
return this.caches.get(key);
|
|
360
263
|
}
|
|
361
264
|
};
|
|
362
265
|
var CacheData = class _CacheData {
|
|
@@ -407,6 +310,15 @@ var CacheEntanglementSync = class extends CacheEntanglement {
|
|
|
407
310
|
constructor(creation, option) {
|
|
408
311
|
super(creation, option);
|
|
409
312
|
}
|
|
313
|
+
recache(key) {
|
|
314
|
+
if (!this.parameters.has(key)) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (!this.caches.has(key) || this.updateRequirements.has(key)) {
|
|
318
|
+
this.resolve(key, ...this.parameters.get(key));
|
|
319
|
+
}
|
|
320
|
+
return this.caches.get(key);
|
|
321
|
+
}
|
|
410
322
|
resolve(key, ...parameter) {
|
|
411
323
|
const resolved = {};
|
|
412
324
|
const dependencyKey = this.dependencyKey(key);
|
|
@@ -414,59 +326,53 @@ var CacheEntanglementSync = class extends CacheEntanglement {
|
|
|
414
326
|
for (let i = 0, len = this.dependencyProperties.length; i < len; i++) {
|
|
415
327
|
const name = this.dependencyProperties[i];
|
|
416
328
|
const dependency = this.dependencies[name];
|
|
417
|
-
if (!dependency.
|
|
329
|
+
if (!dependency.exists(key) && !dependency.exists(dependencyKey)) {
|
|
418
330
|
throw new Error(`The key '${key}' or '${dependencyKey}' has not been assigned yet in dependency '${name.toString()}'.`, {
|
|
419
331
|
cause: {
|
|
420
332
|
from: this
|
|
421
333
|
}
|
|
422
334
|
});
|
|
423
335
|
}
|
|
424
|
-
const dependencyValue = dependency.
|
|
336
|
+
const dependencyValue = dependency.recache(key) ?? dependency.recache(dependencyKey);
|
|
425
337
|
resolved[name] = dependencyValue;
|
|
426
338
|
}
|
|
427
|
-
this.parameters[key] = parameter;
|
|
428
339
|
const value = new CacheData(this.creation(key, resolved, ...parameter));
|
|
340
|
+
this.updateRequirements.delete(key);
|
|
341
|
+
this.parameters.set(key, parameter);
|
|
429
342
|
this.caches.set(key, value);
|
|
430
343
|
return value;
|
|
431
344
|
}
|
|
345
|
+
get(key) {
|
|
346
|
+
if (!this.parameters.has(key)) {
|
|
347
|
+
throw new Error(`Cache value not found: ${key}`);
|
|
348
|
+
}
|
|
349
|
+
return this.cache(key, ...this.parameters.get(key));
|
|
350
|
+
}
|
|
432
351
|
cache(key, ...parameter) {
|
|
433
|
-
if (!this.caches.has(key)) {
|
|
434
|
-
this.
|
|
435
|
-
} else {
|
|
436
|
-
this.caches.extendExpire(key);
|
|
352
|
+
if (!this.caches.has(key) || this.updateRequirements.has(key)) {
|
|
353
|
+
this.resolve(key, ...parameter);
|
|
437
354
|
}
|
|
438
355
|
return this.caches.get(key);
|
|
439
356
|
}
|
|
440
357
|
update(key, ...parameter) {
|
|
358
|
+
this.bubbleUpdateSignal(key);
|
|
441
359
|
this.resolve(key, ...parameter);
|
|
442
|
-
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
443
|
-
const t = this.assignments[i];
|
|
444
|
-
const instance = t;
|
|
445
|
-
for (const cacheKey of instance.caches.keys()) {
|
|
446
|
-
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
447
|
-
instance.update(cacheKey, ...instance.parameters[cacheKey]);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
360
|
return this.caches.get(key);
|
|
452
361
|
}
|
|
453
|
-
delete(key) {
|
|
454
|
-
this.caches.delete(key);
|
|
455
|
-
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
456
|
-
const t = this.assignments[i];
|
|
457
|
-
const instance = t;
|
|
458
|
-
for (const cacheKey of instance.caches.keys()) {
|
|
459
|
-
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
460
|
-
instance.delete(cacheKey);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
362
|
};
|
|
466
363
|
var CacheEntanglementAsync = class extends CacheEntanglement {
|
|
467
364
|
constructor(creation, option) {
|
|
468
365
|
super(creation, option);
|
|
469
366
|
}
|
|
367
|
+
async recache(key) {
|
|
368
|
+
if (!this.parameters.has(key)) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
if (!this.caches.has(key) || this.updateRequirements.has(key)) {
|
|
372
|
+
await this.resolve(key, ...this.parameters.get(key));
|
|
373
|
+
}
|
|
374
|
+
return this.caches.get(key);
|
|
375
|
+
}
|
|
470
376
|
async resolve(key, ...parameter) {
|
|
471
377
|
const resolved = {};
|
|
472
378
|
const dependencyKey = this.dependencyKey(key);
|
|
@@ -474,54 +380,39 @@ var CacheEntanglementAsync = class extends CacheEntanglement {
|
|
|
474
380
|
for (let i = 0, len = this.dependencyProperties.length; i < len; i++) {
|
|
475
381
|
const name = this.dependencyProperties[i];
|
|
476
382
|
const dependency = this.dependencies[name];
|
|
477
|
-
if (!dependency.
|
|
383
|
+
if (!dependency.exists(key) && !dependency.exists(dependencyKey)) {
|
|
478
384
|
throw new Error(`The key '${key}' or '${dependencyKey}' has not been assigned yet in dependency '${name.toString()}'.`, {
|
|
479
385
|
cause: {
|
|
480
386
|
from: this
|
|
481
387
|
}
|
|
482
388
|
});
|
|
483
389
|
}
|
|
484
|
-
const dependencyValue = dependency.
|
|
390
|
+
const dependencyValue = await dependency.recache(key) ?? await dependency.recache(dependencyKey);
|
|
485
391
|
resolved[name] = dependencyValue;
|
|
486
392
|
}
|
|
487
|
-
this.parameters[key] = parameter;
|
|
488
393
|
const value = new CacheData(await this.creation(key, resolved, ...parameter));
|
|
394
|
+
this.updateRequirements.delete(key);
|
|
395
|
+
this.parameters.set(key, parameter);
|
|
489
396
|
this.caches.set(key, value);
|
|
490
397
|
return value;
|
|
491
398
|
}
|
|
399
|
+
async get(key) {
|
|
400
|
+
if (!this.parameters.has(key)) {
|
|
401
|
+
throw new Error(`Cache value not found: ${key}`);
|
|
402
|
+
}
|
|
403
|
+
return this.cache(key, ...this.parameters.get(key));
|
|
404
|
+
}
|
|
492
405
|
async cache(key, ...parameter) {
|
|
493
|
-
if (!this.caches.has(key)) {
|
|
406
|
+
if (!this.caches.has(key) || this.updateRequirements.has(key)) {
|
|
494
407
|
await this.update(key, ...parameter);
|
|
495
|
-
} else {
|
|
496
|
-
this.caches.extendExpire(key);
|
|
497
408
|
}
|
|
498
409
|
return this.caches.get(key);
|
|
499
410
|
}
|
|
500
411
|
async update(key, ...parameter) {
|
|
412
|
+
this.bubbleUpdateSignal(key);
|
|
501
413
|
await this.resolve(key, ...parameter);
|
|
502
|
-
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
503
|
-
const t = this.assignments[i];
|
|
504
|
-
const instance = t;
|
|
505
|
-
for (const cacheKey of instance.caches.keys()) {
|
|
506
|
-
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
507
|
-
await instance.update(cacheKey, ...instance.parameters[cacheKey]);
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
414
|
return this.caches.get(key);
|
|
512
415
|
}
|
|
513
|
-
async delete(key) {
|
|
514
|
-
this.caches.delete(key);
|
|
515
|
-
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
516
|
-
const t = this.assignments[i];
|
|
517
|
-
const instance = t;
|
|
518
|
-
for (const cacheKey of instance.caches.keys()) {
|
|
519
|
-
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
520
|
-
await instance.delete(cacheKey);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
416
|
};
|
|
526
417
|
|
|
527
418
|
// src/base/BPTree.ts
|
|
@@ -601,7 +492,7 @@ var BPTree = class {
|
|
|
601
492
|
const regexp = new RegExp(`^${pattern}$`, "i");
|
|
602
493
|
return regexp;
|
|
603
494
|
}, {
|
|
604
|
-
|
|
495
|
+
capacity: this.option.capacity ?? 1e3
|
|
605
496
|
});
|
|
606
497
|
}
|
|
607
498
|
ensureValues(v) {
|
|
@@ -625,9 +516,7 @@ var BPTree = class {
|
|
|
625
516
|
if (this.comparator.isSame(value, nValue)) {
|
|
626
517
|
const keys = node.keys[i];
|
|
627
518
|
if (keys.includes(key)) {
|
|
628
|
-
|
|
629
|
-
cause: { key, value }
|
|
630
|
-
});
|
|
519
|
+
break;
|
|
631
520
|
}
|
|
632
521
|
keys.push(key);
|
|
633
522
|
this.bufferForNodeUpdate(node);
|
|
@@ -696,7 +585,7 @@ var BPTreeSync = class extends BPTree {
|
|
|
696
585
|
return new CacheEntanglementSync((key) => {
|
|
697
586
|
return this.strategy.read(key);
|
|
698
587
|
}, {
|
|
699
|
-
|
|
588
|
+
capacity: this.option.capacity ?? 1e3
|
|
700
589
|
});
|
|
701
590
|
}
|
|
702
591
|
getPairsRightToLeft(value, startNode, endNode, comparator) {
|
|
@@ -1288,7 +1177,7 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1288
1177
|
return new CacheEntanglementAsync(async (key) => {
|
|
1289
1178
|
return await this.strategy.read(key);
|
|
1290
1179
|
}, {
|
|
1291
|
-
|
|
1180
|
+
capacity: this.option.capacity ?? 1e3
|
|
1292
1181
|
});
|
|
1293
1182
|
}
|
|
1294
1183
|
async getPairsRightToLeft(value, startNode, endNode, comparator) {
|
package/dist/esm/index.mjs
CHANGED
|
@@ -28,253 +28,132 @@ var StringComparator = class extends ValueComparator {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
// node_modules/cache-entanglement/dist/esm/index.mjs
|
|
31
|
-
var
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
31
|
+
var LRUMap = class {
|
|
32
|
+
capacity;
|
|
33
|
+
map;
|
|
34
|
+
head = null;
|
|
35
|
+
tail = null;
|
|
36
|
+
constructor(capacity) {
|
|
37
|
+
this.capacity = capacity;
|
|
38
|
+
this.map = /* @__PURE__ */ new Map();
|
|
39
|
+
}
|
|
40
|
+
// 내부 유틸리티: 노드를 헤드로 이동 (가장 최근 사용됨 표시)
|
|
41
|
+
promote(node) {
|
|
42
|
+
this.extract(node);
|
|
43
|
+
this.prepend(node);
|
|
44
|
+
}
|
|
45
|
+
// 내부 유틸리티: 리스트에서 노드 연결 끊기
|
|
46
|
+
extract(node) {
|
|
47
|
+
if (node.prev) node.prev.next = node.next;
|
|
48
|
+
else this.head = node.next;
|
|
49
|
+
if (node.next) node.next.prev = node.prev;
|
|
50
|
+
else this.tail = node.prev;
|
|
51
|
+
node.prev = null;
|
|
52
|
+
node.next = null;
|
|
53
|
+
}
|
|
54
|
+
// 내부 유틸리티: 리스트 맨 앞에 노드 삽입
|
|
55
|
+
prepend(node) {
|
|
56
|
+
node.next = this.head;
|
|
57
|
+
if (this.head) this.head.prev = node;
|
|
58
|
+
this.head = node;
|
|
59
|
+
if (!this.tail) this.tail = node;
|
|
45
60
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
var require_ms = __commonJS({
|
|
57
|
-
"node_modules/ms/index.js"(exports, module) {
|
|
58
|
-
var s = 1e3;
|
|
59
|
-
var m = s * 60;
|
|
60
|
-
var h = m * 60;
|
|
61
|
-
var d = h * 24;
|
|
62
|
-
var w = d * 7;
|
|
63
|
-
var y = d * 365.25;
|
|
64
|
-
module.exports = function(val, options) {
|
|
65
|
-
options = options || {};
|
|
66
|
-
var type = typeof val;
|
|
67
|
-
if (type === "string" && val.length > 0) {
|
|
68
|
-
return parse(val);
|
|
69
|
-
} else if (type === "number" && isFinite(val)) {
|
|
70
|
-
return options.long ? fmtLong(val) : fmtShort(val);
|
|
71
|
-
}
|
|
72
|
-
throw new Error(
|
|
73
|
-
"val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
|
|
74
|
-
);
|
|
75
|
-
};
|
|
76
|
-
function parse(str) {
|
|
77
|
-
str = String(str);
|
|
78
|
-
if (str.length > 100) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
|
|
82
|
-
str
|
|
83
|
-
);
|
|
84
|
-
if (!match) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
var n = parseFloat(match[1]);
|
|
88
|
-
var type = (match[2] || "ms").toLowerCase();
|
|
89
|
-
switch (type) {
|
|
90
|
-
case "years":
|
|
91
|
-
case "year":
|
|
92
|
-
case "yrs":
|
|
93
|
-
case "yr":
|
|
94
|
-
case "y":
|
|
95
|
-
return n * y;
|
|
96
|
-
case "weeks":
|
|
97
|
-
case "week":
|
|
98
|
-
case "w":
|
|
99
|
-
return n * w;
|
|
100
|
-
case "days":
|
|
101
|
-
case "day":
|
|
102
|
-
case "d":
|
|
103
|
-
return n * d;
|
|
104
|
-
case "hours":
|
|
105
|
-
case "hour":
|
|
106
|
-
case "hrs":
|
|
107
|
-
case "hr":
|
|
108
|
-
case "h":
|
|
109
|
-
return n * h;
|
|
110
|
-
case "minutes":
|
|
111
|
-
case "minute":
|
|
112
|
-
case "mins":
|
|
113
|
-
case "min":
|
|
114
|
-
case "m":
|
|
115
|
-
return n * m;
|
|
116
|
-
case "seconds":
|
|
117
|
-
case "second":
|
|
118
|
-
case "secs":
|
|
119
|
-
case "sec":
|
|
120
|
-
case "s":
|
|
121
|
-
return n * s;
|
|
122
|
-
case "milliseconds":
|
|
123
|
-
case "millisecond":
|
|
124
|
-
case "msecs":
|
|
125
|
-
case "msec":
|
|
126
|
-
case "ms":
|
|
127
|
-
return n;
|
|
128
|
-
default:
|
|
129
|
-
return void 0;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
function fmtShort(ms2) {
|
|
133
|
-
var msAbs = Math.abs(ms2);
|
|
134
|
-
if (msAbs >= d) {
|
|
135
|
-
return Math.round(ms2 / d) + "d";
|
|
136
|
-
}
|
|
137
|
-
if (msAbs >= h) {
|
|
138
|
-
return Math.round(ms2 / h) + "h";
|
|
139
|
-
}
|
|
140
|
-
if (msAbs >= m) {
|
|
141
|
-
return Math.round(ms2 / m) + "m";
|
|
142
|
-
}
|
|
143
|
-
if (msAbs >= s) {
|
|
144
|
-
return Math.round(ms2 / s) + "s";
|
|
145
|
-
}
|
|
146
|
-
return ms2 + "ms";
|
|
61
|
+
/**
|
|
62
|
+
* 데이터를 저장하거나 업데이트합니다.
|
|
63
|
+
* 용량 초과 시 가장 오래된 항목(tail)을 제거합니다.
|
|
64
|
+
*/
|
|
65
|
+
set(key, value) {
|
|
66
|
+
const existing = this.map.get(key);
|
|
67
|
+
if (existing) {
|
|
68
|
+
existing.value = value;
|
|
69
|
+
this.promote(existing);
|
|
70
|
+
return;
|
|
147
71
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return plural(ms2, msAbs, h, "hour");
|
|
155
|
-
}
|
|
156
|
-
if (msAbs >= m) {
|
|
157
|
-
return plural(ms2, msAbs, m, "minute");
|
|
158
|
-
}
|
|
159
|
-
if (msAbs >= s) {
|
|
160
|
-
return plural(ms2, msAbs, s, "second");
|
|
161
|
-
}
|
|
162
|
-
return ms2 + " ms";
|
|
163
|
-
}
|
|
164
|
-
function plural(ms2, msAbs, n, name) {
|
|
165
|
-
var isPlural = msAbs >= n * 1.5;
|
|
166
|
-
return Math.round(ms2 / n) + " " + name + (isPlural ? "s" : "");
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
var import_ms = __toESM(require_ms());
|
|
171
|
-
var InvertedWeakMap = class {
|
|
172
|
-
_map;
|
|
173
|
-
_keepAlive;
|
|
174
|
-
_timeouts;
|
|
175
|
-
_registry;
|
|
176
|
-
_lifespan;
|
|
177
|
-
constructor(option) {
|
|
178
|
-
const { lifespan } = option;
|
|
179
|
-
this._lifespan = lifespan;
|
|
180
|
-
this._map = /* @__PURE__ */ new Map();
|
|
181
|
-
this._keepAlive = /* @__PURE__ */ new Map();
|
|
182
|
-
this._timeouts = /* @__PURE__ */ new Map();
|
|
183
|
-
this._registry = new FinalizationRegistry((key) => {
|
|
184
|
-
this._stopExpire(key, true);
|
|
185
|
-
this._map.delete(key);
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
clear() {
|
|
189
|
-
this._keepAlive.clear();
|
|
190
|
-
this._map.clear();
|
|
191
|
-
}
|
|
192
|
-
delete(key) {
|
|
193
|
-
const ref = this._map.get(key);
|
|
194
|
-
if (ref) {
|
|
195
|
-
const raw = ref.deref();
|
|
196
|
-
if (raw !== void 0) {
|
|
197
|
-
this._registry.unregister(raw);
|
|
198
|
-
}
|
|
72
|
+
const newNode = { key, value, prev: null, next: null };
|
|
73
|
+
this.map.set(key, newNode);
|
|
74
|
+
this.prepend(newNode);
|
|
75
|
+
if (this.map.size > this.capacity && this.tail) {
|
|
76
|
+
this.map.delete(this.tail.key);
|
|
77
|
+
this.extract(this.tail);
|
|
199
78
|
}
|
|
200
|
-
this._stopExpire(key, true);
|
|
201
|
-
this._keepAlive.delete(key);
|
|
202
|
-
return this._map.delete(key);
|
|
203
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* 데이터를 가져옵니다. 접근한 데이터는 "최근 사용됨"으로 갱신됩니다.
|
|
82
|
+
*/
|
|
204
83
|
get(key) {
|
|
205
|
-
|
|
84
|
+
const node = this.map.get(key);
|
|
85
|
+
if (!node) return void 0;
|
|
86
|
+
this.promote(node);
|
|
87
|
+
return node.value;
|
|
206
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* 키의 존재 여부를 확인합니다. (순서는 변경하지 않는 것이 일반적입니다)
|
|
91
|
+
*/
|
|
207
92
|
has(key) {
|
|
208
|
-
return this.
|
|
209
|
-
}
|
|
210
|
-
set(key, value) {
|
|
211
|
-
this._map.set(key, new WeakRef(value));
|
|
212
|
-
this._registry.register(value, key);
|
|
213
|
-
if (this._lifespan > 0) {
|
|
214
|
-
this._stopExpire(key, true);
|
|
215
|
-
this._startExpire(key, value);
|
|
216
|
-
}
|
|
217
|
-
return this;
|
|
93
|
+
return this.map.has(key);
|
|
218
94
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
this.
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
_startExpire(key, value) {
|
|
230
|
-
this._keepAlive.set(key, value);
|
|
231
|
-
this._timeouts.set(key, setTimeout(() => {
|
|
232
|
-
this._keepAlive.delete(key);
|
|
233
|
-
}, this._lifespan));
|
|
95
|
+
/**
|
|
96
|
+
* 특정 키와 데이터를 캐시에서 완전히 제거합니다.
|
|
97
|
+
*/
|
|
98
|
+
delete(key) {
|
|
99
|
+
const node = this.map.get(key);
|
|
100
|
+
if (!node) return false;
|
|
101
|
+
this.extract(node);
|
|
102
|
+
this.map.delete(key);
|
|
103
|
+
return true;
|
|
234
104
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
this._keepAlive.delete(key);
|
|
105
|
+
/**
|
|
106
|
+
* 현재 캐시된 키들을 최근 사용된 순서대로 반환합니다.
|
|
107
|
+
*/
|
|
108
|
+
*keys() {
|
|
109
|
+
let current = this.head;
|
|
110
|
+
while (current) {
|
|
111
|
+
yield current.key;
|
|
112
|
+
current = current.next;
|
|
244
113
|
}
|
|
245
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* 현재 캐시된 아이템의 개수를 반환합니다.
|
|
117
|
+
*/
|
|
246
118
|
get size() {
|
|
247
|
-
return this.
|
|
119
|
+
return this.map.size;
|
|
248
120
|
}
|
|
249
|
-
|
|
250
|
-
|
|
121
|
+
/**
|
|
122
|
+
* 캐시를 완전히 비웁니다.
|
|
123
|
+
*/
|
|
124
|
+
clear() {
|
|
125
|
+
this.map.clear();
|
|
126
|
+
this.head = null;
|
|
127
|
+
this.tail = null;
|
|
251
128
|
}
|
|
252
129
|
};
|
|
253
130
|
var CacheEntanglement = class {
|
|
254
131
|
creation;
|
|
255
132
|
beforeUpdateHook;
|
|
256
|
-
|
|
133
|
+
capacity;
|
|
257
134
|
dependencies;
|
|
258
135
|
caches;
|
|
259
|
-
assignments;
|
|
260
136
|
parameters;
|
|
137
|
+
assignments;
|
|
261
138
|
dependencyProperties;
|
|
139
|
+
updateRequirements;
|
|
262
140
|
constructor(creation, option) {
|
|
263
141
|
option = option ?? {};
|
|
264
142
|
const {
|
|
265
143
|
dependencies,
|
|
266
|
-
|
|
144
|
+
capacity,
|
|
267
145
|
beforeUpdateHook
|
|
268
146
|
} = option;
|
|
269
147
|
this.creation = creation;
|
|
270
148
|
this.beforeUpdateHook = beforeUpdateHook ?? (() => {
|
|
271
149
|
});
|
|
272
|
-
this.
|
|
150
|
+
this.capacity = capacity ?? 100;
|
|
273
151
|
this.assignments = [];
|
|
274
|
-
this.caches = new
|
|
152
|
+
this.caches = new LRUMap(this.capacity);
|
|
153
|
+
this.parameters = /* @__PURE__ */ new Map();
|
|
275
154
|
this.dependencies = dependencies ?? {};
|
|
276
155
|
this.dependencyProperties = Object.keys(this.dependencies);
|
|
277
|
-
this.
|
|
156
|
+
this.updateRequirements = /* @__PURE__ */ new Set();
|
|
278
157
|
for (const name in this.dependencies) {
|
|
279
158
|
const dependency = this.dependencies[name];
|
|
280
159
|
if (!dependency.assignments.includes(this)) {
|
|
@@ -282,22 +161,30 @@ var CacheEntanglement = class {
|
|
|
282
161
|
}
|
|
283
162
|
}
|
|
284
163
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
164
|
+
bubbleUpdateSignal(key) {
|
|
165
|
+
this.updateRequirements.add(key);
|
|
166
|
+
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
167
|
+
const t = this.assignments[i];
|
|
168
|
+
const instance = t;
|
|
169
|
+
for (const cacheKey of instance.caches.keys()) {
|
|
170
|
+
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
171
|
+
instance.bubbleUpdateSignal(cacheKey);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
288
174
|
}
|
|
289
|
-
return time;
|
|
290
175
|
}
|
|
291
176
|
dependencyKey(key) {
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
177
|
+
const i = key.lastIndexOf("/");
|
|
178
|
+
if (i === -1) {
|
|
179
|
+
return key;
|
|
180
|
+
}
|
|
181
|
+
return key.substring(0, i);
|
|
295
182
|
}
|
|
296
183
|
/**
|
|
297
184
|
* Returns all keys stored in the instance.
|
|
298
185
|
*/
|
|
299
186
|
keys() {
|
|
300
|
-
return this.
|
|
187
|
+
return this.parameters.keys();
|
|
301
188
|
}
|
|
302
189
|
/**
|
|
303
190
|
* Deletes all cache values stored in the instance.
|
|
@@ -312,17 +199,33 @@ var CacheEntanglement = class {
|
|
|
312
199
|
* @param key The key to search.
|
|
313
200
|
*/
|
|
314
201
|
exists(key) {
|
|
315
|
-
return this.
|
|
202
|
+
return this.parameters.has(key);
|
|
316
203
|
}
|
|
317
204
|
/**
|
|
318
|
-
*
|
|
205
|
+
* Checks if there is a cache value stored in the key within the instance.
|
|
206
|
+
* This method is an alias for `exists`.
|
|
319
207
|
* @param key The key to search.
|
|
320
208
|
*/
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
209
|
+
has(key) {
|
|
210
|
+
return this.exists(key);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Deletes the cache value stored in the key within the instance.
|
|
214
|
+
* @param key The key to delete.
|
|
215
|
+
*/
|
|
216
|
+
delete(key) {
|
|
217
|
+
this.caches.delete(key);
|
|
218
|
+
this.parameters.delete(key);
|
|
219
|
+
this.updateRequirements.delete(key);
|
|
220
|
+
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
221
|
+
const t = this.assignments[i];
|
|
222
|
+
const instance = t;
|
|
223
|
+
for (const cacheKey of instance.keys()) {
|
|
224
|
+
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
225
|
+
instance.delete(cacheKey);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
324
228
|
}
|
|
325
|
-
return this.caches.get(key);
|
|
326
229
|
}
|
|
327
230
|
};
|
|
328
231
|
var CacheData = class _CacheData {
|
|
@@ -373,6 +276,15 @@ var CacheEntanglementSync = class extends CacheEntanglement {
|
|
|
373
276
|
constructor(creation, option) {
|
|
374
277
|
super(creation, option);
|
|
375
278
|
}
|
|
279
|
+
recache(key) {
|
|
280
|
+
if (!this.parameters.has(key)) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
if (!this.caches.has(key) || this.updateRequirements.has(key)) {
|
|
284
|
+
this.resolve(key, ...this.parameters.get(key));
|
|
285
|
+
}
|
|
286
|
+
return this.caches.get(key);
|
|
287
|
+
}
|
|
376
288
|
resolve(key, ...parameter) {
|
|
377
289
|
const resolved = {};
|
|
378
290
|
const dependencyKey = this.dependencyKey(key);
|
|
@@ -380,59 +292,53 @@ var CacheEntanglementSync = class extends CacheEntanglement {
|
|
|
380
292
|
for (let i = 0, len = this.dependencyProperties.length; i < len; i++) {
|
|
381
293
|
const name = this.dependencyProperties[i];
|
|
382
294
|
const dependency = this.dependencies[name];
|
|
383
|
-
if (!dependency.
|
|
295
|
+
if (!dependency.exists(key) && !dependency.exists(dependencyKey)) {
|
|
384
296
|
throw new Error(`The key '${key}' or '${dependencyKey}' has not been assigned yet in dependency '${name.toString()}'.`, {
|
|
385
297
|
cause: {
|
|
386
298
|
from: this
|
|
387
299
|
}
|
|
388
300
|
});
|
|
389
301
|
}
|
|
390
|
-
const dependencyValue = dependency.
|
|
302
|
+
const dependencyValue = dependency.recache(key) ?? dependency.recache(dependencyKey);
|
|
391
303
|
resolved[name] = dependencyValue;
|
|
392
304
|
}
|
|
393
|
-
this.parameters[key] = parameter;
|
|
394
305
|
const value = new CacheData(this.creation(key, resolved, ...parameter));
|
|
306
|
+
this.updateRequirements.delete(key);
|
|
307
|
+
this.parameters.set(key, parameter);
|
|
395
308
|
this.caches.set(key, value);
|
|
396
309
|
return value;
|
|
397
310
|
}
|
|
311
|
+
get(key) {
|
|
312
|
+
if (!this.parameters.has(key)) {
|
|
313
|
+
throw new Error(`Cache value not found: ${key}`);
|
|
314
|
+
}
|
|
315
|
+
return this.cache(key, ...this.parameters.get(key));
|
|
316
|
+
}
|
|
398
317
|
cache(key, ...parameter) {
|
|
399
|
-
if (!this.caches.has(key)) {
|
|
400
|
-
this.
|
|
401
|
-
} else {
|
|
402
|
-
this.caches.extendExpire(key);
|
|
318
|
+
if (!this.caches.has(key) || this.updateRequirements.has(key)) {
|
|
319
|
+
this.resolve(key, ...parameter);
|
|
403
320
|
}
|
|
404
321
|
return this.caches.get(key);
|
|
405
322
|
}
|
|
406
323
|
update(key, ...parameter) {
|
|
324
|
+
this.bubbleUpdateSignal(key);
|
|
407
325
|
this.resolve(key, ...parameter);
|
|
408
|
-
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
409
|
-
const t = this.assignments[i];
|
|
410
|
-
const instance = t;
|
|
411
|
-
for (const cacheKey of instance.caches.keys()) {
|
|
412
|
-
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
413
|
-
instance.update(cacheKey, ...instance.parameters[cacheKey]);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
326
|
return this.caches.get(key);
|
|
418
327
|
}
|
|
419
|
-
delete(key) {
|
|
420
|
-
this.caches.delete(key);
|
|
421
|
-
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
422
|
-
const t = this.assignments[i];
|
|
423
|
-
const instance = t;
|
|
424
|
-
for (const cacheKey of instance.caches.keys()) {
|
|
425
|
-
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
426
|
-
instance.delete(cacheKey);
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
328
|
};
|
|
432
329
|
var CacheEntanglementAsync = class extends CacheEntanglement {
|
|
433
330
|
constructor(creation, option) {
|
|
434
331
|
super(creation, option);
|
|
435
332
|
}
|
|
333
|
+
async recache(key) {
|
|
334
|
+
if (!this.parameters.has(key)) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (!this.caches.has(key) || this.updateRequirements.has(key)) {
|
|
338
|
+
await this.resolve(key, ...this.parameters.get(key));
|
|
339
|
+
}
|
|
340
|
+
return this.caches.get(key);
|
|
341
|
+
}
|
|
436
342
|
async resolve(key, ...parameter) {
|
|
437
343
|
const resolved = {};
|
|
438
344
|
const dependencyKey = this.dependencyKey(key);
|
|
@@ -440,54 +346,39 @@ var CacheEntanglementAsync = class extends CacheEntanglement {
|
|
|
440
346
|
for (let i = 0, len = this.dependencyProperties.length; i < len; i++) {
|
|
441
347
|
const name = this.dependencyProperties[i];
|
|
442
348
|
const dependency = this.dependencies[name];
|
|
443
|
-
if (!dependency.
|
|
349
|
+
if (!dependency.exists(key) && !dependency.exists(dependencyKey)) {
|
|
444
350
|
throw new Error(`The key '${key}' or '${dependencyKey}' has not been assigned yet in dependency '${name.toString()}'.`, {
|
|
445
351
|
cause: {
|
|
446
352
|
from: this
|
|
447
353
|
}
|
|
448
354
|
});
|
|
449
355
|
}
|
|
450
|
-
const dependencyValue = dependency.
|
|
356
|
+
const dependencyValue = await dependency.recache(key) ?? await dependency.recache(dependencyKey);
|
|
451
357
|
resolved[name] = dependencyValue;
|
|
452
358
|
}
|
|
453
|
-
this.parameters[key] = parameter;
|
|
454
359
|
const value = new CacheData(await this.creation(key, resolved, ...parameter));
|
|
360
|
+
this.updateRequirements.delete(key);
|
|
361
|
+
this.parameters.set(key, parameter);
|
|
455
362
|
this.caches.set(key, value);
|
|
456
363
|
return value;
|
|
457
364
|
}
|
|
365
|
+
async get(key) {
|
|
366
|
+
if (!this.parameters.has(key)) {
|
|
367
|
+
throw new Error(`Cache value not found: ${key}`);
|
|
368
|
+
}
|
|
369
|
+
return this.cache(key, ...this.parameters.get(key));
|
|
370
|
+
}
|
|
458
371
|
async cache(key, ...parameter) {
|
|
459
|
-
if (!this.caches.has(key)) {
|
|
372
|
+
if (!this.caches.has(key) || this.updateRequirements.has(key)) {
|
|
460
373
|
await this.update(key, ...parameter);
|
|
461
|
-
} else {
|
|
462
|
-
this.caches.extendExpire(key);
|
|
463
374
|
}
|
|
464
375
|
return this.caches.get(key);
|
|
465
376
|
}
|
|
466
377
|
async update(key, ...parameter) {
|
|
378
|
+
this.bubbleUpdateSignal(key);
|
|
467
379
|
await this.resolve(key, ...parameter);
|
|
468
|
-
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
469
|
-
const t = this.assignments[i];
|
|
470
|
-
const instance = t;
|
|
471
|
-
for (const cacheKey of instance.caches.keys()) {
|
|
472
|
-
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
473
|
-
await instance.update(cacheKey, ...instance.parameters[cacheKey]);
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
380
|
return this.caches.get(key);
|
|
478
381
|
}
|
|
479
|
-
async delete(key) {
|
|
480
|
-
this.caches.delete(key);
|
|
481
|
-
for (let i = 0, len = this.assignments.length; i < len; i++) {
|
|
482
|
-
const t = this.assignments[i];
|
|
483
|
-
const instance = t;
|
|
484
|
-
for (const cacheKey of instance.caches.keys()) {
|
|
485
|
-
if (cacheKey === key || cacheKey.startsWith(`${key}/`)) {
|
|
486
|
-
await instance.delete(cacheKey);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
382
|
};
|
|
492
383
|
|
|
493
384
|
// src/base/BPTree.ts
|
|
@@ -567,7 +458,7 @@ var BPTree = class {
|
|
|
567
458
|
const regexp = new RegExp(`^${pattern}$`, "i");
|
|
568
459
|
return regexp;
|
|
569
460
|
}, {
|
|
570
|
-
|
|
461
|
+
capacity: this.option.capacity ?? 1e3
|
|
571
462
|
});
|
|
572
463
|
}
|
|
573
464
|
ensureValues(v) {
|
|
@@ -591,9 +482,7 @@ var BPTree = class {
|
|
|
591
482
|
if (this.comparator.isSame(value, nValue)) {
|
|
592
483
|
const keys = node.keys[i];
|
|
593
484
|
if (keys.includes(key)) {
|
|
594
|
-
|
|
595
|
-
cause: { key, value }
|
|
596
|
-
});
|
|
485
|
+
break;
|
|
597
486
|
}
|
|
598
487
|
keys.push(key);
|
|
599
488
|
this.bufferForNodeUpdate(node);
|
|
@@ -662,7 +551,7 @@ var BPTreeSync = class extends BPTree {
|
|
|
662
551
|
return new CacheEntanglementSync((key) => {
|
|
663
552
|
return this.strategy.read(key);
|
|
664
553
|
}, {
|
|
665
|
-
|
|
554
|
+
capacity: this.option.capacity ?? 1e3
|
|
666
555
|
});
|
|
667
556
|
}
|
|
668
557
|
getPairsRightToLeft(value, startNode, endNode, comparator) {
|
|
@@ -1254,7 +1143,7 @@ var BPTreeAsync = class extends BPTree {
|
|
|
1254
1143
|
return new CacheEntanglementAsync(async (key) => {
|
|
1255
1144
|
return await this.strategy.read(key);
|
|
1256
1145
|
}, {
|
|
1257
|
-
|
|
1146
|
+
capacity: this.option.capacity ?? 1e3
|
|
1258
1147
|
});
|
|
1259
1148
|
}
|
|
1260
1149
|
async getPairsRightToLeft(value, startNode, endNode, comparator) {
|
|
@@ -4,7 +4,7 @@ import { ValueComparator } from './base/ValueComparator';
|
|
|
4
4
|
import { SerializableData } from './base/SerializeStrategy';
|
|
5
5
|
export declare class BPTreeAsync<K, V> extends BPTree<K, V> {
|
|
6
6
|
protected readonly strategy: SerializeStrategyAsync<K, V>;
|
|
7
|
-
protected readonly nodes: ReturnType<
|
|
7
|
+
protected readonly nodes: ReturnType<typeof this._createCachedNode>;
|
|
8
8
|
constructor(strategy: SerializeStrategyAsync<K, V>, comparator: ValueComparator<V>, option?: BPTreeConstructorOption);
|
|
9
9
|
private _createCachedNode;
|
|
10
10
|
protected getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean): Promise<BPTreePair<K, V>>;
|
|
@@ -4,7 +4,7 @@ import { ValueComparator } from './base/ValueComparator';
|
|
|
4
4
|
import { SerializableData } from './base/SerializeStrategy';
|
|
5
5
|
export declare class BPTreeSync<K, V> extends BPTree<K, V> {
|
|
6
6
|
protected readonly strategy: SerializeStrategySync<K, V>;
|
|
7
|
-
protected readonly nodes: ReturnType<
|
|
7
|
+
protected readonly nodes: ReturnType<typeof this._createCachedNode>;
|
|
8
8
|
constructor(strategy: SerializeStrategySync<K, V>, comparator: ValueComparator<V>, option?: BPTreeConstructorOption);
|
|
9
9
|
private _createCachedNode;
|
|
10
10
|
protected getPairsRightToLeft(value: V, startNode: BPTreeLeafNode<K, V>, endNode: BPTreeLeafNode<K, V> | null, comparator: (nodeValue: V, value: V) => boolean): BPTreePair<K, V>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CacheEntanglementSync, CacheEntanglementAsync
|
|
1
|
+
import { CacheEntanglementSync, CacheEntanglementAsync } from 'cache-entanglement';
|
|
2
2
|
import { ValueComparator } from './ValueComparator';
|
|
3
3
|
import { SerializableData, SerializeStrategy } from './SerializeStrategy';
|
|
4
4
|
type Sync<T> = T;
|
|
@@ -27,14 +27,11 @@ export type BPTreePair<K, V> = Map<K, V>;
|
|
|
27
27
|
export type BPTreeUnknownNode<K, V> = BPTreeInternalNode<K, V> | BPTreeLeafNode<K, V>;
|
|
28
28
|
export interface BPTreeConstructorOption {
|
|
29
29
|
/**
|
|
30
|
-
* The
|
|
31
|
-
* This value is used to determine how
|
|
32
|
-
* If
|
|
33
|
-
* If the lifespan is set to `0` or a negative number, the cache will not prevent garbage collection.
|
|
34
|
-
* If the lifespan is set to a string, the string will be parsed as a time duration.
|
|
35
|
-
* For example, '1m' means 1 minute, '1h' means 1 hour, '1d' means 1 day, '1w' means 1 week.
|
|
30
|
+
* The capacity of the cache.
|
|
31
|
+
* This value is used to determine how many nodes can be cached.
|
|
32
|
+
* If not specified, the default value is 1000.
|
|
36
33
|
*/
|
|
37
|
-
|
|
34
|
+
capacity?: number;
|
|
38
35
|
}
|
|
39
36
|
export interface BPTreeNode<K, V> {
|
|
40
37
|
id: string;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { BPTreeNode, BPTreeCondition } from './base/BPTree';
|
|
1
|
+
export type { BPTreeNode, BPTreeInternalNode, BPTreeLeafNode, BPTreeNodeKey, BPTreePair, BPTreeUnknownNode, BPTreeCondition } from './base/BPTree';
|
|
2
2
|
export type { SerializeStrategyHead, SerializableData } from './base/SerializeStrategy';
|
|
3
3
|
export { ValueComparator, NumericComparator, StringComparator } from './base/ValueComparator';
|
|
4
4
|
export { BPTreeSync } from './BPTreeSync';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "serializable-bptree",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"description": "Store the B+tree flexibly, not only in-memory.",
|
|
5
5
|
"types": "./dist/types/index.d.ts",
|
|
6
6
|
"main": "./dist/cjs/index.cjs",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"dist/**/*"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
-
"test": "jest
|
|
19
|
+
"test": "jest",
|
|
20
20
|
"build": "node build/index.js && tsc"
|
|
21
21
|
},
|
|
22
22
|
"author": "izure <admin@izure.org>",
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
},
|
|
37
37
|
"license": "MIT",
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@types/jest": "^
|
|
40
|
-
"esbuild": "^0.
|
|
41
|
-
"jest": "^
|
|
42
|
-
"ts-jest": "^29.4.
|
|
43
|
-
"typescript": "^5.
|
|
39
|
+
"@types/jest": "^30.0.0",
|
|
40
|
+
"esbuild": "^0.27.2",
|
|
41
|
+
"jest": "^30.2.0",
|
|
42
|
+
"ts-jest": "^29.4.6",
|
|
43
|
+
"typescript": "^5.9.3"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"cache-entanglement": "^1.
|
|
46
|
+
"cache-entanglement": "^1.7.0"
|
|
47
47
|
}
|
|
48
|
-
}
|
|
48
|
+
}
|