deepbase
Version:
⚡ DeepBase - Fastest and simplest way to add persistence to your projects.
154 lines (126 loc) • 3.84 kB
JavaScript
import { customAlphabet } from 'nanoid';
export class DeepBaseDriver {
constructor({nidAlphabet, nidLength, ...opts} = {}) {
this.opts = opts;
this.nidAlphabet = nidAlphabet || "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
this.nidLength = nidLength || 10;
this.nanoid = customAlphabet(this.nidAlphabet, this.nidLength);
this._connected = false;
}
async connect() {
// Default implementation does nothing
this._connected = true;
}
async disconnect() {
// Default implementation does nothing
}
async get(...args) {
throw new Error('get() must be implemented by driver');
}
getSync(...args) {
throw new Error('getSync() is not implemented by this driver');
}
async set(...args) {
throw new Error('set() must be implemented by driver');
}
async del(...args) {
throw new Error('del() must be implemented by driver');
}
async inc(...args) {
throw new Error('inc() must be implemented by driver');
}
async dec(...args) {
throw new Error('dec() must be implemented by driver');
}
async add(...args) {
throw new Error('add() must be implemented by driver');
}
async upd(...args) {
throw new Error('upd() must be implemented by driver');
}
async pop(...args) {
throw new Error('pop() must be implemented by driver');
}
async shift(...args) {
throw new Error('shift() must be implemented by driver');
}
async keys(...args) {
const r = await this.get(...args);
return (r !== null && typeof r === "object") ? Object.keys(r) : [];
}
async first(...args) {
const keys = await this.keys(...args);
return keys[0];
}
async last(...args) {
const keys = await this.keys(...args);
return keys[keys.length - 1];
}
async values(...args) {
const r = await this.get(...args);
return (r !== null && typeof r === "object") ? Object.values(r) : [];
}
async entries(...args) {
const r = await this.get(...args);
return (r !== null && typeof r === "object") ? Object.entries(r) : [];
}
async len(...args) {
const k = await this.keys(...args);
return k.length;
}
/**
* Escape special characters in a key component
* Escapes backslashes first, then dots
* @param {string} str - The string to escape
* @returns {string} The escaped string
*/
_escapeDots(str) {
return str.replace(/\\/g, '\\\\').replace(/\./g, '\\.');
}
/**
* Unescape special characters in a key component
* Unescapes dots first, then backslashes
* @param {string} str - The string to unescape
* @returns {string} The unescaped string
*/
_unescapeDots(str) {
return str.replace(/\\\./g, '.').replace(/\\\\/g, '\\');
}
/**
* Convert a path array to a key string with proper escaping
* @param {Array} path - Array of path components
* @returns {string} Escaped key string with dots as separators
*/
_pathToKey(path) {
return path.map(key => this._escapeDots(String(key))).join('.');
}
/**
* Convert a key string to a path array, handling escaped dots
* @param {string} key - The key string to parse
* @returns {Array} Array of unescaped path components
*/
_keyToPath(key) {
const parts = [];
let current = '';
let i = 0;
while (i < key.length) {
if (key[i] === '\\' && i + 1 < key.length) {
// Escaped character
current += key[i] + key[i + 1];
i += 2;
} else if (key[i] === '.') {
// Unescaped dot = separator
parts.push(this._unescapeDots(current));
current = '';
i++;
} else {
current += key[i];
i++;
}
}
if (current || parts.length > 0) {
parts.push(this._unescapeDots(current));
}
return parts;
}
}