UNPKG

meta-log-db

Version:

Native database package for Meta-Log (ProLog, DataLog, R5RS)

169 lines 4.72 kB
"use strict"; /** * DAG Manager * * Manages Directed Acyclic Graph operations for MetaLogNodes */ Object.defineProperty(exports, "__esModule", { value: true }); exports.DAGManager = void 0; /** * DAG Manager * * Handles DAG operations: LCA finding, ancestor/descendant queries, node management */ class DAGManager { constructor(dag) { this.dag = dag || { nodes: new Map(), edges: new Map(), roots: new Set(), heads: new Set() }; } /** * Get DAG instance */ getDAG() { return this.dag; } /** * Add node to DAG * * @param node - MetaLogNode to add */ addNode(node) { this.dag.nodes.set(node.cid, node); // Update edges (child → parents) if (node.parent !== 'genesis') { const children = this.dag.edges.get(node.parent) || []; if (!children.includes(node.cid)) { children.push(node.cid); this.dag.edges.set(node.parent, children); } } else { // Root node this.dag.roots.add(node.cid); } // Update heads (remove parent from heads if it was a head) if (node.parent !== 'genesis' && this.dag.heads.has(node.parent)) { this.dag.heads.delete(node.parent); } // Check if this node is a head (no children yet) if (!this.dag.edges.has(node.cid)) { this.dag.heads.add(node.cid); } } /** * Find Lowest Common Ancestor (LCA) of two nodes * * @param cid1 - First node CID * @param cid2 - Second node CID * @returns LCA CID or null if no common ancestor */ findLCA(cid1, cid2) { const ancestors1 = this.getAncestors(cid1); const ancestors2 = this.getAncestors(cid2); // Find first common ancestor (LCA) for (const a1 of ancestors1) { if (ancestors2.includes(a1)) { return a1; } } return null; // No common ancestor (different roots) } /** * Get all ancestors of a node * * @param cid - Node CID * @returns Array of ancestor CIDs (ordered from immediate parent to root) */ getAncestors(cid) { const ancestors = []; let current = cid; while (current) { const node = this.dag.nodes.get(current); if (!node || node.parent === 'genesis') { break; } ancestors.push(node.parent); current = node.parent; } return ancestors; } /** * Get all children of a node * * @param cid - Node CID * @returns Array of child CIDs */ getChildren(cid) { return this.dag.edges.get(cid) || []; } /** * Get all descendants of a node (recursive) * * @param cid - Node CID * @returns Array of descendant CIDs */ getDescendants(cid) { const descendants = []; const visited = new Set(); const traverse = (current) => { if (visited.has(current)) return; visited.add(current); const children = this.getChildren(current); for (const child of children) { descendants.push(child); traverse(child); } }; traverse(cid); return descendants; } /** * Get depth of a node (distance from root) * * @param cid - Node CID * @returns Depth (0 for root nodes) */ getDepth(cid) { return this.getAncestors(cid).length; } /** * Check if DAG has cycles (should always return false for valid DAG) * * @returns true if cycle detected */ hasCycles() { const visited = new Set(); const recStack = new Set(); const hasCycle = (cid) => { if (recStack.has(cid)) { return true; // Cycle detected } if (visited.has(cid)) { return false; } visited.add(cid); recStack.add(cid); const node = this.dag.nodes.get(cid); if (node && node.parent !== 'genesis') { if (hasCycle(node.parent)) { return true; } } recStack.delete(cid); return false; }; for (const cid of this.dag.nodes.keys()) { if (!visited.has(cid) && hasCycle(cid)) { return true; } } return false; } } exports.DAGManager = DAGManager; //# sourceMappingURL=manager.js.map