datastore-core
Version:
Wrapper implementation for interface-datastore
108 lines • 3.43 kB
JavaScript
import { Key } from 'interface-datastore';
import { OpenFailedError } from 'interface-store';
import { BaseDatastore } from './base.js';
import { KeyTransformDatastore } from './keytransform.js';
import { readShardFun, SHARDING_FN } from './shard.js';
const shardKey = new Key(SHARDING_FN);
/**
* Backend independent abstraction of go-ds-flatfs.
*
* Wraps another datastore such that all values are stored
* sharded according to the given sharding function.
*/
export class ShardingDatastore extends BaseDatastore {
child;
shard;
constructor(store, shard) {
super();
this.child = new KeyTransformDatastore(store, {
convert: this._convertKey.bind(this),
invert: this._invertKey.bind(this)
});
this.shard = shard;
}
async open() {
this.shard = await ShardingDatastore.create(this.child, this.shard);
}
_convertKey(key) {
const s = key.toString();
if (s === shardKey.toString()) {
return key;
}
const parent = new Key(this.shard.fun(s));
return parent.child(key);
}
_invertKey(key) {
const s = key.toString();
if (s === shardKey.toString()) {
return key;
}
return Key.withNamespaces(key.list().slice(1));
}
static async create(store, shard) {
const hasShard = await store.has(shardKey);
if (!hasShard) {
if (shard == null) {
throw new OpenFailedError('Shard is required when datastore doesn\'t have a shard key already');
}
await store.put(shardKey, new TextEncoder().encode(shard.toString() + '\n'));
}
if (shard == null) {
shard = await readShardFun('/', store);
}
// test shards
const diskShard = await readShardFun('/', store);
const a = diskShard.toString();
const b = shard.toString();
if (a !== b) {
throw new Error(`specified fun ${b} does not match repo shard fun ${a}`);
}
return diskShard;
}
async put(key, val, options) {
await this.child.put(key, val, options);
return key;
}
async get(key, options) {
return this.child.get(key, options);
}
async has(key, options) {
return this.child.has(key, options);
}
async delete(key, options) {
await this.child.delete(key, options);
}
async *putMany(source, options = {}) {
yield* this.child.putMany(source, options);
}
async *getMany(source, options = {}) {
yield* this.child.getMany(source, options);
}
async *deleteMany(source, options = {}) {
yield* this.child.deleteMany(source, options);
}
batch() {
return this.child.batch();
}
query(q, options) {
const omitShard = ({ key }) => key.toString() !== shardKey.toString();
const tq = {
...q,
filters: [
omitShard
].concat(q.filters ?? [])
};
return this.child.query(tq, options);
}
queryKeys(q, options) {
const omitShard = (key) => key.toString() !== shardKey.toString();
const tq = {
...q,
filters: [
omitShard
].concat(q.filters ?? [])
};
return this.child.queryKeys(tq, options);
}
}
//# sourceMappingURL=sharding.js.map