@pixagram/lacerta-db 0.3.0 → 0.5.0
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 +6 -5
- package/dist/index.min.js +6 -5
- package/index.js +1544 -88
- package/legacy.js +1901 -0
- package/package.json +9 -5
- package/readme.md +1168 -130
package/readme.md
CHANGED
|
@@ -1,207 +1,1245 @@
|
|
|
1
|
-
LacertaDB
|
|
2
|
-
LacertaDB
|
|
1
|
+
# LacertaDB
|
|
2
|
+

|
|
3
|
+
|
|
4
|
+
> 🦎 **LacertaDB v4.0.3** - A powerful, feature-rich browser-based document database with encryption, compression, and advanced querying capabilities.
|
|
5
|
+
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[]()
|
|
8
|
+
[]()
|
|
9
|
+
|
|
10
|
+
## 📚 Table of Contents
|
|
11
|
+
|
|
12
|
+
- [✨ Features](#-features)
|
|
13
|
+
- [🚀 Quick Start](#-quick-start)
|
|
14
|
+
- [📦 Installation](#-installation)
|
|
15
|
+
- [🎯 Basic Usage](#-basic-usage)
|
|
16
|
+
- [🔧 Core Concepts](#-core-concepts)
|
|
17
|
+
- [Database](#database)
|
|
18
|
+
- [Collections](#collections)
|
|
19
|
+
- [Documents](#documents)
|
|
20
|
+
- [🔍 Querying](#-querying)
|
|
21
|
+
- [Basic Queries](#basic-queries)
|
|
22
|
+
- [Advanced Queries](#advanced-queries)
|
|
23
|
+
- [Aggregation Pipeline](#aggregation-pipeline)
|
|
24
|
+
- [🔐 Security Features](#-security-features)
|
|
25
|
+
- [Encryption](#encryption)
|
|
26
|
+
- [Password Protection](#password-protection)
|
|
27
|
+
- [📎 Attachments](#-attachments)
|
|
28
|
+
- [⚡ Performance](#-performance)
|
|
29
|
+
- [Compression](#compression)
|
|
30
|
+
- [Performance Monitoring](#performance-monitoring)
|
|
31
|
+
- [Query Caching](#query-caching)
|
|
32
|
+
- [🔄 Data Migration](#-data-migration)
|
|
33
|
+
- [💾 Backup & Restore](#-backup--restore)
|
|
34
|
+
- [🛠️ Advanced Features](#️-advanced-features)
|
|
35
|
+
- [Batch Operations](#batch-operations)
|
|
36
|
+
- [Event System](#event-system)
|
|
37
|
+
- [Quick Store](#quick-store)
|
|
38
|
+
- [📊 Storage Management](#-storage-management)
|
|
39
|
+
- [🎨 API Reference](#-api-reference)
|
|
40
|
+
- [💡 Examples](#-examples)
|
|
41
|
+
- [🐛 Error Handling](#-error-handling)
|
|
42
|
+
- [📝 Best Practices](#-best-practices)
|
|
43
|
+
- [🤝 Contributing](#-contributing)
|
|
44
|
+
|
|
45
|
+
## ✨ Features
|
|
46
|
+
|
|
47
|
+
🎯 **Core Features**
|
|
48
|
+
- 📁 **Document-based storage** using IndexedDB
|
|
49
|
+
- 🔍 **MongoDB-like query syntax** for familiar operations
|
|
50
|
+
- 🔐 **AES-256-GCM encryption** with PBKDF2 key derivation
|
|
51
|
+
- 🗜️ **Built-in compression** using CompressionStream API
|
|
52
|
+
- 📎 **File attachments** via Origin Private File System (OPFS)
|
|
53
|
+
- ⚡ **High performance** with async operations and caching
|
|
54
|
+
|
|
55
|
+
🚀 **Advanced Capabilities**
|
|
56
|
+
- 📊 **Aggregation pipeline** for complex data processing
|
|
57
|
+
- 🔄 **Schema migration system** for version management
|
|
58
|
+
- 📈 **Performance monitoring** with real-time metrics
|
|
59
|
+
- 🎭 **Event-driven architecture** with hooks
|
|
60
|
+
- 💾 **Import/Export functionality** with encryption support
|
|
61
|
+
- 🔧 **Batch operations** for efficient bulk processing
|
|
62
|
+
|
|
63
|
+
## 🚀 Quick Start
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
import { LacertaDB } from './lacertadb.js';
|
|
67
|
+
|
|
68
|
+
// Initialize LacertaDB
|
|
69
|
+
const lacerta = new LacertaDB();
|
|
70
|
+
|
|
71
|
+
// Get or create a database
|
|
72
|
+
const db = await lacerta.getDatabase('myApp');
|
|
73
|
+
|
|
74
|
+
// Create a collection
|
|
75
|
+
const users = await db.createCollection('users');
|
|
76
|
+
|
|
77
|
+
// Add a document
|
|
78
|
+
const userId = await users.add({
|
|
79
|
+
name: 'Alice Johnson',
|
|
80
|
+
email: 'alice@example.com',
|
|
81
|
+
age: 28,
|
|
82
|
+
tags: ['developer', 'javascript']
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Query documents
|
|
86
|
+
const results = await users.query({
|
|
87
|
+
age: { $gte: 25 },
|
|
88
|
+
tags: { $in: ['developer'] }
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
console.log('Found users:', results);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 📦 Installation
|
|
95
|
+
|
|
96
|
+
### NPM/Yarn Installation
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npm install @pixagram/lacertadb
|
|
100
|
+
# or
|
|
101
|
+
yarn add @pixagram/lacertadb
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Browser Module
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<script type="module">
|
|
108
|
+
import { LacertaDB } from './lacertadb.js';
|
|
109
|
+
const lacerta = new LacertaDB();
|
|
110
|
+
</script>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Dependencies
|
|
114
|
+
|
|
115
|
+
LacertaDB requires:
|
|
116
|
+
- `@pixagram/turboserial` - High-performance serialization
|
|
117
|
+
- `@pixagram/turbobase64` - Optimized Base64 encoding
|
|
118
|
+
|
|
119
|
+
## 🎯 Basic Usage
|
|
120
|
+
|
|
121
|
+
### Creating a Database and Collection
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
const lacerta = new LacertaDB();
|
|
125
|
+
|
|
126
|
+
// Create or get a database
|
|
127
|
+
const db = await lacerta.getDatabase('myDatabase');
|
|
128
|
+
|
|
129
|
+
// Create a collection with options
|
|
130
|
+
const products = await db.createCollection('products', {
|
|
131
|
+
compressed: true, // Enable compression by default
|
|
132
|
+
encrypted: false // Encryption disabled by default
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Adding Documents
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
// Simple document
|
|
140
|
+
await products.add({
|
|
141
|
+
name: 'Laptop',
|
|
142
|
+
price: 999.99,
|
|
143
|
+
inStock: true
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Document with options
|
|
147
|
+
await products.add(
|
|
148
|
+
{
|
|
149
|
+
name: 'Secure Document',
|
|
150
|
+
data: 'sensitive information'
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
id: 'custom-id-123', // Custom ID
|
|
154
|
+
encrypted: true, // Encrypt this document
|
|
155
|
+
password: 'secretPassword', // Encryption password
|
|
156
|
+
compressed: true, // Compress the document
|
|
157
|
+
permanent: true // Mark as permanent (won't be auto-deleted)
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
```
|
|
3
161
|
|
|
4
|
-
|
|
162
|
+
### Retrieving Documents
|
|
5
163
|
|
|
6
|
-
|
|
7
|
-
|
|
164
|
+
```javascript
|
|
165
|
+
// Get by ID
|
|
166
|
+
const product = await products.get('custom-id-123', {
|
|
167
|
+
password: 'secretPassword' // Required for encrypted documents
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Get all documents
|
|
171
|
+
const allProducts = await products.getAll();
|
|
8
172
|
|
|
9
|
-
|
|
173
|
+
// Get with attachments
|
|
174
|
+
const withFiles = await products.get('doc-id', {
|
|
175
|
+
includeAttachments: true
|
|
176
|
+
});
|
|
177
|
+
```
|
|
10
178
|
|
|
11
|
-
|
|
179
|
+
## 🔧 Core Concepts
|
|
12
180
|
|
|
13
|
-
|
|
181
|
+
### Database
|
|
14
182
|
|
|
15
|
-
|
|
183
|
+
The database is the top-level container for your collections.
|
|
16
184
|
|
|
17
|
-
|
|
185
|
+
```javascript
|
|
186
|
+
// Get existing or create new database
|
|
187
|
+
const db = await lacerta.getDatabase('appDB');
|
|
18
188
|
|
|
19
|
-
|
|
189
|
+
// List all collections
|
|
190
|
+
const collections = db.listCollections();
|
|
20
191
|
|
|
21
|
-
|
|
192
|
+
// Get database statistics
|
|
193
|
+
const stats = db.getStats();
|
|
194
|
+
console.log(`Total size: ${stats.totalSizeKB} KB`);
|
|
195
|
+
console.log(`Total documents: ${stats.totalDocuments}`);
|
|
22
196
|
|
|
23
|
-
|
|
197
|
+
// Configure database settings
|
|
198
|
+
db.updateSettings({
|
|
199
|
+
sizeLimitKB: 50000, // 50MB limit
|
|
200
|
+
bufferLimitKB: 40000, // Start cleanup at 40MB
|
|
201
|
+
freeSpaceEvery: 60000 // Run cleanup every minute
|
|
202
|
+
});
|
|
203
|
+
```
|
|
24
204
|
|
|
25
|
-
|
|
26
|
-
Install the package using your favorite package manager.
|
|
205
|
+
### Collections
|
|
27
206
|
|
|
28
|
-
|
|
207
|
+
Collections are containers for documents of similar type.
|
|
29
208
|
|
|
30
|
-
|
|
31
|
-
|
|
209
|
+
```javascript
|
|
210
|
+
// Create collection
|
|
211
|
+
const posts = await db.createCollection('posts');
|
|
32
212
|
|
|
33
|
-
//
|
|
34
|
-
|
|
213
|
+
// Get existing collection
|
|
214
|
+
const existingPosts = await db.getCollection('posts');
|
|
35
215
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const db = await LacertaDB.getDatabase('my-app-db');
|
|
216
|
+
// Collection operations
|
|
217
|
+
await posts.clear(); // Remove all documents
|
|
218
|
+
await db.dropCollection('posts'); // Delete collection entirely
|
|
40
219
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
220
|
+
// Collection events
|
|
221
|
+
posts.on('afterAdd', (doc) => {
|
|
222
|
+
console.log('Document added:', doc._id);
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Documents
|
|
227
|
+
|
|
228
|
+
Documents are JavaScript objects with automatic metadata.
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
// Document structure
|
|
232
|
+
const doc = {
|
|
233
|
+
// User data
|
|
234
|
+
title: 'My Post',
|
|
235
|
+
content: 'Lorem ipsum...',
|
|
236
|
+
|
|
237
|
+
// Automatic metadata (added by LacertaDB)
|
|
238
|
+
_id: 'doc_1234567890_abc', // Auto-generated unique ID
|
|
239
|
+
_created: 1704067200000, // Creation timestamp
|
|
240
|
+
_modified: 1704067200000, // Last modification timestamp
|
|
241
|
+
_permanent: false, // Deletion protection flag
|
|
242
|
+
};
|
|
243
|
+
```
|
|
44
244
|
|
|
45
|
-
|
|
46
|
-
const newUserId = await users.add({
|
|
47
|
-
name: 'Alex',
|
|
48
|
-
level: 10,
|
|
49
|
-
joined: new Date()
|
|
50
|
-
});
|
|
51
|
-
console.log(`User created with ID: ${newUserId}`);
|
|
245
|
+
## 🔍 Querying
|
|
52
246
|
|
|
53
|
-
|
|
54
|
-
const user = await users.get(newUserId);
|
|
55
|
-
console.log('Retrieved user:', user);
|
|
247
|
+
### Basic Queries
|
|
56
248
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
249
|
+
```javascript
|
|
250
|
+
// Find all documents matching criteria
|
|
251
|
+
const results = await users.query({
|
|
252
|
+
age: 30, // Exact match
|
|
253
|
+
'address.city': 'New York' // Nested field
|
|
254
|
+
});
|
|
60
255
|
|
|
61
|
-
|
|
62
|
-
|
|
256
|
+
// With options
|
|
257
|
+
const paginatedResults = await users.query(
|
|
258
|
+
{ status: 'active' },
|
|
259
|
+
{
|
|
260
|
+
sort: { createdAt: -1 }, // Sort descending
|
|
261
|
+
skip: 10, // Skip first 10
|
|
262
|
+
limit: 20, // Limit to 20 results
|
|
263
|
+
projection: { // Select fields
|
|
264
|
+
name: 1,
|
|
265
|
+
email: 1,
|
|
266
|
+
_id: 0
|
|
267
|
+
}
|
|
63
268
|
}
|
|
64
|
-
|
|
269
|
+
);
|
|
270
|
+
```
|
|
65
271
|
|
|
66
|
-
|
|
272
|
+
### Advanced Queries
|
|
67
273
|
|
|
68
|
-
|
|
69
|
-
Database
|
|
70
|
-
The Database object is your main entry point for managing collections.
|
|
274
|
+
LacertaDB supports MongoDB-style query operators:
|
|
71
275
|
|
|
72
|
-
|
|
73
|
-
Retrieves a database instance. If it doesn't exist, it's created.
|
|
276
|
+
#### Comparison Operators
|
|
74
277
|
|
|
75
|
-
|
|
278
|
+
```javascript
|
|
279
|
+
// $eq, $ne, $gt, $gte, $lt, $lte
|
|
280
|
+
await products.query({
|
|
281
|
+
price: { $gte: 100, $lte: 500 }
|
|
282
|
+
});
|
|
76
283
|
|
|
77
|
-
|
|
78
|
-
|
|
284
|
+
// $in, $nin
|
|
285
|
+
await users.query({
|
|
286
|
+
role: { $in: ['admin', 'moderator'] }
|
|
287
|
+
});
|
|
288
|
+
```
|
|
79
289
|
|
|
80
|
-
|
|
290
|
+
#### Logical Operators
|
|
81
291
|
|
|
82
|
-
|
|
83
|
-
|
|
292
|
+
```javascript
|
|
293
|
+
// $and
|
|
294
|
+
await products.query({
|
|
295
|
+
$and: [
|
|
296
|
+
{ price: { $lt: 1000 } },
|
|
297
|
+
{ category: 'electronics' }
|
|
298
|
+
]
|
|
299
|
+
});
|
|
84
300
|
|
|
85
|
-
|
|
301
|
+
// $or
|
|
302
|
+
await users.query({
|
|
303
|
+
$or: [
|
|
304
|
+
{ age: { $gte: 65 } },
|
|
305
|
+
{ status: 'premium' }
|
|
306
|
+
]
|
|
307
|
+
});
|
|
86
308
|
|
|
87
|
-
|
|
88
|
-
|
|
309
|
+
// $not
|
|
310
|
+
await products.query({
|
|
311
|
+
discontinued: { $not: { $eq: true } }
|
|
312
|
+
});
|
|
313
|
+
```
|
|
89
314
|
|
|
90
|
-
|
|
91
|
-
Adds a new document to the collection.
|
|
315
|
+
#### Array Operators
|
|
92
316
|
|
|
93
|
-
|
|
317
|
+
```javascript
|
|
318
|
+
// $all - Array contains all values
|
|
319
|
+
await posts.query({
|
|
320
|
+
tags: { $all: ['javascript', 'database'] }
|
|
321
|
+
});
|
|
94
322
|
|
|
95
|
-
|
|
323
|
+
// $elemMatch - Element matching
|
|
324
|
+
await orders.query({
|
|
325
|
+
items: {
|
|
326
|
+
$elemMatch: {
|
|
327
|
+
product: 'laptop',
|
|
328
|
+
quantity: { $gte: 2 }
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
});
|
|
96
332
|
|
|
97
|
-
|
|
333
|
+
// $size - Array length
|
|
334
|
+
await users.query({
|
|
335
|
+
hobbies: { $size: 3 }
|
|
336
|
+
});
|
|
337
|
+
```
|
|
98
338
|
|
|
99
|
-
|
|
339
|
+
#### Text Search
|
|
100
340
|
|
|
101
|
-
|
|
341
|
+
```javascript
|
|
342
|
+
// $regex - Regular expression
|
|
343
|
+
await users.query({
|
|
344
|
+
email: { $regex: '@company\\.com$' }
|
|
345
|
+
});
|
|
102
346
|
|
|
103
|
-
|
|
347
|
+
// $text - Case-insensitive text search
|
|
348
|
+
await posts.query({
|
|
349
|
+
content: { $text: 'javascript' }
|
|
350
|
+
});
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Aggregation Pipeline
|
|
354
|
+
|
|
355
|
+
Powerful data processing with aggregation stages:
|
|
356
|
+
|
|
357
|
+
```javascript
|
|
358
|
+
// Sales analysis pipeline
|
|
359
|
+
const salesReport = await orders.aggregate([
|
|
360
|
+
// Stage 1: Filter orders
|
|
361
|
+
{ $match: { status: 'completed' } },
|
|
362
|
+
|
|
363
|
+
// Stage 2: Group by customer
|
|
364
|
+
{
|
|
365
|
+
$group: {
|
|
366
|
+
_id: '$customerId',
|
|
367
|
+
totalSpent: { $sum: '$amount' },
|
|
368
|
+
orderCount: { $count: {} },
|
|
369
|
+
avgOrderValue: { $avg: '$amount' }
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
|
|
373
|
+
// Stage 3: Sort by total spent
|
|
374
|
+
{ $sort: { totalSpent: -1 } },
|
|
375
|
+
|
|
376
|
+
// Stage 4: Limit to top 10
|
|
377
|
+
{ $limit: 10 },
|
|
378
|
+
|
|
379
|
+
// Stage 5: Project final shape
|
|
380
|
+
{
|
|
381
|
+
$project: {
|
|
382
|
+
customer: '$_id',
|
|
383
|
+
metrics: {
|
|
384
|
+
total: '$totalSpent',
|
|
385
|
+
orders: '$orderCount',
|
|
386
|
+
average: '$avgOrderValue'
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
]);
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
#### Lookup (Join) Operations
|
|
394
|
+
|
|
395
|
+
```javascript
|
|
396
|
+
// Join with another collection
|
|
397
|
+
const ordersWithProducts = await orders.aggregate([
|
|
398
|
+
{
|
|
399
|
+
$lookup: {
|
|
400
|
+
from: 'products', // Foreign collection
|
|
401
|
+
localField: 'productId', // Field in orders
|
|
402
|
+
foreignField: '_id', // Field in products
|
|
403
|
+
as: 'productDetails' // Output array field
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
]);
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
## 🔐 Security Features
|
|
410
|
+
|
|
411
|
+
### Encryption
|
|
412
|
+
|
|
413
|
+
Documents can be individually encrypted with AES-256-GCM:
|
|
414
|
+
|
|
415
|
+
```javascript
|
|
416
|
+
// Add encrypted document
|
|
417
|
+
await users.add(
|
|
418
|
+
{
|
|
419
|
+
ssn: '123-45-6789',
|
|
420
|
+
bankAccount: 'SECRET123',
|
|
421
|
+
salary: 75000
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
encrypted: true,
|
|
425
|
+
password: 'strong-password-here',
|
|
426
|
+
permanent: true // Protect from auto-deletion
|
|
427
|
+
}
|
|
428
|
+
);
|
|
104
429
|
|
|
105
|
-
|
|
430
|
+
// Retrieve encrypted document
|
|
431
|
+
const userData = await users.get('user-id', {
|
|
432
|
+
password: 'strong-password-here' // Required for decryption
|
|
433
|
+
});
|
|
106
434
|
|
|
107
|
-
|
|
108
|
-
|
|
435
|
+
// Update encrypted document
|
|
436
|
+
await users.update('user-id',
|
|
437
|
+
{ salary: 80000 },
|
|
438
|
+
{
|
|
439
|
+
encrypted: true,
|
|
440
|
+
password: 'strong-password-here'
|
|
441
|
+
}
|
|
442
|
+
);
|
|
443
|
+
```
|
|
109
444
|
|
|
110
|
-
|
|
445
|
+
### Password Protection
|
|
111
446
|
|
|
112
|
-
|
|
447
|
+
Secure your exports and backups:
|
|
113
448
|
|
|
114
|
-
|
|
449
|
+
```javascript
|
|
450
|
+
// Export with encryption
|
|
451
|
+
const encryptedExport = await db.export('encrypted', 'export-password');
|
|
115
452
|
|
|
116
|
-
|
|
453
|
+
// Import encrypted data
|
|
454
|
+
await db.import(encryptedExport, 'encrypted', 'export-password');
|
|
117
455
|
|
|
118
|
-
|
|
456
|
+
// Create encrypted backup
|
|
457
|
+
const backup = await lacerta.createBackup('backup-password');
|
|
119
458
|
|
|
120
|
-
|
|
121
|
-
|
|
459
|
+
// Restore from encrypted backup
|
|
460
|
+
await lacerta.restoreBackup(backup, 'backup-password');
|
|
461
|
+
```
|
|
122
462
|
|
|
123
|
-
|
|
463
|
+
## 📎 Attachments
|
|
124
464
|
|
|
125
|
-
|
|
465
|
+
Store files using the Origin Private File System:
|
|
126
466
|
|
|
127
|
-
|
|
467
|
+
```javascript
|
|
468
|
+
// Prepare files
|
|
469
|
+
const file1 = new File(['content'], 'document.pdf', { type: 'application/pdf' });
|
|
470
|
+
const file2 = new Blob(['image data'], { type: 'image/png' });
|
|
128
471
|
|
|
129
|
-
|
|
472
|
+
// Add document with attachments
|
|
473
|
+
const docId = await documents.add(
|
|
474
|
+
{ title: 'Report with Files' },
|
|
475
|
+
{
|
|
476
|
+
attachments: [
|
|
477
|
+
file1,
|
|
478
|
+
file2,
|
|
479
|
+
{
|
|
480
|
+
name: 'custom.txt',
|
|
481
|
+
type: 'text/plain',
|
|
482
|
+
data: new TextEncoder().encode('Custom file content')
|
|
483
|
+
}
|
|
484
|
+
]
|
|
485
|
+
}
|
|
486
|
+
);
|
|
130
487
|
|
|
131
|
-
|
|
488
|
+
// Retrieve with attachments
|
|
489
|
+
const docWithFiles = await documents.get(docId, {
|
|
490
|
+
includeAttachments: true
|
|
491
|
+
});
|
|
132
492
|
|
|
133
|
-
|
|
493
|
+
// Access attachments
|
|
494
|
+
docWithFiles._attachments.forEach(attachment => {
|
|
495
|
+
console.log(`File: ${attachment.name} (${attachment.size} bytes)`);
|
|
496
|
+
// attachment.data is Uint8Array
|
|
497
|
+
});
|
|
498
|
+
```
|
|
134
499
|
|
|
135
|
-
|
|
136
|
-
Updates the data of a specific document.
|
|
500
|
+
## ⚡ Performance
|
|
137
501
|
|
|
138
|
-
|
|
502
|
+
### Compression
|
|
139
503
|
|
|
140
|
-
|
|
141
|
-
Removes a document from the collection.
|
|
504
|
+
Reduce storage size with automatic compression:
|
|
142
505
|
|
|
143
|
-
|
|
506
|
+
```javascript
|
|
507
|
+
// Enable compression for all documents in collection
|
|
508
|
+
const compressedColl = await db.createCollection('largeDocs', {
|
|
509
|
+
compressed: true
|
|
510
|
+
});
|
|
144
511
|
|
|
145
|
-
|
|
146
|
-
|
|
512
|
+
// Per-document compression
|
|
513
|
+
await collection.add(largeData, {
|
|
514
|
+
compressed: true // Uses DeflateStream compression
|
|
515
|
+
});
|
|
516
|
+
```
|
|
147
517
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
518
|
+
### Performance Monitoring
|
|
519
|
+
|
|
520
|
+
Track database performance metrics:
|
|
521
|
+
|
|
522
|
+
```javascript
|
|
523
|
+
// Start monitoring
|
|
524
|
+
lacerta.performanceMonitor.startMonitoring();
|
|
525
|
+
|
|
526
|
+
// Perform operations...
|
|
527
|
+
|
|
528
|
+
// Get performance stats
|
|
529
|
+
const stats = lacerta.performanceMonitor.getStats();
|
|
530
|
+
console.log(`Operations/sec: ${stats.opsPerSec}`);
|
|
531
|
+
console.log(`Avg latency: ${stats.avgLatency}ms`);
|
|
532
|
+
console.log(`Cache hit rate: ${stats.cacheHitRate}%`);
|
|
533
|
+
console.log(`Memory usage: ${stats.memoryUsageMB}MB`);
|
|
534
|
+
|
|
535
|
+
// Get optimization tips
|
|
536
|
+
const tips = lacerta.performanceMonitor.getOptimizationTips();
|
|
537
|
+
tips.forEach(tip => console.log(`💡 ${tip}`));
|
|
538
|
+
|
|
539
|
+
// Stop monitoring
|
|
540
|
+
lacerta.performanceMonitor.stopMonitoring();
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### Query Caching
|
|
544
|
+
|
|
545
|
+
Queries are automatically cached for 60 seconds:
|
|
152
546
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
547
|
+
```javascript
|
|
548
|
+
// First query - hits database
|
|
549
|
+
const results1 = await users.query({ status: 'active' });
|
|
156
550
|
|
|
157
|
-
|
|
551
|
+
// Second identical query - served from cache
|
|
552
|
+
const results2 = await users.query({ status: 'active' });
|
|
158
553
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
554
|
+
// Clear cache manually if needed
|
|
555
|
+
users.clearCache();
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
## 🔄 Data Migration
|
|
559
|
+
|
|
560
|
+
Version your schema changes:
|
|
561
|
+
|
|
562
|
+
```javascript
|
|
563
|
+
const migrationManager = new MigrationManager(db);
|
|
564
|
+
|
|
565
|
+
// Define migrations
|
|
566
|
+
migrationManager.addMigration({
|
|
567
|
+
version: '2.0.0',
|
|
568
|
+
name: 'Add user roles',
|
|
569
|
+
up: async (doc) => {
|
|
570
|
+
if (doc.type === 'user' && !doc.role) {
|
|
571
|
+
return { ...doc, role: 'standard' };
|
|
572
|
+
}
|
|
573
|
+
return doc;
|
|
574
|
+
},
|
|
575
|
+
down: async (doc) => {
|
|
576
|
+
if (doc.type === 'user') {
|
|
577
|
+
const { role, ...rest } = doc;
|
|
578
|
+
return rest;
|
|
579
|
+
}
|
|
580
|
+
return doc;
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
// Run migrations
|
|
585
|
+
await migrationManager.runMigrations('2.0.0');
|
|
586
|
+
|
|
587
|
+
// Rollback if needed
|
|
588
|
+
await migrationManager.rollback('1.0.0');
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
## 💾 Backup & Restore
|
|
592
|
+
|
|
593
|
+
### Database Export/Import
|
|
594
|
+
|
|
595
|
+
```javascript
|
|
596
|
+
// Export single database
|
|
597
|
+
const exportData = await db.export('json');
|
|
598
|
+
// Save exportData to file or send to server
|
|
599
|
+
|
|
600
|
+
// Import data
|
|
601
|
+
const importResult = await db.import(exportData, 'json');
|
|
602
|
+
console.log(`Imported ${importResult.documents} documents`);
|
|
603
|
+
|
|
604
|
+
// Export with encryption
|
|
605
|
+
const secureExport = await db.export('encrypted', 'password123');
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### Full System Backup
|
|
609
|
+
|
|
610
|
+
```javascript
|
|
611
|
+
// Backup all databases
|
|
612
|
+
const systemBackup = await lacerta.createBackup();
|
|
613
|
+
// Optional: encrypt the backup
|
|
614
|
+
const encryptedBackup = await lacerta.createBackup('backup-password');
|
|
615
|
+
|
|
616
|
+
// Restore from backup
|
|
617
|
+
const restoreResult = await lacerta.restoreBackup(systemBackup);
|
|
618
|
+
console.log(`Restored: ${restoreResult.databases} databases`);
|
|
619
|
+
console.log(`Total documents: ${restoreResult.documents}`);
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
## 🛠️ Advanced Features
|
|
623
|
+
|
|
624
|
+
### Batch Operations
|
|
625
|
+
|
|
626
|
+
Efficient bulk operations with transaction support:
|
|
627
|
+
|
|
628
|
+
```javascript
|
|
629
|
+
// Batch insert
|
|
630
|
+
const documents = [
|
|
631
|
+
{ name: 'Doc 1', value: 100 },
|
|
632
|
+
{ name: 'Doc 2', value: 200 },
|
|
633
|
+
{ name: 'Doc 3', value: 300 }
|
|
634
|
+
];
|
|
635
|
+
|
|
636
|
+
const results = await collection.batchAdd(documents, {
|
|
637
|
+
compressed: true,
|
|
638
|
+
encrypted: false
|
|
162
639
|
});
|
|
163
640
|
|
|
164
|
-
//
|
|
165
|
-
|
|
166
|
-
|
|
641
|
+
// Check results
|
|
642
|
+
results.forEach(result => {
|
|
643
|
+
if (result.success) {
|
|
644
|
+
console.log(`✅ Added: ${result.id}`);
|
|
645
|
+
} else {
|
|
646
|
+
console.log(`❌ Failed: ${result.error}`);
|
|
647
|
+
}
|
|
167
648
|
});
|
|
168
649
|
|
|
169
|
-
|
|
170
|
-
|
|
650
|
+
// Batch update
|
|
651
|
+
const updates = [
|
|
652
|
+
{ id: 'doc1', data: { status: 'active' } },
|
|
653
|
+
{ id: 'doc2', data: { status: 'inactive' } }
|
|
654
|
+
];
|
|
655
|
+
await collection.batchUpdate(updates);
|
|
171
656
|
|
|
172
|
-
//
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
657
|
+
// Batch delete
|
|
658
|
+
const idsToDelete = ['doc3', 'doc4', 'doc5'];
|
|
659
|
+
await collection.batchDelete(idsToDelete);
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
### Event System
|
|
663
|
+
|
|
664
|
+
React to database operations:
|
|
665
|
+
|
|
666
|
+
```javascript
|
|
667
|
+
// Collection-level events
|
|
668
|
+
collection.on('beforeAdd', async (data) => {
|
|
669
|
+
console.log('Validating document...');
|
|
670
|
+
// Perform validation
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
collection.on('afterAdd', async (doc) => {
|
|
674
|
+
console.log(`Document ${doc._id} added`);
|
|
675
|
+
// Send notification, update cache, etc.
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
collection.on('beforeUpdate', async ({ docId, updates }) => {
|
|
679
|
+
console.log(`Updating ${docId}`);
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
collection.on('afterDelete', async (docId) => {
|
|
683
|
+
console.log(`Document ${docId} deleted`);
|
|
684
|
+
// Cleanup related data
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
// Remove event listener
|
|
688
|
+
const handler = (doc) => console.log(doc);
|
|
689
|
+
collection.on('afterAdd', handler);
|
|
690
|
+
collection.off('afterAdd', handler);
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
### Quick Store
|
|
694
|
+
|
|
695
|
+
Fast localStorage-based storage for small data:
|
|
696
|
+
|
|
697
|
+
```javascript
|
|
698
|
+
// Access QuickStore
|
|
699
|
+
const quickStore = db.quickStore;
|
|
700
|
+
|
|
701
|
+
// Store data
|
|
702
|
+
quickStore.add('user-prefs', {
|
|
703
|
+
theme: 'dark',
|
|
704
|
+
language: 'en',
|
|
705
|
+
notifications: true
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
// Retrieve data
|
|
709
|
+
const prefs = quickStore.get('user-prefs');
|
|
710
|
+
|
|
711
|
+
// Update
|
|
712
|
+
quickStore.update('user-prefs', { theme: 'light' });
|
|
713
|
+
|
|
714
|
+
// Get all stored items
|
|
715
|
+
const allItems = quickStore.getAll();
|
|
716
|
+
|
|
717
|
+
// Clear QuickStore
|
|
718
|
+
quickStore.clear();
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
## 📊 Storage Management
|
|
722
|
+
|
|
723
|
+
### Size Limits and Auto-Cleanup
|
|
724
|
+
|
|
725
|
+
```javascript
|
|
726
|
+
// Configure storage limits
|
|
727
|
+
db.updateSettings({
|
|
728
|
+
sizeLimitKB: 100000, // 100MB total limit
|
|
729
|
+
bufferLimitKB: 80000, // Start cleanup at 80MB
|
|
730
|
+
freeSpaceEvery: 30000 // Check every 30 seconds
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
// Manual cleanup
|
|
734
|
+
await collection.freeSpace();
|
|
735
|
+
|
|
736
|
+
// Mark documents as permanent
|
|
737
|
+
await collection.add(importantData, {
|
|
738
|
+
permanent: true // Won't be deleted during cleanup
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
// Check collection size
|
|
742
|
+
const stats = collection.metadata;
|
|
743
|
+
console.log(`Collection size: ${stats.sizeKB} KB`);
|
|
744
|
+
console.log(`Document count: ${stats.length}`);
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
### Storage Information
|
|
748
|
+
|
|
749
|
+
```javascript
|
|
750
|
+
// Database statistics
|
|
751
|
+
const dbStats = db.getStats();
|
|
752
|
+
console.log(dbStats);
|
|
753
|
+
/* Output:
|
|
754
|
+
{
|
|
755
|
+
name: 'myDatabase',
|
|
756
|
+
totalSizeKB: 2457.3,
|
|
757
|
+
totalDocuments: 1250,
|
|
758
|
+
collections: [
|
|
759
|
+
{
|
|
760
|
+
name: 'users',
|
|
761
|
+
sizeKB: 1024.5,
|
|
762
|
+
documents: 500,
|
|
763
|
+
createdAt: '2024-01-01T00:00:00.000Z',
|
|
764
|
+
modifiedAt: '2024-01-15T10:30:00.000Z'
|
|
765
|
+
}
|
|
766
|
+
]
|
|
767
|
+
}
|
|
768
|
+
*/
|
|
769
|
+
|
|
770
|
+
// List all databases
|
|
771
|
+
const allDatabases = lacerta.listDatabases();
|
|
772
|
+
console.log('Available databases:', allDatabases);
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
## 🎨 API Reference
|
|
776
|
+
|
|
777
|
+
### LacertaDB Class
|
|
778
|
+
|
|
779
|
+
| Method | Description | Returns |
|
|
780
|
+
|--------|-------------|---------|
|
|
781
|
+
| `getDatabase(name)` | Get or create a database | `Promise<Database>` |
|
|
782
|
+
| `dropDatabase(name)` | Delete a database | `Promise<void>` |
|
|
783
|
+
| `listDatabases()` | List all database names | `Array<string>` |
|
|
784
|
+
| `createBackup(password?)` | Create full system backup | `Promise<string>` |
|
|
785
|
+
| `restoreBackup(data, password?)` | Restore from backup | `Promise<Object>` |
|
|
786
|
+
|
|
787
|
+
### Database Class
|
|
788
|
+
|
|
789
|
+
| Method | Description | Returns |
|
|
790
|
+
|--------|-------------|---------|
|
|
791
|
+
| `createCollection(name, options?)` | Create new collection | `Promise<Collection>` |
|
|
792
|
+
| `getCollection(name)` | Get existing collection | `Promise<Collection>` |
|
|
793
|
+
| `dropCollection(name)` | Delete collection | `Promise<void>` |
|
|
794
|
+
| `listCollections()` | Get collection names | `Array<string>` |
|
|
795
|
+
| `getStats()` | Get database statistics | `Object` |
|
|
796
|
+
| `updateSettings(settings)` | Update configuration | `void` |
|
|
797
|
+
| `export(format, password?)` | Export database | `Promise<string>` |
|
|
798
|
+
| `import(data, format, password?)` | Import data | `Promise<Object>` |
|
|
799
|
+
| `clearAll()` | Delete all collections | `Promise<void>` |
|
|
800
|
+
|
|
801
|
+
### Collection Class
|
|
802
|
+
|
|
803
|
+
| Method | Description | Returns |
|
|
804
|
+
|--------|-------------|---------|
|
|
805
|
+
| `add(data, options?)` | Add document | `Promise<string>` |
|
|
806
|
+
| `get(id, options?)` | Get document by ID | `Promise<Object>` |
|
|
807
|
+
| `getAll(options?)` | Get all documents | `Promise<Array>` |
|
|
808
|
+
| `update(id, updates, options?)` | Update document | `Promise<string>` |
|
|
809
|
+
| `delete(id)` | Delete document | `Promise<void>` |
|
|
810
|
+
| `query(filter, options?)` | Query documents | `Promise<Array>` |
|
|
811
|
+
| `aggregate(pipeline)` | Run aggregation | `Promise<Array>` |
|
|
812
|
+
| `batchAdd(documents, options?)` | Add multiple documents | `Promise<Array>` |
|
|
813
|
+
| `batchUpdate(updates, options?)` | Update multiple documents | `Promise<Array>` |
|
|
814
|
+
| `batchDelete(ids)` | Delete multiple documents | `Promise<Array>` |
|
|
815
|
+
| `clear()` | Remove all documents | `Promise<void>` |
|
|
816
|
+
| `on(event, callback)` | Add event listener | `void` |
|
|
817
|
+
| `off(event, callback)` | Remove event listener | `void` |
|
|
818
|
+
| `clearCache()` | Clear query cache | `void` |
|
|
819
|
+
|
|
820
|
+
## 💡 Examples
|
|
821
|
+
|
|
822
|
+
### Todo Application
|
|
823
|
+
|
|
824
|
+
```javascript
|
|
825
|
+
// Initialize
|
|
826
|
+
const lacerta = new LacertaDB();
|
|
827
|
+
const db = await lacerta.getDatabase('todoApp');
|
|
828
|
+
const todos = await db.createCollection('todos');
|
|
829
|
+
|
|
830
|
+
// Add todos
|
|
831
|
+
await todos.add({
|
|
832
|
+
title: 'Learn LacertaDB',
|
|
833
|
+
completed: false,
|
|
834
|
+
priority: 'high',
|
|
835
|
+
tags: ['learning', 'database'],
|
|
836
|
+
createdAt: Date.now()
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
// Query incomplete high-priority todos
|
|
840
|
+
const urgentTodos = await todos.query({
|
|
841
|
+
completed: false,
|
|
842
|
+
priority: 'high'
|
|
843
|
+
}, {
|
|
844
|
+
sort: { createdAt: -1 }
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
// Mark as complete
|
|
848
|
+
await todos.update(todoId, {
|
|
849
|
+
completed: true,
|
|
850
|
+
completedAt: Date.now()
|
|
851
|
+
});
|
|
852
|
+
|
|
853
|
+
// Get statistics
|
|
854
|
+
const stats = await todos.aggregate([
|
|
855
|
+
{
|
|
856
|
+
$group: {
|
|
857
|
+
_id: '$priority',
|
|
858
|
+
count: { $count: {} },
|
|
859
|
+
completed: {
|
|
860
|
+
$sum: { $cond: ['$completed', 1, 0] }
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
]);
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
### E-Commerce Inventory
|
|
868
|
+
|
|
869
|
+
```javascript
|
|
870
|
+
// Setup
|
|
871
|
+
const db = await lacerta.getDatabase('shop');
|
|
872
|
+
const products = await db.createCollection('products');
|
|
873
|
+
const orders = await db.createCollection('orders');
|
|
874
|
+
|
|
875
|
+
// Product with images
|
|
876
|
+
const productId = await products.add(
|
|
877
|
+
{
|
|
878
|
+
name: 'Wireless Mouse',
|
|
879
|
+
price: 29.99,
|
|
880
|
+
stock: 150,
|
|
881
|
+
category: 'electronics'
|
|
882
|
+
},
|
|
883
|
+
{
|
|
884
|
+
attachments: [productImage1, productImage2]
|
|
885
|
+
}
|
|
886
|
+
);
|
|
887
|
+
|
|
888
|
+
// Complex inventory query
|
|
889
|
+
const lowStock = await products.query({
|
|
890
|
+
$and: [
|
|
891
|
+
{ stock: { $lt: 20 } },
|
|
892
|
+
{ category: { $in: ['electronics', 'accessories'] } }
|
|
893
|
+
]
|
|
894
|
+
}, {
|
|
895
|
+
projection: { name: 1, stock: 1, price: 1 }
|
|
896
|
+
});
|
|
897
|
+
|
|
898
|
+
// Sales report with joins
|
|
899
|
+
const salesReport = await orders.aggregate([
|
|
900
|
+
{ $match: { status: 'completed' } },
|
|
901
|
+
{
|
|
902
|
+
$lookup: {
|
|
903
|
+
from: 'products',
|
|
904
|
+
localField: 'productId',
|
|
905
|
+
foreignField: '_id',
|
|
906
|
+
as: 'product'
|
|
907
|
+
}
|
|
908
|
+
},
|
|
909
|
+
{
|
|
910
|
+
$group: {
|
|
911
|
+
_id: '$product.category',
|
|
912
|
+
revenue: { $sum: '$total' },
|
|
913
|
+
orderCount: { $count: {} }
|
|
914
|
+
}
|
|
915
|
+
},
|
|
916
|
+
{ $sort: { revenue: -1 } }
|
|
917
|
+
]);
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
### User Session Management
|
|
921
|
+
|
|
922
|
+
```javascript
|
|
923
|
+
// Encrypted session storage
|
|
924
|
+
const sessions = await db.createCollection('sessions');
|
|
925
|
+
|
|
926
|
+
// Store session with encryption
|
|
927
|
+
await sessions.add(
|
|
928
|
+
{
|
|
929
|
+
userId: 'user123',
|
|
930
|
+
token: 'secret-session-token',
|
|
931
|
+
ipAddress: '192.168.1.1',
|
|
932
|
+
userAgent: navigator.userAgent,
|
|
933
|
+
expiresAt: Date.now() + (24 * 60 * 60 * 1000)
|
|
934
|
+
},
|
|
935
|
+
{
|
|
936
|
+
encrypted: true,
|
|
937
|
+
password: process.env.SESSION_KEY,
|
|
938
|
+
permanent: false
|
|
939
|
+
}
|
|
940
|
+
);
|
|
941
|
+
|
|
942
|
+
// Cleanup expired sessions
|
|
943
|
+
const now = Date.now();
|
|
944
|
+
const expired = await sessions.query({
|
|
945
|
+
expiresAt: { $lt: now }
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
await sessions.batchDelete(expired.map(s => s._id));
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
## 🐛 Error Handling
|
|
952
|
+
|
|
953
|
+
LacertaDB provides detailed error information:
|
|
954
|
+
|
|
955
|
+
```javascript
|
|
956
|
+
try {
|
|
957
|
+
await collection.get('non-existent-id');
|
|
958
|
+
} catch (error) {
|
|
959
|
+
if (error instanceof LacertaDBError) {
|
|
960
|
+
console.error('Error:', error.message);
|
|
961
|
+
console.error('Code:', error.code);
|
|
962
|
+
console.error('Timestamp:', error.timestamp);
|
|
963
|
+
|
|
964
|
+
// Handle specific error codes
|
|
965
|
+
switch(error.code) {
|
|
966
|
+
case 'DOCUMENT_NOT_FOUND':
|
|
967
|
+
// Handle missing document
|
|
968
|
+
break;
|
|
969
|
+
case 'ENCRYPTION_FAILED':
|
|
970
|
+
// Handle encryption error
|
|
971
|
+
break;
|
|
972
|
+
case 'QUOTA_EXCEEDED':
|
|
973
|
+
// Handle storage limit
|
|
974
|
+
break;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
```
|
|
979
|
+
|
|
980
|
+
### Common Error Codes
|
|
981
|
+
|
|
982
|
+
| Code | Description | Solution |
|
|
983
|
+
|------|-------------|----------|
|
|
984
|
+
| `DOCUMENT_NOT_FOUND` | Document ID doesn't exist | Check ID or use query |
|
|
985
|
+
| `COLLECTION_NOT_FOUND` | Collection doesn't exist | Create collection first |
|
|
986
|
+
| `ENCRYPTION_FAILED` | Encryption/decryption error | Check password |
|
|
987
|
+
| `COMPRESSION_FAILED` | Compression error | Check data format |
|
|
988
|
+
| `QUOTA_EXCEEDED` | Storage limit reached | Increase limit or cleanup |
|
|
989
|
+
| `INVALID_OPERATION` | Operation not allowed | Check document flags |
|
|
990
|
+
| `TRANSACTION_FAILED` | Database transaction error | Retry operation |
|
|
991
|
+
|
|
992
|
+
## 📝 Best Practices
|
|
993
|
+
|
|
994
|
+
### 1. Index Strategy
|
|
995
|
+
|
|
996
|
+
```javascript
|
|
997
|
+
// Analyze query patterns first
|
|
998
|
+
const queryPatterns = {
|
|
999
|
+
byEmail: { email: 'user@example.com' }, // Hash index
|
|
1000
|
+
byAgeRange: { age: { $gte: 25, $lte: 35 } }, // B-Tree index
|
|
1001
|
+
byDescription: { $text: 'search terms' }, // Text index
|
|
1002
|
+
byLocation: { $near: { lat: 0, lng: 0 } } // Geo index
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
// Create appropriate indexes
|
|
1006
|
+
await users.createIndex('email', { type: 'hash', unique: true });
|
|
1007
|
+
await users.createIndex('age', { type: 'btree' });
|
|
1008
|
+
await users.createIndex('bio', { type: 'text' });
|
|
1009
|
+
await users.createIndex('location', { type: 'geo' });
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
### 2. Cache Optimization
|
|
1013
|
+
|
|
1014
|
+
```javascript
|
|
1015
|
+
// Match cache strategy to access patterns
|
|
1016
|
+
const cacheStrategies = {
|
|
1017
|
+
// Frequently changing data - LRU with short TTL
|
|
1018
|
+
activeSessions: { type: 'lru', maxSize: 1000, ttl: 60000 },
|
|
1019
|
+
|
|
1020
|
+
// Hot data - LFU for keeping popular items
|
|
1021
|
+
trendingProducts: { type: 'lfu', maxSize: 500 },
|
|
1022
|
+
|
|
1023
|
+
// Time-sensitive - TTL only
|
|
1024
|
+
tempTokens: { type: 'ttl', ttl: 300000 },
|
|
1025
|
+
|
|
1026
|
+
// Sensitive data - No cache
|
|
1027
|
+
privateKeys: { type: 'none', enabled: false }
|
|
178
1028
|
};
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
### 3. Security Best Practices
|
|
179
1032
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
1033
|
+
```javascript
|
|
1034
|
+
// For private keys and sensitive data
|
|
1035
|
+
const secureDb = await lacerta.getSecureDatabase(
|
|
1036
|
+
'vault',
|
|
1037
|
+
SecureDatabaseEncryption.generateSecurePIN(12) // 12-digit secure PIN
|
|
184
1038
|
);
|
|
185
1039
|
|
|
186
|
-
//
|
|
187
|
-
|
|
188
|
-
|
|
1040
|
+
// Always use additional authentication
|
|
1041
|
+
await secureDb.storePrivateKey('key-name', privateKey, userEmail);
|
|
1042
|
+
|
|
1043
|
+
// Regular PIN rotation
|
|
1044
|
+
const rotatePin = async () => {
|
|
1045
|
+
const newPin = SecureDatabaseEncryption.generateSecurePIN(12);
|
|
1046
|
+
await secureDb.changePin(currentPin, newPin);
|
|
1047
|
+
// Securely store newPin
|
|
1048
|
+
};
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
### 4. Performance Optimization
|
|
1052
|
+
|
|
1053
|
+
```javascript
|
|
1054
|
+
// Enable monitoring during development
|
|
1055
|
+
lacerta.performanceMonitor.startMonitoring();
|
|
1056
|
+
|
|
1057
|
+
// Test different strategies
|
|
1058
|
+
const testPerformance = async () => {
|
|
1059
|
+
// Test without index
|
|
1060
|
+
const start1 = Date.now();
|
|
1061
|
+
await collection.query({ field: 'value' });
|
|
1062
|
+
console.log('Without index:', Date.now() - start1);
|
|
1063
|
+
|
|
1064
|
+
// Create index
|
|
1065
|
+
await collection.createIndex('field', { type: 'hash' });
|
|
1066
|
+
|
|
1067
|
+
// Test with index
|
|
1068
|
+
const start2 = Date.now();
|
|
1069
|
+
await collection.query({ field: 'value' });
|
|
1070
|
+
console.log('With index:', Date.now() - start2);
|
|
1071
|
+
};
|
|
1072
|
+
|
|
1073
|
+
// Get optimization suggestions
|
|
1074
|
+
const tips = lacerta.performanceMonitor.getOptimizationTips();
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
### 5. Storage Management
|
|
1078
|
+
|
|
1079
|
+
```javascript
|
|
1080
|
+
// Set appropriate limits
|
|
1081
|
+
db.updateSettings({
|
|
1082
|
+
sizeLimitKB: 100000, // 100MB total
|
|
1083
|
+
bufferLimitKB: 80000, // Start cleanup at 80MB
|
|
1084
|
+
freeSpaceEvery: 300000 // Check every 5 minutes
|
|
189
1085
|
});
|
|
190
1086
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
1087
|
+
// Mark critical documents as permanent
|
|
1088
|
+
await collection.add(importantData, { permanent: true });
|
|
1089
|
+
|
|
1090
|
+
// Regular maintenance
|
|
1091
|
+
const maintenance = async () => {
|
|
1092
|
+
const stats = db.getStats();
|
|
1093
|
+
if (stats.totalSizeKB > 90000) {
|
|
1094
|
+
// Cleanup old non-permanent documents
|
|
1095
|
+
await collection.freeSpace();
|
|
1096
|
+
}
|
|
1097
|
+
};
|
|
1098
|
+
```
|
|
1099
|
+
|
|
1100
|
+
## 🔄 Migration from v4.x
|
|
1101
|
+
|
|
1102
|
+
### Breaking Changes
|
|
1103
|
+
|
|
1104
|
+
None! LacertaDB v5.0.0 is fully backward compatible. All v4.x code continues to work without modifications.
|
|
1105
|
+
|
|
1106
|
+
### New Features to Adopt
|
|
1107
|
+
|
|
1108
|
+
```javascript
|
|
1109
|
+
// v4.x code (still works)
|
|
1110
|
+
const collection = await db.createCollection('data');
|
|
1111
|
+
const results = await collection.query({ status: 'active' });
|
|
1112
|
+
|
|
1113
|
+
// v5.0.0 optimized code
|
|
1114
|
+
const collection = await db.createCollection('data');
|
|
1115
|
+
|
|
1116
|
+
// Add index for 50x faster queries
|
|
1117
|
+
await collection.createIndex('status', { type: 'hash' });
|
|
1118
|
+
|
|
1119
|
+
// Configure smart caching
|
|
1120
|
+
await collection.configureCacheStrategy({
|
|
1121
|
+
type: 'lru',
|
|
1122
|
+
maxSize: 500,
|
|
1123
|
+
ttl: 120000
|
|
1124
|
+
});
|
|
1125
|
+
|
|
1126
|
+
// Now queries are much faster
|
|
1127
|
+
const results = await collection.query({ status: 'active' });
|
|
1128
|
+
```
|
|
1129
|
+
|
|
1130
|
+
### Migration Checklist
|
|
1131
|
+
|
|
1132
|
+
1. **Add Indexes** to frequently queried fields
|
|
1133
|
+
2. **Configure Cache Strategies** based on access patterns
|
|
1134
|
+
3. **Enable PIN encryption** for databases with sensitive data
|
|
1135
|
+
4. **Update force delete** calls for permanent document management
|
|
1136
|
+
5. **Monitor performance** to identify optimization opportunities
|
|
1137
|
+
|
|
1138
|
+
```javascript
|
|
1139
|
+
// Complete migration example
|
|
1140
|
+
const migrate = async () => {
|
|
1141
|
+
// 1. Get existing database
|
|
1142
|
+
const db = await lacerta.getDatabase('myApp');
|
|
1143
|
+
|
|
1144
|
+
// 2. Add indexes to collections
|
|
1145
|
+
const users = await db.getCollection('users');
|
|
1146
|
+
await users.createIndex('email', { type: 'hash', unique: true });
|
|
1147
|
+
await users.createIndex('createdAt', { type: 'btree' });
|
|
1148
|
+
|
|
1149
|
+
// 3. Configure caching
|
|
1150
|
+
await users.configureCacheStrategy({
|
|
1151
|
+
type: 'lru',
|
|
1152
|
+
maxSize: 1000,
|
|
1153
|
+
ttl: 300000
|
|
1154
|
+
});
|
|
1155
|
+
|
|
1156
|
+
// 4. For sensitive data, create new secure database
|
|
1157
|
+
const secureDb = await lacerta.getSecureDatabase('secure', pin);
|
|
1158
|
+
// Migrate sensitive data to secure database
|
|
1159
|
+
|
|
1160
|
+
console.log('Migration complete!');
|
|
1161
|
+
};
|
|
1162
|
+
```
|
|
1163
|
+
|
|
1164
|
+
## 🤝 Contributing
|
|
1165
|
+
|
|
1166
|
+
We welcome contributions! Here's how you can help:
|
|
1167
|
+
|
|
1168
|
+
1. **Report Bugs**: Open an issue with reproduction steps
|
|
1169
|
+
2. **Suggest Features**: Share your ideas in discussions
|
|
1170
|
+
3. **Improve Docs**: Fix typos or add examples
|
|
1171
|
+
4. **Submit PRs**: Fork, code, test, and submit
|
|
1172
|
+
|
|
1173
|
+
### Development Setup
|
|
1174
|
+
|
|
1175
|
+
```bash
|
|
1176
|
+
# Clone repository
|
|
1177
|
+
git clone https://github.com/pixagram-blockchain/LacertaDB.git
|
|
1178
|
+
cd LacertaDB
|
|
1179
|
+
|
|
1180
|
+
# Install dependencies
|
|
1181
|
+
npm install
|
|
1182
|
+
|
|
1183
|
+
# Run tests
|
|
1184
|
+
npm test
|
|
1185
|
+
|
|
1186
|
+
# Build
|
|
1187
|
+
npm run build
|
|
1188
|
+
```
|
|
1189
|
+
|
|
1190
|
+
### Testing
|
|
1191
|
+
|
|
1192
|
+
```javascript
|
|
1193
|
+
// Test your changes
|
|
1194
|
+
import { LacertaDB } from './lacertadb.js';
|
|
1195
|
+
|
|
1196
|
+
const runTests = async () => {
|
|
1197
|
+
const lacerta = new LacertaDB();
|
|
1198
|
+
const db = await lacerta.getDatabase('test');
|
|
1199
|
+
|
|
1200
|
+
// Test new features
|
|
1201
|
+
const collection = await db.createCollection('test');
|
|
1202
|
+
await collection.createIndex('field', { type: 'hash' });
|
|
1203
|
+
|
|
1204
|
+
// Verify functionality
|
|
1205
|
+
console.assert(collection.indexManager.indexes.size === 1);
|
|
1206
|
+
|
|
1207
|
+
console.log('Tests passed!');
|
|
1208
|
+
};
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
## 📄 License
|
|
1212
|
+
|
|
1213
|
+
MIT License - See [LICENSE](LICENSE) file for details
|
|
1214
|
+
|
|
1215
|
+
## 🙏 Acknowledgments
|
|
1216
|
+
|
|
1217
|
+
- Built with ❤️ by the Pixagram team
|
|
1218
|
+
- Uses TurboSerial and TurboBase64 for high performance
|
|
1219
|
+
- Inspired by MongoDB's query language
|
|
1220
|
+
- Powered by modern browser APIs (IndexedDB, OPFS, Web Crypto)
|
|
194
1221
|
|
|
195
|
-
|
|
196
|
-
A key performance feature of LacertaDB is its use of turboserial instead of JSON. This provides several advantages:
|
|
1222
|
+
## 📮 Support
|
|
197
1223
|
|
|
198
|
-
|
|
1224
|
+
- 📧 Email: support@pixagram.com
|
|
1225
|
+
- 💬 Discord: [Join our community](https://discord.gg/pixagram)
|
|
1226
|
+
- 📚 Documentation: [docs.lacertadb.com](https://docs.lacertadb.com)
|
|
1227
|
+
- 🐛 Issues: [GitHub Issues](https://github.com/pixagram-blockchain/LacertaDB/issues)
|
|
199
1228
|
|
|
200
|
-
|
|
1229
|
+
## 🎉 What's New in v5.0.0
|
|
201
1230
|
|
|
202
|
-
|
|
1231
|
+
- ⚡ **Custom Indexing**: B-Tree, Hash, Text, and Geo indexes for 50x faster queries
|
|
1232
|
+
- 🧠 **Smart Caching**: LRU, LFU, and TTL strategies with per-collection configuration
|
|
1233
|
+
- 🔐 **Database Encryption**: PIN-based security with 1M PBKDF2 iterations for private keys
|
|
1234
|
+
- 💪 **Force Delete**: Administrative control over permanent documents
|
|
1235
|
+
- 📊 **Enhanced Monitoring**: Detailed performance metrics and optimization tips
|
|
203
1236
|
|
|
204
|
-
|
|
1237
|
+
---
|
|
205
1238
|
|
|
206
|
-
|
|
207
|
-
LacertaDB
|
|
1239
|
+
<div align="center">
|
|
1240
|
+
<strong>🦎 LacertaDB v5.0.0 - Fast, Secure, Browser-Native Database</strong>
|
|
1241
|
+
<br>
|
|
1242
|
+
<i>50x faster queries • Military-grade encryption • Smart caching</i>
|
|
1243
|
+
<br><br>
|
|
1244
|
+
Made with ❤️ by Pixagram Blockchain
|
|
1245
|
+
</div>
|