import CID from 'cids'
import { Query, Key, Datastore, Result } from 'interface-datastore'
/**
* Block represents an immutable block of data that is uniquely referenced with a cid.
*
* It satisfies the default IPFS IPLD block interface: https://github.com/ipld/js-ipld-block.
*/
export class Block {
/**
* Block creates an immutable block of data with the given content identifier (CID).
*
* @param {Buffer} data The data to be stored in the block as a buffer.
* @param {CID} cid The content identifier of the data.
*/
constructor(readonly data: Buffer, readonly cid: CID) {}
}
/**
* BlockStore is a simple key/value store for adding, deleting, and retrieving immutable blocks of data.
*
* It satisfies the default IPFS block store interface: https://github.com/ipfs/js-ipfs-repo.
*/
export class BlockStore {
/**
* BlockStore creates a new block store.
*
* @param {Datastore} store The underlying datastore for locally caching immutable blocks of data.
*/
constructor(private store: Datastore) {}
/**
* cidToKey transforms a CID to the appropriate block store key.
*
* @param {CID} cid The content identifier for an immutable block of data.
*/
static cidToKey = (cid: CID) => {
if (!CID.isCID(cid)) {
throw new Error('Not a valid CID')
}
// We'll only deal with CID version 1
return new Key('/' + cid.toV1().toString(), false)
}
/**
* keyToCid transforms a block store key to a CID.
*
* @param {Key} key The key used to encode the CID.
*/
static keyToCid = (key: Key) => {
return new CID(key.toString().slice(1))
}
/**
* put adds a block to the block store.
*
* @param {Block} block An immutable block of data.
*/
async put(block: Block) {
const k = BlockStore.cidToKey(block.cid)
if (await this.store.has(k)) {
return
}
return this.store.put(k, block.data)
}
/**
* putMany adds multiple blocks to the store.
*
* @param {Iterable<Block>} blocks An iterable of immutable blocks of data.
*/
async putMany(blocks: Iterable<Block>) {
const batch = this.store.batch()
for await (const block of blocks) {
const k = BlockStore.cidToKey(block.cid)
if (await this.store.has(k)) {
continue
}
batch.put(k, block.data)
}
return await batch.commit()
}
/**
* get returns a block by cid.
*
* @param {CID} cid The content identifier for an immutable block of data.
*/
async get(cid: CID) {
const k = BlockStore.cidToKey(cid)
return new Block(await this.store.get(k), cid)
}
/**
* delete removes a block from the store.
*
* @param {CID} cid The content identifier for an immutable block of data.
*/
async delete(cid: CID) {
return this.store.delete(BlockStore.cidToKey(cid))
}
/**
* has returns whether the store contains the block associated with the given CID.
*
* @param {CID} cid The content identifier for an immutable block of data.
*/
async has(cid: CID) {
return this.store.has(BlockStore.cidToKey(cid))
}
/**
* query searches the store for blocks matching the query parameters. It returns results from the underlying
* datastore (i.e., not Blocks).
*
* @param {Query} query A set of query options to use when querying the underlying datastore.
*/
async *query(query: Query): AsyncIterableIterator<Result> {
for await (const result of this.store.query(query)) {
yield result
}
}
}
Source