CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-lokijs

Fast document oriented javascript in-memory database

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

persistence-adapters.mddocs/

Persistence Adapters

Storage backends for different environments including file system, localStorage, IndexedDB, and custom adapters. Adapters provide pluggable persistence for LokiJS databases across various platforms.

Capabilities

Adapter Interface

All persistence adapters implement a common interface for loading and saving databases.

/**
 * Standard persistence adapter interface
 */
interface PersistenceAdapter {
  /**
   * Load database from storage
   * @param dbname - Database name/identifier
   * @param callback - Completion callback (err, data)
   */
  loadDatabase(dbname: string, callback: (err?: Error, data?: string) => void): void;
  
  /**
   * Save database to storage
   * @param dbname - Database name/identifier
   * @param dbref - Database reference or serialized data
   * @param callback - Completion callback (err)
   */
  saveDatabase(dbname: string, dbref: object | string, callback: (err?: Error) => void): void;
  
  /**
   * Delete database from storage (optional)
   * @param dbname - Database name/identifier
   * @param callback - Completion callback (err)
   */
  deleteDatabase?(dbname: string, callback: (err?: Error) => void): void;
}

Built-in Adapters

LokiJS includes several built-in adapters for common environments.

LokiMemoryAdapter

In-memory adapter for temporary storage or testing purposes.

/**
 * In-memory persistence adapter
 * @param options - Adapter options
 */
constructor LokiMemoryAdapter(options?: object);

/**
 * Load database from memory
 * @param dbname - Database name
 * @param callback - Completion callback
 */
loadDatabase(dbname: string, callback: (err?: Error, data?: string) => void): void;

/**
 * Save database to memory
 * @param dbname - Database name
 * @param dbref - Database data
 * @param callback - Completion callback
 */
saveDatabase(dbname: string, dbref: string, callback: (err?: Error) => void): void;

Usage Examples:

// Create database with memory adapter
const memoryAdapter = new loki.LokiMemoryAdapter();
const db = new loki('memory.db', {
  adapter: memoryAdapter
});

// Data persists only in memory during session
db.saveDatabase(); // Saves to memory
db.loadDatabase(); // Loads from memory

LokiLocalStorageAdapter

Browser localStorage adapter for client-side persistence.

/**
 * LocalStorage persistence adapter (browser only)
 */
constructor LokiLocalStorageAdapter();

/**
 * Load database from localStorage
 * @param dbname - Database name (used as localStorage key)
 * @param callback - Completion callback
 */
loadDatabase(dbname: string, callback: (err?: Error, data?: string) => void): void;

/**
 * Save database to localStorage
 * @param dbname - Database name (used as localStorage key)
 * @param dbref - Database serialized data
 * @param callback - Completion callback
 */
saveDatabase(dbname: string, dbref: string, callback: (err?: Error) => void): void;

Usage Examples:

// Browser environment only
const localStorageAdapter = new loki.LokiLocalStorageAdapter();
const db = new loki('app.db', {
  adapter: localStorageAdapter,
  autosave: true,
  autosaveInterval: 4000
});

// Data persists in browser localStorage
db.loadDatabase();

LokiFsAdapter

Node.js file system adapter for server-side file persistence.

/**
 * File system persistence adapter (Node.js only)
 */
constructor LokiFsAdapter();

/**
 * Load database from file
 * @param dbname - Database filename
 * @param callback - Completion callback
 */
loadDatabase(dbname: string, callback: (err?: Error, data?: string) => void): void;

/**
 * Save database to file
 * @param dbname - Database filename
 * @param dbref - Database serialized data
 * @param callback - Completion callback
 */
saveDatabase(dbname: string, dbref: string, callback: (err?: Error) => void): void;

Usage Examples:

// Node.js environment only
const fsAdapter = new loki.LokiFsAdapter();
const db = new loki('data/app.db', {
  adapter: fsAdapter,
  autosave: true,
  autosaveInterval: 10000
});

// Data persists to filesystem
db.loadDatabase(() => {
  console.log('Database loaded from file');
});

LokiPartitioningAdapter

Wrapper adapter that partitions large databases across multiple storage operations.

