or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

database-management.mdevents-utilities.mdindex.mdkey-ranges.mdobject-stores.mdtransactions-cursors.md
tile.json

database-management.mddocs/

Database Management

Core database lifecycle operations including opening, creating, upgrading, and deleting databases with full version management support.

Capabilities

IDBFactory (indexedDB)

The main factory interface for creating and managing database connections.

/**
 * Opens a database connection with optional version upgrade
 * @param name - Database name
 * @param version - Optional version number (defaults to 1)
 * @returns IDBOpenDBRequest for handling success/upgrade events
 */
open(name: string, version?: number): IDBOpenDBRequest;

/**
 * Deletes a database completely
 * @param name - Database name to delete
 * @returns IDBOpenDBRequest for handling completion
 */
deleteDatabase(name: string): IDBOpenDBRequest;

/**
 * Lists all available databases
 * @returns Promise resolving to array of database info
 */
databases(): Promise<Array<{ name: string; version: number }>>;

Usage Examples:

import "fake-indexeddb/auto";

// Open database (creates if doesn't exist)
const request = indexedDB.open("myapp", 2);

request.onsuccess = (event) => {
  const db = event.target.result;
  console.log("Database opened:", db.name, "version", db.version);
};

request.onerror = (event) => {
  console.error("Database error:", event.target.error);
};

// Delete database
const deleteRequest = indexedDB.deleteDatabase("oldapp");
deleteRequest.onsuccess = () => console.log("Database deleted");

// List all databases
indexedDB.databases().then(databases => {
  console.log("Available databases:", databases);
});

IDBDatabase

Represents an active database connection with object stores and transactions.

interface IDBDatabase extends EventTarget {
  /** Database name (readonly) */
  readonly name: string;
  
  /** Current database version (readonly) */
  readonly version: number;
  
  /** List of object store names (readonly) */
  readonly objectStoreNames: DOMStringList;
  
  /**
   * Creates a new object store (only during versionchange transaction)
   * @param name - Object store name
   * @param options - Store configuration options
   * @returns Created object store
   */
  createObjectStore(name: string, options?: {
    keyPath?: string | string[];
    autoIncrement?: boolean;
  }): IDBObjectStore;
  
  /**
   * Deletes an object store (only during versionchange transaction)
   * @param name - Object store name to delete
   */
  deleteObjectStore(name: string): void;
  
  /**
   * Creates a new transaction
   * @param storeNames - Object store names to include in transaction
   * @param mode - Transaction mode (default: "readonly")
   * @param options - Transaction options
   * @returns New transaction
   */
  transaction(
    storeNames: string | string[],
    mode?: "readonly" | "readwrite" | "versionchange",
    options?: { durability?: "default" | "strict" | "relaxed" }
  ): IDBTransaction;
  
  /**
   * Closes the database connection
   */
  close(): void;
  
  // Event handlers
  onabort: ((event: Event) => void) | null;
  onclose: ((event: Event) => void) | null;
  onerror: ((event: Event) => void) | null;
  onversionchange: ((event: IDBVersionChangeEvent) => void) | null;
}

Usage Examples:

// Database upgrade handling
const request = indexedDB.open("ecommerce", 3);

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  const transaction = event.target.transaction;
  const oldVersion = event.oldVersion;
  const newVersion = event.newVersion;
  
  console.log(`Upgrading from version ${oldVersion} to ${newVersion}`);
  
  // Create object stores based on version
  if (oldVersion < 1) {
    const productsStore = db.createObjectStore("products", { 
      keyPath: "id", 
      autoIncrement: true 
    });
    productsStore.createIndex("by_category", "category");
    productsStore.createIndex("by_price", "price");
  }
  
  if (oldVersion < 2) {
    const ordersStore = db.createObjectStore("orders", { 
      keyPath: "orderId" 
    });
    ordersStore.createIndex("by_customer", "customerId");
    ordersStore.createIndex("by_date", "orderDate");
  }
  
  if (oldVersion < 3) {
    // Add new index to existing store
    const productsStore = transaction.objectStore("products");
    productsStore.createIndex("by_name", "name", { unique: false });
  }
};

