deepbase-redis
Version:
⚡ DeepBase Redis (vanilla) - driver
393 lines (310 loc) • 12.8 kB
JavaScript
import assert from 'assert';
import { DeepBase } from '../../core/src/index.js';
import { RedisDriver } from '../src/RedisDriver.js';
describe('RedisDriver', function() {
let db;
let testCounter = 0;
// Increase timeout for Redis operations
this.timeout(10000);
beforeEach(async function() {
testCounter++;
db = new DeepBase(new RedisDriver({
url: 'redis://localhost:6379',
prefix: `test_${testCounter}`
}));
try {
await db.connect();
} catch (error) {
this.skip(); // Skip tests if Redis is not available
}
});
afterEach(async function() {
if (db) {
try {
await db.del(); // Clear all data
await db.disconnect();
} catch (error) {
// Ignore cleanup errors
}
}
});
describe('Connection', function() {
it('should connect to Redis', async function() {
const driver = db.getDriver(0);
assert.ok(driver.client);
assert.ok(driver.client.isOpen);
});
});
describe('Basic Operations', function() {
it('should set and get a simple value', async function() {
await db.set('key1', 'value');
const result = await db.get('key1');
assert.strictEqual(result, 'value');
});
it('should set and get nested values', async function() {
await db.set('user', 'name', 'Alice');
await db.set('user', 'age', 30);
const name = await db.get('user', 'name');
const age = await db.get('user', 'age');
assert.strictEqual(name, 'Alice');
assert.strictEqual(age, 30);
});
it('should get entire nested object', async function() {
await db.set('user', 'name', 'Bob');
await db.set('user', 'age', 25);
const user = await db.get('user');
assert.strictEqual(user.name, 'Bob');
assert.strictEqual(user.age, 25);
});
it('should return null for non-existent keys', async function() {
const result = await db.get('nonexistent');
assert.strictEqual(result, null);
});
it('should get all keys', async function() {
await db.set('key1', 'value1');
await db.set('key2', 'value2');
const all = await db.get();
assert.ok(all.key1);
assert.ok(all.key2);
assert.strictEqual(all.key1, 'value1');
assert.strictEqual(all.key2, 'value2');
});
});
describe('Keys with Dots', function() {
it('should handle keys containing dots', async function() {
const setResult = await db.set('value', 'martin.clasen@gmail.com', 1);
assert.strictEqual(setResult.length, 2);
assert.strictEqual(setResult[0], 'value');
assert.strictEqual(setResult[1], 'martin.clasen@gmail.com');
const getValue = await db.get('value');
assert.strictEqual(getValue['martin.clasen@gmail.com'], 1);
});
it('should handle keys with multiple dots', async function() {
await db.set('config', 'api.prod.endpoint', 'https://api.example.com');
const endpoint = await db.get('config', 'api.prod.endpoint');
assert.strictEqual(endpoint, 'https://api.example.com');
});
it('should handle nested paths with dots in keys', async function() {
await db.set('users', 'john.doe@example.com', 'name', 'John Doe');
await db.set('users', 'john.doe@example.com', 'age', 30);
const user = await db.get('users', 'john.doe@example.com');
assert.strictEqual(user.name, 'John Doe');
assert.strictEqual(user.age, 30);
});
it('should handle dots in first level keys', async function() {
await db.set('config.prod', 'value', 100);
const configProd = await db.get('config.prod');
assert.strictEqual(configProd.value, 100);
});
it('should distinguish between dots in keys and path separators', async function() {
// Set a regular nested path
await db.set('users', 'alice', 'email', 'alice@example.com');
// Set a key with dots at the same level
await db.set('users', 'john.doe@company.com', 'email', 'john@work.com');
const users = await db.get('users');
assert.strictEqual(users.alice.email, 'alice@example.com');
assert.strictEqual(users['john.doe@company.com'].email, 'john@work.com');
assert.strictEqual(Object.keys(users).length, 2);
});
it('should delete keys containing dots', async function() {
await db.set('emails', 'user.name@domain.com', 'verified', true);
await db.set('emails', 'other@email.com', 'verified', false);
await db.del('emails', 'user.name@domain.com');
const email1 = await db.get('emails', 'user.name@domain.com');
const email2 = await db.get('emails', 'other@email.com');
assert.strictEqual(email1, undefined);
assert.strictEqual(email2.verified, false);
});
});
describe('Delete Operations', function() {
it('should delete a key', async function() {
await db.set('temp', 'value');
await db.set('keep', 'value');
await db.del('temp');
const temp = await db.get('temp');
const keep = await db.get('keep');
assert.strictEqual(temp, null);
assert.strictEqual(keep, 'value');
});
it('should delete nested field', async function() {
await db.set('user', 'name', 'Alice');
await db.set('user', 'age', 30);
await db.del('user', 'age');
const user = await db.get('user');
assert.strictEqual(user.name, 'Alice');
assert.strictEqual(user.age, undefined);
});
it('should clear all data', async function() {
await db.set('key1', 'value1');
await db.set('key2', 'value2');
await db.del();
const all = await db.get();
assert.deepStrictEqual(all, {});
});
});
describe('Add Operation', function() {
it('should add item with auto-generated ID', async function() {
const path = await db.add('items', 'Charlie');
assert.strictEqual(path.length, 2);
assert.strictEqual(path[0], 'items');
assert.strictEqual(typeof path[1], 'string');
assert.strictEqual(path[1].length, 10);
const item = await db.get(...path);
assert.strictEqual(item, 'Charlie');
});
it('should add multiple items with unique IDs', async function() {
const path1 = await db.add('items', 'item1');
const path2 = await db.add('items', 'item2');
assert.notStrictEqual(path1[1], path2[1]);
});
it('should add complex objects', async function() {
const path = await db.add('users', { name: 'Alice', age: 30 });
const user = await db.get(...path);
assert.deepStrictEqual(user, { name: 'Alice', age: 30 });
});
});
describe('Increment/Decrement', function() {
it('should increment a value', async function() {
await db.set('key', 'counter', 10);
await db.inc('key', 'counter', 5);
const result = await db.get('key', 'counter');
assert.strictEqual(result, 15);
});
it('should decrement a value', async function() {
await db.set('key', 'counter', 20);
await db.dec('key', 'counter', 8);
const result = await db.get('key', 'counter');
assert.strictEqual(result, 12);
});
it('should increment nested value', async function() {
await db.set('user', 'balance', 100);
await db.inc('user', 'balance', 50);
const balance = await db.get('user', 'balance');
assert.strictEqual(balance, 150);
});
it('should handle multiple increments', async function() {
await db.set('key', 'views', 0);
await db.inc('key', 'views', 1);
await db.inc('key', 'views', 1);
await db.inc('key', 'views', 1);
const views = await db.get('key', 'views');
assert.strictEqual(views, 3);
});
it('should increment non-existent value from zero', async function() {
await db.inc('key', 'new_counter', 10);
const result = await db.get('key', 'new_counter');
assert.strictEqual(result, 10);
});
});
describe('Update Operation', function() {
it('should update value with function', async function() {
await db.set('key', 'name', 'alice');
await db.upd('key', 'name', name => name.toUpperCase());
const result = await db.get('key', 'name');
assert.strictEqual(result, 'ALICE');
});
it('should update nested value with function', async function() {
await db.set('user', 'age', 25);
await db.upd('user', 'age', age => age + 1);
const age = await db.get('user', 'age');
assert.strictEqual(age, 26);
});
it('should update complex objects', async function() {
await db.set('config', 'settings', { theme: 'dark', lang: 'en' });
await db.upd('config', 'settings', settings => ({
...settings,
lang: 'es'
}));
const settings = await db.get('config', 'settings');
assert.strictEqual(settings.theme, 'dark');
assert.strictEqual(settings.lang, 'es');
});
});
describe('Keys, Values, Entries', function() {
beforeEach(async function() {
await db.set('users', 'alice', { age: 30 });
await db.set('users', 'bob', { age: 25 });
});
it('should get keys', async function() {
const keys = await db.keys('users');
assert.strictEqual(keys.length, 2);
assert.ok(keys.includes('alice'));
assert.ok(keys.includes('bob'));
});
it('should get values', async function() {
const values = await db.values('users');
assert.strictEqual(values.length, 2);
assert.ok(values.some(v => v.age === 30));
assert.ok(values.some(v => v.age === 25));
});
it('should get entries', async function() {
const entries = await db.entries('users');
assert.strictEqual(entries.length, 2);
assert.ok(entries.some(([k, v]) => k === 'alice' && v.age === 30));
assert.ok(entries.some(([k, v]) => k === 'bob' && v.age === 25));
});
});
describe('Complex Nested Operations', function() {
it('should handle deeply nested objects', async function() {
await db.set('app', 'config', 'database', 'host', 'localhost');
await db.set('app', 'config', 'database', 'port', 6379);
const host = await db.get('app', 'config', 'database', 'host');
const port = await db.get('app', 'config', 'database', 'port');
assert.strictEqual(host, 'localhost');
assert.strictEqual(port, 6379);
});
it('should handle arrays', async function() {
await db.set('key', 'tags', ['redis', 'cache', 'database']);
const tags = await db.get('key', 'tags');
assert.deepStrictEqual(tags, ['redis', 'cache', 'database']);
});
it('should handle mixed types', async function() {
await db.set('key', 'string', 'text');
await db.set('key', 'number', 42);
await db.set('key', 'boolean', true);
await db.set('key', 'null', null);
await db.set('key', 'array', [1, 2, 3]);
const doc = await db.get('key');
assert.strictEqual(doc.string, 'text');
assert.strictEqual(doc.number, 42);
assert.strictEqual(doc.boolean, true);
assert.strictEqual(doc.null, null);
assert.deepStrictEqual(doc.array, [1, 2, 3]);
});
});
describe('JSON Path Operations', function() {
it('should create intermediate objects automatically', async function() {
await db.set('key', 'level1', 'level2', 'value', 'deep');
const result = await db.get('key', 'level1', 'level2', 'value');
assert.strictEqual(result, 'deep');
});
it('should handle object replacement', async function() {
await db.set('key', 'obj', { old: 'value' });
await db.set('key', 'obj', { new: 'value' });
const obj = await db.get('key', 'obj');
assert.deepStrictEqual(obj, { new: 'value' });
});
});
describe('Performance', function() {
it('should handle rapid sequential operations', async function() {
const operations = 50;
for (let i = 0; i < operations; i++) {
await db.set('perf', `key${i}`, i);
}
for (let i = 0; i < operations; i++) {
const value = await db.get('perf', `key${i}`);
assert.strictEqual(value, i);
}
});
it('should handle parallel operations', async function() {
const operations = 20;
const promises = [];
for (let i = 0; i < operations; i++) {
promises.push(db.set('parallel', `key${i}`, i));
}
await Promise.all(promises);
const keys = await db.keys('parallel');
assert.strictEqual(keys.length, operations);
});
});
});