/**
 * Partitioning adapter wrapper
 * @param adapter - Underlying adapter to wrap
 * @param options - Partitioning options
 */
constructor LokiPartitioningAdapter(adapter: PersistenceAdapter, options?: PartitioningOptions);

interface PartitioningOptions {
  /** Partition key function */
  paging?: boolean;
  /** Partition size in bytes */
  pageSize?: number;
  /** Page delimiter */
  delimiter?: string;
}

/**
 * Load partitioned database
 * @param dbname - Database name
 * @param callback - Completion callback
 */
loadDatabase(dbname: string, callback: (err?: Error, data?: string) => void): void;

/**
 * Save partitioned database
 * @param dbname - Database name
 * @param dbref - Database data
 * @param callback - Completion callback
 */
saveDatabase(dbname: string, dbref: string, callback: (err?: Error) => void): void;

Usage Examples:

// Wrap file system adapter with partitioning
const fsAdapter = new loki.LokiFsAdapter();
const partitioningAdapter = new loki.LokiPartitioningAdapter(fsAdapter, {
  paging: true,
  pageSize: 25 * 1024 * 1024  // 25MB partitions
});

const db = new loki('large-app.db', {
  adapter: partitioningAdapter
});

// Large databases are automatically split across multiple files
db.saveDatabase();

External Adapters

Additional adapters are available as separate files for specialized storage needs.

LokiIndexedAdapter

IndexedDB adapter for advanced browser storage with better performance and storage limits.

/**
 * IndexedDB persistence adapter (browser only)
 * @param appname - Application name for IndexedDB
 * @param options - Adapter options
 */
constructor LokiIndexedAdapter(appname: string, options?: IndexedAdapterOptions);

interface IndexedAdapterOptions {
  /** Serialize method */
  serializeMethod?: string;
  /** Inflate method */
  inflate?: Function;
  /** Deflate method */
  deflate?: Function;
}

/**
 * Load database from IndexedDB
 * @param dbname - Database name
 * @param callback - Completion callback
 */
loadDatabase(dbname: string, callback: (err?: Error, data?: string) => void): void;

/**
 * Save database to IndexedDB
 * @param dbname - Database name
 * @param dbstring - Serialized database data
 * @param callback - Completion callback
 */
saveDatabase(dbname: string, dbstring: string, callback: (err?: Error) => void): void;

/**
 * Delete database from IndexedDB
 * @param dbname - Database name
 * @param callback - Completion callback
 */
deleteDatabase(dbname: string, callback: (err?: Error) => void): void;

/**
 * Get list of databases in IndexedDB
 * @param callback - Completion callback with database list
 */
getDatabaseList(callback: (err?: Error, databases?: string[]) => void): void;

Usage Examples:

// Include the indexed adapter script
const indexedAdapter = new LokiIndexedAdapter('MyApp');
const db = new loki('app.db', {
  adapter: indexedAdapter
});

// Provides better performance than localStorage
db.loadDatabase(() => {
  console.log('Loaded from IndexedDB');
});

// List all databases
indexedAdapter.getDatabaseList((err, databases) => {
  console.log('Available databases:', databases);
});

Custom Adapter Development

Create custom adapters by implementing the PersistenceAdapter interface.

/**
 * Custom adapter implementation example
 */
function CustomAdapter(options) {
  this.options = options || {};
}

CustomAdapter.prototype.loadDatabase = function(dbname, callback) {
  // Implement custom load logic
  // Call callback(error, data) when complete
};

CustomAdapter.prototype.saveDatabase = function(dbname, dbref, callback) {
  // Implement custom save logic
  // Call callback(error) when complete
};

// Optional delete method
CustomAdapter.prototype.deleteDatabase = function(dbname, callback) {
  // Implement custom delete logic
  // Call callback(error) when complete
};

Usage Examples:

// REST API adapter example
function RestAdapter(baseUrl) {
  this.baseUrl = baseUrl;
}

RestAdapter.prototype.loadDatabase = function(dbname, callback) {
  fetch(`${this.baseUrl}/databases/${dbname}`)
    .then(response => response.text())
    .then(data => callback(null, data))
    .catch(err => callback(err));
};

