datastore-core
Version:
Wrapper implementation for interface-datastore
142 lines • 4.38 kB
JavaScript
import { DeleteFailedError, NotFoundError, PutFailedError } from 'interface-store';
import filter from 'it-filter';
import merge from 'it-merge';
import sort from 'it-sort';
import take from 'it-take';
import { BaseDatastore } from './base.js';
/**
* A datastore that can combine multiple stores inside various
* key prefixes
*/
export class MountDatastore extends BaseDatastore {
mounts;
constructor(mounts) {
super();
this.mounts = mounts.slice();
}
/**
* Lookup the matching datastore for the given key
*/
_lookup(key) {
for (const mount of this.mounts) {
if (mount.prefix.toString() === key.toString() || mount.prefix.isAncestorOf(key)) {
return {
datastore: mount.datastore,
mountpoint: mount.prefix
};
}
}
}
async put(key, value, options) {
const match = this._lookup(key);
if (match == null) {
throw new PutFailedError('No datastore mounted for this key');
}
await match.datastore.put(key, value, options);
return key;
}
/**
* @param {Key} key
* @param {Options} [options]
*/
async get(key, options = {}) {
const match = this._lookup(key);
if (match == null) {
throw new NotFoundError('No datastore mounted for this key');
}
return match.datastore.get(key, options);
}
async has(key, options) {
const match = this._lookup(key);
if (match == null) {
return Promise.resolve(false);
}
return match.datastore.has(key, options);
}
async delete(key, options) {
const match = this._lookup(key);
if (match == null) {
throw new DeleteFailedError('No datastore mounted for this key');
}
await match.datastore.delete(key, options);
}
batch() {
const batchMounts = {};
const lookup = (key) => {
const match = this._lookup(key);
if (match == null) {
throw new Error('No datastore mounted for this key');
}
const m = match.mountpoint.toString();
if (batchMounts[m] == null) {
batchMounts[m] = match.datastore.batch();
}
return {
batch: batchMounts[m]
};
};
return {
put: (key, value) => {
const match = lookup(key);
match.batch.put(key, value);
},
delete: (key) => {
const match = lookup(key);
match.batch.delete(key);
},
commit: async (options) => {
await Promise.all(Object.keys(batchMounts).map(async (p) => { await batchMounts[p].commit(options); }));
}
};
}
query(q, options) {
const qs = this.mounts.map(m => {
return m.datastore.query({
prefix: q.prefix,
filters: q.filters
}, options);
});
let it = merge(...qs);
if (q.filters != null) {
q.filters.forEach(f => { it = filter(it, f); });
}
if (q.orders != null) {
q.orders.forEach(o => { it = sort(it, o); });
}
if (q.offset != null) {
let i = 0;
const offset = q.offset;
it = filter(it, () => i++ >= offset);
}
if (q.limit != null) {
it = take(it, q.limit);
}
return it;
}
queryKeys(q, options) {
const qs = this.mounts.map(m => {
return m.datastore.queryKeys({
prefix: q.prefix,
filters: q.filters
}, options);
});
/** @type AsyncIterable<Key> */
let it = merge(...qs);
if (q.filters != null) {
q.filters.forEach(f => { it = filter(it, f); });
}
if (q.orders != null) {
q.orders.forEach(o => { it = sort(it, o); });
}
if (q.offset != null) {
let i = 0;
const offset = q.offset;
it = filter(it, () => i++ >= offset);
}
if (q.limit != null) {
it = take(it, q.limit);
}
return it;
}
}
//# sourceMappingURL=mount.js.map