unikvs 0.0.16 → 0.0.17

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unikvs",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "description": "A modular and portable KVS client implemented in TypeScript.",
5
5
  "homepage": "https://tai-kun.github.io/unikvs/",
6
6
  "license": "MIT",
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@tai-kun/valibot-extra-lab": "^0.0.5",
28
- "@unikvs/core": "0.0.16",
28
+ "@unikvs/core": "0.0.17",
29
29
  "abort-signal-utils": "^0.0.6",
30
30
  "asyncmux": "^0.0.12",
31
31
  "call-fn-once": "^0.0.12",
@@ -35,14 +35,14 @@
35
35
  "devDependencies": {
36
36
  "@babel/plugin-proposal-decorators": "^8.0.2",
37
37
  "@rolldown/plugin-babel": "^0.2.4",
38
- "@unikvs/allow-repair": "0.0.16",
39
- "@unikvs/checksum": "0.0.16",
40
- "@unikvs/compression": "0.0.16",
41
- "@unikvs/fs.node": "0.0.16",
42
- "@unikvs/memory": "0.0.16",
43
- "@unikvs/opfs": "0.0.16",
38
+ "@unikvs/allow-repair": "0.0.17",
39
+ "@unikvs/checksum": "0.0.17",
40
+ "@unikvs/compression": "0.0.17",
41
+ "@unikvs/fs.node": "0.0.17",
42
+ "@unikvs/memory": "0.0.17",
43
+ "@unikvs/opfs": "0.0.17",
44
44
  "@unikvs/testing": "0.0.0",
45
- "@unikvs/utils": "0.0.16",
45
+ "@unikvs/utils": "0.0.17",
46
46
  "@vitest/browser-playwright": "5.0.5",
47
47
  "@vitest/coverage-istanbul": "5.0.5",
48
48
  "@vitest/coverage-v8": "5.0.5",
package/src/_contexts.ts CHANGED
@@ -15,9 +15,9 @@ import {
15
15
  type IStreamContext,
16
16
  type IReadableStream,
17
17
  type IPipelineContext,
18
+ type ITransferContext,
18
19
  type ILifecycleContext,
19
20
  type ITransformContext,
20
- type VariablesSnapshot,
21
21
  type IKeyedActionContext,
22
22
  type IDecodeStreamContext,
23
23
  type IEncodeStreamContext,
@@ -119,14 +119,9 @@ type PipelineContextInit = {
119
119
  */
120
120
  class PipelineContext implements IPipelineContext {
121
121
  /**
122
- * 変数のマップです。共有ストアの参照である場合があります。
122
+ * 実行時変数のストアです。共有する場合は参照を共有します。
123
123
  */
124
- readonly #data: Map<string, unknown>;
125
-
126
- /**
127
- * 読み取り専用の変数名の集合です。共有ストアの参照である場合があります。
128
- */
129
- readonly #readonly: Set<string>;
124
+ readonly #store: VariablesStore;
130
125
 
131
126
  /**
132
127
  * コンテキストを作成します。
@@ -136,22 +131,25 @@ class PipelineContext implements IPipelineContext {
136
131
  public constructor(init: PipelineContextInit) {
137
132
  const { store } = init;
138
133
 
139
- if (store) {
140
- // 共有ストアを参照し、下流の変更が上流に見えるようにします。
141
- this.#data = store.data;
142
- this.#readonly = store.readonly;
143
- } else {
144
- this.#data = new Map();
145
- this.#readonly = new Set();
146
- }
134
+ // 共有ストアを参照し、下流の変更が上流に見えるようにします。
135
+ this.#store = store ?? createVariablesStore();
147
136
 
148
137
  const vars = normalizeVariablesInit(init.vars);
149
138
 
150
139
  for (const [name, value] of vars) {
151
- this.#data.set(name, value);
140
+ this.#store.data.set(name, value);
152
141
  }
153
142
  }
154
143
 
144
+ /**
145
+ * 共有する実行時変数のストアを取得します。
146
+ *
147
+ * @returns 実行時変数のストアを返します。
148
+ */
149
+ public get store(): VariablesStore {
150
+ return this.#store;
151
+ }
152
+
155
153
  /**
156
154
  * 変数の値を読み取ります。
157
155
  *
@@ -160,7 +158,7 @@ class PipelineContext implements IPipelineContext {
160
158
  * @returns 変数の値を返します。
161
159
  */
162
160
  public get(name: string): unknown {
163
- return this.#data.get(name);
161
+ return this.#store.data.get(name);
164
162
  }
165
163
 
166
164
  /**
@@ -172,11 +170,11 @@ class PipelineContext implements IPipelineContext {
172
170
  * @returns 自身を返します。
173
171
  */
174
172
  public set(name: string, value: unknown): this {
175
- if (this.#readonly.has(name)) {
173
+ if (this.#store.readonly.has(name)) {
176
174
  throw new ReadonlyVariableError({ name });
177
175
  }
178
176
 
179
- this.#data.set(name, value);
177
+ this.#store.data.set(name, value);
180
178
 
181
179
  return this;
182
180
  }
@@ -190,24 +188,28 @@ class PipelineContext implements IPipelineContext {
190
188
  * @returns 自身を返します。
191
189
  */
192
190
  public setReadonly(name: string, value: unknown): this {
193
- if (this.#readonly.has(name)) {
191
+ if (this.#store.readonly.has(name)) {
194
192
  throw new ReadonlyVariableError({ name });
195
193
  }
196
194
 
197
- this.#data.set(name, value);
198
- this.#readonly.add(name);
195
+ this.#store.data.set(name, value);
196
+ this.#store.readonly.add(name);
199
197
 
200
198
  return this;
201
199
  }
200
+ }
202
201
 
203
- /**
204
- * 現在の実行時変数の浅いコピーを作成します。
205
- *
206
- * @returns 実行時変数のスナップショットを返します。
207
- */
208
- public snapshot(): VariablesSnapshot {
209
- return new Map(this.#data);
210
- }
202
+ /**
203
+ * コンテキストが共有する実行時変数のストアを取得します。
204
+ *
205
+ * 外部実装のコンテキストは共有ストアを公開しないため、独立したストアを返します。
206
+ *
207
+ * @param context 対象のコンテキストです。
208
+ *
209
+ * @returns 実行時変数のストアを返します。
210
+ */
211
+ export function getVariablesStore(context: IPipelineContext): VariablesStore {
212
+ return context instanceof PipelineContext ? context.store : createVariablesStore();
211
213
  }
212
214
 
213
215
  /**
@@ -748,7 +750,10 @@ type TransferContextInit<TAction extends "copy" | "move"> = KeyedActionContextIn
748
750
  /**
749
751
  * コピー・移動で共通のコンテキストです。
750
752
  */
751
- class TransferContext<TAction extends "copy" | "move"> extends KeyedActionContext<TAction> {
753
+ class TransferContext<TAction extends "copy" | "move">
754
+ extends KeyedActionContext<TAction>
755
+ implements ITransferContext
756
+ {
752
757
  /**
753
758
  * コピー先または移動先のキーです。
754
759
  */
package/src/_storage.ts CHANGED
@@ -2,6 +2,7 @@ import type { IStorage, IReadableStream, IWritableStream } from "@unikvs/core";
2
2
  import { asyncmux } from "asyncmux";
3
3
  import { callFnOnce } from "call-fn-once";
4
4
 
5
+ import { CopyContext, MoveContext, getVariablesStore } from "./_contexts.js";
5
6
  import { PluginLifecycle } from "./_plugin-lifecycle.js";
6
7
  import { ReadableStreamSchema, WritableStreamSchema } from "./_streams.schemas.js";
7
8
  import * as v from "./_valibot.js";
@@ -167,6 +168,27 @@ export default class UniKvsStorage {
167
168
  throw new StorageIsNotOpenError({ name: this.name });
168
169
  }
169
170
 
171
+ if (this.#io.copy === undefined) {
172
+ // copy 操作に伴う読み取りであることを伝えるために、必ず CopyContext を渡します。
173
+ const data = await this.#io.read(c);
174
+
175
+ if (c.key !== c.destinationKey) {
176
+ // copy 操作に伴う書き込みであることを伝えるために、必ず CopyContext を渡します。
177
+ // 書き込み先がコピー先になるように、キーを差し替えたコンテキストを作成します。
178
+ await this.#io.write(
179
+ new CopyContext({
180
+ key: c.destinationKey,
181
+ store: getVariablesStore(c),
182
+ signal: c.signal,
183
+ destinationKey: c.destinationKey,
184
+ }),
185
+ data,
186
+ );
187
+ }
188
+
189
+ return;
190
+ }
191
+
170
192
  await this.#io.copy(c);
171
193
  }
172
194
 
@@ -180,6 +202,38 @@ export default class UniKvsStorage {
180
202
  throw new StorageIsNotOpenError({ name: this.name });
181
203
  }
182
204
 
205
+ if (this.#io.move === undefined) {
206
+ if (c.key === c.destinationKey) {
207
+ // move 操作に伴う読み取りであることを伝えるために、必ず MoveContext を渡します。
208
+ await this.#io.read(c);
209
+
210
+ return;
211
+ }
212
+
213
+ if (this.#io.copy === undefined) {
214
+ const data = await this.#io.read(c);
215
+ // move 操作に伴う書き込みであることを伝えるために、必ず MoveContext を渡します。
216
+ // 書き込み先が移動先になるように、キーを差し替えたコンテキストを作成します。
217
+ await this.#io.write(
218
+ new MoveContext({
219
+ key: c.destinationKey,
220
+ store: getVariablesStore(c),
221
+ signal: c.signal,
222
+ destinationKey: c.destinationKey,
223
+ }),
224
+ data,
225
+ );
226
+ } else {
227
+ // move 操作に伴う複製であることを伝えるために、必ず MoveContext を渡します。
228
+ await this.#io.copy(c);
229
+ }
230
+
231
+ // move 操作に伴う削除であることを伝えるために、必ず MoveContext を渡します。
232
+ await this.#io.delete(c);
233
+
234
+ return;
235
+ }
236
+
183
237
  await this.#io.move(c);
184
238
  }
185
239