Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/source/results.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
Consuming Results
*****************

Every time Cypher is executed, a :class:`.BoltStatementResult` is returned.
Every time Cypher is executed, a :class:`neo4j.Result` is returned.
This provides a handle to the result of the query, giving access to the records within it as well as the result metadata.

Each result consists of header metadata, zero or more :class:`.Record` objects and footer metadata (the summary).
Results also contain a buffer that automatically stores unconsumed records when results are consumed out of order.
A :class:`.BoltStatementResult` is attached to an active connection, through a :class:`.Session`, until all its content has been buffered or consumed.
A :class:`neo4j.Result` is attached to an active connection, through a :class:`.Session`, until all its content has been buffered or consumed.

.. class:: neo4j.BoltStatementResult
.. class:: neo4j.Result

.. describe:: iter(result)

Expand Down Expand Up @@ -103,7 +103,7 @@ A :class:`.BoltStatementResult` is attached to an active connection, through a :
Summary Details
---------------

.. autoclass:: neo4j.BoltStatementResultSummary
.. autoclass:: neo4j.ResultSummary
:members:

.. autoclass:: neo4j.SummaryCounters
Expand Down
2 changes: 1 addition & 1 deletion docs/source/types/graph.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Path :class:`.Path`
.. class:: neo4j.types.graph.Graph

A local, self-contained graph object that acts as a container for :class:`.Node` and :class:`.Relationship` instances.
This is typically obtained via the :meth:`.BoltStatementResult.graph` method.
This is typically obtained via the :meth:`neo4j.Result.graph` method.

.. autoattribute:: nodes

Expand Down
4 changes: 2 additions & 2 deletions neo4j/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,11 @@ def __enter__(self):
def __exit__(self, exc_type, exc_value, traceback):
self.close()

