Skip to content

Property Graph

lostcause edited this page Aug 24, 2026 · 1 revision

Property graph

PolyGraph is the main container: typed nodes and edges with arbitrary data payloads, backed by a pluggable persistence adapter.

new PolyGraph(
  adapter?: PersistenceAdapter,
  hotCacheMax?: number,
  embedding?: EmbeddingProvider,
  transform?: DataTransform,
  createVectorIndex?: (onChange: (id: string) => void) => VectorIndexLike,
)

Without an adapter it uses MemoryAdapter. The default hot-node limit is 50,000 — edges stay indexed when nodes are evicted, and dirty evicted nodes are retained until persistence completes. Synchronous queries and mutations operate on currently loaded nodes; use getNodeSafe(id) to restore an evicted node before mutating it.

Lifecycle

  • warm() / load() — load persisted nodes, vectors, and edges. Call it before querying an existing database. warm() is idempotent.
  • flush() — immediately persist queued mutations (serialized).
  • save() — write the complete currently loaded graph without clearing dirty state.
  • dispose() — flush, clear memory, then close the adapter.
  • clear() — clear in-memory state only; does not delete adapter contents.
  • prune(maxNodes) — remove the oldest loaded nodes, applying ownership rules.
  • transaction(callback, options?) — atomic read-your-own-writes, rollback, nested-transaction rejection, and post-commit events. Options may include operationId, actor, baseRevision, and metadata, retained in the durable mutation record when the adapter supports a change feed. See Database core.

Nodes

graph.addNode({
  id: 'doc_1',
  type: 'document',
  data: { title: 'Quantum Computing' },
  vector: new Float64Array([0.95, 0.20, 0.10]),
  insertedAt: Date.now(),
  updatedAt: Date.now(),
})
  • addNode(node) / addNodes(nodes) — insert or replace. addNodes validates the whole batch before inserting any of it, coalesces change events into one flush, and schedules persistence once — prefer it over a loop of addNode for large inserts.
  • getNode(id) — a detached snapshot of a loaded node, synchronously. getNodeSafe(id) restores an evicted node first.
  • updateNode(id, data, vector?, activation?) / updateNodeSafe(...) — shallow-merge data, optionally replace vector or durable activation.
  • patchNode(id, patch, options?) — atomic set/unset/increment/ compareAndSet operations against a loaded node. Paths under data. (or unprefixed) target node data; updatedAt and the provenance fields below are also directly patchable as top-level paths.
  • removeNodeVector(id) / removeNodeVectorSafe(id) — clear a node's vector while retaining the node.
  • removeNode(id) — removes the node, all connected edges, and owned descendants. removeNodeSafe(id) restores an evicted node first, recursively restoring owned descendants — call warm() first so ownership edges are indexed.
  • whereType(type) — detached snapshots of loaded nodes of one type.
  • size / loadedSize — count of currently loaded nodes (not total persisted). hasLoadedNode(id) checks working-set membership.
  • persistedSize(), getNodesByType(type), getNodesByTypeOrdered(type, field, direction?), countNodesByType(type), deleteNodesByType(type) — async convenience methods over the full persisted store.
  • vectors — the public VectorIndex (or substituted engine) backing similarity search. See Vector search & embeddings.

Provenance & memory-class fields

PolyNode also carries optional fields, none of which affect existing nodes that don't set them: memoryClass (overrides the type's default — see Adaptive memory), confidence ([0, 1]), source, observedAt (may predate insertedAt), derivedFrom (soft-referenced node ids), supersedes, and contradicts (soft references). These are ordinary node fields, not activation state — static until explicitly revised, riding the normal addNode/updateNode/patchNode write paths.

Edges

  • addEdge(source, type, target, data?, ownership?) — one unique directed edge.
  • getEdges(source, type?), getEdgeTargets(source, type), getEdgeSources(target, type) — reads.
  • removeEdges(source, type?, target?) — removes matching outgoing edges.

Ownership is stored on the edge and controls cascade behavior:

Ownership Removing the edge...
reference (default) never removes the target
shared keeps the target; invokes the protected onOrphan hook when it loses its final incoming edge
owned removes the target when it loses its final owning source (cycle-safe cascade)

Traversal

  • walkAncestors(id, edgeType) — walk the parent chain backwards through incoming edges. Returns root-to-start, inclusive. Cycle-safe.
  • walkDescendants(id, edgeType) — walk the child chain forwards through outgoing edges. Returns start-to-deepest-child, inclusive. Cycle-safe.
  • searchNodes(text, type, threshold?, topK?) — full-text shorthand for a persisted text query filtered by node type.

For richer filtering/traversal/aggregation, see Query builder.

Reactivity & batching

  • changes — an RxJS Subject<GraphChangeEvent> emitting node_added, node_updated, node_removed, edge_added, edge_removed, activation_updated, and inhibition_updated.
  • startBatch() / endBatch() — queue notifications until the batch ends; endBatch() throws if no batch is open.

Public graph reads, query results, join/collection predicate values, edge data, and vector-index reads are detached copies. Mutate graph state through graph or vector-index methods so persistence tracking and reactive notifications stay correct. Data values must be compatible with the platform's structuredClone.

Optional schema validation

Structural validation is opt-in per type — not a precondition for using a type or edge type:

  • registerNodeType(type, definition?)requiredFields, dataTypes, a custom validate hook, convenience indexes, and a default memoryClass (overridable per node). Re-registering re-validates every currently loaded node of that type and rolls back if any fails.
  • registerEdgeType(type, definition?)sourceTypes/targetTypes, cardinality, requiredFields, dataTypes, a custom validate hook.
  • nodeTypes / edgeTypes — defensive copies of registered definitions.

For non-cloneable data (Blob, File, etc.) and other niche integration points (DataTransform, defineEdges, buildEmbeddingText), see the full API reference.


Back to Home.

Clone this wiki locally