Package Exports
- @pixagram/lacerta-db
- @pixagram/lacerta-db/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@pixagram/lacerta-db) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
LacertaDB 0.7.0

🦎 LacertaDB - A sophisticated, feature-rich browser-based document database with encryption, compression, QuickStore, and advanced querying capabilities.
📖 Table of Contents
- Introduction
- Browser Compatibility
- Quick Start
- Installation
- Core Concepts
- API Reference
- Advanced Features
- Real-World Examples
- Performance Optimization
- Migration Guide
- Architecture Deep Dive
- Troubleshooting
- Error Handling
- Comparison
- Contributing
- Changelog
Introduction
LacertaDB v0.7.0 represents a paradigmatic evolution in browser-based data persistence, architecting a sophisticated NoSQL database atop IndexedDB foundations. This iteration introduces QuickStore for ephemeral caching, implements rigorous encapsulation through private property conventions, and establishes connection pooling mechanisms for optimal resource utilization.
✨ Key Features
- 🚀 QuickStore - High-velocity localStorage-based caching with query capabilities
- 🔐 Database-level encryption with AES-GCM-256 cryptographic primitives
- 🗜️ Automatic compression leveraging native browser APIs (60-80% spatial reduction)
- 🔍 Multiple index architectures (B-Tree, Hash, Text, Geo)
- ⚡ Sophisticated caching strategies (LRU, LFU, TTL)
- 📊 Aggregation pipeline for complex analytical queries
- 🔄 Atomic batch operations with transactional guarantees
- 🔌 Connection pooling for optimized resource management
- 🔒 Async mutex for concurrent operation synchronization
- 📈 Built-in performance telemetry
- 💾 OPFS support for binary attachment persistence
- 🌐 Offline-first architecture - zero backend dependencies
- 📦 Optimized bundle footprint (~48KB gzipped)
🎯 Architectural Use Cases
- Progressive Web Applications - Complete database functionality in disconnected states
- Client-Side Cryptography - Zero-knowledge encryption before network transmission
- Edge Computing - Complex data processing at the browser periphery
- Browser Extensions - Persistent storage with sophisticated querying semantics
- Rapid Prototyping - Backend-agnostic development workflows
- Ephemeral Caching - QuickStore for session-based data persistence
Browser Compatibility
| Browser | Minimum Version | Architectural Notes |
|---|---|---|
| Chrome | 88+ | Full API surface including CompressionStream |
| Firefox | 90+ | Complete implementation |
| Safari | 15.4+ | Full support with OPFS |
| Edge | 88+ | Chromium-based implementation |
| Opera | 74+ | Complete feature parity |
| Chrome Mobile | 88+ | Mobile-optimized performance |
| Safari iOS | 15.4+ | Storage quotas may apply |
Required Browser APIs
- IndexedDB API - Primary persistence layer
- Web Crypto API - Cryptographic operations
- CompressionStream API - Optional compression (graceful degradation)
- Origin Private File System - Binary attachment storage
- LocalStorage API - QuickStore implementation
Quick Start
🚀 Rapid Initialization Sequence
import { LacertaDB } from 'lacertadb';
// 1. Instantiate LacertaDB orchestrator
const lacerta = new LacertaDB();
// 2. Acquire database instance
const db = await lacerta.getDatabase('application-nexus');
// 3. Initialize collection with QuickStore
const users = await db.createCollection('users');
// 4. Leverage QuickStore for ephemeral caching
db.quickStore.add('session', { userId: 'usr_123', token: 'xyz' });
const session = db.quickStore.get('session');
// 5. Persist documents with compression
await users.add({
name: 'John Doe',
email: 'john@example.com',
metadata: { created: Date.now() }
});
// 6. Execute sophisticated queries
const results = await users.query({
$and: [
{ 'metadata.created': { $gte: Date.now() - 86400000 } },
{ email: { $regex: '@example.com$' } }
]
});🔐 Cryptographically Secured Database
// Initialize encrypted database with configurable parameters
const secureDb = await lacerta.getSecureDatabase(
'classified-data',
'user-pin-entropy',
null, // Auto-generate cryptographic salt
{
iterations: 200000, // PBKDF2 iteration count
hashAlgorithm: 'SHA-512' // Hashing algorithm selection
}
);
// Encrypted operations maintain transparency
const secrets = await secureDb.createCollection('api-keys');
await secrets.add({
service: 'stripe',
key: await secureDb.encryption.encryptPrivateKey('sk_live_...', 'stripe.com')
});Installation
Package Manager Installation
# NPM
npm install lacertadb
# Yarn
yarn add lacertadb
# PNPM
pnpm add lacertadbCDN Integration
<script type="module">
import { LacertaDB } from 'https://cdn.jsdelivr.net/npm/lacertadb@0.7.0/dist/index.min.js';
</script>Import Paradigms
// ES6 Module Syntax
import { LacertaDB, QuickStore } from 'lacertadb';
// Selective Component Import
import {
LacertaDB,
SecureDatabaseEncryption,
PerformanceMonitor,
MigrationManager,
QuickStore,
BTreeIndex,
AsyncMutex
} from 'lacertadb';
// CommonJS Pattern
const { LacertaDB } = require('lacertadb');Core Concepts
Hierarchical Architecture
LacertaDB Instance
├── Connection Pool (Global)
│ └── Database Connections (Reusable)
├── Database 1
│ ├── QuickStore (LocalStorage Layer)
│ ├── Collection A
│ │ ├── Documents (IndexedDB)
│ │ ├── Indexes (B-Tree/Hash/Text/Geo)
│ │ └── Cache Strategy (LRU/LFU/TTL)
│ └── Collection B
└── Database 2
├── QuickStore Instance
└── __private_keys__ (Encrypted Key Storage)Document Metadata Schema
{
_id: "doc_1234567890_abc", // Unique identifier
_created: 1234567890, // Creation timestamp
_modified: 1234567890, // Modification timestamp
_permanent: false, // Cleanup immunity flag
_compressed: true, // Compression status
_encrypted: false, // Encryption status
_attachments: [], // OPFS attachment references
...userDefinedFields // Application data
}Private Property Convention
Version 0.7.0 implements systematic encapsulation through underscore-prefixed private properties and methods, establishing clear API boundaries while optimizing memory through lazy initialization patterns.
API Reference
📦 LacertaDB Class
Primary orchestrator for database lifecycle management.
| Method | Parameters | Returns | Description |
|---|---|---|---|
getDatabase() |
name: stringoptions?: object |
Promise<Database> |
Acquire database instance |
getSecureDatabase() |
name: stringpin: stringsalt?: stringconfig?: object |
Promise<Database> |
Initialize encrypted database |
dropDatabase() |
name: string |
Promise<void> |
Destroy database and QuickStore |
listDatabases() |
- | string[] |
Enumerate databases |
createBackup() |
password?: string |
Promise<string> |
Generate comprehensive backup |
restoreBackup() |
data: stringpassword?: string |
Promise<object> |
Restore from backup |
destroy() |
- | void |
Release all connections |
performanceMonitor |
- | PerformanceMonitor |
Access performance telemetry |
Implementation Examples
const lacerta = new LacertaDB();
// Connection pooling automatically manages resources
const db1 = await lacerta.getDatabase('app1');
const db2 = await lacerta.getDatabase('app2');
// Connections are pooled and reused efficiently
// Access performance monitoring
lacerta.performanceMonitor.startMonitoring();
const metrics = lacerta.performanceMonitor.getStats();
// Comprehensive backup including QuickStore
const backup = await lacerta.createBackup('encryption-key');
localStorage.setItem('backup', backup);
// Cleanup with connection pool release
window.addEventListener('beforeunload', () => {
lacerta.destroy(); // Releases all pooled connections
});🗄️ Database Class
Database-level operations with QuickStore integration.
| Method | Parameters | Returns | Description |
|---|---|---|---|
createCollection() |
name: stringoptions?: object |
Promise<Collection> |
Initialize collection |
getCollection() |
name: string |
Promise<Collection> |
Retrieve collection (lazy init) |
dropCollection() |
name: string |
Promise<void> |
Remove collection |
listCollections() |
- | string[] |
Enumerate collections |
getStats() |
- | object |
Database metrics |
updateSettings() |
settings: object |
void |
Configure database |
export() |
format: stringpassword?: string |
Promise<string> |
Export database |
import() |
data: stringformat: stringpassword?: string |
Promise<object> |
Import data |
storePrivateKey() |
name: stringkey: stringauth?: string |
Promise<boolean> |
Secure key storage |
getPrivateKey() |
name: stringauth?: string |
Promise<string> |
Retrieve secured key |
clearAll() |
- | Promise<void> |
Purge all data |
Database Properties (Getters)
| Property | Type | Description |
|---|---|---|
quickStore |
QuickStore |
LocalStorage-based cache |
collections |
Map<string, Collection> |
Collection registry |
metadata |
DatabaseMetadata |
Database metadata |
settings |
Settings |
Configuration parameters |
encryption |
SecureDatabaseEncryption│null |
Encryption instance |
isEncrypted |
boolean |
Encryption status |
performanceMonitor |
PerformanceMonitor |
Performance telemetry |
Advanced Usage Patterns
// Lazy collection initialization
const users = await db.getCollection('users');
// Collection is initialized only on first access
// QuickStore integration for session management
db.quickStore.add('user_session', {
userId: 'usr_123',
loginTime: Date.now(),
permissions: ['read', 'write']
});
// Query QuickStore with same engine
const activeSessions = db.quickStore.query({
loginTime: { $gte: Date.now() - 3600000 }
});
// Configure with size management
db.updateSettings({
sizeLimitKB: 100000,
bufferLimitKB: 80000,
freeSpaceEvery: 30000
});
// Export with QuickStore data
const fullExport = await db.export('encrypted', 'password');🚀 QuickStore
High-performance localStorage-based caching layer with query capabilities.
| Method | Parameters | Returns | Description |
|---|---|---|---|
add() |
docId: stringdata: object |
boolean |
Store document |
get() |
docId: string |
object│null |
Retrieve document |
update() |
docId: stringdata: object |
boolean |
Update document |
delete() |
docId: string |
void |
Remove document |
getAll() |
- | object[] |
Retrieve all documents |
query() |
filter: object |
object[] |
Query documents |
clear() |
- | void |
Purge all data |
size |
- | number |
Document count |
QuickStore Architecture
QuickStore leverages localStorage for ephemeral data persistence, providing:
- Synchronous operations for immediate data access
- Query engine integration using identical syntax as main collections
- Automatic serialization with TurboSerial
- Index management for efficient lookups
- Size limitations based on localStorage quotas (5-10MB)
QuickStore Implementation Patterns
const db = await lacerta.getDatabase('app');
const quickStore = db.quickStore;
// Session management
quickStore.add('current_user', {
id: 'usr_123',
name: 'John Doe',
loginTime: Date.now(),
preferences: {
theme: 'dark',
language: 'en'
}
});
// Shopping cart persistence
quickStore.add('cart', {
items: [
{ productId: 'prod_1', quantity: 2, price: 29.99 },
{ productId: 'prod_2', quantity: 1, price: 49.99 }
],
total: 109.97,
updated: Date.now()
});
// Query capabilities with same syntax
const recentActivity = quickStore.query({
loginTime: { $gte: Date.now() - 3600000 }
});
// Atomic updates
quickStore.update('current_user', {
...quickStore.get('current_user'),
lastActivity: Date.now()
});
// Clear on logout
function logout() {
quickStore.delete('current_user');
quickStore.delete('cart');
}
// Full clear
quickStore.clear();📁 Collection Class
Document management with advanced querying and indexing.
Core Methods
| Method | Parameters | Returns | Description |
|---|---|---|---|
add() |
data: objectoptions?: object |
Promise<string> |
Insert document |
get() |
id: stringoptions?: object |
Promise<object> |
Retrieve document |
update() |
id: stringupdates: objectoptions?: object |
Promise<string> |
Modify document |
delete() |
id: stringoptions?: object |
Promise<void> |
Remove document |
getAll() |
options?: object |
Promise<object[]> |
Retrieve all documents |
clear() |
options?: object |
Promise<void> |
Purge collection |
Query and Aggregation
| Method | Parameters | Returns | Description |
|---|---|---|---|
query() |
filter: objectoptions?: object |
Promise<object[]> |
Execute query |
aggregate() |
pipeline: object[] |
Promise<object[]> |
Aggregation pipeline |
findOne() |
filter: object |
Promise<object│null> |
First match |
count() |
filter?: object |
Promise<number> |
Document count |
Batch Operations
| Method | Parameters | Returns | Description |
|---|---|---|---|
batchAdd() |
documents: object[]options?: object |
Promise<object[]> |
Bulk insert |
batchUpdate() |
updates: object[]options?: object |
Promise<object[]> |
Bulk update |
batchDelete() |
items: string[]│object[] |
Promise<object[]> |
Bulk delete |
Event System
| Method | Parameters | Returns | Description |
|---|---|---|---|
on() |
event: stringcallback: function |
void |
Register listener |
off() |
event: stringcallback: function |
void |
Unregister listener |
Collection Properties
| Property | Type | Description |
|---|---|---|
name |
string |
Collection identifier |
database |
Database |
Parent database |
settings |
Settings |
Configuration |
metadata |
CollectionMetadata |
Collection metrics |
initialized |
boolean |
Initialization status |
🔐 Connection Management
IndexedDBConnectionPool
Global connection pool for optimized database connections.
| Method | Parameters | Returns | Description |
|---|---|---|---|
getConnection() |
dbName: stringversion: numberupgradeCallback?: function |
Promise<IDBDatabase> |
Acquire connection |
releaseConnection() |
dbName: stringversion: number |
void |
Release connection |
closeAll() |
- | void |
Close all connections |
AsyncMutex
Synchronization primitive for concurrent operations.
| Method | Parameters | Returns | Description |
|---|---|---|---|
acquire() |
- | Promise<function> |
Acquire lock |
release() |
- | void |
Release lock |
runExclusive() |
callback: function |
Promise<any> |
Execute exclusively |
Concurrency Control Patterns
// Connection pooling is automatic
const db1 = await connectionPool.getConnection('db1', 1);
const db2 = await connectionPool.getConnection('db1', 1); // Reuses connection
// Mutex for critical sections
const mutex = new AsyncMutex();
async function criticalOperation() {
const release = await mutex.acquire();
try {
// Exclusive access guaranteed
await performCriticalWork();
} finally {
release();
}
}
// Or using runExclusive
await mutex.runExclusive(async () => {
await performCriticalWork();
});🔍 Index Management
Sophisticated indexing strategies for query optimization.
Index Methods
| Method | Parameters | Returns | Description |
|---|---|---|---|
createIndex() |
field: stringoptions: object |
Promise<string> |
Create index |
dropIndex() |
name: string |
Promise<void> |
Remove index |
getIndexes() |
- | Promise<object> |
Index statistics |
verifyIndexes() |
- | Promise<object> |
Self-healing verification |
Index Architectures
| Type | Algorithm | Use Case | Complexity | Space |
|---|---|---|---|---|
btree |
B-Tree | Range queries, sorting | O(log n) | O(n) |
hash |
Hash Table | Exact match | O(1) avg | O(n) |
text |
Inverted Index | Full-text search | O(m) | O(n*m) |
geo |
R-Tree variant | Spatial queries | O(log n) | O(n) |
Self-Healing Indexes
B-Tree indexes include automatic verification and repair mechanisms:
// Automatic verification during operations
const btreeIndex = new BTreeIndex();
btreeIndex.insert(key, value); // Triggers periodic verification
// Manual verification
const report = await collection.verifyIndexes();
// {
// 'age_index': { healthy: true, issues: [] },
// 'email_index': { healthy: false, issues: [...], repaired: 2 }
// }🔐 Encryption
Cryptographic subsystem with configurable parameters.
SecureDatabaseEncryption Class
| Method | Parameters | Returns | Description |
|---|---|---|---|
initialize() |
pin: stringsalt?: Uint8Array |
Promise<string> |
Initialize encryption |
encrypt() |
data: any |
Promise<Uint8Array> |
Encrypt data |
decrypt() |
data: Uint8Array |
Promise<Uint8Array> |
Decrypt data |
encryptPrivateKey() |
key: stringauth?: string |
Promise<string> |
Secure key encryption |
decryptPrivateKey() |
encrypted: stringauth?: string |
Promise<string> |
Key decryption |
changePin() |
oldPin: stringnewPin: string |
Promise<string> |
Rotate PIN |
destroy() |
- | void |
Clear keys |
exportMetadata() |
- | object |
Export config |
importMetadata() |
metadata: object |
boolean |
Import config |
Encryption Properties (Getters)
| Property | Type | Description |
|---|---|---|
initialized |
boolean |
Initialization status |
Cryptographic Parameters
| Parameter | Default | Range | Description |
|---|---|---|---|
iterations |
100000 | 10000-1000000 | PBKDF2 iterations |
hashAlgorithm |
SHA-256 | SHA-256/512 | Hash function |
keyLength |
256 | 128/192/256 | AES key size |
saltLength |
32 | 16-64 | Salt bytes |
Advanced Features
🎯 Query Operators
Comparison Operators
| Operator | Semantic | Example |
|---|---|---|
$eq |
Equality | { status: { $eq: 'active' } } |
$ne |
Inequality | { deleted: { $ne: true } } |
$gt |
Greater than | { score: { $gt: 90 } } |
$gte |
Greater or equal | { age: { $gte: 18 } } |
$lt |
Less than | { price: { $lt: 100 } } |
$lte |
Less or equal | { quantity: { $lte: 10 } } |
Set Operations
| Operator | Semantic | Example |
|---|---|---|
$in |
Set membership | { role: { $in: ['admin', 'mod'] } } |
$nin |
Set exclusion | { status: { $nin: ['deleted'] } } |
Array Operations
| Operator | Semantic | Example |
|---|---|---|
$all |
Contains all | { tags: { $all: ['js', 'ts'] } } |
$elemMatch |
Element match | { scores: { $elemMatch: { $gt: 80 } } } |
$size |
Array length | { items: { $size: 5 } } |
Logical Operators
| Operator | Semantic | Example |
|---|---|---|
$and |
Conjunction | { $and: [{ a: 1 }, { b: 2 }] } |
$or |
Disjunction | { $or: [{ a: 1 }, { b: 2 }] } |
$not |
Negation | { field: { $not: { $eq: 'value' } } } |
$nor |
Joint denial | { $nor: [{ a: 1 }, { b: 2 }] } |
Type and Existence
| Operator | Semantic | Example |
|---|---|---|
$exists |
Field existence | { optional: { $exists: false } } |
$type |
Type checking | { age: { $type: 'number' } } |
Pattern Matching
| Operator | Semantic | Example |
|---|---|---|
$regex |
Regular expression | { email: { $regex: '^[a-z]+@' } } |
$text |
Text search | { content: { $text: 'javascript' } } |
📊 Aggregation Pipeline
Pipeline Stages
| Stage | Function | Example |
|---|---|---|
$match |
Filter documents | { $match: { status: 'active' } } |
$project |
Shape output | { $project: { name: 1, age: 1 } } |
$group |
Aggregate groups | { $group: { _id: '$category', total: { $sum: 1 } } } |
$sort |
Order results | { $sort: { createdAt: -1 } } |
$limit |
Limit count | { $limit: 100 } |
$skip |
Skip documents | { $skip: 20 } |
$lookup |
Join collections | { $lookup: { from: 'orders', localField: 'userId', foreignField: '_id', as: 'orders' } } |
Accumulator Operators
| Operator | Function | Example |
|---|---|---|
$sum |
Summation | { total: { $sum: '$amount' } } |
$avg |
Average | { avgScore: { $avg: '$score' } } |
$min |
Minimum | { lowest: { $min: '$price' } } |
$max |
Maximum | { highest: { $max: '$price' } } |
$count |
Count | { count: { $count: {} } } |
💾 Cache Strategies
Strategy Architectures
| Strategy | Algorithm | Eviction Policy | Configuration |
|---|---|---|---|
lru |
Least Recently Used | Temporal locality | maxSize, ttl |
lfu |
Least Frequently Used | Access frequency | maxSize, ttl |
ttl |
Time To Live | Temporal expiry | ttl |
none |
No caching | Immediate | - |
Cache Strategy Implementation
// LRU with TTL for balanced performance
collection.configureCacheStrategy({
type: 'lru',
maxSize: 200,
ttl: 60000,
enabled: true
});
// LFU for hot data
hotCollection.configureCacheStrategy({
type: 'lfu',
maxSize: 500,
ttl: 300000
});
// TTL-only for sessions
sessionCollection.configureCacheStrategy({
type: 'ttl',
ttl: 900000
});
// Memory optimization through lazy initialization
// Cache is created only when first accessed (getter pattern)
const strategy = new CacheStrategy({ type: 'lru' });
// Internal cache instantiated on first get() callArchitecture Deep Dive
Memory Optimization Patterns
Version 0.7.0 implements sophisticated memory management through:
- Lazy Initialization: Collections and caches instantiate on first access
- Getter/Setter Patterns: Document data uses accessors for memory efficiency
- Connection Pooling: Reuses database connections across operations
- Private Property Convention: Underscore prefix for encapsulation
class Document {
constructor(data = {}) {
this._data = null; // Private storage
// ... other initialization
}
// Lazy getter for memory optimization
get data() {
return this._data || {};
}
set data(value) {
this._data = value;
}
}Concurrency Control
AsyncMutex ensures atomic operations:
class AsyncMutex {
async runExclusive(callback) {
const release = await this.acquire();
try {
return await callback();
} finally {
release();
}
}
}Transaction Resilience
Automatic retry mechanisms with exponential backoff:
async performTransaction(db, storeNames, mode, callback, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await executeTransaction();
} catch (error) {
if (i < retries - 1) {
await new Promise(r => setTimeout(r, (2 ** i) * 100));
}
}
}
}Real-World Examples
🏥 Healthcare Data Management
// HIPAA-compliant patient data storage
const lacerta = new LacertaDB();
const healthDb = await lacerta.getSecureDatabase(
'patient-records',
await SecureDatabaseEncryption.generateSecurePIN(12),
null,
{ iterations: 500000 } // Enhanced security
);
const patients = await healthDb.createCollection('patients');
const vitals = await healthDb.createCollection('vitals');
// QuickStore for current session
healthDb.quickStore.add('current_patient', {
id: 'pat_123',
name: 'John Doe',
sessionStart: Date.now()
});
// Create indexes for efficient queries
await patients.createIndex('mrn', { unique: true }); // Medical Record Number
await vitals.createIndex('patientId', { type: 'hash' });
await vitals.createIndex('timestamp', { type: 'btree' });
// Store patient with encryption
await patients.add({
mrn: 'MRN123456',
name: 'John Doe',
dob: '1980-01-15',
allergies: ['penicillin'],
conditions: ['hypertension']
}, { permanent: true });
// Record vitals
await vitals.add({
patientId: 'pat_123',
timestamp: Date.now(),
bloodPressure: { systolic: 120, diastolic: 80 },
heartRate: 72,
temperature: 98.6
});
// Aggregate patient statistics
const stats = await vitals.aggregate([
{ $match: { patientId: 'pat_123' } },
{ $sort: { timestamp: -1 } },
{ $limit: 100 },
{ $group: {
_id: '$patientId',
avgHeartRate: { $avg: '$heartRate' },
avgSystolic: { $avg: '$bloodPressure.systolic' },
readingCount: { $count: {} }
}}
]);🎮 Real-Time Gaming State
// Game state management with QuickStore
const gameDb = await lacerta.getDatabase('game-state');
const quickStore = gameDb.quickStore;
// Immediate state updates via QuickStore
quickStore.add('player_state', {
position: { x: 100, y: 200, z: 50 },
health: 100,
inventory: ['sword', 'potion'],
score: 5000
});
// Persistent game saves
const saves = await gameDb.createCollection('saves');
await saves.createIndex('timestamp', { type: 'btree' });
async function saveGame() {
const state = quickStore.get('player_state');
await saves.add({
...state,
savePoint: 'checkpoint_3',
timestamp: Date.now()
}, { compressed: true });
}
// Load recent saves
const recentSaves = await saves.query(
{ timestamp: { $gte: Date.now() - 86400000 } },
{ sort: { timestamp: -1 }, limit: 10 }
);📊 Analytics Dashboard
// Real-time analytics with caching strategies
const analyticsDb = await lacerta.getDatabase('analytics');
const events = await analyticsDb.createCollection('events');
// Configure aggressive caching for dashboards
events.configureCacheStrategy({
type: 'lfu', // Frequently accessed metrics
maxSize: 1000,
ttl: 300000 // 5-minute cache
});
// Create performance indexes
await events.createIndex('eventType', { type: 'hash' });
await events.createIndex('timestamp', { type: 'btree' });
await events.createIndex('userId', { type: 'hash' });
// Store events with batch operations
const eventBatch = Array.from({ length: 1000 }, (_, i) => ({
eventType: ['click', 'view', 'purchase'][i % 3],
userId: `user_${i % 100}`,
timestamp: Date.now() - (i * 1000),
metadata: { source: 'web', version: '2.0' }
}));
await events.batchAdd(eventBatch, { compressed: true });
// Complex analytics aggregation
const metrics = await events.aggregate([
{ $match: {
timestamp: { $gte: Date.now() - 3600000 } // Last hour
}},
{ $group: {
_id: '$eventType',
count: { $count: {} },
uniqueUsers: { $addToSet: '$userId' }
}},
{ $project: {
eventType: '$_id',
count: 1,
uniqueUserCount: { $size: '$uniqueUsers' }
}},
{ $sort: { count: -1 } }
]);
// Store computed metrics in QuickStore for instant access
analyticsDb.quickStore.add('dashboard_metrics', {
computed: Date.now(),
metrics,
summary: {
totalEvents: metrics.reduce((sum, m) => sum + m.count, 0),
eventTypes: metrics.length
}
});Performance Optimization
📈 Advanced Performance Monitoring
// Initialize comprehensive monitoring
const monitor = lacerta.performanceMonitor;
monitor.startMonitoring();
// Custom performance tracking
class PerformanceTracker {
constructor(monitor) {
this.monitor = monitor;
this.thresholds = {
query: 50, // ms
write: 100, // ms
aggregate: 200 // ms
};
}
async track(operation, type) {
const start = performance.now();
try {
const result = await operation();
const duration = performance.now() - start;
this.monitor.recordOperation(type, duration);
if (duration > this.thresholds[type]) {
console.warn(`Slow ${type}: ${duration}ms`);
}
return result;
} catch (error) {
this.monitor.recordOperation(`${type}_error`, 0);
throw error;
}
}
}
const tracker = new PerformanceTracker(monitor);
// Track operations
const results = await tracker.track(
() => users.query({ age: { $gte: 18 } }),
'query'
);
// Optimization recommendations
const tips = monitor.getOptimizationTips();
// Analyzes cache hit rates, latency patterns, memory trends⚡ Optimization Strategies
1. Index Architecture Selection
// B-Tree for range queries and sorting
await orders.createIndex('createdAt', { type: 'btree' });
await products.createIndex('price', { type: 'btree' });
// Hash for exact matches
await users.createIndex('email', { type: 'hash', unique: true });
await sessions.createIndex('token', { type: 'hash' });
// Text index for search
await articles.createIndex('content', { type: 'text' });
// Geo index for spatial queries
await stores.createIndex('location', { type: 'geo' });2. QuickStore vs Collection Strategy
// QuickStore for ephemeral, frequently accessed data
db.quickStore.add('ui_state', { theme: 'dark', sidebar: true });
db.quickStore.add('form_draft', { title: 'Unsaved', content: '...' });
// Collections for persistent, structured data
await documents.add({ title: 'Report', content: '...' });3. Connection Pool Optimization
// Connections are automatically pooled and reused
const db1 = await lacerta.getDatabase('app'); // New connection
const db2 = await lacerta.getDatabase('app'); // Reuses connection
// Manual cleanup when necessary
connectionPool.releaseConnection('app');4. Memory-Conscious Patterns
// Use projection to minimize memory footprint
const summaries = await posts.query(
{ published: true },
{
projection: { title: 1, excerpt: 1 }, // Only needed fields
limit: 100
}
);
// Clear caches periodically
setInterval(() => {
posts.clearCache();
}, 300000); // Every 5 minutes
// Configure appropriate cache sizes
posts.configureCacheStrategy({
type: 'lru',
maxSize: 50 // Limit cache entries
});Migration Guide
Version 0.6.x to 0.7.0
// 1. Export existing data
const oldDb = await getOldDatabase();
const backup = await oldDb.export('json');
// 2. Initialize new version
const newLacerta = new LacertaDB();
const newDb = await newLacerta.getDatabase('migrated');
// 3. Import with QuickStore preservation
await newDb.import(backup, 'json');
// 4. Migrate to QuickStore where appropriate
const sessions = await newDb.getCollection('sessions');
const allSessions = await sessions.getAll();
// Move active sessions to QuickStore
for (const session of allSessions) {
if (session.active) {
newDb.quickStore.add(`session_${session.userId}`, session);
await sessions.delete(session._id);
}
}
// 5. Update indexes for new architecture
const collections = newDb.listCollections();
for (const name of collections) {
const coll = await newDb.getCollection(name);
await coll.verifyIndexes(); // Self-healing verification
}Schema Evolution with Migrations
const migrationManager = new MigrationManager(db);
// Migration to add QuickStore references
migrationManager.addMigration({
version: '0.7.0',
name: 'Add QuickStore support',
up: async (doc) => {
if (doc.sessionId && !doc.quickStoreKey) {
// Move session data to QuickStore
db.quickStore.add(`session_${doc.sessionId}`, {
userId: doc.userId,
created: doc._created
});
return { ...doc, quickStoreKey: `session_${doc.sessionId}` };
}
return null;
},
down: async (doc) => {
if (doc.quickStoreKey) {
db.quickStore.delete(doc.quickStoreKey);
const { quickStoreKey, ...rest } = doc;
return rest;
}
return null;
}
});
await migrationManager.runMigrations('0.7.0');Troubleshooting
Common Issues and Solutions
🔴 QuickStore Quota Exceeded
Problem: LocalStorage limit reached (5-10MB)
Solutions:
// 1. Monitor QuickStore usage
console.log(`QuickStore entries: ${db.quickStore.size}`);
// 2. Implement rotation policy
function rotateQuickStore(maxEntries = 100) {
const all = db.quickStore.getAll();
if (all.length > maxEntries) {
const toDelete = all
.sort((a, b) => a._modified - b._modified)
.slice(0, all.length - maxEntries);
toDelete.forEach(doc => db.quickStore.delete(doc._id));
}
}
// 3. Move to collections for larger data
if (data.length > 1000) { // Large dataset
await collection.add(data);
} else {
db.quickStore.add('small_data', data);
}🔴 Connection Pool Exhaustion
Problem: Too many concurrent database operations
Solutions:
// 1. Use batch operations
await users.batchAdd(documents); // Single transaction
// 2. Implement operation queuing
class OperationQueue {
constructor(concurrency = 10) {
this.queue = [];
this.running = 0;
this.concurrency = concurrency;
}
async add(operation) {
if (this.running >= this.concurrency) {
await new Promise(resolve => this.queue.push(resolve));
}
this.running++;
try {
return await operation();
} finally {
this.running--;
if (this.queue.length > 0) {
this.queue.shift()();
}
}
}
}🔴 Memory Leaks with Private Properties
Problem: References to private properties preventing garbage collection
Solutions:
// 1. Proper cleanup in destroy methods
class Collection {
destroy() {
clearInterval(this._cleanupInterval);
this._events.clear();
this._cacheStrategy = null;
this._indexManager = null;
// Release connection
if (this._db) {
connectionPool.releaseConnection(this.database.name);
}
}
}
// 2. WeakMap for external references
const privateData = new WeakMap();
privateData.set(instance, { sensitive: 'data' });Error Handling
Comprehensive Error Taxonomy
| Error Code | Semantic Context | Resolution Strategy |
|---|---|---|
DATABASE_OPEN_FAILED |
IndexedDB initialization failure | Verify browser compatibility, clear data |
DOCUMENT_NOT_FOUND |
Non-existent document reference | Validate document existence |
COLLECTION_NOT_FOUND |
Undefined collection | Initialize collection first |
COLLECTION_EXISTS |
Duplicate collection | Use getCollection() |
UNIQUE_CONSTRAINT |
Index uniqueness violation | Modify value or update |
QUOTA_EXCEEDED |
Storage capacity exceeded | Implement cleanup strategy |
ENCRYPTION_NOT_INITIALIZED |
Missing encryption context | Use getSecureDatabase() |
ENCRYPTION_FAILED |
Cryptographic operation failure | Verify credentials |
PERMANENT_DOCUMENT_PROTECTION |
Protected document deletion | Apply force option |
TRANSACTION_FAILED |
Transaction abort | Retry with backoff |
QUICKSTORE_QUOTA_EXCEEDED |
LocalStorage limit | Rotate QuickStore data |
Error Handling Patterns
class ResilientDatabaseService {
constructor(lacerta) {
this.lacerta = lacerta;
this.mutex = new AsyncMutex();
}
async executeWithRetry(operation, maxRetries = 3) {
return this.mutex.runExclusive(async () => {
let lastError;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error;
// Categorize and handle errors
switch (error.code) {
case 'QUOTA_EXCEEDED':
await this.handleQuotaExceeded();
break;
case 'TRANSACTION_FAILED':
await this.delay((2 ** attempt) * 100);
break;
case 'ENCRYPTION_FAILED':
throw new Error('Authentication required');
default:
if (attempt === maxRetries - 1) throw error;
}
}
}
throw lastError;
});
}
async handleQuotaExceeded() {
// Clear QuickStore
const db = await this.lacerta.getDatabase('app');
db.quickStore.clear();
// Clear old collection data
const collections = db.listCollections();
for (const name of collections) {
const coll = await db.getCollection(name);
const oldDocs = await coll.query({
_modified: { $lt: Date.now() - 86400000 }
});
await coll.batchDelete(oldDocs.map(d => d._id));
}
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}Comparison
LacertaDB v0.7.0 vs Alternatives
| Feature | LacertaDB 0.7 | LocalStorage | IndexedDB | PouchDB | Dexie.js | LokiJS |
|---|---|---|---|---|---|---|
| Storage Limit | ~2GB + 10MB* | 5-10MB | ~2GB | ~2GB | ~2GB | Memory/5MB |
| QuickStore | ✅ Built-in | ≈ | ❌ | ❌ | ❌ | ❌ |
| Encryption | ✅ AES-GCM | ❌ | ❌ | ⚠️ Plugin | ❌ | ❌ |
| Compression | ✅ Native | ❌ | ❌ | ❌ | ❌ | ❌ |
| Connection Pool | ✅ | N/A | ❌ | ❌ | ❌ | ❌ |
| Query Language | ✅ MongoDB | ❌ | ❌ | ✅ MapReduce | ⚠️ Limited | ✅ |
| Indexes | ✅ 4 types | ❌ | ⚠️ Basic | ✅ | ✅ | ✅ |
| Aggregation | ✅ Pipeline | ❌ | ❌ | ⚠️ Views | ❌ | ⚠️ |
| Self-Healing | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Bundle Size | ~48KB | 0KB | 0KB | ~140KB | ~90KB | ~70KB |
| Concurrency | ✅ Mutex | ❌ | ⚠️ | ⚠️ | ⚠️ | ❌ |
*IndexedDB (2GB) + QuickStore LocalStorage (10MB)
Architectural Selection Criteria
Deploy LacertaDB when requiring:
- Dual-layer storage (persistent + ephemeral)
- Zero-knowledge client-side encryption
- Self-healing index structures
- Connection pooling for scalability
- MongoDB-compatible query semantics
- Integrated performance telemetry
Consider alternatives for:
- Minimal storage needs (< 1MB): LocalStorage
- Server synchronization priority: PouchDB/CouchDB
- Memory-only operations: LokiJS
- Simple key-value patterns: LocalStorage/SessionStorage
Changelog
Version 0.7.0 (Latest)
- Added: QuickStore for localStorage-based ephemeral caching
- Added: Connection pooling for optimized resource management
- Added: AsyncMutex for concurrent operation synchronization
- Improved: Private property conventions with underscore prefix
- Improved: Memory optimization through lazy initialization
- Improved: Self-healing B-Tree indexes with automatic verification
- Enhanced: Export/import includes QuickStore data
- Fixed: Connection leaks in collection destruction
- Fixed: Memory optimization in Document class
Version 0.6.2
- Database-level encryption
- Compression support
- Multiple index types
- Aggregation pipeline
- Performance monitoring
Contributing
LacertaDB embraces collaborative development. Contribution vectors include:
- Architecture Enhancement: Propose algorithmic improvements
- Index Strategies: Implement novel index structures
- Performance Optimization: Profile and optimize critical paths
- Documentation: Expand architectural documentation
- Test Coverage: Strengthen test suites
📝 License
MIT © 2024 LacertaDB Contributors