def run(self, statement, parameters=None, mode=None, bookmarks=None, metadata=None,
def run(self, query, parameters=None, mode=None, bookmarks=None, metadata=None,
timeout=None, db=None, **handlers):
""" Appends a RUN message to the output stream.

:param statement: Cypher query string
:param query: Cypher query string
:param parameters: dictionary of Cypher parameters
:param mode: access mode for routing - "READ" or "WRITE" (default)
:param bookmarks: iterable of bookmark values after which this transaction should begin
Expand Down
6 changes: 3 additions & 3 deletions neo4j/io/_bolt3.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def hello(self):
self.send_all()
self.fetch_all()

def run(self, statement, parameters=None, mode=None, bookmarks=None, metadata=None,
def run(self, query, parameters=None, mode=None, bookmarks=None, metadata=None,
timeout=None, db=None, **handlers):
if db is not None:
raise ValueError("Database selection is not supported in Bolt 3")
Expand All @@ -168,9 +168,9 @@ def run(self, statement, parameters=None, mode=None, bookmarks=None, metadata=No
extra["tx_timeout"] = int(1000 * timeout)
except TypeError:
raise TypeError("Timeout must be specified as a number of seconds")
fields = (statement, parameters, extra)
fields = (query, parameters, extra)
log.debug("[#%04X] C: RUN %s", self.local_port, " ".join(map(repr, fields)))
if statement.upper() == u"COMMIT":
if query.upper() == u"COMMIT":
self._append(b"\x10", fields, CommitResponse(self, **handlers))
else:
self._append(b"\x10", fields, Response(self, **handlers))
Expand Down
6 changes: 3 additions & 3 deletions neo4j/io/_bolt4x0.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def hello(self):
self.send_all()
self.fetch_all()

def run(self, statement, parameters=None, mode=None, bookmarks=None, metadata=None,
def run(self, query, parameters=None, mode=None, bookmarks=None, metadata=None,
timeout=None, db=None, **handlers):
if not parameters:
parameters = {}
Expand All @@ -168,9 +168,9 @@ def run(self, statement, parameters=None, mode=None, bookmarks=None, metadata=No
extra["tx_timeout"] = int(1000 * timeout)
except TypeError:
raise TypeError("Timeout must be specified as a number of seconds")
fields = (statement, parameters, extra)
fields = (query, parameters, extra)
log.debug("[#%04X] C: RUN %s", self.local_port, " ".join(map(repr, fields)))
if statement.upper() == u"COMMIT":
if query.upper() == u"COMMIT":
self._append(b"\x10", fields, CommitResponse(self, **handlers))
else:
self._append(b"\x10", fields, Response(self, **handlers))
Expand Down
93 changes: 49 additions & 44 deletions neo4j/work/simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
)
from neo4j._exceptions import BoltIncompleteCommitError
from neo4j.work import Workspace, WorkspaceConfig
from neo4j.work.summary import BoltStatementResultSummary
from neo4j.work.summary import ResultSummary


log = getLogger("neo4j")
Expand Down Expand Up @@ -128,33 +128,33 @@ def close(self):
finally:
self._disconnect()

def run(self, cypher, parameters=None, **kwparameters):
""" Run a Cypher statement within an auto-commit transaction.
def run(self, query, parameters=None, **kwparameters):
""" Run a Cypher query within an auto-commit transaction.

The statement is sent and the result header received
immediately but the :class:`.StatementResult` content is
The query is sent and the result header received
immediately but the :class:`neo4j.Result` content is
fetched lazily as consumed by the client application.

If a statement is executed before a previous
:class:`.StatementResult` in the same :class:`.Session` has
If a query is executed before a previous
:class:`neo4j.Result` in the same :class:`.Session` has
been fully consumed, the first result will be fully fetched
and buffered. Note therefore that the generally recommended
pattern of usage is to fully consume one result before
executing a subsequent statement. If two results need to be
executing a subsequent query. If two results need to be
consumed in parallel, multiple :class:`.Session` objects
can be used as an alternative to result buffering.

For more usage details, see :meth:`.Transaction.run`.

:param cypher: Cypher statement
:param query: Cypher query
:param parameters: dictionary of parameters
:param kwparameters: additional keyword parameters
:returns: :class:`.StatementResult` object
:returns: :class:`neo4j.Result` object
"""
if not cypher:
raise ValueError("Cannot run an empty statement")
if not isinstance(cypher, (str, Statement)):
raise TypeError("Statement must be a string or a Statement instance")
if not query:
raise ValueError("Cannot run an empty query")
if not isinstance(query, (str, Query)):
raise TypeError("query must be a string or a Query instance")

if not self._connection:
self._connect(self._config.default_access_mode)
Expand All @@ -164,24 +164,24 @@ def run(self, cypher, parameters=None, **kwparameters):

has_transaction = self.has_transaction()

statement_text = str(cypher)
statement_metadata = getattr(cypher, "metadata", None)
statement_timeout = getattr(cypher, "timeout", None)
query_text = str(query)
query_metadata = getattr(query, "metadata", None)
query_timeout = getattr(query, "timeout", None)
parameters = DataDehydrator.fix_parameters(dict(parameters or {}, **kwparameters))

def fail(_):
self._close_transaction()

hydrant = DataHydrator()
result_metadata = {
"statement": statement_text,
"query": query_text,
"parameters": parameters,
"server": server,
"protocol_version": protocol_version,
}
run_metadata = {
"metadata": statement_metadata,
"timeout": statement_timeout,
"metadata": query_metadata,
"timeout": query_timeout,
"on_success": result_metadata.update,
"on_failure": fail,
}
Expand All @@ -193,20 +193,20 @@ def done(summary_metadata):
self._bookmarks_in = tuple([bookmark])
self._bookmark_out = bookmark

self._last_result = result = BoltStatementResult(self, hydrant, result_metadata)
self._last_result = result = Result(self, hydrant, result_metadata)

if has_transaction:
if statement_metadata:
if query_metadata:
raise ValueError("Metadata can only be attached at transaction level")
if statement_timeout:
if query_timeout:
raise ValueError("Timeouts only apply at transaction level")
# TODO: fail if explicit database name has been set
else:
run_metadata["bookmarks"] = self._bookmarks_in

# TODO: capture ValueError and surface as SessionError/TransactionError if
# TODO: explicit database selection has been made
cx.run(statement_text, parameters, **run_metadata)
cx.run(query_text, parameters, **run_metadata)
cx.pull(
on_records=lambda records: result._records.extend(
hydrant.hydrate_records(result.keys(), records)),
Expand Down Expand Up @@ -488,40 +488,40 @@ def __exit__(self, exc_type, exc_value, traceback):
self._success = not bool(exc_type)
self._close()

def run(self, statement, parameters=None, **kwparameters):
""" Run a Cypher statement within the context of this transaction.
def run(self, query, parameters=None, **kwparameters):
""" Run a Cypher query within the context of this transaction.

The statement is sent to the server lazily, when its result is
consumed. To force the statement to be sent to the server, use
The query is sent to the server lazily, when its result is
consumed. To force the query to be sent to the server, use
the :meth:`.Transaction.sync` method.

Cypher is typically expressed as a statement template plus a
Cypher is typically expressed as a query template plus a
set of named parameters. In Python, parameters may be expressed
through a dictionary of parameters, through individual parameter
arguments, or as a mixture of both. For example, the `run`
statements below are all equivalent::
queries below are all equivalent::

>>> statement = "CREATE (a:Person {name:{name}, age:{age}})"
>>> tx.run(statement, {"name": "Alice", "age": 33})
>>> tx.run(statement, {"name": "Alice"}, age=33)
>>> tx.run(statement, name="Alice", age=33)
>>> query = "CREATE (a:Person {name:{name}, age:{age}})"
>>> tx.run(query, {"name": "Alice", "age": 33})
>>> tx.run(query, {"name": "Alice"}, age=33)
>>> tx.run(query, name="Alice", age=33)

Parameter values can be of any type supported by the Neo4j type
system. In Python, this includes :class:`bool`, :class:`int`,
:class:`str`, :class:`list` and :class:`dict`. Note however that
:class:`list` properties must be homogenous.

:param statement: template Cypher statement
:param query: template Cypher query
:param parameters: dictionary of parameters
:param kwparameters: additional keyword parameters
:returns: :class:`.StatementResult` object
:returns: :class:`neo4j.Result` object
:raise TransactionError: if the transaction is closed
"""
self._assert_open()
return self.session.run(statement, parameters, **kwparameters)
return self.session.run(query, parameters, **kwparameters)

def sync(self):
""" Force any queued statements to be sent to the server and
""" Force any queued queries to be sent to the server and
all related results to be fetched and buffered.

:raise TransactionError: if the transaction is closed
Expand Down Expand Up @@ -578,8 +578,13 @@ def _assert_open(self):
raise TransactionError("Transaction closed")


class Statement:
class Query:
""" Create a new query.

:param text: The query text.
:param metadata: Dictionary of parameters, metadata attached to the query.
:param timeout: Timeout in seconds.
"""
def __init__(self, text, metadata=None, timeout=None):
self.text = text
try:
Expand All @@ -595,8 +600,8 @@ def __str__(self):
return str(self.text)


class BoltStatementResult:
""" A handler for the result of Cypher statement execution. Instances
class Result:
""" A handler for the result of Cypher query execution. Instances
of this class are typically constructed and returned by
:meth:`.Session.run` and :meth:`.Transaction.run`.
"""
Expand Down Expand Up @@ -668,17 +673,17 @@ def records(self):
def summary(self):
""" Obtain the summary of this result, buffering any remaining records.

:returns: The :class:`.ResultSummary` for this result
:returns: The :class:`neo4j.ResultSummary` for this result
"""
self.detach()
if self._summary is None:
self._summary = BoltStatementResultSummary(**self._metadata)
self._summary = ResultSummary(**self._metadata)
return self._summary

def consume(self):
""" Consume the remainder of this result and return the summary.

:returns: The :class:`.ResultSummary` for this result
:returns: The :class:`neo4j.ResultSummary` for this result
"""
if self.attached():
for _ in self:
Expand Down
16 changes: 8 additions & 8 deletions neo4j/work/summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
BOLT_VERSION_4 = 4


class BoltStatementResultSummary:
""" A summary of execution returned with a :class:`.StatementResult` object.
class ResultSummary:
""" A summary of execution returned with a :class:`.Result` object.
"""

#: The version of Bolt protocol over which this result was obtained.
Expand All @@ -37,14 +37,14 @@ class BoltStatementResultSummary:
#: The server on which this result was generated.
server = None

#: The statement that was executed to produce this result.
statement = None
#: The query that was executed to produce this result.
query = None

#: Dictionary of parameters passed with the statement.
parameters = None

#: The type of statement (``'r'`` = read-only, ``'rw'`` = read/write).
statement_type = None
#: The type of query (``'r'`` = read-only, ``'rw'`` = read/write).
query_type = None

#: A set of statistical information held in a :class:`.Counters` instance.
counters = None
Expand All @@ -71,9 +71,9 @@ def __init__(self, **metadata):
self.metadata = metadata
self.protocol_version = metadata.get("protocol_version")
self.server = metadata.get("server")
self.statement = metadata.get("statement")
self.query = metadata.get("query")
self.parameters = metadata.get("parameters")
self.statement_type = metadata.get("type")
self.query_type = metadata.get("type")
self.counters = SummaryCounters(metadata.get("stats", {}))
if self.protocol_version[0] < BOLT_VERSION_3:
self.result_available_after = metadata.get("result_available_after")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@


# tag::autocommit-transaction-import[]
from neo4j.work.simple import Statement
from neo4j.work.simple import Query
# end::autocommit-transaction-import[]


Expand All @@ -39,7 +39,7 @@ def add_person(self, name):
# Alternative implementation, with a one second timeout
def add_person_within_a_second(self, name):
with self.driver.session() as session:
session.run(Statement("CREATE (a:Person {name: $name})", timeout=1.0), name=name)
session.run(Query("CREATE (a:Person {name: $name})", timeout=1.0), name=name)
# end::autocommit-transaction[]


Expand Down
Loading