newOS for Developers

Cache System

IndexedDB-based caching layer using Dexie for persistent client-side storage.

packages/newgraph-signals/src/cache.ts

Overview

The cache system provides a graph-based storage layer built on IndexedDB via Dexie. It stores edges between entities (users, folders, posts) enabling efficient traversal and relationship queries.

import { Store } from "newgraph-signals";

// Create a store with custom tables
const cache = Store<MyTables>("my-cache", {
  users: "id,username",
  folders: "id,ownerId,updated"
});

Store Class

Extended Dexie class with transaction queue management and edge storage capabilities.

Store<T>(
  name: string = "iosdk-cache",
  stores: Record<string, any>
): T & _Store

Parameters

  • name - Database name (default: "iosdk-cache")
  • stores - Table definitions with index schemas

Edge Storage

The cache uses a graph edge model to represent relationships between entities. All edges are stored in a special __EDGES table.

IGraphEdge Interface

type IGraphEdge = {
  id?: string;        // Edge identifier
  fromLabel?: string; // Source entity type (e.g., "user")
  toLabel?: string;   // Target entity type (e.g., "folder")
  from?: string;      // Source entity ID
  to?: string;        // Target entity ID
  label: string;      // Relationship type (e.g., "owns", "contains")
  props?: any;        // Additional edge properties
};

Edge Entry (Stored Format)

type IGraphEdgeEntry = IGraphEdge & {
  cached: string;   // ISO timestamp when cached
  __outE: string;   // Outbound edge key: "fromLabel+from+label+toLabel+to"
  __inE: string;    // Inbound edge key: "toLabel+to+label+fromLabel+from"
};

The __outE and __inE composite keys enable efficient bidirectional traversal.

Edge Methods

MethodDescription
storeEdge(edge)Store a single edge relationship
storeEdges(edges)Bulk store multiple edges
storeEdgesDelayed(edges)Bulk store with transaction queuing
deleteEdges(ids)Remove edges by ID

Usage Example

// Store a relationship
await cache.storeEdge({
  fromLabel: "user",
  from: "user123",
  label: "owns",
  toLabel: "folder",
  to: "folder456"
});

// Bulk store multiple relationships
await cache.storeEdges([
  { fromLabel: "folder", from: "f1", label: "contains", toLabel: "post", to: "p1" },
  { fromLabel: "folder", from: "f1", label: "contains", toLabel: "post", to: "p2" }
]);

Transaction Queue

The store manages concurrent IndexedDB transactions with a queue system to prevent overwhelming the database with too many parallel operations.

MethodDescription
block()Request a transaction slot (waits if at max)
unblock()Release a transaction slot
flushQueue(minItems?)Wait for queue to drain
Max Transactions: 20 concurrent transactions allowed. Queue blocks additional requests until slots free up.

DelayedTable Interface

Extended Dexie.Table with delayed bulk operations that respect the transaction queue.

interface DelayedTable<T, U> extends Dexie.Table<T, U> {
  bulkAddDelayed: Dexie.Table["bulkAdd"];
  bulkPutDelayed: Dexie.Table["bulkPut"];
}

Use bulkAddDelayed and bulkPutDelayed for large batch operations to prevent transaction overflow.

Edges Table Schema

// Index definition
"++id,__outE,__inE,updated"

// Enables queries like:
// - Find all edges FROM a specific entity
cache.__EDGES.where("__outE").startsWith("user+user123+");

// - Find all edges TO a specific entity
cache.__EDGES.where("__inE").startsWith("folder+folder456+");

Common Patterns

Cache with Action

// Actions automatically cache results
export function readFolder(params: { id: string }) {
  const cache = db.folders.where("id").equals(params.id);
  
  return progressiveHandler(
    params,
    cache,
    async (progress, cache, params) => {
      const result = await api.folder.read(params);
      await db.folders.put(result);  // Cache the result
      return { done: true };
    }
  );
}

Relationship Caching

// Cache folder-post relationships
async function cacheFolderPosts(folderId: string, posts: Post[]) {
  await cache.storeEdges(
    posts.map(post => ({
      fromLabel: "folder",
      from: folderId,
      label: "contains",
      toLabel: "post",
      to: post.id
    }))
  );
}

Imported Utilities

CountersUtility

Transaction counter for tracking concurrent operations.

XPromiseUtility

Externally resolvable promise for queue management.