unikvs 0.0.2 → 0.0.4
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/LICENSE +21 -0
- package/dist/src/_combine-signals.d.ts +9 -0
- package/dist/src/_combine-signals.d.ts.map +1 -0
- package/dist/src/_combine-signals.js +59 -0
- package/dist/src/_logger.d.ts +3 -0
- package/dist/src/_logger.d.ts.map +1 -0
- package/dist/src/_logger.js +3 -0
- package/dist/src/_merge-context.d.ts +4 -0
- package/dist/src/_merge-context.d.ts.map +1 -0
- package/dist/src/_merge-context.js +3 -0
- package/dist/src/_storage.d.ts +17 -0
- package/dist/src/_storage.d.ts.map +1 -0
- package/dist/src/_storage.js +84 -0
- package/dist/src/_to-value-stream.d.ts +12 -0
- package/dist/src/_to-value-stream.d.ts.map +1 -0
- package/dist/src/_to-value-stream.js +53 -0
- package/dist/src/_transformer.d.ts +12 -0
- package/dist/src/_transformer.d.ts.map +1 -0
- package/dist/src/_transformer.js +52 -0
- package/dist/src/_valibot.d.ts +13 -0
- package/dist/src/_valibot.d.ts.map +1 -0
- package/dist/src/_valibot.js +12 -0
- package/dist/src/context.types.d.ts +17 -0
- package/dist/src/context.types.d.ts.map +1 -0
- package/dist/src/context.types.js +1 -0
- package/dist/src/errors.d.ts +108 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +169 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +3 -0
- package/dist/src/unikvs-config.d.ts +255 -0
- package/dist/src/unikvs-config.d.ts.map +1 -0
- package/dist/src/unikvs-config.js +105 -0
- package/dist/src/unikvs.d.ts +324 -0
- package/dist/src/unikvs.d.ts.map +1 -0
- package/dist/src/unikvs.js +693 -0
- package/dist/src/utils.types.d.ts +7 -0
- package/dist/src/utils.types.d.ts.map +1 -0
- package/dist/src/utils.types.js +1 -0
- package/dist/src/value-stream.types.d.ts +11 -0
- package/dist/src/value-stream.types.d.ts.map +1 -0
- package/dist/src/value-stream.types.js +1 -0
- package/package.json +53 -7
- package/src/_combine-signals.ts +67 -0
- package/src/_logger.ts +5 -0
- package/src/_merge-context.ts +10 -0
- package/src/_storage.ts +130 -0
- package/src/_to-value-stream.ts +59 -0
- package/src/_transformer.ts +75 -0
- package/src/_valibot.ts +30 -0
- package/src/context.types.ts +19 -0
- package/src/errors.ts +382 -0
- package/src/index.ts +52 -0
- package/src/unikvs-config.ts +429 -0
- package/src/unikvs.ts +1171 -0
- package/src/utils.types.ts +6 -0
- package/src/value-stream.types.ts +14 -0
- package/README.md +0 -45
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _UniKvs_con, _UniKvs_context, _UniKvs_destinations, _UniKvs_transformers;
|
|
13
|
+
import { asyncmux, Asyncmux } from "asyncmux";
|
|
14
|
+
import * as v from "valibot";
|
|
15
|
+
import combineSignals from "./_combine-signals.js";
|
|
16
|
+
import logger from "./_logger.js";
|
|
17
|
+
import mergeContext from "./_merge-context.js";
|
|
18
|
+
import toValueStream from "./_to-value-stream.js";
|
|
19
|
+
import { parse } from "./_valibot.js";
|
|
20
|
+
import { KeyNotFoundError, PluginOperationAggregateError, UniKvsIsNotOpenError, UniKvsIsOpenError, } from "./errors.js";
|
|
21
|
+
import UniKvsConfig from "./unikvs-config.js";
|
|
22
|
+
// -------------------------------------------------------------------------------------------------
|
|
23
|
+
//
|
|
24
|
+
// スキーマ
|
|
25
|
+
//
|
|
26
|
+
// -------------------------------------------------------------------------------------------------
|
|
27
|
+
const ContextKeySchema = v.union([v.string(), v.symbol(), v.number()]);
|
|
28
|
+
const ContextSourceSchema = v.union([
|
|
29
|
+
v.record(v.any(), v.unknown()),
|
|
30
|
+
v.array(v.tuple([ContextKeySchema, v.unknown()])),
|
|
31
|
+
]);
|
|
32
|
+
const OpenOptionsSchema = v.object({
|
|
33
|
+
signal: v.optional(v.instance(AbortSignal)),
|
|
34
|
+
context: v.optional(ContextSourceSchema),
|
|
35
|
+
});
|
|
36
|
+
const OpenArgsSchema = v.tuple([v.optional(OpenOptionsSchema)]);
|
|
37
|
+
const CloseOptionsSchema = v.object({
|
|
38
|
+
signal: v.optional(v.instance(AbortSignal)),
|
|
39
|
+
context: v.optional(ContextSourceSchema),
|
|
40
|
+
});
|
|
41
|
+
const CloseArgsSchema = v.tuple([v.optional(CloseOptionsSchema)]);
|
|
42
|
+
const SetOptionsSchema = v.object({
|
|
43
|
+
key: v.string(),
|
|
44
|
+
value: v.unknown(),
|
|
45
|
+
signal: v.optional(v.instance(AbortSignal)),
|
|
46
|
+
context: v.optional(ContextSourceSchema),
|
|
47
|
+
});
|
|
48
|
+
const SetArgsSchema = v.union([
|
|
49
|
+
v.tuple([SetOptionsSchema]),
|
|
50
|
+
v.pipe(v.tuple([
|
|
51
|
+
SetOptionsSchema.entries.key,
|
|
52
|
+
SetOptionsSchema.entries.value,
|
|
53
|
+
v.optional(v.omit(SetOptionsSchema, ["key", "value"])),
|
|
54
|
+
]), v.transform(([key, value, options]) => [{ ...options, key, value }])),
|
|
55
|
+
]);
|
|
56
|
+
const GetOptionsSchema = v.object({
|
|
57
|
+
key: v.string(),
|
|
58
|
+
signal: v.optional(v.instance(AbortSignal)),
|
|
59
|
+
context: v.optional(ContextSourceSchema),
|
|
60
|
+
});
|
|
61
|
+
const GetArgsSchema = v.union([
|
|
62
|
+
v.tuple([GetOptionsSchema]),
|
|
63
|
+
v.pipe(v.tuple([GetOptionsSchema.entries.key, v.optional(v.omit(GetOptionsSchema, ["key"]))]), v.transform(([key, options]) => [{ ...options, key }])),
|
|
64
|
+
]);
|
|
65
|
+
const StreamOptionsSchema = v.object({
|
|
66
|
+
key: v.string(),
|
|
67
|
+
signal: v.optional(v.instance(AbortSignal)),
|
|
68
|
+
context: v.optional(ContextSourceSchema),
|
|
69
|
+
});
|
|
70
|
+
const StreamArgsSchema = v.union([
|
|
71
|
+
v.tuple([StreamOptionsSchema]),
|
|
72
|
+
v.pipe(v.tuple([StreamOptionsSchema.entries.key, v.optional(v.omit(StreamOptionsSchema, ["key"]))]), v.transform(([key, options]) => [{ ...options, key }])),
|
|
73
|
+
]);
|
|
74
|
+
const HasOptionsSchema = v.object({
|
|
75
|
+
key: v.string(),
|
|
76
|
+
signal: v.optional(v.instance(AbortSignal)),
|
|
77
|
+
context: v.optional(ContextSourceSchema),
|
|
78
|
+
});
|
|
79
|
+
const HasArgsSchema = v.union([
|
|
80
|
+
v.tuple([HasOptionsSchema]),
|
|
81
|
+
v.pipe(v.tuple([HasOptionsSchema.entries.key, v.optional(v.omit(HasOptionsSchema, ["key"]))]), v.transform(([key, options]) => [{ ...options, key }])),
|
|
82
|
+
]);
|
|
83
|
+
const DeleteOptionsSchema = v.object({
|
|
84
|
+
key: v.string(),
|
|
85
|
+
signal: v.optional(v.instance(AbortSignal)),
|
|
86
|
+
context: v.optional(ContextSourceSchema),
|
|
87
|
+
});
|
|
88
|
+
const DeleteArgsSchema = v.union([
|
|
89
|
+
v.tuple([DeleteOptionsSchema]),
|
|
90
|
+
v.pipe(v.tuple([DeleteOptionsSchema.entries.key, v.optional(v.omit(DeleteOptionsSchema, ["key"]))]), v.transform(([key, options]) => [{ ...options, key }])),
|
|
91
|
+
]);
|
|
92
|
+
const ClearOptionsSchema = v.object({
|
|
93
|
+
signal: v.optional(v.instance(AbortSignal)),
|
|
94
|
+
context: v.optional(ContextSourceSchema),
|
|
95
|
+
});
|
|
96
|
+
const ClearArgsSchema = v.tuple([v.optional(ClearOptionsSchema)]);
|
|
97
|
+
// -------------------------------------------------------------------------------------------------
|
|
98
|
+
//
|
|
99
|
+
// UniKvs
|
|
100
|
+
//
|
|
101
|
+
// -------------------------------------------------------------------------------------------------
|
|
102
|
+
/**
|
|
103
|
+
* ストリームの読み取りロックを自動解放するための FinalizationRegistry です。
|
|
104
|
+
*/
|
|
105
|
+
const ioLockRegistry = typeof FinalizationRegistry !== "function"
|
|
106
|
+
? null
|
|
107
|
+
: new FinalizationRegistry((lock) => {
|
|
108
|
+
try {
|
|
109
|
+
lock.unlock();
|
|
110
|
+
}
|
|
111
|
+
catch { }
|
|
112
|
+
});
|
|
113
|
+
/**
|
|
114
|
+
* UniKvs メインクラスです。
|
|
115
|
+
*
|
|
116
|
+
* 複数のストレージとトランスフォーマーを統合して KVS 操作を提供します。
|
|
117
|
+
*
|
|
118
|
+
* @template TKeyValueMapping キーと値のマッピング定義です。
|
|
119
|
+
*/
|
|
120
|
+
export default class UniKvs {
|
|
121
|
+
/**
|
|
122
|
+
* UniKvs の設定ビルダーを作成します。
|
|
123
|
+
*
|
|
124
|
+
* @template TKeyValueMapping マッピング定義です。
|
|
125
|
+
* @returns 設定ビルダーのインスタンスです。
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* import { Compression } from "@unikvs/compression";
|
|
129
|
+
* import { FileSystem } from "@unikvs/fs.node";
|
|
130
|
+
* import { UniKvs, type Value } from "unikvs";
|
|
131
|
+
*
|
|
132
|
+
* const kvs = UniKvs.config<{
|
|
133
|
+
* foo: Value<Uint8Array<ArrayBuffer>>;
|
|
134
|
+
* }>()
|
|
135
|
+
* .appendTransformer(new Compression("gzip"))
|
|
136
|
+
* .appendStorage(new FileSystem(".tmp"))
|
|
137
|
+
* .create();
|
|
138
|
+
*
|
|
139
|
+
* await kvs.open();
|
|
140
|
+
*
|
|
141
|
+
* await kvs.set("foo", Uint8Array.from([0, 1, 2]));
|
|
142
|
+
*
|
|
143
|
+
* await kvs.close();
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
static config() {
|
|
147
|
+
return new UniKvsConfig(this);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* インスタンスを初期化します。
|
|
151
|
+
*
|
|
152
|
+
* @internal UniKvs の設定ビルダー経由で使用します。
|
|
153
|
+
* @param context コンテキストです。
|
|
154
|
+
* @param destinations ストレージのリストです。
|
|
155
|
+
* @param transformers トランスフォーマーのリストです。
|
|
156
|
+
*/
|
|
157
|
+
constructor(context, destinations, transformers) {
|
|
158
|
+
/**
|
|
159
|
+
* 現在の接続状態です。非接続時は null となります。
|
|
160
|
+
*/
|
|
161
|
+
_UniKvs_con.set(this, void 0);
|
|
162
|
+
/**
|
|
163
|
+
* 基本となる実行コンテキスト情報です。
|
|
164
|
+
*/
|
|
165
|
+
_UniKvs_context.set(this, void 0);
|
|
166
|
+
/**
|
|
167
|
+
* データの永続化先となるストレージのリストです。
|
|
168
|
+
*/
|
|
169
|
+
_UniKvs_destinations.set(this, void 0);
|
|
170
|
+
/**
|
|
171
|
+
* データの変換を行うトランスフォーマーのリストです。
|
|
172
|
+
*/
|
|
173
|
+
_UniKvs_transformers.set(this, void 0);
|
|
174
|
+
__classPrivateFieldSet(this, _UniKvs_con, null, "f");
|
|
175
|
+
__classPrivateFieldSet(this, _UniKvs_context, {
|
|
176
|
+
...context,
|
|
177
|
+
"unikvs:instance": this,
|
|
178
|
+
}, "f");
|
|
179
|
+
__classPrivateFieldSet(this, _UniKvs_destinations, destinations, "f");
|
|
180
|
+
__classPrivateFieldSet(this, _UniKvs_transformers, transformers, "f");
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* UniKvs が利用可能であるかを確認します。
|
|
184
|
+
*
|
|
185
|
+
* @returns 利用可能である場合は true、そうでない場合は false を返します。
|
|
186
|
+
*/
|
|
187
|
+
get isOpen() {
|
|
188
|
+
return !!__classPrivateFieldGet(this, _UniKvs_con, "f");
|
|
189
|
+
}
|
|
190
|
+
async open(...args) {
|
|
191
|
+
if (__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
192
|
+
throw new UniKvsIsOpenError();
|
|
193
|
+
}
|
|
194
|
+
__classPrivateFieldSet(this, _UniKvs_con, {
|
|
195
|
+
conAc: new AbortController(),
|
|
196
|
+
ioMux: new Asyncmux(),
|
|
197
|
+
}, "f");
|
|
198
|
+
try {
|
|
199
|
+
const [options = {}] = parse(OpenArgsSchema, args);
|
|
200
|
+
const { signal: signalOption, context: contextOption } = options;
|
|
201
|
+
const { conAc } = __classPrivateFieldGet(this, _UniKvs_con, "f");
|
|
202
|
+
const signal = combineSignals([conAc.signal, signalOption]);
|
|
203
|
+
const context = mergeContext(__classPrivateFieldGet(this, _UniKvs_context, "f"), contextOption);
|
|
204
|
+
context["unikvs:action"] = "open";
|
|
205
|
+
const openFns = [];
|
|
206
|
+
const dispose = [];
|
|
207
|
+
const lock = await asyncmux(this, signal);
|
|
208
|
+
try {
|
|
209
|
+
// ロック待機中に接続状態が変更されていないか再確認します。
|
|
210
|
+
if (__classPrivateFieldGet(this, _UniKvs_con, "f").conAc !== conAc) {
|
|
211
|
+
throw new UniKvsIsOpenError();
|
|
212
|
+
}
|
|
213
|
+
// 各ストレージのオープン処理をリストに追加します。
|
|
214
|
+
for (const storage of __classPrivateFieldGet(this, _UniKvs_destinations, "f")) {
|
|
215
|
+
openFns.push([
|
|
216
|
+
async () => {
|
|
217
|
+
await storage.open(context, signal);
|
|
218
|
+
dispose.push(async () => {
|
|
219
|
+
try {
|
|
220
|
+
await storage.close(context, signal);
|
|
221
|
+
}
|
|
222
|
+
catch (ex) {
|
|
223
|
+
logger.error `Failed to close storage: ${ex}`;
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
},
|
|
227
|
+
"storage",
|
|
228
|
+
]);
|
|
229
|
+
}
|
|
230
|
+
// 各トランスフォーマーのオープン処理をリストに追加します。
|
|
231
|
+
for (const transformer of __classPrivateFieldGet(this, _UniKvs_transformers, "f")) {
|
|
232
|
+
openFns.push([
|
|
233
|
+
async () => {
|
|
234
|
+
await transformer.open(context, signal);
|
|
235
|
+
dispose.push(async () => {
|
|
236
|
+
try {
|
|
237
|
+
await transformer.close(context, signal);
|
|
238
|
+
}
|
|
239
|
+
catch (ex) {
|
|
240
|
+
logger.error `Failed to close transformer: ${ex}`;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
},
|
|
244
|
+
"transformer",
|
|
245
|
+
]);
|
|
246
|
+
}
|
|
247
|
+
// すべての処理を並列に実行し、エラーが発生した場合は集約します。
|
|
248
|
+
const errors = [];
|
|
249
|
+
await Promise.all(openFns.map(async ([f, plugin]) => {
|
|
250
|
+
try {
|
|
251
|
+
await f();
|
|
252
|
+
}
|
|
253
|
+
catch (reason) {
|
|
254
|
+
errors.push({ plugin, reason });
|
|
255
|
+
}
|
|
256
|
+
}));
|
|
257
|
+
if (errors.length > 0) {
|
|
258
|
+
throw new PluginOperationAggregateError({ action: "open", errors });
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch (ex) {
|
|
262
|
+
__classPrivateFieldSet(this, _UniKvs_con, null, "f"); // unlock の前に null に戻します。
|
|
263
|
+
if (dispose.length > 0) {
|
|
264
|
+
await Promise.all(dispose.map(async (f) => {
|
|
265
|
+
await f();
|
|
266
|
+
}));
|
|
267
|
+
}
|
|
268
|
+
throw ex;
|
|
269
|
+
}
|
|
270
|
+
finally {
|
|
271
|
+
lock.unlock();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch (ex) {
|
|
275
|
+
__classPrivateFieldSet(this, _UniKvs_con, null, "f");
|
|
276
|
+
throw ex;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
async close(...args) {
|
|
280
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
281
|
+
throw new UniKvsIsNotOpenError();
|
|
282
|
+
}
|
|
283
|
+
const [options = {}] = parse(CloseArgsSchema, args);
|
|
284
|
+
const { signal = AbortSignal.timeout(10e3), context: contextOption } = options;
|
|
285
|
+
const context = mergeContext(__classPrivateFieldGet(this, _UniKvs_context, "f"), contextOption);
|
|
286
|
+
context["unikvs:action"] = "close";
|
|
287
|
+
const { conAc, ioMux } = __classPrivateFieldGet(this, _UniKvs_con, "f");
|
|
288
|
+
conAc.abort(new UniKvsIsNotOpenError()); // 実行中の他の操作をすべて中断させるために signal を発火させます。
|
|
289
|
+
const lock = await asyncmux(this, signal);
|
|
290
|
+
try {
|
|
291
|
+
// ロック待機中に接続状態が変更されていないか再確認します。
|
|
292
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
293
|
+
throw new UniKvsIsNotOpenError();
|
|
294
|
+
}
|
|
295
|
+
const lock = await ioMux.lock({ signal });
|
|
296
|
+
try {
|
|
297
|
+
const closeFns = [];
|
|
298
|
+
// ストレージのクローズ処理を登録します。
|
|
299
|
+
for (const plugin of __classPrivateFieldGet(this, _UniKvs_destinations, "f")) {
|
|
300
|
+
closeFns.push([
|
|
301
|
+
async () => {
|
|
302
|
+
await plugin.close(context, signal);
|
|
303
|
+
},
|
|
304
|
+
"storage",
|
|
305
|
+
]);
|
|
306
|
+
}
|
|
307
|
+
// トランスフォーマーのクローズ処理を登録します。
|
|
308
|
+
for (const plugin of __classPrivateFieldGet(this, _UniKvs_transformers, "f")) {
|
|
309
|
+
closeFns.push([
|
|
310
|
+
async () => {
|
|
311
|
+
await plugin.close(context, signal);
|
|
312
|
+
},
|
|
313
|
+
"transformer",
|
|
314
|
+
]);
|
|
315
|
+
}
|
|
316
|
+
// すべての処理を並列に実行し、エラーが発生した場合は集約します。
|
|
317
|
+
const errors = [];
|
|
318
|
+
await Promise.all(closeFns.map(async ([f, plugin]) => {
|
|
319
|
+
try {
|
|
320
|
+
await f();
|
|
321
|
+
}
|
|
322
|
+
catch (reason) {
|
|
323
|
+
errors.push({ plugin, reason });
|
|
324
|
+
}
|
|
325
|
+
}));
|
|
326
|
+
if (errors.length > 0) {
|
|
327
|
+
throw new PluginOperationAggregateError({ action: "close", errors });
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
finally {
|
|
331
|
+
lock.unlock();
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
finally {
|
|
335
|
+
__classPrivateFieldSet(this, _UniKvs_con, null, "f");
|
|
336
|
+
lock.unlock();
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
async [(_UniKvs_con = new WeakMap(), _UniKvs_context = new WeakMap(), _UniKvs_destinations = new WeakMap(), _UniKvs_transformers = new WeakMap(), Symbol.asyncDispose)]() {
|
|
340
|
+
if (!this.isOpen) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
await this.close({
|
|
344
|
+
signal: AbortSignal.timeout(10e3),
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
async set(...args) {
|
|
348
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
349
|
+
throw new UniKvsIsNotOpenError();
|
|
350
|
+
}
|
|
351
|
+
const [options] = parse(SetArgsSchema, args);
|
|
352
|
+
const { key, value, signal: signalOption, context: contextOption } = options;
|
|
353
|
+
const { conAc, ioMux } = __classPrivateFieldGet(this, _UniKvs_con, "f");
|
|
354
|
+
const signal = combineSignals([conAc.signal, signalOption]);
|
|
355
|
+
const context = mergeContext(__classPrivateFieldGet(this, _UniKvs_context, "f"), contextOption);
|
|
356
|
+
context["unikvs:action"] = "set";
|
|
357
|
+
context["unikvs:key"] = key;
|
|
358
|
+
const lock = await asyncmux(this, signal);
|
|
359
|
+
try {
|
|
360
|
+
// ロック待機中に接続状態が変更されていないか再確認します。
|
|
361
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
362
|
+
throw new UniKvsIsNotOpenError();
|
|
363
|
+
}
|
|
364
|
+
const errors = [];
|
|
365
|
+
const errorStorageSet = new Set();
|
|
366
|
+
if (value instanceof ReadableStream) {
|
|
367
|
+
// 各トランスフォーマーを通してデータをエンコードストリームへ変換します。
|
|
368
|
+
let data = value;
|
|
369
|
+
for (const transformer of __classPrivateFieldGet(this, _UniKvs_transformers, "f")) {
|
|
370
|
+
const e = await transformer.getEncodable(context, signal);
|
|
371
|
+
data = data.pipeThrough(e);
|
|
372
|
+
}
|
|
373
|
+
const lock = await ioMux.lock({ key, signal });
|
|
374
|
+
try {
|
|
375
|
+
await Promise.all(__classPrivateFieldGet(this, _UniKvs_destinations, "f").map(async (storage, i) => {
|
|
376
|
+
try {
|
|
377
|
+
// 複数のストレージがある場合は、tee メソッドを使用してストリームを分岐させます。
|
|
378
|
+
let r = data;
|
|
379
|
+
if (i !== __classPrivateFieldGet(this, _UniKvs_destinations, "f").length - 1) {
|
|
380
|
+
[r, data] = data.tee();
|
|
381
|
+
}
|
|
382
|
+
const w = await storage.getWritable(context, signal, key);
|
|
383
|
+
await r.pipeTo(w, { signal });
|
|
384
|
+
}
|
|
385
|
+
catch (reason) {
|
|
386
|
+
errors.push({ reason });
|
|
387
|
+
errorStorageSet.add(storage);
|
|
388
|
+
}
|
|
389
|
+
}));
|
|
390
|
+
}
|
|
391
|
+
finally {
|
|
392
|
+
lock.unlock();
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
// 登録されているトランスフォーマーを順番に適用してデータをエンコードします。
|
|
397
|
+
let data = value;
|
|
398
|
+
for (const transformer of __classPrivateFieldGet(this, _UniKvs_transformers, "f")) {
|
|
399
|
+
data = await transformer.encode(context, signal, data);
|
|
400
|
+
}
|
|
401
|
+
const lock = await ioMux.lock({ key, signal });
|
|
402
|
+
try {
|
|
403
|
+
await Promise.all(__classPrivateFieldGet(this, _UniKvs_destinations, "f").map(async (storage) => {
|
|
404
|
+
try {
|
|
405
|
+
await storage.write(context, signal, key, data);
|
|
406
|
+
}
|
|
407
|
+
catch (reason) {
|
|
408
|
+
errors.push({ reason });
|
|
409
|
+
errorStorageSet.add(storage);
|
|
410
|
+
}
|
|
411
|
+
}));
|
|
412
|
+
}
|
|
413
|
+
finally {
|
|
414
|
+
lock.unlock();
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
// エラーが発生した場合は集約します。
|
|
418
|
+
if (errors.length > 0) {
|
|
419
|
+
const error = new PluginOperationAggregateError({
|
|
420
|
+
plugin: "storage",
|
|
421
|
+
action: "write",
|
|
422
|
+
errors,
|
|
423
|
+
});
|
|
424
|
+
{
|
|
425
|
+
const errors = [];
|
|
426
|
+
await Promise.all(__classPrivateFieldGet(this, _UniKvs_destinations, "f").map(async (storage) => {
|
|
427
|
+
if (errorStorageSet.has(storage)) {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
try {
|
|
431
|
+
await storage.onOtherWriteError(context, signal, key, error);
|
|
432
|
+
}
|
|
433
|
+
catch (ex) {
|
|
434
|
+
errors.push(ex);
|
|
435
|
+
}
|
|
436
|
+
}));
|
|
437
|
+
if (errors.length > 0) {
|
|
438
|
+
logger.error(new AggregateError(errors, "Failed to handle error"));
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
throw error;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
finally {
|
|
445
|
+
lock.unlock();
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
async get(...args) {
|
|
449
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
450
|
+
throw new UniKvsIsNotOpenError();
|
|
451
|
+
}
|
|
452
|
+
const [options] = parse(GetArgsSchema, args);
|
|
453
|
+
const { key, signal: signalOption, context: contextOption } = options;
|
|
454
|
+
const { conAc, ioMux } = __classPrivateFieldGet(this, _UniKvs_con, "f");
|
|
455
|
+
const signal = combineSignals([conAc.signal, signalOption]);
|
|
456
|
+
const context = mergeContext(__classPrivateFieldGet(this, _UniKvs_context, "f"), contextOption);
|
|
457
|
+
context["unikvs:action"] = "get";
|
|
458
|
+
context["unikvs:key"] = key;
|
|
459
|
+
const lock = await asyncmux.readonly(this, signal);
|
|
460
|
+
try {
|
|
461
|
+
// ロック待機中に接続状態が変更されていないか再確認します。
|
|
462
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
463
|
+
throw new UniKvsIsNotOpenError();
|
|
464
|
+
}
|
|
465
|
+
const NONE = {};
|
|
466
|
+
let data = NONE;
|
|
467
|
+
const lock = await ioMux.rLock({ key, signal });
|
|
468
|
+
try {
|
|
469
|
+
// 各ストレージを巡回し、最初に見つかったデータを取得します。
|
|
470
|
+
for (const storage of __classPrivateFieldGet(this, _UniKvs_destinations, "f")) {
|
|
471
|
+
if (await storage.exists(context, signal, key)) {
|
|
472
|
+
data = await storage.read(context, signal, key);
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
finally {
|
|
478
|
+
lock.unlock();
|
|
479
|
+
}
|
|
480
|
+
if (data === NONE) {
|
|
481
|
+
throw new KeyNotFoundError({ key });
|
|
482
|
+
}
|
|
483
|
+
// トランスフォーマーを逆順に適用してデータをデコードします。
|
|
484
|
+
if (__classPrivateFieldGet(this, _UniKvs_transformers, "f").length > 0) {
|
|
485
|
+
for (const transformer of __classPrivateFieldGet(this, _UniKvs_transformers, "f").toReversed()) {
|
|
486
|
+
data = await transformer.decode(context, signal, data);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return data;
|
|
490
|
+
}
|
|
491
|
+
finally {
|
|
492
|
+
lock.unlock();
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
async stream(...args) {
|
|
496
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
497
|
+
throw new UniKvsIsNotOpenError();
|
|
498
|
+
}
|
|
499
|
+
const [options] = parse(StreamArgsSchema, args);
|
|
500
|
+
const { key, signal: signalOption, context: contextOption } = options;
|
|
501
|
+
const { conAc, ioMux } = __classPrivateFieldGet(this, _UniKvs_con, "f");
|
|
502
|
+
const signal = combineSignals([conAc.signal, signalOption]);
|
|
503
|
+
const context = mergeContext(__classPrivateFieldGet(this, _UniKvs_context, "f"), contextOption);
|
|
504
|
+
context["unikvs:action"] = "stream";
|
|
505
|
+
context["unikvs:key"] = key;
|
|
506
|
+
const lock = await asyncmux(this, signal);
|
|
507
|
+
try {
|
|
508
|
+
// ロック待機中に接続状態が変更されていないか再確認します。
|
|
509
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
510
|
+
throw new UniKvsIsNotOpenError();
|
|
511
|
+
}
|
|
512
|
+
const NONE = {};
|
|
513
|
+
let r = NONE;
|
|
514
|
+
const lock = await ioMux.rLock({ key, signal });
|
|
515
|
+
try {
|
|
516
|
+
// 各ストレージを巡回し、最初に見つかったデータを取得します。
|
|
517
|
+
for (const storage of __classPrivateFieldGet(this, _UniKvs_destinations, "f")) {
|
|
518
|
+
if (await storage.exists(context, signal, key)) {
|
|
519
|
+
r = await storage.getReadable(context, signal, key);
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (r === NONE) {
|
|
524
|
+
throw new KeyNotFoundError({ key });
|
|
525
|
+
}
|
|
526
|
+
// トランスフォーマーを逆順に適用し、デコード用トランスフォームを連結します。
|
|
527
|
+
if (__classPrivateFieldGet(this, _UniKvs_transformers, "f").length > 0) {
|
|
528
|
+
for (const transformer of __classPrivateFieldGet(this, _UniKvs_transformers, "f").toReversed()) {
|
|
529
|
+
const d = await transformer.getDecodable(context, signal);
|
|
530
|
+
r = r.pipeThrough(d);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
if (!ioLockRegistry) {
|
|
534
|
+
return toValueStream(r, async () => {
|
|
535
|
+
try {
|
|
536
|
+
await r.cancel();
|
|
537
|
+
}
|
|
538
|
+
catch { }
|
|
539
|
+
try {
|
|
540
|
+
lock.unlock();
|
|
541
|
+
}
|
|
542
|
+
catch { }
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
const unregisterToken = {};
|
|
546
|
+
const valueStream = toValueStream(r, async () => {
|
|
547
|
+
try {
|
|
548
|
+
ioLockRegistry.unregister(unregisterToken);
|
|
549
|
+
}
|
|
550
|
+
catch { }
|
|
551
|
+
try {
|
|
552
|
+
await r.cancel();
|
|
553
|
+
}
|
|
554
|
+
catch { }
|
|
555
|
+
try {
|
|
556
|
+
lock.unlock();
|
|
557
|
+
}
|
|
558
|
+
catch { }
|
|
559
|
+
});
|
|
560
|
+
// valueStream が GC されるタイミングでストリームが終了していなければロックを自動解放します。
|
|
561
|
+
ioLockRegistry.register(valueStream, lock, unregisterToken);
|
|
562
|
+
return valueStream;
|
|
563
|
+
}
|
|
564
|
+
catch (ex) {
|
|
565
|
+
lock.unlock();
|
|
566
|
+
throw ex;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
finally {
|
|
570
|
+
lock.unlock();
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
async has(...args) {
|
|
574
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
575
|
+
throw new UniKvsIsNotOpenError();
|
|
576
|
+
}
|
|
577
|
+
const [options] = parse(HasArgsSchema, args);
|
|
578
|
+
const { key, signal: signalOption, context: contextOption } = options;
|
|
579
|
+
const { conAc, ioMux } = __classPrivateFieldGet(this, _UniKvs_con, "f");
|
|
580
|
+
const signal = combineSignals([conAc.signal, signalOption]);
|
|
581
|
+
const context = mergeContext(__classPrivateFieldGet(this, _UniKvs_context, "f"), contextOption);
|
|
582
|
+
context["unikvs:action"] = "has";
|
|
583
|
+
context["unikvs:key"] = key;
|
|
584
|
+
const lock = await asyncmux(this, signal);
|
|
585
|
+
try {
|
|
586
|
+
// ロック待機中に接続状態が変更されていないか再確認します。
|
|
587
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
588
|
+
throw new UniKvsIsNotOpenError();
|
|
589
|
+
}
|
|
590
|
+
const lock = await ioMux.rLock({ key, signal });
|
|
591
|
+
try {
|
|
592
|
+
// いずれかのストレージに存在すれば true を返します。
|
|
593
|
+
for (const storage of __classPrivateFieldGet(this, _UniKvs_destinations, "f")) {
|
|
594
|
+
if (await storage.exists(context, signal, key)) {
|
|
595
|
+
return true;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
return false;
|
|
599
|
+
}
|
|
600
|
+
finally {
|
|
601
|
+
lock.unlock();
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
finally {
|
|
605
|
+
lock.unlock();
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
async delete(...args) {
|
|
609
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
610
|
+
throw new UniKvsIsNotOpenError();
|
|
611
|
+
}
|
|
612
|
+
const [options] = parse(DeleteArgsSchema, args);
|
|
613
|
+
const { key, signal: signalOption, context: contextOption } = options;
|
|
614
|
+
const { conAc, ioMux } = __classPrivateFieldGet(this, _UniKvs_con, "f");
|
|
615
|
+
const signal = combineSignals([conAc.signal, signalOption]);
|
|
616
|
+
const context = mergeContext(__classPrivateFieldGet(this, _UniKvs_context, "f"), contextOption);
|
|
617
|
+
context["unikvs:action"] = "delete";
|
|
618
|
+
context["unikvs:key"] = key;
|
|
619
|
+
const lock = await asyncmux(this, signal);
|
|
620
|
+
try {
|
|
621
|
+
// ロック待機中に接続状態が変更されていないか再確認します。
|
|
622
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
623
|
+
throw new UniKvsIsNotOpenError();
|
|
624
|
+
}
|
|
625
|
+
const lock = await ioMux.lock({ key, signal });
|
|
626
|
+
try {
|
|
627
|
+
// すべてのストレージから対象データを削除します。
|
|
628
|
+
// すべての処理を並列に実行し、エラーが発生した場合は集約します。
|
|
629
|
+
const errors = [];
|
|
630
|
+
await Promise.all(__classPrivateFieldGet(this, _UniKvs_destinations, "f").map(async (storage) => {
|
|
631
|
+
try {
|
|
632
|
+
if (await storage.exists(context, signal, key)) {
|
|
633
|
+
await storage.delete(context, signal, key);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
catch (reason) {
|
|
637
|
+
errors.push({ reason });
|
|
638
|
+
}
|
|
639
|
+
}));
|
|
640
|
+
if (errors.length > 0) {
|
|
641
|
+
throw new PluginOperationAggregateError({ plugin: "storage", action: "delete", errors });
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
finally {
|
|
645
|
+
lock.unlock();
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
finally {
|
|
649
|
+
lock.unlock();
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
async clear(...args) {
|
|
653
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
654
|
+
throw new UniKvsIsNotOpenError();
|
|
655
|
+
}
|
|
656
|
+
const [options = {}] = parse(ClearArgsSchema, args);
|
|
657
|
+
const { signal: signalOption, context: contextOption } = options;
|
|
658
|
+
const { conAc, ioMux } = __classPrivateFieldGet(this, _UniKvs_con, "f");
|
|
659
|
+
const signal = combineSignals([conAc.signal, signalOption]);
|
|
660
|
+
const context = mergeContext(__classPrivateFieldGet(this, _UniKvs_context, "f"), contextOption);
|
|
661
|
+
context["unikvs:action"] = "clear";
|
|
662
|
+
const lock = await asyncmux(this, signal);
|
|
663
|
+
try {
|
|
664
|
+
// ロック待機中に接続状態が変更されていないか再確認します。
|
|
665
|
+
if (!__classPrivateFieldGet(this, _UniKvs_con, "f")) {
|
|
666
|
+
throw new UniKvsIsNotOpenError();
|
|
667
|
+
}
|
|
668
|
+
const lock = await ioMux.lock({ signal });
|
|
669
|
+
try {
|
|
670
|
+
// すべてのストレージで一括削除を実行します。
|
|
671
|
+
// すべての処理を並列に実行し、エラーが発生した場合は集約します。
|
|
672
|
+
const errors = [];
|
|
673
|
+
await Promise.all(__classPrivateFieldGet(this, _UniKvs_destinations, "f").map(async (storage) => {
|
|
674
|
+
try {
|
|
675
|
+
await storage.clear(context, signal);
|
|
676
|
+
}
|
|
677
|
+
catch (reason) {
|
|
678
|
+
errors.push({ reason });
|
|
679
|
+
}
|
|
680
|
+
}));
|
|
681
|
+
if (errors.length > 0) {
|
|
682
|
+
throw new PluginOperationAggregateError({ plugin: "storage", action: "clear", errors });
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
finally {
|
|
686
|
+
lock.unlock();
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
finally {
|
|
690
|
+
lock.unlock();
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|