Skip to content
UniKVS
Esc
↑↓navigate↵open⌘Jpreview
On this page

Using Multiple Storages

How to write to multiple storages and repair on read.

Register multiple storages when combining, for example, a fast backend with a durable one.

Register Multiple Storages

Calling persist() multiple times writes to every backend in parallel. Reads check backends in registration order and return the value from the first backend that has it.

import { Memory } from "@unikvs/memory";
import { NodeFs } from "@unikvs/fs.node";
import * as unikvs from "unikvs";

const kvs = new unikvs.Builder<{
  profile: unikvs.PlainValue<Uint8Array>;
}>()
  .persist(new Memory())
  .persist(new NodeFs(".unikvs"))
  .build();

In this example, writes go to both memory and files, while reads check memory first.

copy() and move() also apply to every backend where the source exists. If the source exists in only some backends, only those backends are updated. If it exists in none, the operation throws KeyNotFoundError.

Repair on Read

get() and stream() accept repair: true to write values found in later backends back to earlier ones. The default is false.

const bytes = await kvs.get("profile", { repair: true });

To control repair, use @unikvs/allow-repair. On branches that disallow repair, reads still succeed and a warning is logged. To fail reads when repair is denied, pass throwOnRepairDenied: true.

import { AllowRepair } from "@unikvs/allow-repair";

const noRepair = new AllowRepair();
noRepair.disable();

const kvs = new unikvs.Builder<{
  profile: unikvs.PlainValue<Uint8Array>;
}>()
  .persist(new Memory())
  .fork(new unikvs.Branch().use(noRepair).persist(new NodeFs(".unikvs")))
  .build();

Vary Transformations per Storage

Use fork() when each branch needs a different middleware combination. Each backend uses a snapshot of the pipeline taken at the time persist() is called. Middleware added after registration therefore does not affect already-registered backends.

import { Json } from "@unikvs/json";
import { Memory } from "@unikvs/memory";
import { NodeFs } from "@unikvs/fs.node";
import * as unikvs from "unikvs";

const kvs = new unikvs.Builder<{
  settings: unikvs.PlainValue<Uint8Array>;
}>()
  .fork(new unikvs.Branch().use(new Json()).persist(new Memory()))
  .persist(new NodeFs(".unikvs"))
  .build();

In this example, JSON transformation applies only to the memory side; the file side stores raw bytes.

Was this page helpful?