Writing Adapters

This guide covers building custom storage adapters for NebulaDB with full examples.

SQLite Adapter

The SQLite Adapter persists data to a SQLite database file.

Installation

npm install @nebula/adapter-sqlite

Usage

import { createDb } from '@nebula/core';
import { SQLiteAdapter } from '@nebula/adapter-sqlite';

const db = createDb({
  adapter: new SQLiteAdapter('data.sqlite')
});
const users = db.collection('users');
await users.insert({ name: 'Alice', age: 30 });

Options

const adapter = new SQLiteAdapter('data.sqlite', {
  readonly: false,
  fileMustExist: false,
  timeout: 5000,
  verbose: console.log
});

Redis Adapter

Installation

npm install @nebula/adapter-redis

Usage

import { createDb } from '@nebula/core';
import { RedisAdapter } from '@nebula/adapter-redis';

const db = createDb({
  adapter: new RedisAdapter(
    { host: 'localhost', port: 6379, password: 'your-password' },
    'nebula:' // Key prefix
  )
});
await db.adapter.close();

Comparing Adapters

FeatureMemoryLocalStorageIndexedDBFileSystemSQLiteRedis
Persistence
Browser
Node.js
Edge
Transactions
ScalabilityLowLowMediumMediumMediumHigh
SpeedVery FastFastMediumMediumFastVery Fast
External DepsNoneNoneNoneNoneNoneRedis

Choosing the Right Adapter

Creating Custom Adapters

Implement the Adapter interface:

import { Adapter, Document } from '@nebula/core';

class CustomAdapter implements Adapter {
  async load(): Promise<Record<string, Document[]>> {
    // Load data from your storage
  }
  async save(data: Record<string, Document[]>): Promise<void> {
    // Save data to your storage
  }
}

Example: MongoDB Adapter

import { Adapter, Document } from '@nebula/core';
import { MongoClient, Db } from 'mongodb';

export class MongoDBAdapter implements Adapter {
  private client: MongoClient;
  private db: Db | null = null;
  private dbName: string;

  constructor(uri: string, dbName: string) {
    this.client = new MongoClient(uri);
    this.dbName = dbName;
  }

  private async connect(): Promise<Db> {
    if (!this.db) {
      await this.client.connect();
      this.db = this.client.db(this.dbName);
    }
    return this.db;
  }

  async load(): Promise<Record<string, Document[]>> {
    const db = await this.connect();
    const result: Record<string, Document[]> = {};
    const collections = await db.listCollections().toArray();
    for (const collection of collections) {
      const collectionName = collection.name;
      if (collectionName.startsWith('system.')) continue;
      const docs = await db.collection(collectionName).find().toArray();
      result[collectionName] = docs.map(doc => {
        const { _id, ...rest } = doc;
        return { id: _id.toString(), ...rest };
      });
    }
    return result;
  }

  async save(data: Record<string, Document[]>): Promise<void> {
    const db = await this.connect();
    for (const [collectionName, documents] of Object.entries(data)) {
      const collection = db.collection(collectionName);
      await collection.deleteMany({});
      if (documents.length > 0) await collection.insertMany(documents);
    }
  }

  async close(): Promise<void> {
    if (this.client) await this.client.close();
  }
}