Pre release (#85)

* docs: Update README to match new version.

* docs: Update events example to use new API.

* docs: Correctly print out db query results.

* test: Remove concurrent.

* test: Remove unimplemented and 3rd party AC tests.

* test: Remove unimplemented and 3rd party identity tests.

* docs: Move jsdoc config to conf directory.

* Point package.json main at index.js to access all exported functions.

* docs: Vetted AC docs; these examples should work if implemented in code. Explicitly show orbit-db function imports.

* docs: Fix incorrectly declared write objects.

* docs: Improved canAppend documentation. Better JS syntax highlighting.

* docs: wss and define filters for localhost separately.

* docs: Simplified webSockets implementation with filters.

* docs: Return manifest json only (no hash). JS highlighting.

* docs: Remove operations documentation.

* docs: Update heading levels.

* docs: Differentiate between db types which expose put/add function.

* docs: Correctly import IPFS and pass config.

* docs: A simple method for full db replication.

* docs: Link to existing examples of db implementation.

* docs: Update heading.

* docs: JS code formatting. import statements.

* docs: Expand on the concepts of identities and identity management.

* docs: Describe head sync-ing and full replication.

* docs: Comprehensive explanation of setting up a db and sync-ing/replicating data across peers. Examples can be run in node.js.

* docs: Syntax highlighting. Correct code implementation for custom/3rd party storage implementations.

* docs: Getting started cleanup.

* docs: Manifest as an IPLD data strcture.
This commit is contained in:
Hayden Young
2023-06-18 02:13:54 +08:00
committed by GitHub
parent 0c01bd22b7
commit 85e6848f4c
7 changed files with 502 additions and 172 deletions

View File

@@ -1,4 +1,4 @@
# DB
# Databases
DB provides a variety of different data stores with a common interface.
@@ -13,14 +13,14 @@ OrbitDB provides four types of data stores:
The type of database can be specified when calling OrbitDB's `open` function by using the `type` parameter:
```
```js
const type = 'documents'
orbitdb.open('my-db', { type })
```
If no type is specified, Events will the default database type.
### Address
## Address
When a database is created, it is assigned an address by OrbitDB. The address consists of three parts:
@@ -32,7 +32,7 @@ The first part, `/orbitdb`, specifies the protocol in use. The second part, an I
In order to replicate the database with peers, the address is what you need to give to other peers in order for them to start replicating the database.
```javascript
```js
import IPFS from 'ipfs-core'
import OrbitDB from 'orbit-db'
@@ -43,7 +43,7 @@ console.log(db.address)
// /orbitdb/zdpuAmrcSRUhkQcnRQ6p4bphs7DJWGBkqczSGFYynX6moTcDL
```
### Manifest
## Manifest
The second part of the address, the IPFS multihash `zdpuAmrcSRUhkQcnRQ6p4bphs7DJWGBkqczSGFYynX6moTcDL`, is also the hash of the database's manifest. The manifest contains information about the database such as name, type and other metadata. It also contains a reference to the access controller, which is made up of the type and the hash of the access controller object.
@@ -51,70 +51,68 @@ An example of a manifest is given below:
```json
{
hash: 'zdpuAzzxCWEzRffxFrxNNVkcVFbkmA1EQdpZJJPc3wpjojkAT',
manifest: {
name: 'my-db',
type: 'events',
accessController: '/ipfs/zdpuB1TUuF5E81MFChDbRsZZ1A3Kz2piLJwKQ2ddnfZLEBx64'
}
name: 'my-db',
type: 'events',
accessController: '/ipfs/zdpuB1TUuF5E81MFChDbRsZZ1A3Kz2piLJwKQ2ddnfZLEBx64'
}
```
## Operations
The manifest is simply an [IPLD data structure](https://ipld.io/docs/) which can be retrived from IPFS just like any other hash:
Operations are of either type "PUT" or "DEL".
```js
import { create } from 'ipfs-core'
import * as Block from 'multiformats/block'
import OrbitDB from 'orbit-db'
A PUT operation describes a record which has been created or edited. If operations share the same key or id, they are assumed to be related and the operation which was created after all other operations with the same key will be the latest version of the record.
const ipfs = await create()
A DEL operation describes a record which has been removed. It will share the same key as a previous PUT operation and will indicate that the record that was PUT is now deleted.
// Create the db then close.
const orbitdb = await OrbitDB({ ipfs })
const db = await orbitdb.open('my-db')
await db.close()
A PUT record might look like:
// Get the db address.
const addr = OrbitDBAddress(db.address)
// Extract the hash from the full db path.
const bytes = await ipfs.get(addr.path)
// Defines how we serialize/hash the data.
const codec = dagCbor
const hasher = sha256
// Retrieve the block data, decoding it to human-readable JSON text.
const { value } = await Block.decode({ bytes, codec, hasher })
console.log(value)
```
{
id: 'log-1',
payload: { op: 'PUT', key: 4, value: 'Some data' },
next: [ '3' ],
refs: [
'2',
'1'
],
clock: Clock {
id: '038cc50a92f10c39f74394a1779dffb2c79ddc6b7d1bbef8c484bd4bbf8330c426',
time: 4
},
v: 2
}
```
In the above example, payload holds the information about the record. `op` is the operation carried out, in this case PUT (the other option is DEL). `key` holds a unique identifier for the record and value contains some data. In the above example, data is a string but it could be a number, XML or even the JSON representation of an object.
## Opening a new database
Opening a default event store:
```
```js
const orbitdb = await OrbitDB()
await orbitdb.open('my-db')
```
Opening a documents database:
```
```js
const orbitdb = await OrbitDB()
await orbitdb.open('my-db', { type: 'documents' })
```
Opening a keyvalue database:
```
```js
const orbitdb = await OrbitDB()
await orbitdb.open('my-db', { type: 'keyvalue' })
```
Opening a database and adding meta
```
```js
const meta = { description: 'A database with metadata.' }
const orbitdb = await OrbitDB()
await orbitdb.open('my-db', { meta })
@@ -122,10 +120,10 @@ await orbitdb.open('my-db', { meta })
## Loading an existing database
```
```js
const orbitdb = await OrbitDB()
const db = await orbitdb.open('my-db')
db.close()
await db.close()
const dbReopened = await orbitdb.open(db.address)
```
@@ -133,25 +131,17 @@ const dbReopened = await orbitdb.open(db.address)
### Adding/Putting items in a database
All databases expose a common `put` function which is used to add items to the database.
Database types such as **documents** and **keyvalue** expose the `put` function which is used to add items as a key/value combination to the database.
```
```js
const orbitdb = await OrbitDB()
const db = await orbitdb.open('my-db', { type: keyvalue })
const hash = await db.put('key', 'value')
```
For databases such as Events which is an append-only data store, a `null` key will need to be used:
Alternatively, append-only database types such as **events** expose the `add` function which adds a value to the database:
```
const orbitdb = await OrbitDB()
const db = await orbitdb.open('my-db')
const hash = await db.put(null, 'event')
```
Alternatively, append-only databases can implement the convenience function `add`:
```
```js
const orbitdb = await OrbitDB()
const db = await orbitdb.open('my-db')
const hash = await db.add('event')
@@ -159,9 +149,9 @@ const hash = await db.add('event')
### Removing/Deleting items from a database
To delete an item from a databse, use the `del` function:
To delete an item from a database, use the `del` function:
```
```js
const orbitdb = await OrbitDB()
const db = await orbitdb.open('my-db', { type: keyvalue })
const hash = await db.put('key', 'value')
@@ -170,24 +160,49 @@ await db.del(hash)
## Replicating a database across peers
```
import * as IPFS from 'ipfs-core'
The power of OrbitDB lies in its ability to replicate databases across distributed systems that may not always be connected.
const ipfs1 = await IPFS.create({ config1, repo: './ipfs1' })
const ipfs2 = await IPFS.create({ config2, repo: './ipfs2' })
A simple replication process between two databases can be accomplished by listening for updates and iterating over the record set as those updates occur.
```js
import { create } from 'ipfs-core'
import { OrbitDB } from 'orbit-db'
const ipfs1 = await create({ config1, repo: './ipfs1' })
const ipfs2 = await create({ config2, repo: './ipfs2' })
orbitdb1 = await OrbitDB({ ipfs: ipfs1, id: 'user1', directory: './orbitdb1' })
orbitdb2 = await OrbitDB({ ipfs: ipfs2, id: 'user2', directory: './orbitdb2' })
const db1 = await orbitdb1.open('my-db')
await db1.add('hello world')
// Opening a db by address will start the synchronization process but only the
// database heads will be synchronized.
const db2 = await orbitdb2.open(db1.address)
// We only have the heads of db1. To replicate all of db1's records, we will
// need to iterate over db1's entire record set.
// We can determine when heads have been synchronized from db1 to db2 by
// listening for the "update" event and iterating over the record set.
db2.events.on('update', async (entry) => {
for await (const record of db2.iterator()) {
console.log(record)
}
// we can use the convenience function db.all() instead of iterating over
// db2's records.
// await db2.all()
})
```
To learn more, check out [OrbitDB's sychronization protocol](https://orbitdb.org/api/module-Sync.html) and the [OrbitDB replication documentation](./REPLICATION.md).
## Building a custom database
OrbitDB can be extended to use custom or third party data stores. To implement a custom database, ensure the Database object is extended and that the OrbitDB database interface is implement. The database will also require a unique type.
```
```js
const CustomStore = async ({ OpLog, Database, ipfs, identity, address, name, access, directory, storage, meta, syncAutomatically, indexBy = '_id' }) => {
const database = await Database({ OpLog, ipfs, identity, address, name, access, directory, storage, meta, syncAutomatically })
@@ -229,4 +244,6 @@ const CustomStore = async ({ OpLog, Database, ipfs, identity, address, name, acc
iterator
}
}
```
```
[Documents](../src/db/documents.js), [Events](../src/db/events.js) and [KeyValue](../src/db/keyvalue.js) provide good examples of how a database is implemented in OrbitDB.