0
# Persistence Adapters
1
2
Storage backends for different environments including file system, localStorage, IndexedDB, and custom adapters. Adapters provide pluggable persistence for LokiJS databases across various platforms.
3
4
## Capabilities
5
6
### Adapter Interface
7
8
All persistence adapters implement a common interface for loading and saving databases.
9
10
```javascript { .api }
11
/**
12
* Standard persistence adapter interface
13
*/
14
interface PersistenceAdapter {
15
/**
16
* Load database from storage
17
* @param dbname - Database name/identifier
18
* @param callback - Completion callback (err, data)
19
*/
20
loadDatabase(dbname: string, callback: (err?: Error, data?: string) => void): void;
21
22
/**
23
* Save database to storage
24
* @param dbname - Database name/identifier
25
* @param dbref - Database reference or serialized data
26
* @param callback - Completion callback (err)
27
*/
28
saveDatabase(dbname: string, dbref: object | string, callback: (err?: Error) => void): void;
29
30
/**
31
* Delete database from storage (optional)
32
* @param dbname - Database name/identifier
33
* @param callback - Completion callback (err)
34
*/
35
deleteDatabase?(dbname: string, callback: (err?: Error) => void): void;
36
}
37
```
38
39
### Built-in Adapters
40
41
LokiJS includes several built-in adapters for common environments.
42
43
#### LokiMemoryAdapter
44
45
In-memory adapter for temporary storage or testing purposes.
46
47
```javascript { .api }
48
/**
49
* In-memory persistence adapter
50
* @param options - Adapter options
51
*/
52
constructor LokiMemoryAdapter(options?: object);
53
54
/**
55
* Load database from memory
56
* @param dbname - Database name
57
* @param callback - Completion callback
58
*/
59
loadDatabase(dbname: string, callback: (err?: Error, data?: string) => void): void;
60
61
/**
62
* Save database to memory
63
* @param dbname - Database name
64
* @param dbref - Database data
65
* @param callback - Completion callback
66
*/
67
saveDatabase(dbname: string, dbref: string, callback: (err?: Error) => void): void;
68
```
69
70
**Usage Examples:**
71
72
```javascript
73
// Create database with memory adapter
74
const memoryAdapter = new loki.LokiMemoryAdapter();
75
const db = new loki('memory.db', {
76
adapter: memoryAdapter
77
});
78
79
// Data persists only in memory during session
80
db.saveDatabase(); // Saves to memory
81
db.loadDatabase(); // Loads from memory
82
```
83
84
#### LokiLocalStorageAdapter
85
86
Browser localStorage adapter for client-side persistence.
87
88
```javascript { .api }
89
/**
90
* LocalStorage persistence adapter (browser only)
91
*/
92
constructor LokiLocalStorageAdapter();
93
94
/**
95
* Load database from localStorage
96
* @param dbname - Database name (used as localStorage key)
97
* @param callback - Completion callback
98
*/
99
loadDatabase(dbname: string, callback: (err?: Error, data?: string) => void): void;
100
101
/**
102
* Save database to localStorage
103
* @param dbname - Database name (used as localStorage key)
104
* @param dbref - Database serialized data
105
* @param callback - Completion callback
106
*/
107
saveDatabase(dbname: string, dbref: string, callback: (err?: Error) => void): void;
108
```
109
110
**Usage Examples:**
111
112
```javascript
113
// Browser environment only
114
const localStorageAdapter = new loki.LokiLocalStorageAdapter();
115
const db = new loki('app.db', {
116
adapter: localStorageAdapter,
117
autosave: true,
118
autosaveInterval: 4000
119
});
120
121
// Data persists in browser localStorage
122
db.loadDatabase();
123
```
124
125
#### LokiFsAdapter
126
127
Node.js file system adapter for server-side file persistence.
128
129
```javascript { .api }
130
/**
131
* File system persistence adapter (Node.js only)
132
*/
133
constructor LokiFsAdapter();
134
135
/**
136
* Load database from file
137
* @param dbname - Database filename
138
* @param callback - Completion callback
139
*/
140
loadDatabase(dbname: string, callback: (err?: Error, data?: string) => void): void;
141
142
/**
143
* Save database to file
144
* @param dbname - Database filename
145
* @param dbref - Database serialized data
146
* @param callback - Completion callback
147
*/
148
saveDatabase(dbname: string, dbref: string, callback: (err?: Error) => void): void;
149
```
150
151
**Usage Examples:**
152
153
```javascript
154
// Node.js environment only
155
const fsAdapter = new loki.LokiFsAdapter();
156
const db = new loki('data/app.db', {
157
adapter: fsAdapter,
158
autosave: true,
159
autosaveInterval: 10000
160
});
161
162
// Data persists to filesystem
163
db.loadDatabase(() => {
164
console.log('Database loaded from file');
165
});
166
```
167
168
#### LokiPartitioningAdapter
169
170
Wrapper adapter that partitions large databases across multiple storage operations.
171
172
```javascript { .api }
173
/**
174
* Partitioning adapter wrapper
175
* @param adapter - Underlying adapter to wrap
176
* @param options - Partitioning options
177
*/
178
constructor LokiPartitioningAdapter(adapter: PersistenceAdapter, options?: PartitioningOptions);
179
180
interface PartitioningOptions {
181
/** Partition key function */
182
paging?: boolean;
183
/** Partition size in bytes */
184
pageSize?: number;
185
/** Page delimiter */
186
delimiter?: string;
187
}
188
189
/**
190
* Load partitioned database
191
* @param dbname - Database name
192
* @param callback - Completion callback
193
*/
194
loadDatabase(dbname: string, callback: (err?: Error, data?: string) => void): void;
195
196
/**
197
* Save partitioned database
198
* @param dbname - Database name
199
* @param dbref - Database data
200
* @param callback - Completion callback
201
*/
202
saveDatabase(dbname: string, dbref: string, callback: (err?: Error) => void): void;
203
```
204
205
**Usage Examples:**
206
207
```javascript
208
// Wrap file system adapter with partitioning
209
const fsAdapter = new loki.LokiFsAdapter();
210
const partitioningAdapter = new loki.LokiPartitioningAdapter(fsAdapter, {
211
paging: true,
212
pageSize: 25 * 1024 * 1024 // 25MB partitions
213
});
214
215
const db = new loki('large-app.db', {
216
adapter: partitioningAdapter
217
});
218
219
// Large databases are automatically split across multiple files
220
db.saveDatabase();
221
```
222
223
### External Adapters
224
225
Additional adapters are available as separate files for specialized storage needs.
226
227
#### LokiIndexedAdapter
228
229
IndexedDB adapter for advanced browser storage with better performance and storage limits.
230
231
```javascript { .api }
232
/**
233
* IndexedDB persistence adapter (browser only)
234
* @param appname - Application name for IndexedDB
235
* @param options - Adapter options
236
*/
237
constructor LokiIndexedAdapter(appname: string, options?: IndexedAdapterOptions);
238
239
interface IndexedAdapterOptions {
240
/** Serialize method */
241
serializeMethod?: string;
242
/** Inflate method */
243
inflate?: Function;
244
/** Deflate method */
245
deflate?: Function;
246
}
247
248
/**
249
* Load database from IndexedDB
250
* @param dbname - Database name
251
* @param callback - Completion callback
252
*/
253
loadDatabase(dbname: string, callback: (err?: Error, data?: string) => void): void;
254
255
/**
256
* Save database to IndexedDB
257
* @param dbname - Database name
258
* @param dbstring - Serialized database data
259
* @param callback - Completion callback
260
*/
261
saveDatabase(dbname: string, dbstring: string, callback: (err?: Error) => void): void;
262
263
/**
264
* Delete database from IndexedDB
265
* @param dbname - Database name
266
* @param callback - Completion callback
267
*/
268
deleteDatabase(dbname: string, callback: (err?: Error) => void): void;
269
270
/**
271
* Get list of databases in IndexedDB
272
* @param callback - Completion callback with database list
273
*/
274
getDatabaseList(callback: (err?: Error, databases?: string[]) => void): void;
275
```
276
277
**Usage Examples:**
278
279
```javascript
280
// Include the indexed adapter script
281
const indexedAdapter = new LokiIndexedAdapter('MyApp');
282
const db = new loki('app.db', {
283
adapter: indexedAdapter
284
});
285
286
// Provides better performance than localStorage
287
db.loadDatabase(() => {
288
console.log('Loaded from IndexedDB');
289
});
290
291
// List all databases
292
indexedAdapter.getDatabaseList((err, databases) => {
293
console.log('Available databases:', databases);
294
});
295
```
296
297
### Custom Adapter Development
298
299
Create custom adapters by implementing the PersistenceAdapter interface.
300
301
```javascript { .api }
302
/**
303
* Custom adapter implementation example
304
*/
305
function CustomAdapter(options) {
306
this.options = options || {};
307
}
308
309
CustomAdapter.prototype.loadDatabase = function(dbname, callback) {
310
// Implement custom load logic
311
// Call callback(error, data) when complete
312
};
313
314
CustomAdapter.prototype.saveDatabase = function(dbname, dbref, callback) {
315
// Implement custom save logic
316
// Call callback(error) when complete
317
};
318
319
// Optional delete method
320
CustomAdapter.prototype.deleteDatabase = function(dbname, callback) {
321
// Implement custom delete logic
322
// Call callback(error) when complete
323
};
324
```
325
326
**Usage Examples:**
327
328
```javascript
329
// REST API adapter example
330
function RestAdapter(baseUrl) {
331
this.baseUrl = baseUrl;
332
}
333
334
RestAdapter.prototype.loadDatabase = function(dbname, callback) {
335
fetch(`${this.baseUrl}/databases/${dbname}`)
336
.then(response => response.text())
337
.then(data => callback(null, data))
338
.catch(err => callback(err));
339
};
340
341
RestAdapter.prototype.saveDatabase = function(dbname, dbref, callback) {
342
fetch(`${this.baseUrl}/databases/${dbname}`, {
343
method: 'POST',
344
body: dbref,
345
headers: { 'Content-Type': 'application/json' }
346
})
347
.then(() => callback())
348
.catch(err => callback(err));
349
};
350
351
// Use custom adapter
352
const restAdapter = new RestAdapter('https://api.example.com');
353
const db = new loki('remote.db', {
354
adapter: restAdapter
355
});
356
```
357
358
### Adapter Configuration
359
360
Configure database to use specific adapters with options.
361
362
```javascript { .api }
363
/**
364
* Database adapter configuration
365
*/
366
interface DatabaseOptions {
367
/** Persistence adapter instance */
368
adapter?: PersistenceAdapter;
369
/** Persistence method name (deprecated, use adapter) */
370
persistenceMethod?: string;
371
/** Adapter-specific options */
372
adapterOptions?: object;
373
}
374
```
375
376
**Usage Examples:**
377
378
```javascript
379
// Configure adapter at database creation
380
const db = new loki('app.db', {
381
adapter: new loki.LokiFsAdapter(),
382
autosave: true,
383
autosaveInterval: 5000
384
});
385
386
// Change adapter after creation
387
db.persistenceAdapter = new loki.LokiMemoryAdapter();
388
389
// Check current adapter
390
console.log('Using adapter:', db.persistenceAdapter.constructor.name);
391
```
392
393
### Error Handling
394
395
Proper error handling with persistence operations.
396
397
```javascript
398
// Load with error handling
399
db.loadDatabase((err) => {
400
if (err) {
401
console.error('Failed to load database:', err.message);
402
403
// Handle specific error types
404
if (err.name === 'SyntaxError') {
405
console.log('Database file corrupted, starting fresh');
406
db.collections = [];
407
} else if (err.code === 'ENOENT') {
408
console.log('Database file not found, will create new');
409
}
410
} else {
411
console.log('Database loaded successfully');
412
}
413
});
414
415
// Save with error handling
416
db.saveDatabase((err) => {
417
if (err) {
418
console.error('Failed to save database:', err.message);
419
420
// Retry logic
421
setTimeout(() => {
422
db.saveDatabase();
423
}, 5000);
424
} else {
425
console.log('Database saved successfully');
426
}
427
});
428
```
429
430
## Environment-Specific Usage
431
432
### Browser Environment
433
434
```javascript
435
// Detect and use appropriate browser adapter
436
let adapter;
437
if (typeof indexedDB !== 'undefined') {
438
// Use IndexedDB for better performance
439
adapter = new LokiIndexedAdapter('MyApp');
440
} else if (typeof localStorage !== 'undefined') {
441
// Fallback to localStorage
442
adapter = new loki.LokiLocalStorageAdapter();
443
} else {
444
// Use memory adapter as last resort
445
adapter = new loki.LokiMemoryAdapter();
446
}
447
448
const db = new loki('browser.db', { adapter });
449
```
450
451
### Node.js Environment
452
453
```javascript
454
// Node.js with file system persistence
455
const path = require('path');
456
const dataDir = path.join(__dirname, 'data');
457
458
const db = new loki(path.join(dataDir, 'app.db'), {
459
adapter: new loki.LokiFsAdapter(),
460
autosave: true,
461
autosaveInterval: 30000 // Save every 30 seconds
462
});
463
```
464
465
### Electron/Hybrid Apps
466
467
```javascript
468
// Detect environment and choose adapter
469
let adapter;
470
if (typeof window !== 'undefined' && window.require) {
471
// Electron renderer process - use file system
472
adapter = new loki.LokiFsAdapter();
473
} else if (typeof indexedDB !== 'undefined') {
474
// Browser environment - use IndexedDB
475
adapter = new LokiIndexedAdapter('ElectronApp');
476
} else {
477
// Node.js main process - use file system
478
adapter = new loki.LokiFsAdapter();
479
}
480
481
const db = new loki('hybrid.db', { adapter });
482
```
483
484
## Properties
485
486
```javascript { .api }
487
// Built-in adapter availability
488
loki.LokiMemoryAdapter: typeof LokiMemoryAdapter;
489
loki.LokiLocalStorageAdapter: typeof LokiLocalStorageAdapter;
490
loki.LokiFsAdapter: typeof LokiFsAdapter;
491
loki.LokiPartitioningAdapter: typeof LokiPartitioningAdapter;
492
493
// Adapter registry
494
loki.persistenceAdapters: {
495
fs: typeof LokiFsAdapter;
496
localStorage: typeof LokiLocalStorageAdapter;
497
};
498
```