🔍 Code Extractor

class ResultWrapper

Maturity: 56

ResultWrapper is a tuple subclass that wraps Cypher query results from Neo4j, providing methods to convert results into various formats including Node/Relationship objects, DataFrames, dictionaries, and Subgraphs.

File:
/tf/active/vicechatdev/neo4j_driver/neo4j_driver.py
Lines:
8 - 90
Complexity:
moderate

Purpose

This class serves as a wrapper around Neo4j Cypher query results, extending the built-in tuple class to provide convenient methods for transforming query results into different data structures. It handles conversion of raw Neo4j graph objects (nodes, relationships, paths) into higher-level Python objects and data structures like Pandas DataFrames, lists of dictionaries, and Subgraph objects. The class maintains a reference to the parent graph for proper object instantiation.

Source Code

class ResultWrapper(tuple):
    """
    The ResultWrapper class is a custom class that extends the built-in tuple class. It is used to wrap the results of Cypher queries and provide additional methods for working with the results. 
    The methods include evaluating the results to return Node and Relationship objects, converting the results to a Pandas DataFrame, returning the data as a list of dictionaries, 
    and returning the results as a Subgraph object.
    """
    def __init__(self, *args, graph=None):
        tuple.__init__(self)
        self._graph=graph
        
    def evaluate(self):
        if not self:
            return None
        if isinstance(self[0].value(), neo4j.graph.Node):
            if len(self) > 1:
                warnings.warn("Query matched multiple nodes, but .evaluate only processes a single node. Either use .subgraph or call `RETURN COLLECT(nodes)`", stacklevel=2)
            return Node._from_neo4j_node(self[0].value(), graph=self._graph)
        elif isinstance(self[0].value(), list) and len(self[0].value()) > 0 and isinstance(self[0].value()[0], neo4j.graph.Node):
            return [Node._from_neo4j_node(i, graph=self._graph) for i in self[0].value()]
        elif isinstance(self[0].value(), list) and len(self[0].value()) > 0 and isinstance(self[0].value()[0], neo4j.graph.Relationship):
            return [Relationship._from_neo4j_node(i, graph=self._graph) for i in self[0].value()]
        elif isinstance(self[0].value(), neo4j.graph.Relationship):
            return Relationship._from_neo4j_node(self[0].value(), graph=self._graph)
        return self[0].value()
    
    def to_data_frame(self):
        import pandas as pd
        try:
            if isinstance(self.values[0], Node):
                return pd.DataFrame([dict(i) for i in self.values])
            return pd.DataFrame(self.values, columns=self.keys)
        except:
            return pd.DataFrame()
    
    def data(self):
        if self.values is None:
            return []
        data=[]
        for values in self.values:
            if isinstance(values, Node):
                d=dict(values)
            else:
                d= dict(zip(self.keys, values))
            data.append(d)
        return data
    
    def to_ndarray(self):
        warnings.warn("This function was only implemented to return lists and does not actually return an ndarray. Please return collections and call .evaluate instead", stacklevel=5)
        return self.values
    
    def to_subgraph(self):
        if not self:
            return Subgraph(graph=self._graph)
        if isinstance(self[0].values(), neo4j.graph.Path) or isinstance(self[0].values()[0], neo4j.graph.Path):
            relationships=[]
            for path in self:
                for relationship in path.value():
                    relationships.append(relationship)
            subgraph = Subgraph(relationships=[Relationship._from_neo4j_node(i) for i in relationships], graph=self)
        elif isinstance(self[0].values()[0], neo4j.graph.Node):
            subgraph = Subgraph(nodes=self.values, graph=self._graph)
        elif isinstance(self[0].values()[0], neo4j.graph.Relationship):
            subgraph = Subgraph(relationships=self.values, graph=self._graph)
        else:
            raise TypeError(".to_subgraph only works on neo4j path, node and relationship objects.")
        return subgraph
            
        
    @property
    def values(self):
        if len(self) == 0:
            return None
        if isinstance(self[0].value(), neo4j.graph.Node):
            return [Node._from_neo4j_node(i.value(), graph=self._graph) for i in self]
        elif isinstance(self[0].value(), neo4j.graph.Relationship):
            return [Relationship._from_neo4j_node(i.value(), graph=self._graph) for i in self]
        return [i.values() for i in self]
    
    @property
    def keys(self):
        keys = []
        keys.extend(j for i in self for j in i.keys() if not j in keys)
        return keys

Parameters

Name Type Default Kind
bases tuple -

Parameter Details

*args: Variable positional arguments passed to the tuple constructor, typically containing Neo4j query result records

graph: Optional reference to the parent Graph object that executed the query. Used to maintain graph context when creating Node and Relationship objects from Neo4j results. Defaults to None.

Return Value

Instantiation returns a ResultWrapper object that behaves like a tuple but with additional methods. Key method returns: evaluate() returns Node, Relationship objects, or lists thereof, or primitive values; to_data_frame() returns a Pandas DataFrame; data() returns a list of dictionaries; to_subgraph() returns a Subgraph object; values property returns a list of converted values; keys property returns a list of unique keys from all records.

Class Interface

Methods

__init__(self, *args, graph=None)

Purpose: Initialize the ResultWrapper with query results and optional graph reference

