@pixagram/lacerta-db 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.min.js +7 -7
- package/dist/index.min.js +7 -7
- package/index.js +841 -692
- package/package.json +1 -1
- package/readme.md +989 -961
package/readme.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
# LacertaDB 0.
|
|
1
|
+
# LacertaDB 0.7.0
|
|
2
2
|

|
|
3
3
|
|
|
4
|
-
> 🦎 **LacertaDB** - A
|
|
4
|
+
> 🦎 **LacertaDB** - A sophisticated, feature-rich browser-based document database with encryption, compression, QuickStore, and advanced querying capabilities.
|
|
5
5
|
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[]()
|
|
8
8
|
[]()
|
|
9
9
|
[](https://www.npmjs.com/package/lacertadb)
|
|
10
10
|
[](https://bundlephobia.com/package/lacertadb)
|
|
11
11
|
|
|
12
|
-
[**🎮 PLAYGROUND**](https://codepen.io/Matias-Affolter/pen/ogjrQdB)
|
|
12
|
+
[**🎮 PLAYGROUND**](https://codepen.io/Matias-Affolter/pen/ogjrQdB)
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -21,162 +21,180 @@
|
|
|
21
21
|
4. [Installation](#installation)
|
|
22
22
|
5. [Core Concepts](#core-concepts)
|
|
23
23
|
6. [API Reference](#api-reference)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
- [LacertaDB Class](#lacertadb-class)
|
|
25
|
+
- [Database Class](#database-class)
|
|
26
|
+
- [Collection Class](#collection-class)
|
|
27
|
+
- [QuickStore](#quickstore)
|
|
28
|
+
- [Document Class](#document-class)
|
|
29
|
+
- [Index Management](#index-management)
|
|
30
|
+
- [Encryption](#encryption)
|
|
31
|
+
- [Connection Management](#connection-management)
|
|
30
32
|
7. [Advanced Features](#advanced-features)
|
|
31
33
|
8. [Real-World Examples](#real-world-examples)
|
|
32
34
|
9. [Performance Optimization](#performance-optimization)
|
|
33
35
|
10. [Migration Guide](#migration-guide)
|
|
34
|
-
11. [
|
|
35
|
-
12. [
|
|
36
|
-
13. [
|
|
37
|
-
14. [
|
|
38
|
-
15. [
|
|
36
|
+
11. [Architecture Deep Dive](#architecture-deep-dive)
|
|
37
|
+
12. [Troubleshooting](#troubleshooting)
|
|
38
|
+
13. [Error Handling](#error-handling)
|
|
39
|
+
14. [Comparison](#comparison)
|
|
40
|
+
15. [Contributing](#contributing)
|
|
41
|
+
16. [Changelog](#changelog)
|
|
39
42
|
|
|
40
43
|
---
|
|
41
44
|
|
|
42
45
|
## Introduction
|
|
43
46
|
|
|
44
|
-
LacertaDB
|
|
47
|
+
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.
|
|
45
48
|
|
|
46
49
|
### ✨ Key Features
|
|
47
50
|
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
- **
|
|
65
|
-
- **
|
|
51
|
+
- 🚀 **QuickStore** - High-velocity localStorage-based caching with query capabilities
|
|
52
|
+
- 🔐 **Database-level encryption** with AES-GCM-256 cryptographic primitives
|
|
53
|
+
- 🗜️ **Automatic compression** leveraging native browser APIs (60-80% spatial reduction)
|
|
54
|
+
- 🔍 **Multiple index architectures** (B-Tree, Hash, Text, Geo)
|
|
55
|
+
- ⚡ **Sophisticated caching strategies** (LRU, LFU, TTL)
|
|
56
|
+
- 📊 **Aggregation pipeline** for complex analytical queries
|
|
57
|
+
- 🔄 **Atomic batch operations** with transactional guarantees
|
|
58
|
+
- 🔌 **Connection pooling** for optimized resource management
|
|
59
|
+
- 🔒 **Async mutex** for concurrent operation synchronization
|
|
60
|
+
- 📈 **Built-in performance telemetry**
|
|
61
|
+
- 💾 **OPFS support** for binary attachment persistence
|
|
62
|
+
- 🌐 **Offline-first architecture** - zero backend dependencies
|
|
63
|
+
- 📦 **Optimized bundle footprint** (~48KB gzipped)
|
|
64
|
+
|
|
65
|
+
### 🎯 Architectural Use Cases
|
|
66
|
+
|
|
67
|
+
- **Progressive Web Applications** - Complete database functionality in disconnected states
|
|
68
|
+
- **Client-Side Cryptography** - Zero-knowledge encryption before network transmission
|
|
69
|
+
- **Edge Computing** - Complex data processing at the browser periphery
|
|
70
|
+
- **Browser Extensions** - Persistent storage with sophisticated querying semantics
|
|
71
|
+
- **Rapid Prototyping** - Backend-agnostic development workflows
|
|
72
|
+
- **Ephemeral Caching** - QuickStore for session-based data persistence
|
|
66
73
|
|
|
67
74
|
---
|
|
68
75
|
|
|
69
76
|
## Browser Compatibility
|
|
70
77
|
|
|
71
|
-
| Browser | Minimum Version | Notes |
|
|
72
|
-
|
|
73
|
-
| Chrome | 88+ | Full
|
|
74
|
-
| Firefox | 90+ |
|
|
75
|
-
| Safari | 15.4+ | Full support |
|
|
76
|
-
| Edge | 88+ |
|
|
77
|
-
| Opera | 74+ |
|
|
78
|
-
| Chrome Mobile | 88+ |
|
|
79
|
-
| Safari iOS | 15.4+ | Storage
|
|
78
|
+
| Browser | Minimum Version | Architectural Notes |
|
|
79
|
+
|---------|----------------|---------------------|
|
|
80
|
+
| Chrome | 88+ | Full API surface including CompressionStream |
|
|
81
|
+
| Firefox | 90+ | Complete implementation |
|
|
82
|
+
| Safari | 15.4+ | Full support with OPFS |
|
|
83
|
+
| Edge | 88+ | Chromium-based implementation |
|
|
84
|
+
| Opera | 74+ | Complete feature parity |
|
|
85
|
+
| Chrome Mobile | 88+ | Mobile-optimized performance |
|
|
86
|
+
| Safari iOS | 15.4+ | Storage quotas may apply |
|
|
80
87
|
|
|
81
88
|
### Required Browser APIs
|
|
82
|
-
- IndexedDB API
|
|
83
|
-
- Web Crypto API
|
|
84
|
-
- CompressionStream API
|
|
85
|
-
- Origin Private File System
|
|
89
|
+
- **IndexedDB API** - Primary persistence layer
|
|
90
|
+
- **Web Crypto API** - Cryptographic operations
|
|
91
|
+
- **CompressionStream API** - Optional compression (graceful degradation)
|
|
92
|
+
- **Origin Private File System** - Binary attachment storage
|
|
93
|
+
- **LocalStorage API** - QuickStore implementation
|
|
86
94
|
|
|
87
95
|
---
|
|
88
96
|
|
|
89
97
|
## Quick Start
|
|
90
98
|
|
|
91
|
-
### 🚀
|
|
99
|
+
### 🚀 Rapid Initialization Sequence
|
|
92
100
|
|
|
93
101
|
```javascript
|
|
94
102
|
import { LacertaDB } from 'lacertadb';
|
|
95
103
|
|
|
96
|
-
// 1.
|
|
104
|
+
// 1. Instantiate LacertaDB orchestrator
|
|
97
105
|
const lacerta = new LacertaDB();
|
|
98
106
|
|
|
99
|
-
// 2.
|
|
100
|
-
const db = await lacerta.getDatabase('
|
|
107
|
+
// 2. Acquire database instance
|
|
108
|
+
const db = await lacerta.getDatabase('application-nexus');
|
|
101
109
|
|
|
102
|
-
// 3.
|
|
110
|
+
// 3. Initialize collection with QuickStore
|
|
103
111
|
const users = await db.createCollection('users');
|
|
104
112
|
|
|
105
|
-
// 4.
|
|
113
|
+
// 4. Leverage QuickStore for ephemeral caching
|
|
114
|
+
db.quickStore.add('session', { userId: 'usr_123', token: 'xyz' });
|
|
115
|
+
const session = db.quickStore.get('session');
|
|
116
|
+
|
|
117
|
+
// 5. Persist documents with compression
|
|
106
118
|
await users.add({
|
|
107
119
|
name: 'John Doe',
|
|
108
120
|
email: 'john@example.com',
|
|
109
|
-
|
|
110
|
-
tags: ['developer', 'javascript']
|
|
121
|
+
metadata: { created: Date.now() }
|
|
111
122
|
});
|
|
112
123
|
|
|
113
|
-
//
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
124
|
+
// 6. Execute sophisticated queries
|
|
125
|
+
const results = await users.query({
|
|
126
|
+
$and: [
|
|
127
|
+
{ 'metadata.created': { $gte: Date.now() - 86400000 } },
|
|
128
|
+
{ email: { $regex: '@example.com$' } }
|
|
129
|
+
]
|
|
117
130
|
});
|
|
118
|
-
|
|
119
|
-
// 6. Use aggregation
|
|
120
|
-
const stats = await users.aggregate([
|
|
121
|
-
{ $match: { age: { $gte: 18 } } },
|
|
122
|
-
{ $group: {
|
|
123
|
-
_id: null,
|
|
124
|
-
avgAge: { $avg: '$age' },
|
|
125
|
-
total: { $count: {} }
|
|
126
|
-
}}
|
|
127
|
-
]);
|
|
128
131
|
```
|
|
129
132
|
|
|
130
|
-
### 🔐
|
|
133
|
+
### 🔐 Cryptographically Secured Database
|
|
131
134
|
|
|
132
135
|
```javascript
|
|
133
|
-
//
|
|
136
|
+
// Initialize encrypted database with configurable parameters
|
|
134
137
|
const secureDb = await lacerta.getSecureDatabase(
|
|
135
|
-
'
|
|
136
|
-
'user-pin-
|
|
138
|
+
'classified-data',
|
|
139
|
+
'user-pin-entropy',
|
|
140
|
+
null, // Auto-generate cryptographic salt
|
|
141
|
+
{
|
|
142
|
+
iterations: 200000, // PBKDF2 iteration count
|
|
143
|
+
hashAlgorithm: 'SHA-512' // Hashing algorithm selection
|
|
144
|
+
}
|
|
137
145
|
);
|
|
138
146
|
|
|
139
|
-
//
|
|
140
|
-
const secrets = await secureDb.createCollection('
|
|
141
|
-
await secrets.add({
|
|
147
|
+
// Encrypted operations maintain transparency
|
|
148
|
+
const secrets = await secureDb.createCollection('api-keys');
|
|
149
|
+
await secrets.add({
|
|
150
|
+
service: 'stripe',
|
|
151
|
+
key: await secureDb.encryption.encryptPrivateKey('sk_live_...', 'stripe.com')
|
|
152
|
+
});
|
|
142
153
|
```
|
|
143
154
|
|
|
144
155
|
---
|
|
145
156
|
|
|
146
157
|
## Installation
|
|
147
158
|
|
|
148
|
-
###
|
|
159
|
+
### Package Manager Installation
|
|
160
|
+
|
|
149
161
|
```bash
|
|
162
|
+
# NPM
|
|
150
163
|
npm install lacertadb
|
|
151
|
-
```
|
|
152
164
|
|
|
153
|
-
|
|
154
|
-
```bash
|
|
165
|
+
# Yarn
|
|
155
166
|
yarn add lacertadb
|
|
167
|
+
|
|
168
|
+
# PNPM
|
|
169
|
+
pnpm add lacertadb
|
|
156
170
|
```
|
|
157
171
|
|
|
158
|
-
### CDN
|
|
172
|
+
### CDN Integration
|
|
173
|
+
|
|
159
174
|
```html
|
|
160
175
|
<script type="module">
|
|
161
|
-
import { LacertaDB } from 'https://cdn.jsdelivr.net/npm/lacertadb@
|
|
176
|
+
import { LacertaDB } from 'https://cdn.jsdelivr.net/npm/lacertadb@0.7.0/dist/index.min.js';
|
|
162
177
|
</script>
|
|
163
178
|
```
|
|
164
179
|
|
|
165
|
-
### Import
|
|
180
|
+
### Import Paradigms
|
|
166
181
|
|
|
167
182
|
```javascript
|
|
168
|
-
// ES6
|
|
169
|
-
import { LacertaDB } from 'lacertadb';
|
|
183
|
+
// ES6 Module Syntax
|
|
184
|
+
import { LacertaDB, QuickStore } from 'lacertadb';
|
|
170
185
|
|
|
171
|
-
//
|
|
186
|
+
// Selective Component Import
|
|
172
187
|
import {
|
|
173
188
|
LacertaDB,
|
|
174
189
|
SecureDatabaseEncryption,
|
|
175
190
|
PerformanceMonitor,
|
|
176
|
-
MigrationManager
|
|
191
|
+
MigrationManager,
|
|
192
|
+
QuickStore,
|
|
193
|
+
BTreeIndex,
|
|
194
|
+
AsyncMutex
|
|
177
195
|
} from 'lacertadb';
|
|
178
196
|
|
|
179
|
-
// CommonJS
|
|
197
|
+
// CommonJS Pattern
|
|
180
198
|
const { LacertaDB } = require('lacertadb');
|
|
181
199
|
```
|
|
182
200
|
|
|
@@ -184,90 +202,84 @@ const { LacertaDB } = require('lacertadb');
|
|
|
184
202
|
|
|
185
203
|
## Core Concepts
|
|
186
204
|
|
|
187
|
-
###
|
|
205
|
+
### Hierarchical Architecture
|
|
188
206
|
|
|
189
207
|
```
|
|
190
208
|
LacertaDB Instance
|
|
209
|
+
├── Connection Pool (Global)
|
|
210
|
+
│ └── Database Connections (Reusable)
|
|
191
211
|
├── Database 1
|
|
212
|
+
│ ├── QuickStore (LocalStorage Layer)
|
|
192
213
|
│ ├── Collection A
|
|
193
|
-
│ │ ├──
|
|
194
|
-
│ │ ├──
|
|
195
|
-
│ │ └──
|
|
214
|
+
│ │ ├── Documents (IndexedDB)
|
|
215
|
+
│ │ ├── Indexes (B-Tree/Hash/Text/Geo)
|
|
216
|
+
│ │ └── Cache Strategy (LRU/LFU/TTL)
|
|
196
217
|
│ └── Collection B
|
|
197
218
|
└── Database 2
|
|
198
|
-
|
|
219
|
+
├── QuickStore Instance
|
|
220
|
+
└── __private_keys__ (Encrypted Key Storage)
|
|
199
221
|
```
|
|
200
222
|
|
|
201
|
-
### Document
|
|
202
|
-
|
|
203
|
-
Every document automatically includes:
|
|
223
|
+
### Document Metadata Schema
|
|
204
224
|
|
|
205
225
|
```javascript
|
|
206
226
|
{
|
|
207
|
-
_id: "doc_1234567890_abc", //
|
|
227
|
+
_id: "doc_1234567890_abc", // Unique identifier
|
|
208
228
|
_created: 1234567890, // Creation timestamp
|
|
209
|
-
_modified: 1234567890, //
|
|
210
|
-
_permanent: false, //
|
|
211
|
-
|
|
229
|
+
_modified: 1234567890, // Modification timestamp
|
|
230
|
+
_permanent: false, // Cleanup immunity flag
|
|
231
|
+
_compressed: true, // Compression status
|
|
232
|
+
_encrypted: false, // Encryption status
|
|
233
|
+
_attachments: [], // OPFS attachment references
|
|
234
|
+
...userDefinedFields // Application data
|
|
212
235
|
}
|
|
213
236
|
```
|
|
214
237
|
|
|
238
|
+
### Private Property Convention
|
|
239
|
+
|
|
240
|
+
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.
|
|
241
|
+
|
|
215
242
|
---
|
|
216
243
|
|
|
217
244
|
## API Reference
|
|
218
245
|
|
|
219
246
|
### 📦 LacertaDB Class
|
|
220
247
|
|
|
221
|
-
|
|
248
|
+
Primary orchestrator for database lifecycle management.
|
|
222
249
|
|
|
223
250
|
| Method | Parameters | Returns | Description |
|
|
224
251
|
|--------|------------|---------|-------------|
|
|
225
|
-
| `getDatabase()` | `name: string`<br/>`options?: object` | `Promise<Database>` |
|
|
226
|
-
| `getSecureDatabase()` | `name: string`<br/>`pin: string`<br/>`salt?: string`<br/>`config?: object` | `Promise<Database>` |
|
|
227
|
-
| `dropDatabase()` | `name: string` | `Promise<void>` |
|
|
228
|
-
| `listDatabases()` | - | `string[]` |
|
|
229
|
-
| `createBackup()` | `password?: string` | `Promise<string>` |
|
|
252
|
+
| `getDatabase()` | `name: string`<br/>`options?: object` | `Promise<Database>` | Acquire database instance |
|
|
253
|
+
| `getSecureDatabase()` | `name: string`<br/>`pin: string`<br/>`salt?: string`<br/>`config?: object` | `Promise<Database>` | Initialize encrypted database |
|
|
254
|
+
| `dropDatabase()` | `name: string` | `Promise<void>` | Destroy database and QuickStore |
|
|
255
|
+
| `listDatabases()` | - | `string[]` | Enumerate databases |
|
|
256
|
+
| `createBackup()` | `password?: string` | `Promise<string>` | Generate comprehensive backup |
|
|
230
257
|
| `restoreBackup()` | `data: string`<br/>`password?: string` | `Promise<object>` | Restore from backup |
|
|
231
|
-
| `destroy()` | - | `void` |
|
|
258
|
+
| `destroy()` | - | `void` | Release all connections |
|
|
259
|
+
| `performanceMonitor` | - | `PerformanceMonitor` | Access performance telemetry |
|
|
232
260
|
|
|
233
261
|
<details>
|
|
234
|
-
<summary><strong>Examples</strong></summary>
|
|
262
|
+
<summary><strong>Implementation Examples</strong></summary>
|
|
235
263
|
|
|
236
264
|
```javascript
|
|
237
|
-
// Initialize LacertaDB
|
|
238
265
|
const lacerta = new LacertaDB();
|
|
239
266
|
|
|
240
|
-
//
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
//
|
|
244
|
-
const secureDb = await lacerta.getSecureDatabase(
|
|
245
|
-
'sensitive-data',
|
|
246
|
-
'my-secure-pin-123456',
|
|
247
|
-
null, // Auto-generate salt
|
|
248
|
-
{
|
|
249
|
-
iterations: 200000, // Higher = more secure but slower
|
|
250
|
-
keyLength: 256
|
|
251
|
-
}
|
|
252
|
-
);
|
|
253
|
-
|
|
254
|
-
// Create a full backup
|
|
255
|
-
const backup = await lacerta.createBackup('backup-password');
|
|
256
|
-
// Save to file or cloud
|
|
257
|
-
await saveToCloud(backup);
|
|
267
|
+
// Connection pooling automatically manages resources
|
|
268
|
+
const db1 = await lacerta.getDatabase('app1');
|
|
269
|
+
const db2 = await lacerta.getDatabase('app2');
|
|
270
|
+
// Connections are pooled and reused efficiently
|
|
258
271
|
|
|
259
|
-
//
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
console.log(`Restored: ${result.databases} databases, ${result.documents} documents`);
|
|
272
|
+
// Access performance monitoring
|
|
273
|
+
lacerta.performanceMonitor.startMonitoring();
|
|
274
|
+
const metrics = lacerta.performanceMonitor.getStats();
|
|
263
275
|
|
|
264
|
-
//
|
|
265
|
-
const
|
|
266
|
-
|
|
276
|
+
// Comprehensive backup including QuickStore
|
|
277
|
+
const backup = await lacerta.createBackup('encryption-key');
|
|
278
|
+
localStorage.setItem('backup', backup);
|
|
267
279
|
|
|
268
|
-
//
|
|
280
|
+
// Cleanup with connection pool release
|
|
269
281
|
window.addEventListener('beforeunload', () => {
|
|
270
|
-
lacerta.destroy();
|
|
282
|
+
lacerta.destroy(); // Releases all pooled connections
|
|
271
283
|
});
|
|
272
284
|
```
|
|
273
285
|
|
|
@@ -277,76 +289,140 @@ window.addEventListener('beforeunload', () => {
|
|
|
277
289
|
|
|
278
290
|
### 🗄️ Database Class
|
|
279
291
|
|
|
280
|
-
|
|
292
|
+
Database-level operations with QuickStore integration.
|
|
281
293
|
|
|
282
294
|
| Method | Parameters | Returns | Description |
|
|
283
295
|
|--------|------------|---------|-------------|
|
|
284
|
-
| `createCollection()` | `name: string`<br/>`options?: object` | `Promise<Collection>` |
|
|
285
|
-
| `getCollection()` | `name: string` | `Promise<Collection>` |
|
|
286
|
-
| `dropCollection()` | `name: string` | `Promise<void>` |
|
|
287
|
-
| `listCollections()` | - | `string[]` |
|
|
288
|
-
| `getStats()` | - | `object` |
|
|
289
|
-
| `updateSettings()` | `settings: object` | `void` |
|
|
290
|
-
| `export()` | `format:
|
|
296
|
+
| `createCollection()` | `name: string`<br/>`options?: object` | `Promise<Collection>` | Initialize collection |
|
|
297
|
+
| `getCollection()` | `name: string` | `Promise<Collection>` | Retrieve collection (lazy init) |
|
|
298
|
+
| `dropCollection()` | `name: string` | `Promise<void>` | Remove collection |
|
|
299
|
+
| `listCollections()` | - | `string[]` | Enumerate collections |
|
|
300
|
+
| `getStats()` | - | `object` | Database metrics |
|
|
301
|
+
| `updateSettings()` | `settings: object` | `void` | Configure database |
|
|
302
|
+
| `export()` | `format: string`<br/>`password?: string` | `Promise<string>` | Export database |
|
|
291
303
|
| `import()` | `data: string`<br/>`format: string`<br/>`password?: string` | `Promise<object>` | Import data |
|
|
292
|
-
| `storePrivateKey()` | `name: string`<br/>`key: string`<br/>`auth?: string` | `Promise<boolean>` |
|
|
293
|
-
| `getPrivateKey()` | `name: string`<br/>`auth?: string` | `Promise<string>` | Retrieve
|
|
294
|
-
| `clearAll()` | - | `Promise<void>` |
|
|
295
|
-
|
|
296
|
-
#### Database
|
|
297
|
-
|
|
298
|
-
|
|
|
299
|
-
|
|
300
|
-
| `
|
|
301
|
-
| `
|
|
302
|
-
| `
|
|
304
|
+
| `storePrivateKey()` | `name: string`<br/>`key: string`<br/>`auth?: string` | `Promise<boolean>` | Secure key storage |
|
|
305
|
+
| `getPrivateKey()` | `name: string`<br/>`auth?: string` | `Promise<string>` | Retrieve secured key |
|
|
306
|
+
| `clearAll()` | - | `Promise<void>` | Purge all data |
|
|
307
|
+
|
|
308
|
+
#### Database Properties (Getters)
|
|
309
|
+
|
|
310
|
+
| Property | Type | Description |
|
|
311
|
+
|----------|------|-------------|
|
|
312
|
+
| `quickStore` | `QuickStore` | LocalStorage-based cache |
|
|
313
|
+
| `collections` | `Map<string, Collection>` | Collection registry |
|
|
314
|
+
| `metadata` | `DatabaseMetadata` | Database metadata |
|
|
315
|
+
| `settings` | `Settings` | Configuration parameters |
|
|
316
|
+
| `encryption` | `SecureDatabaseEncryption│null` | Encryption instance |
|
|
317
|
+
| `isEncrypted` | `boolean` | Encryption status |
|
|
318
|
+
| `performanceMonitor` | `PerformanceMonitor` | Performance telemetry |
|
|
303
319
|
|
|
304
320
|
<details>
|
|
305
|
-
<summary><strong>
|
|
321
|
+
<summary><strong>Advanced Usage Patterns</strong></summary>
|
|
306
322
|
|
|
307
323
|
```javascript
|
|
308
|
-
//
|
|
309
|
-
const users = await db.
|
|
310
|
-
|
|
311
|
-
|
|
324
|
+
// Lazy collection initialization
|
|
325
|
+
const users = await db.getCollection('users');
|
|
326
|
+
// Collection is initialized only on first access
|
|
327
|
+
|
|
328
|
+
// QuickStore integration for session management
|
|
329
|
+
db.quickStore.add('user_session', {
|
|
330
|
+
userId: 'usr_123',
|
|
331
|
+
loginTime: Date.now(),
|
|
332
|
+
permissions: ['read', 'write']
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// Query QuickStore with same engine
|
|
336
|
+
const activeSessions = db.quickStore.query({
|
|
337
|
+
loginTime: { $gte: Date.now() - 3600000 }
|
|
312
338
|
});
|
|
313
339
|
|
|
314
|
-
// Configure
|
|
340
|
+
// Configure with size management
|
|
315
341
|
db.updateSettings({
|
|
316
|
-
sizeLimitKB: 100000,
|
|
317
|
-
bufferLimitKB: 80000,
|
|
318
|
-
freeSpaceEvery: 30000
|
|
342
|
+
sizeLimitKB: 100000,
|
|
343
|
+
bufferLimitKB: 80000,
|
|
344
|
+
freeSpaceEvery: 30000
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// Export with QuickStore data
|
|
348
|
+
const fullExport = await db.export('encrypted', 'password');
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
</details>
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
### 🚀 QuickStore
|
|
356
|
+
|
|
357
|
+
High-performance localStorage-based caching layer with query capabilities.
|
|
358
|
+
|
|
359
|
+
| Method | Parameters | Returns | Description |
|
|
360
|
+
|--------|------------|---------|-------------|
|
|
361
|
+
| `add()` | `docId: string`<br/>`data: object` | `boolean` | Store document |
|
|
362
|
+
| `get()` | `docId: string` | `object│null` | Retrieve document |
|
|
363
|
+
| `update()` | `docId: string`<br/>`data: object` | `boolean` | Update document |
|
|
364
|
+
| `delete()` | `docId: string` | `void` | Remove document |
|
|
365
|
+
| `getAll()` | - | `object[]` | Retrieve all documents |
|
|
366
|
+
| `query()` | `filter: object` | `object[]` | Query documents |
|
|
367
|
+
| `clear()` | - | `void` | Purge all data |
|
|
368
|
+
| `size` | - | `number` | Document count |
|
|
369
|
+
|
|
370
|
+
#### QuickStore Architecture
|
|
371
|
+
|
|
372
|
+
QuickStore leverages localStorage for ephemeral data persistence, providing:
|
|
373
|
+
- **Synchronous operations** for immediate data access
|
|
374
|
+
- **Query engine integration** using identical syntax as main collections
|
|
375
|
+
- **Automatic serialization** with TurboSerial
|
|
376
|
+
- **Index management** for efficient lookups
|
|
377
|
+
- **Size limitations** based on localStorage quotas (5-10MB)
|
|
378
|
+
|
|
379
|
+
<details>
|
|
380
|
+
<summary><strong>QuickStore Implementation Patterns</strong></summary>
|
|
381
|
+
|
|
382
|
+
```javascript
|
|
383
|
+
const db = await lacerta.getDatabase('app');
|
|
384
|
+
const quickStore = db.quickStore;
|
|
385
|
+
|
|
386
|
+
// Session management
|
|
387
|
+
quickStore.add('current_user', {
|
|
388
|
+
id: 'usr_123',
|
|
389
|
+
name: 'John Doe',
|
|
390
|
+
loginTime: Date.now(),
|
|
391
|
+
preferences: {
|
|
392
|
+
theme: 'dark',
|
|
393
|
+
language: 'en'
|
|
394
|
+
}
|
|
319
395
|
});
|
|
320
396
|
|
|
321
|
-
//
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
397
|
+
// Shopping cart persistence
|
|
398
|
+
quickStore.add('cart', {
|
|
399
|
+
items: [
|
|
400
|
+
{ productId: 'prod_1', quantity: 2, price: 29.99 },
|
|
401
|
+
{ productId: 'prod_2', quantity: 1, price: 49.99 }
|
|
402
|
+
],
|
|
403
|
+
total: 109.97,
|
|
404
|
+
updated: Date.now()
|
|
328
405
|
});
|
|
329
406
|
|
|
330
|
-
//
|
|
331
|
-
const
|
|
332
|
-
|
|
407
|
+
// Query capabilities with same syntax
|
|
408
|
+
const recentActivity = quickStore.query({
|
|
409
|
+
loginTime: { $gte: Date.now() - 3600000 }
|
|
410
|
+
});
|
|
333
411
|
|
|
334
|
-
//
|
|
335
|
-
|
|
336
|
-
|
|
412
|
+
// Atomic updates
|
|
413
|
+
quickStore.update('current_user', {
|
|
414
|
+
...quickStore.get('current_user'),
|
|
415
|
+
lastActivity: Date.now()
|
|
416
|
+
});
|
|
337
417
|
|
|
338
|
-
//
|
|
339
|
-
|
|
340
|
-
'
|
|
341
|
-
'
|
|
342
|
-
|
|
343
|
-
);
|
|
418
|
+
// Clear on logout
|
|
419
|
+
function logout() {
|
|
420
|
+
quickStore.delete('current_user');
|
|
421
|
+
quickStore.delete('cart');
|
|
422
|
+
}
|
|
344
423
|
|
|
345
|
-
//
|
|
346
|
-
|
|
347
|
-
'stripe-api',
|
|
348
|
-
'myapp.com'
|
|
349
|
-
);
|
|
424
|
+
// Full clear
|
|
425
|
+
quickStore.clear();
|
|
350
426
|
```
|
|
351
427
|
|
|
352
428
|
</details>
|
|
@@ -355,156 +431,102 @@ const apiKey = await secureDb.getPrivateKey(
|
|
|
355
431
|
|
|
356
432
|
### 📁 Collection Class
|
|
357
433
|
|
|
358
|
-
|
|
434
|
+
Document management with advanced querying and indexing.
|
|
359
435
|
|
|
360
436
|
#### Core Methods
|
|
361
437
|
|
|
362
438
|
| Method | Parameters | Returns | Description |
|
|
363
439
|
|--------|------------|---------|-------------|
|
|
364
|
-
| `add()` | `data: object`<br/>`options?: object` | `Promise<string>` |
|
|
365
|
-
| `get()` | `id: string`<br/>`options?: object` | `Promise<object>` |
|
|
366
|
-
| `update()` | `id: string`<br/>`updates: object`<br/>`options?: object` | `Promise<string>` |
|
|
367
|
-
| `delete()` | `id: string`<br/>`options?: object` | `Promise<void>` |
|
|
368
|
-
| `getAll()` | `options?: object` | `Promise<object[]>` |
|
|
369
|
-
| `clear()` | `options?: object` | `Promise<void>` |
|
|
370
|
-
| `count()` | `filter?: object` | `Promise<number>` | Count documents |
|
|
440
|
+
| `add()` | `data: object`<br/>`options?: object` | `Promise<string>` | Insert document |
|
|
441
|
+
| `get()` | `id: string`<br/>`options?: object` | `Promise<object>` | Retrieve document |
|
|
442
|
+
| `update()` | `id: string`<br/>`updates: object`<br/>`options?: object` | `Promise<string>` | Modify document |
|
|
443
|
+
| `delete()` | `id: string`<br/>`options?: object` | `Promise<void>` | Remove document |
|
|
444
|
+
| `getAll()` | `options?: object` | `Promise<object[]>` | Retrieve all documents |
|
|
445
|
+
| `clear()` | `options?: object` | `Promise<void>` | Purge collection |
|
|
371
446
|
|
|
372
|
-
#### Query
|
|
447
|
+
#### Query and Aggregation
|
|
373
448
|
|
|
374
449
|
| Method | Parameters | Returns | Description |
|
|
375
450
|
|--------|------------|---------|-------------|
|
|
376
|
-
| `query()` | `filter: object`<br/>`options?: object` | `Promise<object[]>` |
|
|
377
|
-
| `aggregate()` | `pipeline: object[]` | `Promise<object[]>` |
|
|
378
|
-
| `findOne()` | `filter: object` | `Promise<object│null>` |
|
|
451
|
+
| `query()` | `filter: object`<br/>`options?: object` | `Promise<object[]>` | Execute query |
|
|
452
|
+
| `aggregate()` | `pipeline: object[]` | `Promise<object[]>` | Aggregation pipeline |
|
|
453
|
+
| `findOne()` | `filter: object` | `Promise<object│null>` | First match |
|
|
454
|
+
| `count()` | `filter?: object` | `Promise<number>` | Document count |
|
|
379
455
|
|
|
380
456
|
#### Batch Operations
|
|
381
457
|
|
|
382
458
|
| Method | Parameters | Returns | Description |
|
|
383
459
|
|--------|------------|---------|-------------|
|
|
384
|
-
| `batchAdd()` | `documents: object[]`<br/>`options?: object` | `Promise<object[]>` |
|
|
385
|
-
| `batchUpdate()` | `updates: object[]`<br/>`options?: object` | `Promise<object[]>` |
|
|
386
|
-
| `batchDelete()` | `items: string[]│object[]` | `Promise<object[]>` |
|
|
387
|
-
|
|
388
|
-
#### Event Methods
|
|
389
|
-
|
|
390
|
-
| Method | Parameters | Returns | Description |
|
|
391
|
-
|--------|------------|---------|-------------|
|
|
392
|
-
| `on()` | `event: string`<br/>`callback: function` | `void` | Add event listener |
|
|
393
|
-
| `off()` | `event: string`<br/>`callback: function` | `void` | Remove event listener |
|
|
460
|
+
| `batchAdd()` | `documents: object[]`<br/>`options?: object` | `Promise<object[]>` | Bulk insert |
|
|
461
|
+
| `batchUpdate()` | `updates: object[]`<br/>`options?: object` | `Promise<object[]>` | Bulk update |
|
|
462
|
+
| `batchDelete()` | `items: string[]│object[]` | `Promise<object[]>` | Bulk delete |
|
|
394
463
|
|
|
395
|
-
####
|
|
464
|
+
#### Event System
|
|
396
465
|
|
|
397
466
|
| Method | Parameters | Returns | Description |
|
|
398
467
|
|--------|------------|---------|-------------|
|
|
399
|
-
| `
|
|
400
|
-
| `
|
|
401
|
-
|
|
402
|
-
#### Options Parameters
|
|
403
|
-
|
|
404
|
-
| Option | Type | Default | Description |
|
|
405
|
-
|--------|------|---------|-------------|
|
|
406
|
-
| `id` | `string` | auto-generated | Custom document ID |
|
|
407
|
-
| `compressed` | `boolean` | `true` | Enable compression |
|
|
408
|
-
| `permanent` | `boolean` | `false` | Prevent auto-deletion |
|
|
409
|
-
| `includeAttachments` | `boolean` | `false` | Include file attachments |
|
|
410
|
-
| `attachments` | `Array` | `[]` | File attachments to store |
|
|
411
|
-
| `force` | `boolean` | `false` | Force delete permanent docs |
|
|
412
|
-
| `limit` | `number` | - | Limit results |
|
|
413
|
-
| `skip` | `number` | - | Skip results |
|
|
414
|
-
| `sort` | `object` | - | Sort criteria |
|
|
415
|
-
| `projection` | `object` | - | Field projection |
|
|
468
|
+
| `on()` | `event: string`<br/>`callback: function` | `void` | Register listener |
|
|
469
|
+
| `off()` | `event: string`<br/>`callback: function` | `void` | Unregister listener |
|
|
416
470
|
|
|
417
|
-
|
|
418
|
-
<summary><strong>Examples</strong></summary>
|
|
471
|
+
#### Collection Properties
|
|
419
472
|
|
|
420
|
-
|
|
421
|
-
|
|
473
|
+
| Property | Type | Description |
|
|
474
|
+
|----------|------|-------------|
|
|
475
|
+
| `name` | `string` | Collection identifier |
|
|
476
|
+
| `database` | `Database` | Parent database |
|
|
477
|
+
| `settings` | `Settings` | Configuration |
|
|
478
|
+
| `metadata` | `CollectionMetadata` | Collection metrics |
|
|
479
|
+
| `initialized` | `boolean` | Initialization status |
|
|
422
480
|
|
|
423
|
-
|
|
424
|
-
const userId = await users.add({
|
|
425
|
-
name: 'John Doe',
|
|
426
|
-
email: 'john@example.com',
|
|
427
|
-
age: 30,
|
|
428
|
-
skills: ['JavaScript', 'TypeScript', 'React']
|
|
429
|
-
}, {
|
|
430
|
-
id: 'user_john_doe',
|
|
431
|
-
permanent: true // Protect from auto-cleanup
|
|
432
|
-
});
|
|
481
|
+
---
|
|
433
482
|
|
|
434
|
-
|
|
435
|
-
const john = await users.findOne({ email: 'john@example.com' });
|
|
483
|
+
### 🔐 Connection Management
|
|
436
484
|
|
|
437
|
-
|
|
438
|
-
const seniorDevs = await users.query(
|
|
439
|
-
{
|
|
440
|
-
age: { $gte: 25, $lte: 45 },
|
|
441
|
-
skills: { $all: ['JavaScript', 'React'] }
|
|
442
|
-
},
|
|
443
|
-
{
|
|
444
|
-
sort: { age: -1 },
|
|
445
|
-
limit: 10,
|
|
446
|
-
projection: { name: 1, email: 1, skills: 1 }
|
|
447
|
-
}
|
|
448
|
-
);
|
|
485
|
+
#### IndexedDBConnectionPool
|
|
449
486
|
|
|
450
|
-
|
|
451
|
-
const skillStats = await users.aggregate([
|
|
452
|
-
{ $match: { age: { $gte: 18 } } },
|
|
453
|
-
{ $project: { skills: 1 } },
|
|
454
|
-
{ $unwind: '$skills' },
|
|
455
|
-
{ $group: {
|
|
456
|
-
_id: '$skills',
|
|
457
|
-
count: { $count: {} },
|
|
458
|
-
users: { $push: '$_id' }
|
|
459
|
-
}
|
|
460
|
-
},
|
|
461
|
-
{ $sort: { count: -1 } },
|
|
462
|
-
{ $limit: 5 }
|
|
463
|
-
]);
|
|
487
|
+
Global connection pool for optimized database connections.
|
|
464
488
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
489
|
+
| Method | Parameters | Returns | Description |
|
|
490
|
+
|--------|------------|---------|-------------|
|
|
491
|
+
| `getConnection()` | `dbName: string`<br/>`version: number`<br/>`upgradeCallback?: function` | `Promise<IDBDatabase>` | Acquire connection |
|
|
492
|
+
| `releaseConnection()` | `dbName: string`<br/>`version: number` | `void` | Release connection |
|
|
493
|
+
| `closeAll()` | - | `void` | Close all connections |
|
|
470
494
|
|
|
471
|
-
|
|
472
|
-
compressed: true,
|
|
473
|
-
permanent: false
|
|
474
|
-
});
|
|
495
|
+
#### AsyncMutex
|
|
475
496
|
|
|
476
|
-
|
|
477
|
-
if (result.success) {
|
|
478
|
-
console.log(`Added user: ${result.id}`);
|
|
479
|
-
} else {
|
|
480
|
-
console.error(`Failed to add user: ${result.error}`);
|
|
481
|
-
}
|
|
482
|
-
});
|
|
497
|
+
Synchronization primitive for concurrent operations.
|
|
483
498
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
499
|
+
| Method | Parameters | Returns | Description |
|
|
500
|
+
|--------|------------|---------|-------------|
|
|
501
|
+
| `acquire()` | - | `Promise<function>` | Acquire lock |
|
|
502
|
+
| `release()` | - | `void` | Release lock |
|
|
503
|
+
| `runExclusive()` | `callback: function` | `Promise<any>` | Execute exclusively |
|
|
488
504
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
});
|
|
505
|
+
<details>
|
|
506
|
+
<summary><strong>Concurrency Control Patterns</strong></summary>
|
|
492
507
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
508
|
+
```javascript
|
|
509
|
+
// Connection pooling is automatic
|
|
510
|
+
const db1 = await connectionPool.getConnection('db1', 1);
|
|
511
|
+
const db2 = await connectionPool.getConnection('db1', 1); // Reuses connection
|
|
512
|
+
|
|
513
|
+
// Mutex for critical sections
|
|
514
|
+
const mutex = new AsyncMutex();
|
|
515
|
+
|
|
516
|
+
async function criticalOperation() {
|
|
517
|
+
const release = await mutex.acquire();
|
|
518
|
+
try {
|
|
519
|
+
// Exclusive access guaranteed
|
|
520
|
+
await performCriticalWork();
|
|
521
|
+
} finally {
|
|
522
|
+
release();
|
|
523
|
+
}
|
|
524
|
+
}
|
|
502
525
|
|
|
503
|
-
//
|
|
504
|
-
|
|
505
|
-
|
|
526
|
+
// Or using runExclusive
|
|
527
|
+
await mutex.runExclusive(async () => {
|
|
528
|
+
await performCriticalWork();
|
|
506
529
|
});
|
|
507
|
-
// userWithFiles._attachments will contain the file data
|
|
508
530
|
```
|
|
509
531
|
|
|
510
532
|
</details>
|
|
@@ -513,182 +535,77 @@ const userWithFiles = await users.get(profile, {
|
|
|
513
535
|
|
|
514
536
|
### 🔍 Index Management
|
|
515
537
|
|
|
516
|
-
|
|
538
|
+
Sophisticated indexing strategies for query optimization.
|
|
539
|
+
|
|
540
|
+
#### Index Methods
|
|
517
541
|
|
|
518
542
|
| Method | Parameters | Returns | Description |
|
|
519
543
|
|--------|------------|---------|-------------|
|
|
520
|
-
| `createIndex()` | `field: string`<br/>`options: object` | `Promise<string>` | Create
|
|
521
|
-
| `dropIndex()` | `name: string` | `Promise<void>` | Remove
|
|
522
|
-
| `getIndexes()` | - | `Promise<object>` |
|
|
523
|
-
| `verifyIndexes()` | - | `Promise<object>` |
|
|
524
|
-
| `reindexCollection()` | - | `Promise<void>` | Rebuild all indexes |
|
|
525
|
-
|
|
526
|
-
#### Index Types and Use Cases
|
|
527
|
-
|
|
528
|
-
| Type | Use Case | Query Performance | Space Overhead |
|
|
529
|
-
|------|----------|-------------------|----------------|
|
|
530
|
-
| `btree` | Range queries, sorting | O(log n) | Medium |
|
|
531
|
-
| `hash` | Exact match queries | O(1) | Low |
|
|
532
|
-
| `text` | Full-text search | O(n) for terms | High |
|
|
533
|
-
| `geo` | Spatial queries | O(n log n) | Medium |
|
|
534
|
-
|
|
535
|
-
#### Index Options
|
|
536
|
-
|
|
537
|
-
| Option | Type | Default | Values | Description |
|
|
538
|
-
|--------|------|---------|--------|-------------|
|
|
539
|
-
| `type` | `string` | `'btree'` | `'btree'`, `'hash'`, `'text'`, `'geo'` | Index type |
|
|
540
|
-
| `unique` | `boolean` | `false` | - | Enforce uniqueness |
|
|
541
|
-
| `sparse` | `boolean` | `false` | - | Skip null values |
|
|
542
|
-
| `name` | `string` | field name | - | Custom index name |
|
|
543
|
-
| `collation` | `object` | null | - | Collation rules |
|
|
544
|
+
| `createIndex()` | `field: string`<br/>`options: object` | `Promise<string>` | Create index |
|
|
545
|
+
| `dropIndex()` | `name: string` | `Promise<void>` | Remove index |
|
|
546
|
+
| `getIndexes()` | - | `Promise<object>` | Index statistics |
|
|
547
|
+
| `verifyIndexes()` | - | `Promise<object>` | Self-healing verification |
|
|
544
548
|
|
|
545
|
-
|
|
546
|
-
<summary><strong>Examples</strong></summary>
|
|
549
|
+
#### Index Architectures
|
|
547
550
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
// Create compound index (nested fields)
|
|
556
|
-
await users.createIndex('address.city', {
|
|
557
|
-
type: 'hash',
|
|
558
|
-
name: 'city_index'
|
|
559
|
-
});
|
|
560
|
-
|
|
561
|
-
// Create unique index on email
|
|
562
|
-
await users.createIndex('email', {
|
|
563
|
-
unique: true,
|
|
564
|
-
sparse: true // Allow multiple nulls
|
|
565
|
-
});
|
|
566
|
-
|
|
567
|
-
// Create text index for full-text search
|
|
568
|
-
await posts.createIndex('content', {
|
|
569
|
-
type: 'text',
|
|
570
|
-
name: 'content_search'
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
// Use text index
|
|
574
|
-
const searchResults = await posts.query({
|
|
575
|
-
content: { $text: 'javascript tutorial' }
|
|
576
|
-
});
|
|
577
|
-
|
|
578
|
-
// Create geo index for location queries
|
|
579
|
-
await stores.createIndex('location', {
|
|
580
|
-
type: 'geo'
|
|
581
|
-
});
|
|
551
|
+
| Type | Algorithm | Use Case | Complexity | Space |
|
|
552
|
+
|------|-----------|----------|------------|-------|
|
|
553
|
+
| `btree` | B-Tree | Range queries, sorting | O(log n) | O(n) |
|
|
554
|
+
| `hash` | Hash Table | Exact match | O(1) avg | O(n) |
|
|
555
|
+
| `text` | Inverted Index | Full-text search | O(m) | O(n*m) |
|
|
556
|
+
| `geo` | R-Tree variant | Spatial queries | O(log n) | O(n) |
|
|
582
557
|
|
|
583
|
-
|
|
584
|
-
const nearbyStores = await stores.query({
|
|
585
|
-
location: {
|
|
586
|
-
$near: {
|
|
587
|
-
coordinates: { lat: 40.7128, lng: -74.0060 },
|
|
588
|
-
maxDistance: 5000 // 5km in meters
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
});
|
|
558
|
+
#### Self-Healing Indexes
|
|
592
559
|
|
|
593
|
-
|
|
594
|
-
const storesInArea = await stores.query({
|
|
595
|
-
location: {
|
|
596
|
-
$within: {
|
|
597
|
-
minLat: 40.7,
|
|
598
|
-
maxLat: 40.8,
|
|
599
|
-
minLng: -74.1,
|
|
600
|
-
maxLng: -74.0
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
});
|
|
560
|
+
B-Tree indexes include automatic verification and repair mechanisms:
|
|
604
561
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
console.log(` Type: ${info.type}`);
|
|
610
|
-
console.log(` Size: ${info.size} entries`);
|
|
611
|
-
console.log(` Memory: ~${info.memoryUsage} bytes`);
|
|
612
|
-
});
|
|
562
|
+
```javascript
|
|
563
|
+
// Automatic verification during operations
|
|
564
|
+
const btreeIndex = new BTreeIndex();
|
|
565
|
+
btreeIndex.insert(key, value); // Triggers periodic verification
|
|
613
566
|
|
|
614
|
-
//
|
|
615
|
-
const report = await
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
}
|
|
567
|
+
// Manual verification
|
|
568
|
+
const report = await collection.verifyIndexes();
|
|
569
|
+
// {
|
|
570
|
+
// 'age_index': { healthy: true, issues: [] },
|
|
571
|
+
// 'email_index': { healthy: false, issues: [...], repaired: 2 }
|
|
572
|
+
// }
|
|
619
573
|
```
|
|
620
574
|
|
|
621
|
-
</details>
|
|
622
|
-
|
|
623
575
|
---
|
|
624
576
|
|
|
625
577
|
### 🔐 Encryption
|
|
626
578
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
| Method | Parameters | Returns | Description |
|
|
630
|
-
|--------|------------|---------|-------------|
|
|
631
|
-
| `initialize()` | `pin: string`<br/>`salt?: Uint8Array` | `Promise<string>` | Initialize encryption |
|
|
632
|
-
| `changePin()` | `oldPin: string`<br/>`newPin: string` | `Promise<string>` | Change encryption PIN |
|
|
633
|
-
| `destroy()` | - | `void` | Clear encryption keys |
|
|
634
|
-
| `exportMetadata()` | - | `object` | Export encryption config |
|
|
635
|
-
| `importMetadata()` | `metadata: object` | `boolean` | Import encryption config |
|
|
636
|
-
|
|
637
|
-
#### Encryption Configuration
|
|
638
|
-
|
|
639
|
-
| Option | Type | Default | Range | Description |
|
|
640
|
-
|--------|------|---------|-------|-------------|
|
|
641
|
-
| `iterations` | `number` | `100000` | 10000-1000000 | PBKDF2 iterations |
|
|
642
|
-
| `hashAlgorithm` | `string` | `'SHA-256'` | SHA-256/SHA-512 | Hash algorithm |
|
|
643
|
-
| `keyLength` | `number` | `256` | 128/192/256 | Key length in bits |
|
|
644
|
-
| `saltLength` | `number` | `32` | 16-64 | Salt length in bytes |
|
|
579
|
+
Cryptographic subsystem with configurable parameters.
|
|
645
580
|
|
|
646
|
-
####
|
|
581
|
+
#### SecureDatabaseEncryption Class
|
|
647
582
|
|
|
648
583
|
| Method | Parameters | Returns | Description |
|
|
649
584
|
|--------|------------|---------|-------------|
|
|
650
|
-
| `
|
|
651
|
-
|
|
652
|
-
<
|
|
653
|
-
<
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
// Generate secure PIN
|
|
676
|
-
const securePin = SecureDatabaseEncryption.generateSecurePIN(8);
|
|
677
|
-
console.log('Generated PIN:', securePin);
|
|
678
|
-
|
|
679
|
-
// Export encryption metadata (for backup)
|
|
680
|
-
const encryptionMeta = secureDb.encryption.exportMetadata();
|
|
681
|
-
// Store this securely with your backups
|
|
682
|
-
|
|
683
|
-
// Restore encryption with same config
|
|
684
|
-
const restoredDb = await lacerta.getSecureDatabase(
|
|
685
|
-
'secure-app',
|
|
686
|
-
userPin,
|
|
687
|
-
encryptionMeta.salt // Use stored salt
|
|
688
|
-
);
|
|
689
|
-
```
|
|
690
|
-
|
|
691
|
-
</details>
|
|
585
|
+
| `initialize()` | `pin: string`<br/>`salt?: Uint8Array` | `Promise<string>` | Initialize encryption |
|
|
586
|
+
| `encrypt()` | `data: any` | `Promise<Uint8Array>` | Encrypt data |
|
|
587
|
+
| `decrypt()` | `data: Uint8Array` | `Promise<Uint8Array>` | Decrypt data |
|
|
588
|
+
| `encryptPrivateKey()` | `key: string`<br/>`auth?: string` | `Promise<string>` | Secure key encryption |
|
|
589
|
+
| `decryptPrivateKey()` | `encrypted: string`<br/>`auth?: string` | `Promise<string>` | Key decryption |
|
|
590
|
+
| `changePin()` | `oldPin: string`<br/>`newPin: string` | `Promise<string>` | Rotate PIN |
|
|
591
|
+
| `destroy()` | - | `void` | Clear keys |
|
|
592
|
+
| `exportMetadata()` | - | `object` | Export config |
|
|
593
|
+
| `importMetadata()` | `metadata: object` | `boolean` | Import config |
|
|
594
|
+
|
|
595
|
+
#### Encryption Properties (Getters)
|
|
596
|
+
|
|
597
|
+
| Property | Type | Description |
|
|
598
|
+
|----------|------|-------------|
|
|
599
|
+
| `initialized` | `boolean` | Initialization status |
|
|
600
|
+
|
|
601
|
+
#### Cryptographic Parameters
|
|
602
|
+
|
|
603
|
+
| Parameter | Default | Range | Description |
|
|
604
|
+
|-----------|---------|-------|-------------|
|
|
605
|
+
| `iterations` | 100000 | 10000-1000000 | PBKDF2 iterations |
|
|
606
|
+
| `hashAlgorithm` | SHA-256 | SHA-256/512 | Hash function |
|
|
607
|
+
| `keyLength` | 256 | 128/192/256 | AES key size |
|
|
608
|
+
| `saltLength` | 32 | 16-64 | Salt bytes |
|
|
692
609
|
|
|
693
610
|
---
|
|
694
611
|
|
|
@@ -697,415 +614,524 @@ const restoredDb = await lacerta.getSecureDatabase(
|
|
|
697
614
|
### 🎯 Query Operators
|
|
698
615
|
|
|
699
616
|
#### Comparison Operators
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
| `$
|
|
704
|
-
| `$
|
|
705
|
-
| `$
|
|
706
|
-
| `$
|
|
707
|
-
| `$
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
|
717
|
-
|
|
718
|
-
| `$
|
|
617
|
+
| Operator | Semantic | Example |
|
|
618
|
+
|----------|----------|---------|
|
|
619
|
+
| `$eq` | Equality | `{ status: { $eq: 'active' } }` |
|
|
620
|
+
| `$ne` | Inequality | `{ deleted: { $ne: true } }` |
|
|
621
|
+
| `$gt` | Greater than | `{ score: { $gt: 90 } }` |
|
|
622
|
+
| `$gte` | Greater or equal | `{ age: { $gte: 18 } }` |
|
|
623
|
+
| `$lt` | Less than | `{ price: { $lt: 100 } }` |
|
|
624
|
+
| `$lte` | Less or equal | `{ quantity: { $lte: 10 } }` |
|
|
625
|
+
|
|
626
|
+
#### Set Operations
|
|
627
|
+
| Operator | Semantic | Example |
|
|
628
|
+
|----------|----------|---------|
|
|
629
|
+
| `$in` | Set membership | `{ role: { $in: ['admin', 'mod'] } }` |
|
|
630
|
+
| `$nin` | Set exclusion | `{ status: { $nin: ['deleted'] } }` |
|
|
631
|
+
|
|
632
|
+
#### Array Operations
|
|
633
|
+
| Operator | Semantic | Example |
|
|
634
|
+
|----------|----------|---------|
|
|
635
|
+
| `$all` | Contains all | `{ tags: { $all: ['js', 'ts'] } }` |
|
|
636
|
+
| `$elemMatch` | Element match | `{ scores: { $elemMatch: { $gt: 80 } } }` |
|
|
637
|
+
| `$size` | Array length | `{ items: { $size: 5 } }` |
|
|
719
638
|
|
|
720
639
|
#### Logical Operators
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
| `$
|
|
725
|
-
| `$
|
|
726
|
-
| `$
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
| `$
|
|
748
|
-
| `$group` |
|
|
749
|
-
| `$sort` |
|
|
750
|
-
| `$limit` | Limit
|
|
751
|
-
| `$skip` | Skip
|
|
752
|
-
| `$
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
| `$
|
|
760
|
-
| `$
|
|
761
|
-
| `$
|
|
762
|
-
| `$
|
|
763
|
-
| `$count` | Count documents | `{ total: { $count: {} } }` |
|
|
640
|
+
| Operator | Semantic | Example |
|
|
641
|
+
|----------|----------|---------|
|
|
642
|
+
| `$and` | Conjunction | `{ $and: [{ a: 1 }, { b: 2 }] }` |
|
|
643
|
+
| `$or` | Disjunction | `{ $or: [{ a: 1 }, { b: 2 }] }` |
|
|
644
|
+
| `$not` | Negation | `{ field: { $not: { $eq: 'value' } } }` |
|
|
645
|
+
| `$nor` | Joint denial | `{ $nor: [{ a: 1 }, { b: 2 }] }` |
|
|
646
|
+
|
|
647
|
+
#### Type and Existence
|
|
648
|
+
| Operator | Semantic | Example |
|
|
649
|
+
|----------|----------|---------|
|
|
650
|
+
| `$exists` | Field existence | `{ optional: { $exists: false } }` |
|
|
651
|
+
| `$type` | Type checking | `{ age: { $type: 'number' } }` |
|
|
652
|
+
|
|
653
|
+
#### Pattern Matching
|
|
654
|
+
| Operator | Semantic | Example |
|
|
655
|
+
|----------|----------|---------|
|
|
656
|
+
| `$regex` | Regular expression | `{ email: { $regex: '^[a-z]+@' } }` |
|
|
657
|
+
| `$text` | Text search | `{ content: { $text: 'javascript' } }` |
|
|
658
|
+
|
|
659
|
+
### 📊 Aggregation Pipeline
|
|
660
|
+
|
|
661
|
+
#### Pipeline Stages
|
|
662
|
+
|
|
663
|
+
| Stage | Function | Example |
|
|
664
|
+
|-------|----------|---------|
|
|
665
|
+
| `$match` | Filter documents | `{ $match: { status: 'active' } }` |
|
|
666
|
+
| `$project` | Shape output | `{ $project: { name: 1, age: 1 } }` |
|
|
667
|
+
| `$group` | Aggregate groups | `{ $group: { _id: '$category', total: { $sum: 1 } } }` |
|
|
668
|
+
| `$sort` | Order results | `{ $sort: { createdAt: -1 } }` |
|
|
669
|
+
| `$limit` | Limit count | `{ $limit: 100 }` |
|
|
670
|
+
| `$skip` | Skip documents | `{ $skip: 20 }` |
|
|
671
|
+
| `$lookup` | Join collections | `{ $lookup: { from: 'orders', localField: 'userId', foreignField: '_id', as: 'orders' } }` |
|
|
672
|
+
|
|
673
|
+
#### Accumulator Operators
|
|
674
|
+
|
|
675
|
+
| Operator | Function | Example |
|
|
676
|
+
|----------|----------|---------|
|
|
677
|
+
| `$sum` | Summation | `{ total: { $sum: '$amount' } }` |
|
|
678
|
+
| `$avg` | Average | `{ avgScore: { $avg: '$score' } }` |
|
|
679
|
+
| `$min` | Minimum | `{ lowest: { $min: '$price' } }` |
|
|
680
|
+
| `$max` | Maximum | `{ highest: { $max: '$price' } }` |
|
|
681
|
+
| `$count` | Count | `{ count: { $count: {} } }` |
|
|
764
682
|
|
|
765
683
|
### 💾 Cache Strategies
|
|
766
684
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
|
770
|
-
|
|
771
|
-
| `
|
|
772
|
-
| `
|
|
685
|
+
#### Strategy Architectures
|
|
686
|
+
|
|
687
|
+
| Strategy | Algorithm | Eviction Policy | Configuration |
|
|
688
|
+
|----------|-----------|-----------------|---------------|
|
|
689
|
+
| `lru` | Least Recently Used | Temporal locality | `maxSize`, `ttl` |
|
|
690
|
+
| `lfu` | Least Frequently Used | Access frequency | `maxSize`, `ttl` |
|
|
691
|
+
| `ttl` | Time To Live | Temporal expiry | `ttl` |
|
|
692
|
+
| `none` | No caching | Immediate | - |
|
|
773
693
|
|
|
774
694
|
<details>
|
|
775
|
-
<summary><strong>
|
|
695
|
+
<summary><strong>Cache Strategy Implementation</strong></summary>
|
|
776
696
|
|
|
777
697
|
```javascript
|
|
778
|
-
//
|
|
779
|
-
|
|
698
|
+
// LRU with TTL for balanced performance
|
|
699
|
+
collection.configureCacheStrategy({
|
|
780
700
|
type: 'lru',
|
|
781
|
-
maxSize: 200,
|
|
782
|
-
ttl: 60000,
|
|
701
|
+
maxSize: 200,
|
|
702
|
+
ttl: 60000,
|
|
783
703
|
enabled: true
|
|
784
704
|
});
|
|
785
705
|
|
|
786
|
-
//
|
|
787
|
-
|
|
706
|
+
// LFU for hot data
|
|
707
|
+
hotCollection.configureCacheStrategy({
|
|
788
708
|
type: 'lfu',
|
|
789
709
|
maxSize: 500,
|
|
790
|
-
ttl: 300000
|
|
710
|
+
ttl: 300000
|
|
791
711
|
});
|
|
792
712
|
|
|
793
|
-
// TTL-only for
|
|
794
|
-
|
|
713
|
+
// TTL-only for sessions
|
|
714
|
+
sessionCollection.configureCacheStrategy({
|
|
795
715
|
type: 'ttl',
|
|
796
|
-
ttl: 900000
|
|
797
|
-
});
|
|
798
|
-
|
|
799
|
-
// Disable caching for real-time data
|
|
800
|
-
liveData.configureCacheStrategy({
|
|
801
|
-
type: 'none'
|
|
716
|
+
ttl: 900000
|
|
802
717
|
});
|
|
803
718
|
|
|
804
|
-
//
|
|
805
|
-
|
|
719
|
+
// Memory optimization through lazy initialization
|
|
720
|
+
// Cache is created only when first accessed (getter pattern)
|
|
721
|
+
const strategy = new CacheStrategy({ type: 'lru' });
|
|
722
|
+
// Internal cache instantiated on first get() call
|
|
806
723
|
```
|
|
807
724
|
|
|
808
725
|
</details>
|
|
809
726
|
|
|
810
727
|
---
|
|
811
728
|
|
|
729
|
+
## Architecture Deep Dive
|
|
730
|
+
|
|
731
|
+
### Memory Optimization Patterns
|
|
732
|
+
|
|
733
|
+
Version 0.7.0 implements sophisticated memory management through:
|
|
734
|
+
|
|
735
|
+
1. **Lazy Initialization**: Collections and caches instantiate on first access
|
|
736
|
+
2. **Getter/Setter Patterns**: Document data uses accessors for memory efficiency
|
|
737
|
+
3. **Connection Pooling**: Reuses database connections across operations
|
|
738
|
+
4. **Private Property Convention**: Underscore prefix for encapsulation
|
|
739
|
+
|
|
740
|
+
```javascript
|
|
741
|
+
class Document {
|
|
742
|
+
constructor(data = {}) {
|
|
743
|
+
this._data = null; // Private storage
|
|
744
|
+
// ... other initialization
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// Lazy getter for memory optimization
|
|
748
|
+
get data() {
|
|
749
|
+
return this._data || {};
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
set data(value) {
|
|
753
|
+
this._data = value;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
### Concurrency Control
|
|
759
|
+
|
|
760
|
+
AsyncMutex ensures atomic operations:
|
|
761
|
+
|
|
762
|
+
```javascript
|
|
763
|
+
class AsyncMutex {
|
|
764
|
+
async runExclusive(callback) {
|
|
765
|
+
const release = await this.acquire();
|
|
766
|
+
try {
|
|
767
|
+
return await callback();
|
|
768
|
+
} finally {
|
|
769
|
+
release();
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
### Transaction Resilience
|
|
776
|
+
|
|
777
|
+
Automatic retry mechanisms with exponential backoff:
|
|
778
|
+
|
|
779
|
+
```javascript
|
|
780
|
+
async performTransaction(db, storeNames, mode, callback, retries = 3) {
|
|
781
|
+
for (let i = 0; i < retries; i++) {
|
|
782
|
+
try {
|
|
783
|
+
return await executeTransaction();
|
|
784
|
+
} catch (error) {
|
|
785
|
+
if (i < retries - 1) {
|
|
786
|
+
await new Promise(r => setTimeout(r, (2 ** i) * 100));
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
---
|
|
794
|
+
|
|
812
795
|
## Real-World Examples
|
|
813
796
|
|
|
814
|
-
###
|
|
797
|
+
### 🏥 Healthcare Data Management
|
|
815
798
|
|
|
816
799
|
```javascript
|
|
817
|
-
//
|
|
800
|
+
// HIPAA-compliant patient data storage
|
|
818
801
|
const lacerta = new LacertaDB();
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
await
|
|
827
|
-
await
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
content: 'Check out this photo!',
|
|
835
|
-
timestamp: Date.now(),
|
|
836
|
-
read: false
|
|
837
|
-
}, {
|
|
838
|
-
attachments: [imageFile],
|
|
839
|
-
permanent: false
|
|
802
|
+
const healthDb = await lacerta.getSecureDatabase(
|
|
803
|
+
'patient-records',
|
|
804
|
+
await SecureDatabaseEncryption.generateSecurePIN(12),
|
|
805
|
+
null,
|
|
806
|
+
{ iterations: 500000 } // Enhanced security
|
|
807
|
+
);
|
|
808
|
+
|
|
809
|
+
const patients = await healthDb.createCollection('patients');
|
|
810
|
+
const vitals = await healthDb.createCollection('vitals');
|
|
811
|
+
|
|
812
|
+
// QuickStore for current session
|
|
813
|
+
healthDb.quickStore.add('current_patient', {
|
|
814
|
+
id: 'pat_123',
|
|
815
|
+
name: 'John Doe',
|
|
816
|
+
sessionStart: Date.now()
|
|
840
817
|
});
|
|
841
818
|
|
|
842
|
-
//
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
sort: { timestamp: -1 },
|
|
847
|
-
limit: 20,
|
|
848
|
-
skip: 0
|
|
849
|
-
}
|
|
850
|
-
);
|
|
819
|
+
// Create indexes for efficient queries
|
|
820
|
+
await patients.createIndex('mrn', { unique: true }); // Medical Record Number
|
|
821
|
+
await vitals.createIndex('patientId', { type: 'hash' });
|
|
822
|
+
await vitals.createIndex('timestamp', { type: 'btree' });
|
|
851
823
|
|
|
852
|
-
//
|
|
853
|
-
|
|
854
|
-
|
|
824
|
+
// Store patient with encryption
|
|
825
|
+
await patients.add({
|
|
826
|
+
mrn: 'MRN123456',
|
|
827
|
+
name: 'John Doe',
|
|
828
|
+
dob: '1980-01-15',
|
|
829
|
+
allergies: ['penicillin'],
|
|
830
|
+
conditions: ['hypertension']
|
|
831
|
+
}, { permanent: true });
|
|
832
|
+
|
|
833
|
+
// Record vitals
|
|
834
|
+
await vitals.add({
|
|
835
|
+
patientId: 'pat_123',
|
|
836
|
+
timestamp: Date.now(),
|
|
837
|
+
bloodPressure: { systolic: 120, diastolic: 80 },
|
|
838
|
+
heartRate: 72,
|
|
839
|
+
temperature: 98.6
|
|
855
840
|
});
|
|
856
841
|
|
|
857
|
-
//
|
|
858
|
-
await
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
842
|
+
// Aggregate patient statistics
|
|
843
|
+
const stats = await vitals.aggregate([
|
|
844
|
+
{ $match: { patientId: 'pat_123' } },
|
|
845
|
+
{ $sort: { timestamp: -1 } },
|
|
846
|
+
{ $limit: 100 },
|
|
847
|
+
{ $group: {
|
|
848
|
+
_id: '$patientId',
|
|
849
|
+
avgHeartRate: { $avg: '$heartRate' },
|
|
850
|
+
avgSystolic: { $avg: '$bloodPressure.systolic' },
|
|
851
|
+
readingCount: { $count: {} }
|
|
852
|
+
}}
|
|
853
|
+
]);
|
|
864
854
|
```
|
|
865
855
|
|
|
866
|
-
###
|
|
856
|
+
### 🎮 Real-Time Gaming State
|
|
867
857
|
|
|
868
858
|
```javascript
|
|
869
|
-
//
|
|
870
|
-
const
|
|
871
|
-
const
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
addedAt: Date.now()
|
|
859
|
+
// Game state management with QuickStore
|
|
860
|
+
const gameDb = await lacerta.getDatabase('game-state');
|
|
861
|
+
const quickStore = gameDb.quickStore;
|
|
862
|
+
|
|
863
|
+
// Immediate state updates via QuickStore
|
|
864
|
+
quickStore.add('player_state', {
|
|
865
|
+
position: { x: 100, y: 200, z: 50 },
|
|
866
|
+
health: 100,
|
|
867
|
+
inventory: ['sword', 'potion'],
|
|
868
|
+
score: 5000
|
|
880
869
|
});
|
|
881
870
|
|
|
882
|
-
//
|
|
883
|
-
const
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
total: { $multiply: ['$quantity', '$price'] }
|
|
895
|
-
}
|
|
896
|
-
},
|
|
897
|
-
{ $group: {
|
|
898
|
-
_id: null,
|
|
899
|
-
subtotal: { $sum: '$total' },
|
|
900
|
-
items: { $sum: '$quantity' }
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
]);
|
|
871
|
+
// Persistent game saves
|
|
872
|
+
const saves = await gameDb.createCollection('saves');
|
|
873
|
+
await saves.createIndex('timestamp', { type: 'btree' });
|
|
874
|
+
|
|
875
|
+
async function saveGame() {
|
|
876
|
+
const state = quickStore.get('player_state');
|
|
877
|
+
await saves.add({
|
|
878
|
+
...state,
|
|
879
|
+
savePoint: 'checkpoint_3',
|
|
880
|
+
timestamp: Date.now()
|
|
881
|
+
}, { compressed: true });
|
|
882
|
+
}
|
|
904
883
|
|
|
905
|
-
//
|
|
906
|
-
const
|
|
907
|
-
|
|
908
|
-
{
|
|
909
|
-
).then(oldItems =>
|
|
910
|
-
cart.batchDelete(oldItems.map(item => item._id))
|
|
884
|
+
// Load recent saves
|
|
885
|
+
const recentSaves = await saves.query(
|
|
886
|
+
{ timestamp: { $gte: Date.now() - 86400000 } },
|
|
887
|
+
{ sort: { timestamp: -1 }, limit: 10 }
|
|
911
888
|
);
|
|
912
889
|
```
|
|
913
890
|
|
|
914
|
-
###
|
|
891
|
+
### 📊 Analytics Dashboard
|
|
915
892
|
|
|
916
893
|
```javascript
|
|
917
|
-
//
|
|
918
|
-
const
|
|
919
|
-
const
|
|
920
|
-
|
|
921
|
-
//
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
//
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
894
|
+
// Real-time analytics with caching strategies
|
|
895
|
+
const analyticsDb = await lacerta.getDatabase('analytics');
|
|
896
|
+
const events = await analyticsDb.createCollection('events');
|
|
897
|
+
|
|
898
|
+
// Configure aggressive caching for dashboards
|
|
899
|
+
events.configureCacheStrategy({
|
|
900
|
+
type: 'lfu', // Frequently accessed metrics
|
|
901
|
+
maxSize: 1000,
|
|
902
|
+
ttl: 300000 // 5-minute cache
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
// Create performance indexes
|
|
906
|
+
await events.createIndex('eventType', { type: 'hash' });
|
|
907
|
+
await events.createIndex('timestamp', { type: 'btree' });
|
|
908
|
+
await events.createIndex('userId', { type: 'hash' });
|
|
909
|
+
|
|
910
|
+
// Store events with batch operations
|
|
911
|
+
const eventBatch = Array.from({ length: 1000 }, (_, i) => ({
|
|
912
|
+
eventType: ['click', 'view', 'purchase'][i % 3],
|
|
913
|
+
userId: `user_${i % 100}`,
|
|
914
|
+
timestamp: Date.now() - (i * 1000),
|
|
915
|
+
metadata: { source: 'web', version: '2.0' }
|
|
916
|
+
}));
|
|
917
|
+
|
|
918
|
+
await events.batchAdd(eventBatch, { compressed: true });
|
|
919
|
+
|
|
920
|
+
// Complex analytics aggregation
|
|
921
|
+
const metrics = await events.aggregate([
|
|
922
|
+
{ $match: {
|
|
923
|
+
timestamp: { $gte: Date.now() - 3600000 } // Last hour
|
|
924
|
+
}},
|
|
925
|
+
{ $group: {
|
|
926
|
+
_id: '$eventType',
|
|
927
|
+
count: { $count: {} },
|
|
928
|
+
uniqueUsers: { $addToSet: '$userId' }
|
|
929
|
+
}},
|
|
930
|
+
{ $project: {
|
|
931
|
+
eventType: '$_id',
|
|
932
|
+
count: 1,
|
|
933
|
+
uniqueUserCount: { $size: '$uniqueUsers' }
|
|
934
|
+
}},
|
|
935
|
+
{ $sort: { count: -1 } }
|
|
936
|
+
]);
|
|
937
|
+
|
|
938
|
+
// Store computed metrics in QuickStore for instant access
|
|
939
|
+
analyticsDb.quickStore.add('dashboard_metrics', {
|
|
940
|
+
computed: Date.now(),
|
|
941
|
+
metrics,
|
|
942
|
+
summary: {
|
|
943
|
+
totalEvents: metrics.reduce((sum, m) => sum + m.count, 0),
|
|
944
|
+
eventTypes: metrics.length
|
|
940
945
|
}
|
|
941
|
-
};
|
|
942
|
-
|
|
943
|
-
// Search notes
|
|
944
|
-
const searchNotes = async (query) => {
|
|
945
|
-
return await notes.query({
|
|
946
|
-
$or: [
|
|
947
|
-
{ content: { $text: query } },
|
|
948
|
-
{ title: { $regex: query } },
|
|
949
|
-
{ tags: { $in: [query] } }
|
|
950
|
-
]
|
|
951
|
-
});
|
|
952
|
-
};
|
|
946
|
+
});
|
|
953
947
|
```
|
|
954
948
|
|
|
955
949
|
---
|
|
956
950
|
|
|
957
951
|
## Performance Optimization
|
|
958
952
|
|
|
959
|
-
### 📈 Performance Monitoring
|
|
953
|
+
### 📈 Advanced Performance Monitoring
|
|
960
954
|
|
|
961
955
|
```javascript
|
|
962
|
-
//
|
|
963
|
-
lacerta.performanceMonitor
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
956
|
+
// Initialize comprehensive monitoring
|
|
957
|
+
const monitor = lacerta.performanceMonitor;
|
|
958
|
+
monitor.startMonitoring();
|
|
959
|
+
|
|
960
|
+
// Custom performance tracking
|
|
961
|
+
class PerformanceTracker {
|
|
962
|
+
constructor(monitor) {
|
|
963
|
+
this.monitor = monitor;
|
|
964
|
+
this.thresholds = {
|
|
965
|
+
query: 50, // ms
|
|
966
|
+
write: 100, // ms
|
|
967
|
+
aggregate: 200 // ms
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
async track(operation, type) {
|
|
972
|
+
const start = performance.now();
|
|
973
|
+
try {
|
|
974
|
+
const result = await operation();
|
|
975
|
+
const duration = performance.now() - start;
|
|
976
|
+
|
|
977
|
+
this.monitor.recordOperation(type, duration);
|
|
978
|
+
|
|
979
|
+
if (duration > this.thresholds[type]) {
|
|
980
|
+
console.warn(`Slow ${type}: ${duration}ms`);
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
return result;
|
|
984
|
+
} catch (error) {
|
|
985
|
+
this.monitor.recordOperation(`${type}_error`, 0);
|
|
986
|
+
throw error;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
971
990
|
|
|
972
|
-
|
|
973
|
-
const tips = lacerta.performanceMonitor.getOptimizationTips();
|
|
974
|
-
tips.forEach(tip => console.log('💡', tip));
|
|
991
|
+
const tracker = new PerformanceTracker(monitor);
|
|
975
992
|
|
|
976
|
-
//
|
|
977
|
-
const
|
|
978
|
-
|
|
979
|
-
|
|
993
|
+
// Track operations
|
|
994
|
+
const results = await tracker.track(
|
|
995
|
+
() => users.query({ age: { $gte: 18 } }),
|
|
996
|
+
'query'
|
|
997
|
+
);
|
|
980
998
|
|
|
981
|
-
//
|
|
982
|
-
|
|
999
|
+
// Optimization recommendations
|
|
1000
|
+
const tips = monitor.getOptimizationTips();
|
|
1001
|
+
// Analyzes cache hit rates, latency patterns, memory trends
|
|
983
1002
|
```
|
|
984
1003
|
|
|
985
|
-
### ⚡
|
|
1004
|
+
### ⚡ Optimization Strategies
|
|
986
1005
|
|
|
987
|
-
#### 1. **
|
|
1006
|
+
#### 1. **Index Architecture Selection**
|
|
988
1007
|
```javascript
|
|
989
|
-
//
|
|
990
|
-
await
|
|
991
|
-
await
|
|
1008
|
+
// B-Tree for range queries and sorting
|
|
1009
|
+
await orders.createIndex('createdAt', { type: 'btree' });
|
|
1010
|
+
await products.createIndex('price', { type: 'btree' });
|
|
992
1011
|
|
|
993
|
-
//
|
|
994
|
-
await
|
|
995
|
-
await
|
|
996
|
-
```
|
|
1012
|
+
// Hash for exact matches
|
|
1013
|
+
await users.createIndex('email', { type: 'hash', unique: true });
|
|
1014
|
+
await sessions.createIndex('token', { type: 'hash' });
|
|
997
1015
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
// Enable compression for large documents
|
|
1001
|
-
await logs.add(largeLogData, { compressed: true });
|
|
1016
|
+
// Text index for search
|
|
1017
|
+
await articles.createIndex('content', { type: 'text' });
|
|
1002
1018
|
|
|
1003
|
-
//
|
|
1004
|
-
await
|
|
1019
|
+
// Geo index for spatial queries
|
|
1020
|
+
await stores.createIndex('location', { type: 'geo' });
|
|
1005
1021
|
```
|
|
1006
1022
|
|
|
1007
|
-
####
|
|
1023
|
+
#### 2. **QuickStore vs Collection Strategy**
|
|
1008
1024
|
```javascript
|
|
1009
|
-
//
|
|
1010
|
-
|
|
1025
|
+
// QuickStore for ephemeral, frequently accessed data
|
|
1026
|
+
db.quickStore.add('ui_state', { theme: 'dark', sidebar: true });
|
|
1027
|
+
db.quickStore.add('form_draft', { title: 'Unsaved', content: '...' });
|
|
1011
1028
|
|
|
1012
|
-
//
|
|
1013
|
-
|
|
1014
|
-
await users.add(user); // Slow!
|
|
1015
|
-
}
|
|
1029
|
+
// Collections for persistent, structured data
|
|
1030
|
+
await documents.add({ title: 'Report', content: '...' });
|
|
1016
1031
|
```
|
|
1017
1032
|
|
|
1018
|
-
####
|
|
1033
|
+
#### 3. **Connection Pool Optimization**
|
|
1019
1034
|
```javascript
|
|
1020
|
-
//
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
bufferLimitKB: 40000, // Start cleanup at 40MB
|
|
1024
|
-
freeSpaceEvery: 10000 // Check every 10 seconds
|
|
1025
|
-
});
|
|
1035
|
+
// Connections are automatically pooled and reused
|
|
1036
|
+
const db1 = await lacerta.getDatabase('app'); // New connection
|
|
1037
|
+
const db2 = await lacerta.getDatabase('app'); // Reuses connection
|
|
1026
1038
|
|
|
1027
|
-
//
|
|
1028
|
-
|
|
1039
|
+
// Manual cleanup when necessary
|
|
1040
|
+
connectionPool.releaseConnection('app');
|
|
1029
1041
|
```
|
|
1030
1042
|
|
|
1031
|
-
####
|
|
1043
|
+
#### 4. **Memory-Conscious Patterns**
|
|
1032
1044
|
```javascript
|
|
1033
|
-
// Use projection to
|
|
1034
|
-
const
|
|
1035
|
-
{
|
|
1036
|
-
{
|
|
1045
|
+
// Use projection to minimize memory footprint
|
|
1046
|
+
const summaries = await posts.query(
|
|
1047
|
+
{ published: true },
|
|
1048
|
+
{
|
|
1049
|
+
projection: { title: 1, excerpt: 1 }, // Only needed fields
|
|
1050
|
+
limit: 100
|
|
1051
|
+
}
|
|
1037
1052
|
);
|
|
1038
1053
|
|
|
1039
|
-
//
|
|
1040
|
-
|
|
1041
|
-
|
|
1054
|
+
// Clear caches periodically
|
|
1055
|
+
setInterval(() => {
|
|
1056
|
+
posts.clearCache();
|
|
1057
|
+
}, 300000); // Every 5 minutes
|
|
1058
|
+
|
|
1059
|
+
// Configure appropriate cache sizes
|
|
1060
|
+
posts.configureCacheStrategy({
|
|
1061
|
+
type: 'lru',
|
|
1062
|
+
maxSize: 50 // Limit cache entries
|
|
1063
|
+
});
|
|
1042
1064
|
```
|
|
1043
1065
|
|
|
1044
1066
|
---
|
|
1045
1067
|
|
|
1046
1068
|
## Migration Guide
|
|
1047
1069
|
|
|
1048
|
-
###
|
|
1070
|
+
### Version 0.6.x to 0.7.0
|
|
1071
|
+
|
|
1072
|
+
```javascript
|
|
1073
|
+
// 1. Export existing data
|
|
1074
|
+
const oldDb = await getOldDatabase();
|
|
1075
|
+
const backup = await oldDb.export('json');
|
|
1076
|
+
|
|
1077
|
+
// 2. Initialize new version
|
|
1078
|
+
const newLacerta = new LacertaDB();
|
|
1079
|
+
const newDb = await newLacerta.getDatabase('migrated');
|
|
1080
|
+
|
|
1081
|
+
// 3. Import with QuickStore preservation
|
|
1082
|
+
await newDb.import(backup, 'json');
|
|
1083
|
+
|
|
1084
|
+
// 4. Migrate to QuickStore where appropriate
|
|
1085
|
+
const sessions = await newDb.getCollection('sessions');
|
|
1086
|
+
const allSessions = await sessions.getAll();
|
|
1087
|
+
|
|
1088
|
+
// Move active sessions to QuickStore
|
|
1089
|
+
for (const session of allSessions) {
|
|
1090
|
+
if (session.active) {
|
|
1091
|
+
newDb.quickStore.add(`session_${session.userId}`, session);
|
|
1092
|
+
await sessions.delete(session._id);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
// 5. Update indexes for new architecture
|
|
1097
|
+
const collections = newDb.listCollections();
|
|
1098
|
+
for (const name of collections) {
|
|
1099
|
+
const coll = await newDb.getCollection(name);
|
|
1100
|
+
await coll.verifyIndexes(); // Self-healing verification
|
|
1101
|
+
}
|
|
1102
|
+
```
|
|
1103
|
+
|
|
1104
|
+
### Schema Evolution with Migrations
|
|
1049
1105
|
|
|
1050
1106
|
```javascript
|
|
1051
1107
|
const migrationManager = new MigrationManager(db);
|
|
1052
1108
|
|
|
1053
|
-
//
|
|
1109
|
+
// Migration to add QuickStore references
|
|
1054
1110
|
migrationManager.addMigration({
|
|
1055
|
-
version: '
|
|
1056
|
-
name: 'Add
|
|
1111
|
+
version: '0.7.0',
|
|
1112
|
+
name: 'Add QuickStore support',
|
|
1057
1113
|
up: async (doc) => {
|
|
1058
|
-
if (doc.
|
|
1059
|
-
|
|
1114
|
+
if (doc.sessionId && !doc.quickStoreKey) {
|
|
1115
|
+
// Move session data to QuickStore
|
|
1116
|
+
db.quickStore.add(`session_${doc.sessionId}`, {
|
|
1117
|
+
userId: doc.userId,
|
|
1118
|
+
created: doc._created
|
|
1119
|
+
});
|
|
1120
|
+
return { ...doc, quickStoreKey: `session_${doc.sessionId}` };
|
|
1060
1121
|
}
|
|
1061
1122
|
return null;
|
|
1062
1123
|
},
|
|
1063
1124
|
down: async (doc) => {
|
|
1064
|
-
if (doc.
|
|
1065
|
-
|
|
1125
|
+
if (doc.quickStoreKey) {
|
|
1126
|
+
db.quickStore.delete(doc.quickStoreKey);
|
|
1127
|
+
const { quickStoreKey, ...rest } = doc;
|
|
1066
1128
|
return rest;
|
|
1067
1129
|
}
|
|
1068
1130
|
return null;
|
|
1069
1131
|
}
|
|
1070
1132
|
});
|
|
1071
1133
|
|
|
1072
|
-
|
|
1073
|
-
migrationManager.addMigration({
|
|
1074
|
-
version: '2.1.0',
|
|
1075
|
-
name: 'Add timestamps',
|
|
1076
|
-
up: async (doc) => {
|
|
1077
|
-
if (!doc.updatedAt) {
|
|
1078
|
-
return { ...doc, updatedAt: doc._modified };
|
|
1079
|
-
}
|
|
1080
|
-
return null;
|
|
1081
|
-
}
|
|
1082
|
-
});
|
|
1083
|
-
|
|
1084
|
-
// Run all migrations up to version
|
|
1085
|
-
await migrationManager.runMigrations('2.1.0');
|
|
1086
|
-
|
|
1087
|
-
// Rollback if needed
|
|
1088
|
-
await migrationManager.rollback('1.0.0');
|
|
1089
|
-
```
|
|
1090
|
-
|
|
1091
|
-
### Upgrading from v0.5.x to v0.6.x
|
|
1092
|
-
|
|
1093
|
-
```javascript
|
|
1094
|
-
// Export data from old version
|
|
1095
|
-
const oldDb = await getOldDatabase();
|
|
1096
|
-
const backup = await oldDb.export('json');
|
|
1097
|
-
|
|
1098
|
-
// Import to new version
|
|
1099
|
-
const newLacerta = new LacertaDB();
|
|
1100
|
-
const newDb = await newLacerta.getDatabase('upgraded-db');
|
|
1101
|
-
await newDb.import(backup, 'json');
|
|
1102
|
-
|
|
1103
|
-
// Update indexes for better performance
|
|
1104
|
-
const collections = newDb.listCollections();
|
|
1105
|
-
for (const collName of collections) {
|
|
1106
|
-
const coll = await newDb.getCollection(collName);
|
|
1107
|
-
await coll.verifyIndexes();
|
|
1108
|
-
}
|
|
1134
|
+
await migrationManager.runMigrations('0.7.0');
|
|
1109
1135
|
```
|
|
1110
1136
|
|
|
1111
1137
|
---
|
|
@@ -1114,190 +1140,177 @@ for (const collName of collections) {
|
|
|
1114
1140
|
|
|
1115
1141
|
### Common Issues and Solutions
|
|
1116
1142
|
|
|
1117
|
-
#### 🔴 **
|
|
1143
|
+
#### 🔴 **QuickStore Quota Exceeded**
|
|
1118
1144
|
|
|
1119
|
-
**Problem:**
|
|
1145
|
+
**Problem:** LocalStorage limit reached (5-10MB)
|
|
1120
1146
|
|
|
1121
1147
|
**Solutions:**
|
|
1122
1148
|
```javascript
|
|
1123
|
-
// 1.
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
await collection.add(data, { compressed: true });
|
|
1138
|
-
```
|
|
1139
|
-
|
|
1140
|
-
#### 🔴 **Slow Query Performance**
|
|
1141
|
-
|
|
1142
|
-
**Problem:** Queries taking too long
|
|
1143
|
-
|
|
1144
|
-
**Solutions:**
|
|
1145
|
-
```javascript
|
|
1146
|
-
// 1. Add appropriate indexes
|
|
1147
|
-
await collection.createIndex('fieldName', { type: 'btree' });
|
|
1148
|
-
|
|
1149
|
-
// 2. Use query projection
|
|
1150
|
-
const results = await collection.query(
|
|
1151
|
-
filter,
|
|
1152
|
-
{ projection: { needed: 1, fields: 1 } }
|
|
1153
|
-
);
|
|
1154
|
-
|
|
1155
|
-
// 3. Enable caching
|
|
1156
|
-
collection.configureCacheStrategy({
|
|
1157
|
-
type: 'lru',
|
|
1158
|
-
maxSize: 100
|
|
1159
|
-
});
|
|
1149
|
+
// 1. Monitor QuickStore usage
|
|
1150
|
+
console.log(`QuickStore entries: ${db.quickStore.size}`);
|
|
1151
|
+
|
|
1152
|
+
// 2. Implement rotation policy
|
|
1153
|
+
function rotateQuickStore(maxEntries = 100) {
|
|
1154
|
+
const all = db.quickStore.getAll();
|
|
1155
|
+
if (all.length > maxEntries) {
|
|
1156
|
+
const toDelete = all
|
|
1157
|
+
.sort((a, b) => a._modified - b._modified)
|
|
1158
|
+
.slice(0, all.length - maxEntries);
|
|
1159
|
+
|
|
1160
|
+
toDelete.forEach(doc => db.quickStore.delete(doc._id));
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1160
1163
|
|
|
1161
|
-
//
|
|
1162
|
-
|
|
1164
|
+
// 3. Move to collections for larger data
|
|
1165
|
+
if (data.length > 1000) { // Large dataset
|
|
1166
|
+
await collection.add(data);
|
|
1167
|
+
} else {
|
|
1168
|
+
db.quickStore.add('small_data', data);
|
|
1169
|
+
}
|
|
1163
1170
|
```
|
|
1164
1171
|
|
|
1165
|
-
#### 🔴 **
|
|
1172
|
+
#### 🔴 **Connection Pool Exhaustion**
|
|
1166
1173
|
|
|
1167
|
-
**Problem:**
|
|
1174
|
+
**Problem:** Too many concurrent database operations
|
|
1168
1175
|
|
|
1169
1176
|
**Solutions:**
|
|
1170
1177
|
```javascript
|
|
1171
|
-
// 1.
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1178
|
+
// 1. Use batch operations
|
|
1179
|
+
await users.batchAdd(documents); // Single transaction
|
|
1180
|
+
|
|
1181
|
+
// 2. Implement operation queuing
|
|
1182
|
+
class OperationQueue {
|
|
1183
|
+
constructor(concurrency = 10) {
|
|
1184
|
+
this.queue = [];
|
|
1185
|
+
this.running = 0;
|
|
1186
|
+
this.concurrency = concurrency;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
async add(operation) {
|
|
1190
|
+
if (this.running >= this.concurrency) {
|
|
1191
|
+
await new Promise(resolve => this.queue.push(resolve));
|
|
1192
|
+
}
|
|
1193
|
+
this.running++;
|
|
1194
|
+
try {
|
|
1195
|
+
return await operation();
|
|
1196
|
+
} finally {
|
|
1197
|
+
this.running--;
|
|
1198
|
+
if (this.queue.length > 0) {
|
|
1199
|
+
this.queue.shift()();
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1175
1203
|
}
|
|
1176
|
-
|
|
1177
|
-
// 2. Use destroy method
|
|
1178
|
-
window.addEventListener('beforeunload', () => {
|
|
1179
|
-
lacerta.destroy();
|
|
1180
|
-
});
|
|
1181
|
-
|
|
1182
|
-
// 3. Clear caches periodically
|
|
1183
|
-
setInterval(() => {
|
|
1184
|
-
collection.clearCache();
|
|
1185
|
-
}, 300000); // Every 5 minutes
|
|
1186
1204
|
```
|
|
1187
1205
|
|
|
1188
|
-
#### 🔴 **
|
|
1206
|
+
#### 🔴 **Memory Leaks with Private Properties**
|
|
1189
1207
|
|
|
1190
|
-
**Problem:**
|
|
1208
|
+
**Problem:** References to private properties preventing garbage collection
|
|
1191
1209
|
|
|
1192
1210
|
**Solutions:**
|
|
1193
1211
|
```javascript
|
|
1194
|
-
// 1.
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1212
|
+
// 1. Proper cleanup in destroy methods
|
|
1213
|
+
class Collection {
|
|
1214
|
+
destroy() {
|
|
1215
|
+
clearInterval(this._cleanupInterval);
|
|
1216
|
+
this._events.clear();
|
|
1217
|
+
this._cacheStrategy = null;
|
|
1218
|
+
this._indexManager = null;
|
|
1219
|
+
// Release connection
|
|
1220
|
+
if (this._db) {
|
|
1221
|
+
connectionPool.releaseConnection(this.database.name);
|
|
1222
|
+
}
|
|
1200
1223
|
}
|
|
1201
1224
|
}
|
|
1202
1225
|
|
|
1203
|
-
// 2.
|
|
1204
|
-
const
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
// 3. Use same encryption config
|
|
1208
|
-
const db = await lacerta.getSecureDatabase('app', pin, salt, {
|
|
1209
|
-
iterations: 100000, // Must match original
|
|
1210
|
-
keyLength: 256
|
|
1211
|
-
});
|
|
1212
|
-
```
|
|
1213
|
-
|
|
1214
|
-
### Debug Mode
|
|
1215
|
-
|
|
1216
|
-
```javascript
|
|
1217
|
-
// Enable debug logging
|
|
1218
|
-
window.LACERTA_DEBUG = true;
|
|
1219
|
-
|
|
1220
|
-
// Log all operations
|
|
1221
|
-
const originalAdd = collection.add;
|
|
1222
|
-
collection.add = async function(...args) {
|
|
1223
|
-
console.log('Adding document:', args);
|
|
1224
|
-
const result = await originalAdd.apply(this, args);
|
|
1225
|
-
console.log('Document added:', result);
|
|
1226
|
-
return result;
|
|
1227
|
-
};
|
|
1226
|
+
// 2. WeakMap for external references
|
|
1227
|
+
const privateData = new WeakMap();
|
|
1228
|
+
privateData.set(instance, { sensitive: 'data' });
|
|
1228
1229
|
```
|
|
1229
1230
|
|
|
1230
1231
|
---
|
|
1231
1232
|
|
|
1232
1233
|
## Error Handling
|
|
1233
1234
|
|
|
1234
|
-
### Error
|
|
1235
|
-
|
|
1236
|
-
| Error Code |
|
|
1237
|
-
|
|
1238
|
-
| `DATABASE_OPEN_FAILED` |
|
|
1239
|
-
| `DOCUMENT_NOT_FOUND` |
|
|
1240
|
-
| `COLLECTION_NOT_FOUND` |
|
|
1241
|
-
| `COLLECTION_EXISTS` |
|
|
1242
|
-
| `UNIQUE_CONSTRAINT` |
|
|
1243
|
-
| `QUOTA_EXCEEDED` | Storage
|
|
1244
|
-
| `ENCRYPTION_NOT_INITIALIZED` |
|
|
1245
|
-
| `ENCRYPTION_FAILED` |
|
|
1246
|
-
| `PERMANENT_DOCUMENT_PROTECTION` |
|
|
1247
|
-
| `TRANSACTION_FAILED` | Transaction
|
|
1248
|
-
| `
|
|
1235
|
+
### Comprehensive Error Taxonomy
|
|
1236
|
+
|
|
1237
|
+
| Error Code | Semantic Context | Resolution Strategy |
|
|
1238
|
+
|------------|------------------|---------------------|
|
|
1239
|
+
| `DATABASE_OPEN_FAILED` | IndexedDB initialization failure | Verify browser compatibility, clear data |
|
|
1240
|
+
| `DOCUMENT_NOT_FOUND` | Non-existent document reference | Validate document existence |
|
|
1241
|
+
| `COLLECTION_NOT_FOUND` | Undefined collection | Initialize collection first |
|
|
1242
|
+
| `COLLECTION_EXISTS` | Duplicate collection | Use getCollection() |
|
|
1243
|
+
| `UNIQUE_CONSTRAINT` | Index uniqueness violation | Modify value or update |
|
|
1244
|
+
| `QUOTA_EXCEEDED` | Storage capacity exceeded | Implement cleanup strategy |
|
|
1245
|
+
| `ENCRYPTION_NOT_INITIALIZED` | Missing encryption context | Use getSecureDatabase() |
|
|
1246
|
+
| `ENCRYPTION_FAILED` | Cryptographic operation failure | Verify credentials |
|
|
1247
|
+
| `PERMANENT_DOCUMENT_PROTECTION` | Protected document deletion | Apply force option |
|
|
1248
|
+
| `TRANSACTION_FAILED` | Transaction abort | Retry with backoff |
|
|
1249
|
+
| `QUICKSTORE_QUOTA_EXCEEDED` | LocalStorage limit | Rotate QuickStore data |
|
|
1249
1250
|
|
|
1250
1251
|
<details>
|
|
1251
|
-
<summary><strong>
|
|
1252
|
+
<summary><strong>Error Handling Patterns</strong></summary>
|
|
1252
1253
|
|
|
1253
1254
|
```javascript
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
case 'QUOTA_EXCEEDED':
|
|
1267
|
-
console.warn('Storage full, cleaning up...');
|
|
1268
|
-
await this.cleanup();
|
|
1269
|
-
// Retry operation
|
|
1255
|
+
class ResilientDatabaseService {
|
|
1256
|
+
constructor(lacerta) {
|
|
1257
|
+
this.lacerta = lacerta;
|
|
1258
|
+
this.mutex = new AsyncMutex();
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
async executeWithRetry(operation, maxRetries = 3) {
|
|
1262
|
+
return this.mutex.runExclusive(async () => {
|
|
1263
|
+
let lastError;
|
|
1264
|
+
|
|
1265
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
1266
|
+
try {
|
|
1270
1267
|
return await operation();
|
|
1268
|
+
} catch (error) {
|
|
1269
|
+
lastError = error;
|
|
1271
1270
|
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1271
|
+
// Categorize and handle errors
|
|
1272
|
+
switch (error.code) {
|
|
1273
|
+
case 'QUOTA_EXCEEDED':
|
|
1274
|
+
await this.handleQuotaExceeded();
|
|
1275
|
+
break;
|
|
1276
|
+
|
|
1277
|
+
case 'TRANSACTION_FAILED':
|
|
1278
|
+
await this.delay((2 ** attempt) * 100);
|
|
1279
|
+
break;
|
|
1280
|
+
|
|
1281
|
+
case 'ENCRYPTION_FAILED':
|
|
1282
|
+
throw new Error('Authentication required');
|
|
1283
|
+
|
|
1284
|
+
default:
|
|
1285
|
+
if (attempt === maxRetries - 1) throw error;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1283
1288
|
}
|
|
1289
|
+
|
|
1290
|
+
throw lastError;
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
async handleQuotaExceeded() {
|
|
1295
|
+
// Clear QuickStore
|
|
1296
|
+
const db = await this.lacerta.getDatabase('app');
|
|
1297
|
+
db.quickStore.clear();
|
|
1298
|
+
|
|
1299
|
+
// Clear old collection data
|
|
1300
|
+
const collections = db.listCollections();
|
|
1301
|
+
for (const name of collections) {
|
|
1302
|
+
const coll = await db.getCollection(name);
|
|
1303
|
+
const oldDocs = await coll.query({
|
|
1304
|
+
_modified: { $lt: Date.now() - 86400000 }
|
|
1305
|
+
});
|
|
1306
|
+
await coll.batchDelete(oldDocs.map(d => d._id));
|
|
1284
1307
|
}
|
|
1285
1308
|
}
|
|
1286
1309
|
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
const oldLogs = await logs.query({
|
|
1290
|
-
timestamp: { $lt: Date.now() - 86400000 }
|
|
1291
|
-
});
|
|
1292
|
-
await logs.batchDelete(oldLogs.map(log => log._id));
|
|
1310
|
+
delay(ms) {
|
|
1311
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
1293
1312
|
}
|
|
1294
1313
|
}
|
|
1295
|
-
|
|
1296
|
-
// Usage
|
|
1297
|
-
const service = new DatabaseService();
|
|
1298
|
-
const result = await service.safeOperation(async () => {
|
|
1299
|
-
return await users.add({ email: 'test@example.com' });
|
|
1300
|
-
});
|
|
1301
1314
|
```
|
|
1302
1315
|
|
|
1303
1316
|
</details>
|
|
@@ -1306,59 +1319,74 @@ const result = await service.safeOperation(async () => {
|
|
|
1306
1319
|
|
|
1307
1320
|
## Comparison
|
|
1308
1321
|
|
|
1309
|
-
### LacertaDB vs Alternatives
|
|
1310
|
-
|
|
1311
|
-
| Feature | LacertaDB | LocalStorage | IndexedDB
|
|
1312
|
-
|
|
1313
|
-
| **
|
|
1314
|
-
| **
|
|
1315
|
-
| **
|
|
1316
|
-
| **
|
|
1317
|
-
| **
|
|
1318
|
-
| **
|
|
1319
|
-
| **
|
|
1320
|
-
| **
|
|
1321
|
-
| **
|
|
1322
|
-
| **
|
|
1323
|
-
| **
|
|
1324
|
-
|
|
1325
|
-
*
|
|
1326
|
-
|
|
1327
|
-
###
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
-
|
|
1331
|
-
-
|
|
1332
|
-
-
|
|
1333
|
-
-
|
|
1334
|
-
-
|
|
1335
|
-
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
-
|
|
1339
|
-
-
|
|
1340
|
-
-
|
|
1341
|
-
-
|
|
1322
|
+
### LacertaDB v0.7.0 vs Alternatives
|
|
1323
|
+
|
|
1324
|
+
| Feature | LacertaDB 0.7 | LocalStorage | IndexedDB | PouchDB | Dexie.js | LokiJS |
|
|
1325
|
+
|---------|---------------|--------------|-----------|---------|----------|---------|
|
|
1326
|
+
| **Storage Limit** | ~2GB + 10MB* | 5-10MB | ~2GB | ~2GB | ~2GB | Memory/5MB |
|
|
1327
|
+
| **QuickStore** | ✅ Built-in | ≈ | ❌ | ❌ | ❌ | ❌ |
|
|
1328
|
+
| **Encryption** | ✅ AES-GCM | ❌ | ❌ | ⚠️ Plugin | ❌ | ❌ |
|
|
1329
|
+
| **Compression** | ✅ Native | ❌ | ❌ | ❌ | ❌ | ❌ |
|
|
1330
|
+
| **Connection Pool** | ✅ | N/A | ❌ | ❌ | ❌ | ❌ |
|
|
1331
|
+
| **Query Language** | ✅ MongoDB | ❌ | ❌ | ✅ MapReduce | ⚠️ Limited | ✅ |
|
|
1332
|
+
| **Indexes** | ✅ 4 types | ❌ | ⚠️ Basic | ✅ | ✅ | ✅ |
|
|
1333
|
+
| **Aggregation** | ✅ Pipeline | ❌ | ❌ | ⚠️ Views | ❌ | ⚠️ |
|
|
1334
|
+
| **Self-Healing** | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
|
1335
|
+
| **Bundle Size** | ~48KB | 0KB | 0KB | ~140KB | ~90KB | ~70KB |
|
|
1336
|
+
| **Concurrency** | ✅ Mutex | ❌ | ⚠️ | ⚠️ | ⚠️ | ❌ |
|
|
1337
|
+
|
|
1338
|
+
*IndexedDB (2GB) + QuickStore LocalStorage (10MB)
|
|
1339
|
+
|
|
1340
|
+
### Architectural Selection Criteria
|
|
1341
|
+
|
|
1342
|
+
**Deploy LacertaDB when requiring:**
|
|
1343
|
+
- Dual-layer storage (persistent + ephemeral)
|
|
1344
|
+
- Zero-knowledge client-side encryption
|
|
1345
|
+
- Self-healing index structures
|
|
1346
|
+
- Connection pooling for scalability
|
|
1347
|
+
- MongoDB-compatible query semantics
|
|
1348
|
+
- Integrated performance telemetry
|
|
1349
|
+
|
|
1350
|
+
**Consider alternatives for:**
|
|
1351
|
+
- Minimal storage needs (< 1MB): LocalStorage
|
|
1352
|
+
- Server synchronization priority: PouchDB/CouchDB
|
|
1353
|
+
- Memory-only operations: LokiJS
|
|
1354
|
+
- Simple key-value patterns: LocalStorage/SessionStorage
|
|
1342
1355
|
|
|
1343
1356
|
---
|
|
1344
1357
|
|
|
1345
|
-
##
|
|
1346
|
-
|
|
1347
|
-
|
|
1358
|
+
## Changelog
|
|
1359
|
+
|
|
1360
|
+
### Version 0.7.0 (Latest)
|
|
1361
|
+
- **Added:** QuickStore for localStorage-based ephemeral caching
|
|
1362
|
+
- **Added:** Connection pooling for optimized resource management
|
|
1363
|
+
- **Added:** AsyncMutex for concurrent operation synchronization
|
|
1364
|
+
- **Improved:** Private property conventions with underscore prefix
|
|
1365
|
+
- **Improved:** Memory optimization through lazy initialization
|
|
1366
|
+
- **Improved:** Self-healing B-Tree indexes with automatic verification
|
|
1367
|
+
- **Enhanced:** Export/import includes QuickStore data
|
|
1368
|
+
- **Fixed:** Connection leaks in collection destruction
|
|
1369
|
+
- **Fixed:** Memory optimization in Document class
|
|
1370
|
+
|
|
1371
|
+
### Version 0.6.2
|
|
1372
|
+
- Database-level encryption
|
|
1373
|
+
- Compression support
|
|
1374
|
+
- Multiple index types
|
|
1375
|
+
- Aggregation pipeline
|
|
1376
|
+
- Performance monitoring
|
|
1348
1377
|
|
|
1349
1378
|
---
|
|
1350
1379
|
|
|
1351
|
-
##
|
|
1380
|
+
## Contributing
|
|
1352
1381
|
|
|
1353
|
-
|
|
1382
|
+
LacertaDB embraces collaborative development. Contribution vectors include:
|
|
1354
1383
|
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1384
|
+
1. **Architecture Enhancement**: Propose algorithmic improvements
|
|
1385
|
+
2. **Index Strategies**: Implement novel index structures
|
|
1386
|
+
3. **Performance Optimization**: Profile and optimize critical paths
|
|
1387
|
+
4. **Documentation**: Expand architectural documentation
|
|
1388
|
+
5. **Test Coverage**: Strengthen test suites
|
|
1358
1389
|
|
|
1359
|
-
|
|
1360
|
-
---
|
|
1390
|
+
## 📝 License
|
|
1361
1391
|
|
|
1362
|
-
|
|
1363
|
-
<strong>Star ⭐ this repository if you find it helpful!</strong>
|
|
1364
|
-
</p>
|
|
1392
|
+
MIT © 2024 LacertaDB Contributors
|