Varasto 📦

Varasto is minimalistic namespaced key-value store written in TypeScript that can store JSON objects identified by namespace and key. Objects can be persisted on disk, database or remote server.

Installation

Choose storage backend that best suits your needs:

Package Description
@varasto/cache-storage Acts as an cache for another storage.
@varasto/fs-storage Persists data to hard disk.
@varasto/memory-storage Data is stored in memory. No persistence.
@varasto/multi-storage Data is stored to multiple storages.
@varasto/postgres-storage Data is stored to PostgreSQL database.
@varasto/remote-storage Data is stored to remote server.
@varasto/redis-storage Data is stored to Redis.
@varasto/single-file-storage Data is stored to single file.
@varasto/sqlite-storage Data is stored to SQLite database.
@varasto/validator-storage Acts as an validator middleware for another storage.
@varasto/web-storage Data is stored to browser storage.

Varasto also has an HTTP interface and useful utilities for querying data and doing bulk operations and even an simple ORM.

Usage

Storage class provided by an backend has following methods:

Storing items

set<T extends JsonObject>(
  namespace: string,
  key: string,
  value: T
): Promise<void>

Attempts to store an item identified by namespace and key.

Returned promise will fail if an I/O error occurs while storing the item.

Example
type Item = {
  value: number;
};

await storage.set<Item>("items", "c57aa66c-2512-11f1-8836-cfad1ba1ae45", { value: 5 });

Retrieving items

get<T extends JsonObject>(
  namespace: string,
  key: string
): Promise<T | undefined>

Attempts to retrieve an item identified by namespace and key. Returned promise will either resolve into the value, or undefined if item with the given identifier does not exist.

The promise will fail if an I/O error occurs while retrieving the item.

Example
type Item = {
  value: number;
};

const item = await storage.get<Item>("items", "c57aa66c-2512-11f1-8836-cfad1ba1ae45");

if (item != null) {
  console.log(`Value of the item is: ${item.value}`);
} else {
  console.error("Item does not exist.");
}

Removing items

delete(
  namespace: string,
  key: string
): Promise<boolean>

Attempts to remove an item identified by namespace and key. Returned promise will resolve into a boolean value which tells whether an value with the given identifier existed or not.

The promise will fail if an I/O error occurs while removing the item.

Example
if (await storage.delete("items", "c57aa66c-2512-11f1-8836-cfad1ba1ae45")) {
  console.log("Item successfully removed.");
} else {
  console.error("Item does not exist.");
}

Updating already existing item

update<T extends JsonObject>(
  namespace: string,
  key: string,
  value: Partial<T>
): Promise<T>

Attempts to update an already existing item identified by namespace and key by shallowly merging with the given new data.

Returned promise will resolve into the new value, or will fail if no such item exists.

Example
type Person = {
  name: string;
  age: number;
};

const john = await storage.update<Person>("people", "john", { age: 39 });

console.log(`Age of ${john.name} is now ${john.age}.`);

Testing whether an item exists or not

has(
  namespace: string,
  key: string
): Promise<boolean>

Returns true if an item identified by namespace and key exists in the storage, or false if it doesn't.

The promise will fail if an I/O error occurs while testing whether item exists or not.

Example
if (await storage.has("items", "c57aa66c-2512-11f1-8836-cfad1ba1ae45")) {
  console.log("Item does exist.");
}

Listing keys stored in a namespace

keys(
  namespace: string
): AsyncGenerator<string>

Returns keys of all items stored under an namespace. The promise will fail if an I/O error occurs while listing the keys.

Example
for await (const key of storage.keys("items")) {
  console.log(key);
}

Listing values stored in a namespace

values<T extends JsonObject>(
  namespace: string
): AsyncGenerator<T>

Returns all items stored under an namespace.

The promise will fail if an I/O error occurs.

Example
type Person = {
  name: string;
  age: number;
};

for await (const person of storage.values<Person>("people")) {
  console.log(`${person.name}, ${person.age} years young.`);
}

Listing entries stored in a namespace

entries<T extends JsonObject>(
  namespace: string
): AsyncGenerator<[string, T]>

Returns all items stored under an namespace, with the keys they are identified by.

The promise will fail if an I/O error occurs.

Example
type Item = {
  value: number;
};

for await (const [key, item] of storage.entries<Item>("items")) {
  console.log(`${item.value} was stored with key ${key}.`);
}

Searching for entries stored in a namespace

find<T extends JsonObject>(
  namespace: string,
  callback: (value: T, key: string) => boolean
): Promise<[string, T] | undefined>

Returns the first entry from specified namespace to which given callback function returns true for, or undefined if the callback function does not return true for any entry in the namespace.

The promise will fail if an I/O error occurs.

Example
type Item = {
  value: number;
};

const item = await storage.find<Item>("items", (item) => item.value === 42);

if (item != null) {
  console.log(`Number ${item[1]} was stored with key ${item[0]}.`);
}

Filtering entries stored in a namespace

filter<T extends JsonObject>(
  namespace: string,
  callback: (value: T, key: string) => boolean
): AsyncGenerator<[string, T]>

Goes through all entries from the given namespace, returning ones for which the given callback function returns true for.

The promise will fail if an I/O error occurs.

Example
type Item = {
  value: number;
};

for await (const [key, item] of storage.filter<Item>("items", (item) => item.value > 10)) {
  console.log(`${key}: ${item.value}`);
}

Map operation

map<T extends JsonObject, U extends JsonObject>(
  namespace: string,
  callback: (value: T, key: string) => U
): AsyncGenerator<[string, U]>

Goes through all entries from given namespace, passing them to the given callback function and returning whatever the callback function returned.

The promise will fail if an I/O error occurs.

Example
type Item = {
  value: number;
};

type ItemAsString = {
  value: string;
};

const itemsAsStrings = await storage.map<Item, ItemAsString>(
  "items",
  (item) => ({ value: `${item.value}` })
);