Parameters:

  • *args: Variable positional arguments containing Neo4j query result records
  • graph: Optional reference to the parent Graph object for maintaining context

Returns: None (constructor)

evaluate(self) -> Node | Relationship | list | Any | None

Purpose: Evaluate the first result and convert it to appropriate Python objects (Node, Relationship, or primitive types)

Returns: Returns None if empty; Node object for single node results; Relationship object for single relationship results; list of Node objects for node collections; list of Relationship objects for relationship collections; or the raw value for other types. Warns if multiple nodes matched but only processes first.

to_data_frame(self) -> pd.DataFrame

Purpose: Convert the query results to a Pandas DataFrame

Returns: Pandas DataFrame containing the results. If values are Node objects, converts them to dictionaries. Otherwise uses keys and values. Returns empty DataFrame on error.

data(self) -> list[dict]

Purpose: Convert query results to a list of dictionaries

Returns: List of dictionaries where each dictionary represents a result record. Node objects are converted to dicts, other values are zipped with keys. Returns empty list if values is None.

to_ndarray(self) -> list

Purpose: Deprecated method that returns values as a list (not an actual ndarray)

Returns: Returns the values property (a list). Emits deprecation warning recommending use of collections and evaluate() instead.

to_subgraph(self) -> Subgraph

Purpose: Convert query results to a Subgraph object containing nodes and/or relationships

Returns: Subgraph object constructed from the results. Handles Path, Node, and Relationship types. Returns empty Subgraph if ResultWrapper is empty. Raises TypeError for unsupported types.

values(self) -> list | None property

Purpose: Property that returns the values from all result records, converting Neo4j objects to Python objects

Returns: None if empty; list of Node objects if results contain nodes; list of Relationship objects if results contain relationships; otherwise list of raw values from each record.

keys(self) -> list[str] property

Purpose: Property that returns all unique keys from the result records

Returns: List of unique key names (strings) from all records in the results, preserving order of first appearance.

Attributes

Name Type Description Scope
_graph Graph | None Private attribute storing reference to the parent Graph object, used for maintaining context when creating Node and Relationship objects instance

Dependencies

  • neo4j
  • pandas
  • warnings
  • neo4j_objects

Required Imports

import neo4j
import warnings
from neo4j_objects import Node, Relationship, Subgraph

Conditional/Optional Imports

These imports are only needed under specific conditions:

import pandas as pd

Condition: only when calling to_data_frame() method

Required (conditional)

Usage Example

# Assuming you have a Neo4j graph connection and query results
from neo4j import GraphDatabase
from neo4j_objects import Node, Relationship, Subgraph

# Execute a query that returns results
driver = GraphDatabase.driver('bolt://localhost:7687', auth=('neo4j', 'password'))
with driver.session() as session:
    raw_results = session.run('MATCH (n:Person) RETURN n LIMIT 5')
    
    # Wrap results
    results = ResultWrapper(*raw_results, graph=my_graph)
    
    # Get single node/relationship
    node = results.evaluate()
    
    # Convert to DataFrame
    df = results.to_data_frame()
    
    # Get as list of dictionaries
    data_list = results.data()
    
    # Convert to Subgraph
    subgraph = results.to_subgraph()
    
    # Access values and keys
    values = results.values
    keys = results.keys

Best Practices

  • Always pass the graph parameter when instantiating to maintain proper graph context for Node and Relationship objects
  • Use evaluate() for single-result queries; it warns if multiple nodes are matched but only processes the first
  • Check if ResultWrapper is empty before calling methods to avoid errors
  • Use to_subgraph() only with Neo4j path, node, or relationship objects; other types will raise TypeError
  • Be aware that to_ndarray() is deprecated and only returns lists, not actual ndarrays
  • The class is immutable (tuple subclass), so results cannot be modified after creation
  • When working with collections of nodes/relationships, use COLLECT() in Cypher queries for proper handling with evaluate()
  • The values property returns None if the ResultWrapper is empty, so check for None before iterating

Similar Components

AI-powered semantic similarity - components with related functionality:

  • class IterationResult 54.0% similar

    A dataclass that encapsulates the complete results of a single iteration in a two-pass process, including table selection, SQL generation, and execution outcomes.

    From: /tf/active/vicechatdev/full_smartstat/two_pass_sql_workflow.py
  • function run_query_v2 52.6% similar

    Executes a Cypher query against a Neo4j graph database and returns the results as a list of dictionaries.

    From: /tf/active/vicechatdev/neo4j_schema/neo4j_python_snippets.py
  • class SqlGenerationResult 50.8% similar

    A dataclass that encapsulates the results of an SQL query generation operation, including the generated query, explanation, confidence score, and metadata about database objects used.

    From: /tf/active/vicechatdev/full_smartstat/two_pass_sql_workflow.py
  • class Graph 50.6% similar

    A Graph class that provides an interface for interacting with a Neo4j graph database, supporting CRUD operations on nodes and relationships through Cypher queries.

    From: /tf/active/vicechatdev/neo4j_driver/neo4j_driver.py
  • class AnalysisResult_v1 49.4% similar

    A dataclass that encapsulates results from statistical analysis operations, providing structured storage and serialization capabilities for analysis outputs.

    From: /tf/active/vicechatdev/vice_ai/models.py
← Back to Browse