@constl/bohr-db
Version:
Type-safe databases for orbit-db.
130 lines (101 loc) • 4.02 kB
Markdown
# BohrDB
Discrete types for your OrbitDBs.
[](https://github.com/reseau-constellation/bohr-db/actions/workflows/tests.yml)
[](https://codecov.io/gh/reseau-constellation/bohr-db)
## Installation
```
$ pnpm add @constl/bohr-db
```
## Introduction
Bohr-DB brings both **TypeScript and runtime-checked types to your orbit-db databases**, so that you can be sure that you'll only receive values that correspond to your specified data schema.
Borh-DB uses AJV to check for data validity behind the scenes. It wraps around existing orbit-db databases with a proxy, so you can use typed Borh-DB databases as a **drop-in and type-safe replacement for the original orbit-db databases** in your code.
Note: `KeyValue` also offers the additional property `.allAsJSON()`, which returns a key, value object instead of a list of entries.
## Why is it called Bohr-DB?
...because now your orbits can only take on [deterministic values](https://en.wikipedia.org/wiki/Bohr_model).
## Support
Borh-DB currently supports the orbit-db `KeyValue`, as well as the `Feed`, `Set` and `OrderedKeyValue` databases from `@constl/orbit-db-kuiper`. Pull requests for additional db types are of course welcome!
## Examples
Below are a few examples of `bohr-db` with `KeyValue` and `Set` databases. See the test folder for examples with other orbit-db database types.
### Set
As simple example with `Set`:
```ts
import { createOrbit, useDatabaseType } from "@orbitdb/core";
import { SetDb } from "@orbitdb/set-db";
import { typedSet } from "@constl/bohr-db";
// Register set-db database type. IMPORTANT - must call before creating orbit instance !
useDatabaseType(SetDb);
const orbit = await createOrbit({ ipfs })
const db = await orbit.open({ type: "set" });
const typedDB = typedSet({
db,
schema: numericSchema,
}); // Is exactly the same as `db`, but now type-safe
console.log(typedDB.type) // "set"
// Add valid values
await typedDB.add(1);
await typedDB.add(2);
const all = await typedDB.all(); // [1, 2]
// Invalid values are not added
await typedDB.add("not a number") // throws both TypeScript and runtime errors !
// Even invalid values somehow added to the log (already present, or received from a peer) will not appear in the data
// Force write invalid value to underlying orbit-db database
await db.add("not a number");
await typedDB.all() // Yay !! Still [1, 2]
```
Any `ajv` schema can be used, for more complex data types:
```ts
type structure = {
a: number;
b?: string;
};
const objectSchema: JSONSchemaType<structure> = {
type: "object",
properties: {
a: { type: "number" },
b: { type: "string", nullable: true },
},
required: ["a"],
};
const db = await orbit.open({ type: "set" });
const typedDB = typedSet({
db,
schema: objectSchema,
});
// Valid data
await typedDB.add({ a: 1, b: "c" });
// Error !!
await typedDB.add({ a: 1, b: 2 });
```
### KeyValue
A more complex example with `KeyValue`:
```ts
import { typedKeyValue } from "@constl/bohr-db";
type structure = { a: number, b: { c: string, d?: number } };
const schema: JSONSchemaType<Partial<structure>> = {
type: "object",
properties: {
a: { type: "number", nullable: true },
b: {
type: "object",
properties: {
c: { type: "string" },
d: { type: "number", nullable: true}
}
nullable: true,
required: []
}
},
required: [],
};
const db = await orbit.open({ type: "keyvalue" });
const typedDB = typedKeyValue({
db,
schema: objectSchema,
});
// Add valid data
await typedDB.put("a", 1);
await typedDB.put("b", { c: 1, d: "e" });
const values = await typedDB.allAsJSON();
// Invalid data
await typedDB.put("a", "text") // Error !!
```