pallas-db
Version:
All in the name
180 lines (179 loc) • 6.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RedisStorage = void 0;
const redis_1 = require("redis");
// Redis storage management
class RedisStorage {
client;
isConnected = false;
connectionPromise = null;
constructor(options = {}) {
const redisConfig = {
socket: {
host: options.host || 'localhost',
port: options.port || 6379
}
};
if (options.password) {
redisConfig.password = options.password;
}
if (options.database !== undefined) {
redisConfig.database = options.database;
}
if (options.url) {
// If URL is provided, use it instead of individual options
this.client = (0, redis_1.createClient)({ url: options.url });
}
else {
this.client = (0, redis_1.createClient)(redisConfig);
}
// Handle Redis connection events
this.client.on('error', (err) => {
console.error('Redis Client Error:', err);
this.isConnected = false;
});
this.client.on('connect', () => {
this.isConnected = true;
});
this.client.on('disconnect', () => {
this.isConnected = false;
});
}
async ensureConnection() {
if (this.isConnected)
return;
if (this.connectionPromise) {
return this.connectionPromise;
}
this.connectionPromise = this.client.connect().then(() => undefined);
await this.connectionPromise;
this.connectionPromise = null;
}
getTableKey(tableName, id) {
return `${tableName}:${id}`;
}
getTablePattern(tableName) {
return `${tableName}:*`;
}
async getRecord(tableName, id) {
await this.ensureConnection();
const key = this.getTableKey(tableName, id);
const value = await this.client.get(key);
if (value === null || value === undefined)
return undefined;
const stringValue = String(value);
try {
return JSON.parse(stringValue);
}
catch {
return stringValue;
}
}
async setTableData(tableName, id, value) {
await this.ensureConnection();
const key = this.getTableKey(tableName, id);
const serializedValue = JSON.stringify(value);
await this.client.set(key, serializedValue);
}
async deleteTableKey(tableName, id) {
await this.ensureConnection();
const key = this.getTableKey(tableName, id);
await this.client.del(key);
}
async clearTable(tableName) {
await this.ensureConnection();
const pattern = this.getTablePattern(tableName);
const keys = await this.client.keys(pattern);
if (keys.length > 0) {
// Convert keys to strings and delete them one by one
for (const key of keys) {
await this.client.del(String(key));
}
}
}
async hasKey(tableName, id) {
await this.ensureConnection();
const key = this.getTableKey(tableName, id);
const exists = await this.client.exists(key);
return exists === 1;
}
async getAllFromTable(tableName) {
await this.ensureConnection();
const pattern = this.getTablePattern(tableName);
const keys = await this.client.keys(pattern);
const results = [];
for (const key of keys) {
const keyStr = String(key); // Ensure key is string
const id = keyStr.substring(tableName.length + 1); // Remove table prefix
const value = await this.client.get(keyStr);
if (value !== null && value !== undefined) {
// Handle case where Redis returns an empty object
if (typeof value === 'object' && Object.keys(value).length === 0) {
continue; // Skip empty objects
}
const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
try {
const parsedValue = JSON.parse(stringValue);
results.push({ id, value: parsedValue });
}
catch {
results.push({ id, value: stringValue });
}
}
}
return results;
}
async getStats(tables) {
await this.ensureConnection();
const stats = {};
for (const tableName of tables) {
const pattern = this.getTablePattern(tableName);
const keys = await this.client.keys(pattern);
stats[tableName] = keys.length;
}
return stats;
}
async repair(tables, validateKey, validateValue) {
await this.ensureConnection();
const deletedKeys = [];
for (const tableName of tables) {
const pattern = this.getTablePattern(tableName);
const keys = await this.client.keys(pattern);
for (const key of keys) {
const keyStr = String(key); // Ensure key is string
const id = keyStr.substring(tableName.length + 1);
const value = await this.client.get(keyStr);
if (value !== null && value !== undefined) {
// Handle case where Redis returns an empty object
if (typeof value === 'object' && Object.keys(value).length === 0) {
// Empty object is invalid, delete the key
await this.client.del(keyStr);
deletedKeys.push(`${tableName}.${id}`);
continue;
}
const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
try {
const parsedValue = JSON.parse(stringValue);
if (!validateKey(id) || !validateValue(parsedValue)) {
await this.client.del(keyStr);
deletedKeys.push(`${tableName}.${id}`);
}
}
catch {
// Invalid JSON, delete the key
await this.client.del(keyStr);
deletedKeys.push(`${tableName}.${id}`);
}
}
}
}
return deletedKeys;
}
async disconnect() {
if (this.isConnected) {
await this.client.disconnect();
this.isConnected = false;
}
}
}
exports.RedisStorage = RedisStorage;