@naturalcycles/db-lib
Version:
Lowest Common Denominator API to supported Databases
164 lines (163 loc) • 5.1 kB
JavaScript
import { AppError } from '@naturalcycles/js-lib/error/error.util.js';
import { SKIP } from '@naturalcycles/js-lib/types';
import { zip2 } from '@naturalcycles/nodejs-lib/zip';
/**
* @deprecated use zstd instead, gzip is obsolete
*/
export function commonKeyValueDaoDeflatedJsonTransformer() {
return {
valueToBuffer: v => zip2.deflateSync(JSON.stringify(v)),
bufferToValue: buf => JSON.parse(zip2.inflateToStringSync(buf)),
};
}
export function commonKeyValueDaoZstdJsonTransformer(level) {
return {
valueToBuffer: v => zip2.zstdCompressSync(JSON.stringify(v), level),
bufferToValue: buf => JSON.parse(zip2.zstdDecompressToStringSync(buf)),
};
}
/**
* Saves: zstd
* Reads: zstd or deflate (backwards compatible)
*/
export function commonKeyValueDaoCompressedTransformer() {
return {
valueToBuffer: v => zip2.zstdCompressSync(JSON.stringify(v)),
bufferToValue: buf => JSON.parse(zip2.decompressZstdOrInflateToStringSync(buf)),
};
}
// todo: logging
// todo: readonly
export class CommonKeyValueDao {
constructor(cfg) {
this.cfg = {
logger: console,
...cfg,
};
}
cfg;
async ping() {
await this.cfg.db.ping();
}
async createTable(opt = {}) {
await this.cfg.db.createTable(this.cfg.table, opt);
}
async getById(id) {
if (!id)
return null;
const [r] = await this.getByIds([id]);
return r?.[1] || null;
}
async getByIdAsBuffer(id) {
if (!id)
return null;
const [r] = await this.cfg.db.getByIds(this.cfg.table, [id]);
return r?.[1] || null;
}
async requireById(id) {
const [r] = await this.getByIds([id]);
if (!r) {
const { table } = this.cfg;
throw new AppError(`DB row required, but not found in ${table}`, {
table,
id,
});
}
return r[1];
}
async requireByIdAsBuffer(id) {
const [r] = await this.cfg.db.getByIds(this.cfg.table, [id]);
if (!r) {
const { table } = this.cfg;
throw new AppError(`DB row required, but not found in ${table}`, {
table,
id,
});
}
return r[1];
}
async getByIds(ids) {
const entries = await this.cfg.db.getByIds(this.cfg.table, ids);
if (!this.cfg.transformer)
return entries;
return entries.map(([id, raw]) => [id, this.cfg.transformer.bufferToValue(raw)]);
}
async getByIdsAsBuffer(ids) {
return await this.cfg.db.getByIds(this.cfg.table, ids);
}
async save(id, value, opt) {
await this.saveBatch([[id, value]], opt);
}
async saveBatch(entries, opt) {
const { transformer } = this.cfg;
let rawEntries;
if (!transformer) {
rawEntries = entries;
}
else {
rawEntries = entries.map(([id, v]) => [id, transformer.valueToBuffer(v)]);
}
await this.cfg.db.saveBatch(this.cfg.table, rawEntries, opt);
}
async deleteByIds(ids) {
await this.cfg.db.deleteByIds(this.cfg.table, ids);
}
async deleteById(id) {
await this.cfg.db.deleteByIds(this.cfg.table, [id]);
}
streamIds(limit) {
return this.cfg.db.streamIds(this.cfg.table, limit);
}
streamValues(limit) {
const { transformer } = this.cfg;
if (!transformer) {
return this.cfg.db.streamValues(this.cfg.table, limit);
}
return this.cfg.db.streamValues(this.cfg.table, limit).mapSync(buf => {
try {
return transformer.bufferToValue(buf);
}
catch (err) {
this.cfg.logger.error(err);
return SKIP;
}
});
}
streamEntries(limit) {
const { transformer } = this.cfg;
if (!transformer) {
return this.cfg.db.streamEntries(this.cfg.table, limit);
}
return this.cfg.db.streamEntries(this.cfg.table, limit).mapSync(([id, buf]) => {
try {
return [id, transformer.bufferToValue(buf)];
}
catch (err) {
this.cfg.logger.error(err);
return SKIP;
}
});
}
async getAllKeys(limit) {
return await this.streamIds(limit).toArray();
}
async getAllValues(limit) {
return await this.streamValues(limit).toArray();
}
async getAllEntries(limit) {
return await this.streamEntries(limit).toArray();
}
/**
* Increments the `id` field by the amount specified in `by`,
* or by 1 if `by` is not specified.
*
* Returns the new value of the field.
*/
async increment(id, by = 1) {
const [t] = await this.cfg.db.incrementBatch(this.cfg.table, [[id, by]]);
return t[1];
}
async incrementBatch(entries) {
return await this.cfg.db.incrementBatch(this.cfg.table, entries);
}
}