feat(core-storage): add PouchEnvelope tests and LocalStorageService implementation
- Introduced tests for PouchEnvelope to validate envelope-aware CRUD operations using an in-memory PouchDB. - Implemented LocalStorageService with encryption support for sensitive keys, including tests for setItem, getItem, removeItem, and clear methods. - Defined a generic storage interface (IStorageService) to enforce type-safe serialization/deserialization across storage implementations.
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { PouchDBManager } from './pouch.manager';
|
||||
import { PouchConfig } from '../services/pouch.service';
|
||||
import { PouchEnvelopeService } from '../services/pouch-envelope.service';
|
||||
|
||||
/**
|
||||
* IoC Factory for managing multiple Envelope-based PouchDB database instances.
|
||||
* Inherits from `PouchDBManager`.
|
||||
*/
|
||||
export class PouchEnvelopeDBManager extends PouchDBManager {
|
||||
/**
|
||||
* Register and initialize a new PouchDB database using the Envelope pattern.
|
||||
* If a database with the same `localName` already exists, returns the existing wrapper.
|
||||
*
|
||||
* @param config - Configuration for the database instance.
|
||||
* @param entity - The domain entity name used as a prefix (e.g., 'item', 'booking').
|
||||
* @returns A `PouchEnvelopeService` with envelope-aware CRUD + query helpers.
|
||||
*/
|
||||
override register<T extends object = any>(config: PouchConfig, entity?: string): PouchEnvelopeService<T> {
|
||||
if (!entity) {
|
||||
throw new Error(`[PouchEnvelopeManager] 'entity' parameter is required for database: ${config.localName}`);
|
||||
}
|
||||
|
||||
if (this.databases.has(config.localName)) {
|
||||
return this.databases.get(config.localName) as PouchEnvelopeService<T>;
|
||||
}
|
||||
|
||||
const wrapper = new PouchEnvelopeService<T>(config, entity);
|
||||
this.databases.set(config.localName, wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a previously registered envelope database wrapper by its local name.
|
||||
*/
|
||||
override get<T extends object = any>(localName: string): PouchEnvelopeService<T> | undefined {
|
||||
return super.get(localName) as PouchEnvelopeService<T> | undefined;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import { PouchConfig, PouchService } from '../services/pouch.service';
|
||||
|
||||
/**
|
||||
* IoC Factory for managing multiple PouchDB database instances with optional
|
||||
* bi-directional CouchDB synchronization.
|
||||
*
|
||||
* `register()` returns a `PouchService` with full CRUD + query helpers,
|
||||
* so developers never need to pass `dbName` into each operation.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const dbManager = new PouchDBManager();
|
||||
*
|
||||
* const itemDB = dbManager.register({ localName: 'items' });
|
||||
* await itemDB.create({ _id: 'item-001', name: 'Widget', price: 9.99 });
|
||||
*
|
||||
* const results = await itemDB.find({ selector: { price: { $gt: 5 } } });
|
||||
* console.log(results); // [{ _id: 'item-001', name: 'Widget', price: 9.99, ... }]
|
||||
*
|
||||
* const salesDB = dbManager.register({
|
||||
* localName: 'sales',
|
||||
* remoteUrl: 'http://admin:pass@localhost:5984/sales_db',
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export class PouchDBManager {
|
||||
protected databases = new Map<string, PouchService<any>>();
|
||||
|
||||
/**
|
||||
* Register and initialize a new PouchDB database.
|
||||
* If a database with the same `localName` already exists, returns the existing wrapper.
|
||||
*
|
||||
* @param config - Configuration for the database instance.
|
||||
* @returns A `PouchService` with CRUD + query helpers.
|
||||
*/
|
||||
register<T extends object = any>(config: PouchConfig): PouchService<T> {
|
||||
if (this.databases.has(config.localName)) {
|
||||
return this.databases.get(config.localName) as PouchService<T>;
|
||||
}
|
||||
|
||||
const wrapper = new PouchService<T>(config);
|
||||
this.databases.set(config.localName, wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a previously registered database wrapper by its local name.
|
||||
*/
|
||||
get<T extends object = any>(localName: string): PouchService<T> | undefined {
|
||||
return this.databases.get(localName) as PouchService<T> | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a specific registered database and remove it from the manager.
|
||||
*/
|
||||
async destroy(localName: string): Promise<void> {
|
||||
const wrapper = this.databases.get(localName);
|
||||
if (!wrapper) return;
|
||||
await wrapper.destroy();
|
||||
this.databases.delete(localName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy all managed databases. Useful for logout/cleanup scenarios.
|
||||
*/
|
||||
async destroyAll(): Promise<void> {
|
||||
const names = Array.from(this.databases.keys());
|
||||
await Promise.all(names.map((name) => this.destroy(name)));
|
||||
}
|
||||
|
||||
/**
|
||||
* List all currently registered database names.
|
||||
*/
|
||||
listDatabases(): string[] {
|
||||
return Array.from(this.databases.keys());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user