request.onsuccess = (event) => {
  const db = event.target.result;
  
  // Handle version change from other connections
  db.onversionchange = () => {
    console.log("Database version changed, closing connection");
    db.close();
  };
  
  // Use database...
  const tx = db.transaction(["products", "orders"], "readonly");
  // ... perform operations
  
  // Always close when done
  db.close();
};

IDBOpenDBRequest

Extended request interface for database opening operations with upgrade events.

interface IDBOpenDBRequest extends IDBRequest {
  /**
   * Fired when database needs to be upgraded or created
   */
  onupgradeneeded: ((event: IDBVersionChangeEvent) => void) | null;
  
  /**
   * Fired when database opening is blocked by other connections
   */
  onblocked: ((event: Event) => void) | null;
}

Usage Examples:

const request = indexedDB.open("analytics", 1);

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  
  // First time or version upgrade
  console.log("Setting up database schema");
  
  const eventsStore = db.createObjectStore("events", {
    keyPath: "id",
    autoIncrement: true
  });
  
  eventsStore.createIndex("by_timestamp", "timestamp");
  eventsStore.createIndex("by_type", "eventType");
  eventsStore.createIndex("by_user", "userId");
};

request.onblocked = (event) => {
  console.warn("Database opening blocked - close other connections");
  
  // Optionally show user message to close other tabs
  alert("Please close other tabs using this application");
};

request.onsuccess = (event) => {
  const db = event.target.result;
  console.log("Database ready for use");
};

request.onerror = (event) => {
  console.error("Failed to open database:", event.target.error);
};

Database Versioning Best Practices

// Handle multiple version upgrades gracefully
const request = indexedDB.open("app_data", 5);

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  const transaction = event.target.transaction;
  const oldVersion = event.oldVersion;
  
  // Progressive upgrades
  if (oldVersion < 1) {
    // Initial schema
    const usersStore = db.createObjectStore("users", { keyPath: "id" });
    usersStore.createIndex("email", "email", { unique: true });
  }
  
  if (oldVersion < 2) {
    // Add new store
    const settingsStore = db.createObjectStore("settings", { keyPath: "key" });
  }
  
  if (oldVersion < 3) {
    // Modify existing store
    const usersStore = transaction.objectStore("users");
    usersStore.createIndex("created_at", "createdAt");
  }
  
  if (oldVersion < 4) {
    // Data migration
    const usersStore = transaction.objectStore("users");
    usersStore.openCursor().onsuccess = (event) => {
      const cursor = event.target.result;
      if (cursor) {
        const user = cursor.value;
        // Add new field with default value
        user.lastLogin = user.lastLogin || new Date().toISOString();
        cursor.update(user);
        cursor.continue();
      }
    };
  }
  
  if (oldVersion < 5) {
    // Remove old index, add new compound index
    const usersStore = transaction.objectStore("users");
    try {
      usersStore.deleteIndex("old_index");
    } catch (e) {
      // Index might not exist
    }
    usersStore.createIndex("email_status", ["email", "status"]);
  }
};

Error Handling

Common database management errors and handling:

const request = indexedDB.open("example", 1);

request.onerror = (event) => {
  const error = event.target.error;
  
  switch (error.name) {
    case "VersionError":
      console.error("Invalid version number");
      break;
    case "InvalidStateError":
      console.error("Invalid operation state");
      break;  
    case "AbortError":
      console.error("Operation was aborted");
      break;
    default:
      console.error("Database error:", error.message);
  }
};

// Handle blocked database deletion
const deleteRequest = indexedDB.deleteDatabase("example");

deleteRequest.onblocked = () => {
  console.log("Database deletion blocked - connections still open");
};

deleteRequest.onsuccess = () => {
  console.log("Database successfully deleted");
};