Skip to main content

Storage Provider

Interface for implementing custom storage backends.

Import

import { IStorageProvider, NodeData, EdgeData } from 'grafio';

Interface

interface IStorageProvider {
// Lifecycle
clear(): Promise<void>;

// Node mutations
insertNode(node: NodeData, transaction?: ITransactionHandle): Promise<void>;
deleteNode(id: string, transaction?: ITransactionHandle): Promise<void>;

// Node queries
hasNode(id: string, transaction?: ITransactionHandle): Promise<boolean>;
getNode(id: string, transaction?: ITransactionHandle): Promise<NodeData | undefined>;
getNodesByIds(ids: string[], transaction?: ITransactionHandle): Promise<Map<string, NodeData>>;
getNodeCount(options?: StorageQueryOptions): Promise<number>;
aggregateNodeProperty(key: string, options?: StorageQueryOptions): Promise<AggregateResult>;
getNodes(options?: StorageQueryOptions): Promise<NodeData[]>;

// Edge mutations
insertEdge(edge: EdgeData, transaction?: ITransactionHandle): Promise<void>;
deleteEdge(id: string, transaction?: ITransactionHandle): Promise<void>;

// Edge queries
hasEdge(id: string, transaction?: ITransactionHandle): Promise<boolean>;
getEdge(id: string, transaction?: ITransactionHandle): Promise<EdgeData | undefined>;
getEdgeCount(options?: StorageQueryOptions): Promise<number>;
aggregateEdgeProperty(key: string, options?: StorageQueryOptions): Promise<AggregateResult>;
getEdges(options?: StorageQueryOptions): Promise<EdgeData[]>;

// Adjacency queries
getEdgesBySource(nodeId: string, options?: StorageQueryOptions): Promise<EdgeData[]>;
getEdgesByTarget(nodeId: string, options?: StorageQueryOptions): Promise<EdgeData[]>;
getDirectEdgesBetween(sourceId: string, targetId: string, options?: StorageQueryOptions): Promise<EdgeData[]>;

// Property mutations
addProperty(target: 'node' | 'edge', id: string, key: string, value: unknown, transaction?: ITransactionHandle): Promise<void>;
updateProperty(target: 'node' | 'edge', id: string, key: string, value: unknown, transaction?: ITransactionHandle): Promise<void>;
deleteProperty(target: 'node' | 'edge', id: string, key: string, transaction?: ITransactionHandle): Promise<void>;
clearProperties(target: 'node' | 'edge', id: string, transaction?: ITransactionHandle): Promise<void>;

// Index management
createIndex(target: 'node' | 'edge', propertyKey: string, type?: string): Promise<void>;
hasIndex(target: 'node' | 'edge', propertyKey: string): Promise<boolean>;

// Serialization
exportJSON(): Promise<GraphData>;
importJSON(data: GraphData): Promise<void>;
}

Data Types

NodeData

interface NodeData {
id: string;
type: string;
properties: Record<string, Primitive>;
}

EdgeData

interface EdgeData {
id: string;
sourceId: string;
targetId: string;
type: string;
properties: Record<string, Primitive>;
}

StorageQueryOptions

interface StorageQueryOptions {
nodeType?: string;
edgeType?: string;
limit?: number;
offset?: number;
}

Example Implementation

class MyStorageProvider implements IStorageProvider {
private nodes: Map<string, Node> = new Map();
private edges: Map<string, Edge> = new Map();

async addNode(nodeData: NodeData): Promise<Node> {
const node = new Node(nodeData.id, nodeData.type, nodeData.properties);
this.nodes.set(node.id, node);
return node;
}

async getNode(id: string): Promise<Node | undefined> {
return this.nodes.get(id);
}

async hasNode(id: string): Promise<boolean> {
return this.nodes.has(id);
}

async getNodes(options?: StorageQueryOptions): Promise<readonly Node[]> {
const nodes = Array.from(this.nodes.values());
return this.filterNodes(nodes, options);
}

// ... implement remaining methods ...

private filterNodes(nodes: Node[], options?: StorageQueryOptions): Node[] {
if (!options?.nodeType) return nodes;
return nodes.filter(n => n.type === options.nodeType);
}
}

Using Custom Provider

import { Graph } from 'grafio';
import type { IStorageProvider } from 'grafio';

const myProvider: IStorageProvider = new MyStorageProvider();
const graph = new Graph(myProvider);