orchestrata_ultimate.knowledge_graph.nodes
Reference › orchestrata_ultimate › knowledge_graph › nodes
Conversion functions between the node dataclasses of types_nodes and the label-plus-properties form that Cypher needs for the operational graph (orchkg on orchgraph). node_to_cypher_props flattens a generic Node. file_node_to_cypher, class_node_to_cypher, function_node_to_cypher, predicate_node_to_cypher and rule_node_to_cypher each return a (label, properties) tuple for their node type. cypher_record_to_node goes the other way, turning a query result record back into a Node, or None when it cannot. The functions are pure; they run no queries. graph_client and graph_node_mixins import them to write and read nodes.
At a glance
| Source | src/orchestrata_ultimate/knowledge_graph/nodes.py |
| Lines of code | 164 |
| Classes | 0 |
| Functions | 7 |
| Imports (internal) | orchestrata_ultimate.core.base.traces, orchestrata_ultimate.knowledge_graph.schema, orchestrata_ultimate.knowledge_graph.types |
| Imported by | orchestrata_ultimate.knowledge_graph.graph_client, orchestrata_ultimate.knowledge_graph.graph_node_mixins, orchestrata_ultimate.knowledge_graph.query_engine, orchestrata_ultimate.knowledge_graph.synchronizer |
| Tests that import it | tests/knowledge_graph/test_code_intelligence_coverage.py, tests/knowledge_graph/test_graph_sync_integration.py, tests/knowledge_graph/test_knowledge_graph_client.py, tests/knowledge_graph/test_knowledge_performance.py, tests/knowledge_graph/test_knowledge_schema.py, tests/knowledge_graph/test_nodes.py, tests/test_knowledge_graph.py |
Class diagram
No classes; see Functions.
Dependency diagram
API
Functions
| Function | Signature | Summary |
|---|---|---|
node_to_cypher_props |
node_to_cypher_props(node: Node) -> dict[str, Any] |
Convert a generic Node to Cypher-compatible properties. |
file_node_to_cypher traces |
file_node_to_cypher(file_node: FileNode) -> tuple[str, dict[str, Any]] |
Convert FileNode to (label, properties) for Cypher. |
class_node_to_cypher traces |
class_node_to_cypher(class_node: ClassNode) -> tuple[str, dict[str, Any]] |
Convert ClassNode to (label, properties) for Cypher. |
function_node_to_cypher traces, traces |
function_node_to_cypher(func_node: FunctionNode) -> tuple[str, dict[str, Any]] |
Convert FunctionNode to (label, properties) for Cypher. |
predicate_node_to_cypher traces |
predicate_node_to_cypher(pred_node: PredicateNode) -> tuple[str, dict[str, Any]] |
Convert PredicateNode to (label, properties) for Cypher. |
rule_node_to_cypher traces |
rule_node_to_cypher(rule_node: RuleNode) -> tuple[str, dict[str, Any]] |
Convert RuleNode to (label, properties) for Cypher. |
cypher_record_to_node traces |
cypher_record_to_node(record: dict[str, Any]) -> Node | None |
Convert a Cypher query result record back to a Node. |
Source
"""Graph node wrappers for the knowledge graph.
Converts between Python data models and Neo4j node representations.
Includes PredicateNode and RuleNode for Prolog entities (REQ-008-018).
"""
import logging
from typing import Any
from orchestrata_ultimate.core.base.traces import traces
from orchestrata_ultimate.knowledge_graph.schema import (
LABEL_CLASS,
LABEL_FILE,
LABEL_FUNCTION,
LABEL_PREDICATE,
LABEL_RULE,
)
from orchestrata_ultimate.knowledge_graph.types import (
ClassNode,
FileNode,
FunctionNode,
Node,
NodeType,
PredicateNode,
RuleNode,
)
logger = logging.getLogger(__name__)
def node_to_cypher_props(node: Node) -> dict[str, Any]:
"""Convert a generic Node to Cypher-compatible properties."""
props = {
"id": node.id,
"name": node.name,
"type": node.type.value,
"created_at": node.created_at.isoformat(),
"updated_at": node.updated_at.isoformat(),
}
if node.valid_until:
props["valid_until"] = node.valid_until.isoformat()
props.update(node.properties)
return props
@traces(spec="008", story="US-001", reqs=["REQ-008-021"])
def file_node_to_cypher(file_node: FileNode) -> tuple[str, dict[str, Any]]:
"""Convert FileNode to (label, properties) for Cypher."""
props = {
"id": file_node.id,
"path": file_node.path,
"name": file_node.name,
"language": file_node.language,
"line_count": file_node.line_count,
"size_bytes": file_node.size_bytes,
"hash": file_node.hash,
"created_at": file_node.created_at.isoformat(),
"updated_at": file_node.updated_at.isoformat(),
}
if file_node.project_id:
props["project_id"] = file_node.project_id
return LABEL_FILE, props
@traces(spec="008", story="US-001", reqs=["REQ-008-021"])
def class_node_to_cypher(class_node: ClassNode) -> tuple[str, dict[str, Any]]:
"""Convert ClassNode to (label, properties) for Cypher."""
props = {
"id": class_node.id,
"name": class_node.name,
"file_id": class_node.file_id,
"line_start": class_node.line_start,
"line_end": class_node.line_end,
"docstring": class_node.docstring,
"methods": class_node.methods,
"base_classes": class_node.base_classes,
"decorators": class_node.decorators,
"created_at": class_node.created_at.isoformat(),
}
return LABEL_CLASS, props
@traces(spec="008", story="US-001", reqs=["REQ-008-021"])
@traces(spec="015", story="US-001", reqs=["REQ-015-120"])
def function_node_to_cypher(func_node: FunctionNode) -> tuple[str, dict[str, Any]]:
"""Convert FunctionNode to (label, properties) for Cypher."""
props = {
"id": func_node.id,
"name": func_node.name,
"file_id": func_node.file_id,
"line_start": func_node.line_start,
"line_end": func_node.line_end,
"signature": func_node.signature,
"parameters": func_node.parameters,
"return_type": func_node.return_type,
"decorators": func_node.decorators,
"calls": func_node.calls,
"is_async": func_node.is_async,
"docstring": func_node.docstring,
"created_at": func_node.created_at.isoformat(),
}
if func_node.class_id:
props["class_id"] = func_node.class_id
return LABEL_FUNCTION, props
@traces(spec="015", story="US-001", reqs=["REQ-015-121"])
def predicate_node_to_cypher(pred_node: PredicateNode) -> tuple[str, dict[str, Any]]:
"""Convert PredicateNode to (label, properties) for Cypher."""
props = {
"id": pred_node.id,
"name": pred_node.name,
"arity": pred_node.arity,
"functor": pred_node.functor,
"file_id": pred_node.file_id,
"module": pred_node.module,
"line_start": pred_node.line_start,
"line_end": pred_node.line_end,
"is_dynamic": pred_node.is_dynamic,
"is_exported": pred_node.is_exported,
"docstring": pred_node.docstring,
"created_at": pred_node.created_at.isoformat(),
}
return LABEL_PREDICATE, props
@traces(spec="015", story="US-001", reqs=["REQ-015-122"])
def rule_node_to_cypher(rule_node: RuleNode) -> tuple[str, dict[str, Any]]:
"""Convert RuleNode to (label, properties) for Cypher."""
props = {
"id": rule_node.id,
"head": rule_node.head,
"body": rule_node.body,
"predicate_id": rule_node.predicate_id,
"file_id": rule_node.file_id,
"line_start": rule_node.line_start,
"line_end": rule_node.line_end,
"created_at": rule_node.created_at.isoformat(),
}
return LABEL_RULE, props
@traces(spec="015", story="US-001", reqs=["REQ-015-123"])
def cypher_record_to_node(record: dict[str, Any]) -> Node | None:
"""Convert a Cypher query result record back to a Node."""
if not record:
return None
node_type = record.get("type", "file")
try:
nt = NodeType(node_type)
except ValueError as exc:
logger.warning("Unknown node type, defaulting to FILE: %s", exc)
nt = NodeType.FILE
return Node(
id=record.get("id", ""),
type=nt,
name=record.get("name", ""),
properties={
k: v
for k, v in record.items()
if k
not in ("id", "type", "name", "created_at", "updated_at", "valid_until")
},
)