RestAdapter.prototype.saveDatabase = function(dbname, dbref, callback) {
  fetch(`${this.baseUrl}/databases/${dbname}`, {
    method: 'POST',
    body: dbref,
    headers: { 'Content-Type': 'application/json' }
  })
    .then(() => callback())
    .catch(err => callback(err));
};

// Use custom adapter
const restAdapter = new RestAdapter('https://api.example.com');
const db = new loki('remote.db', {
  adapter: restAdapter
});

Adapter Configuration

Configure database to use specific adapters with options.

/**
 * Database adapter configuration
 */
interface DatabaseOptions {
  /** Persistence adapter instance */
  adapter?: PersistenceAdapter;
  /** Persistence method name (deprecated, use adapter) */
  persistenceMethod?: string;
  /** Adapter-specific options */
  adapterOptions?: object;
}

Usage Examples:

// Configure adapter at database creation
const db = new loki('app.db', {
  adapter: new loki.LokiFsAdapter(),
  autosave: true,
  autosaveInterval: 5000
});

// Change adapter after creation
db.persistenceAdapter = new loki.LokiMemoryAdapter();

// Check current adapter
console.log('Using adapter:', db.persistenceAdapter.constructor.name);

Error Handling

Proper error handling with persistence operations.

// Load with error handling
db.loadDatabase((err) => {
  if (err) {
    console.error('Failed to load database:', err.message);
    
    // Handle specific error types
    if (err.name === 'SyntaxError') {
      console.log('Database file corrupted, starting fresh');
      db.collections = [];
    } else if (err.code === 'ENOENT') {
      console.log('Database file not found, will create new');
    }
  } else {
    console.log('Database loaded successfully');
  }
});

// Save with error handling
db.saveDatabase((err) => {
  if (err) {
    console.error('Failed to save database:', err.message);
    
    // Retry logic
    setTimeout(() => {
      db.saveDatabase();
    }, 5000);
  } else {
    console.log('Database saved successfully');
  }
});

Environment-Specific Usage

Browser Environment

// Detect and use appropriate browser adapter
let adapter;
if (typeof indexedDB !== 'undefined') {
  // Use IndexedDB for better performance
  adapter = new LokiIndexedAdapter('MyApp');
} else if (typeof localStorage !== 'undefined') {
  // Fallback to localStorage
  adapter = new loki.LokiLocalStorageAdapter();
} else {
  // Use memory adapter as last resort
  adapter = new loki.LokiMemoryAdapter();
}

const db = new loki('browser.db', { adapter });

Node.js Environment

// Node.js with file system persistence
const path = require('path');
const dataDir = path.join(__dirname, 'data');

const db = new loki(path.join(dataDir, 'app.db'), {
  adapter: new loki.LokiFsAdapter(),
  autosave: true,
  autosaveInterval: 30000  // Save every 30 seconds
});

Electron/Hybrid Apps

// Detect environment and choose adapter
let adapter;
if (typeof window !== 'undefined' && window.require) {
  // Electron renderer process - use file system
  adapter = new loki.LokiFsAdapter();
} else if (typeof indexedDB !== 'undefined') {
  // Browser environment - use IndexedDB
  adapter = new LokiIndexedAdapter('ElectronApp');
} else {
  // Node.js main process - use file system
  adapter = new loki.LokiFsAdapter();
}

const db = new loki('hybrid.db', { adapter });

Properties

// Built-in adapter availability
loki.LokiMemoryAdapter: typeof LokiMemoryAdapter;
loki.LokiLocalStorageAdapter: typeof LokiLocalStorageAdapter;
loki.LokiFsAdapter: typeof LokiFsAdapter;
loki.LokiPartitioningAdapter: typeof LokiPartitioningAdapter;

// Adapter registry
loki.persistenceAdapters: {
  fs: typeof LokiFsAdapter;
  localStorage: typeof LokiLocalStorageAdapter;
};

docs

advanced-querying.md

collection-operations.md

database-management.md

dynamic-views.md

index.md

persistence-adapters.md

tile.json