From f124b862f8f98eb6338977b19ee725f70b98e3f9 Mon Sep 17 00:00:00 2001 From: martin bendsoe Date: Fri, 3 Jul 2020 16:20:37 +0200 Subject: [PATCH 1/2] reintroduced helper functions for the Record object and updated documentation --- docs/source/api.rst | 15 ++++-- neo4j/data.py | 21 +++++---- neo4j/work/result.py | 68 +++++++++++++++------------ tests/integration/test_result.py | 18 +++++++ tests/integration/test_result_data.py | 17 +++++++ 5 files changed, 94 insertions(+), 45 deletions(-) diff --git a/docs/source/api.rst b/docs/source/api.rst index 98797f4a..57059f44 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -633,6 +633,11 @@ A :class:`neo4j.Result` is attached to an active connection, through a :class:`n **This is experimental.** + .. automethod:: value + + .. automethod:: values + + .. automethod:: data See https://neo4j.com/docs/driver-manual/current/cypher-workflow/#driver-type-mapping for more about type mapping. @@ -698,6 +703,8 @@ Record Derive a sub-record based on a start and end index. All keys and values within those bounds will be copied across in the same order as in the original record. + .. automethod:: keys + .. describe:: record[key] Obtain a value from the record by key. @@ -705,15 +712,13 @@ Record .. automethod:: get(key, default=None) - .. automethod:: value(key=0, default=None) - .. automethod:: index(key) - .. automethod:: keys + .. automethod:: items - .. automethod:: values + .. automethod:: value(key=0, default=None) - .. automethod:: items + .. automethod:: values .. automethod:: data diff --git a/neo4j/data.py b/neo4j/data.py index 04ac87c4..bc9f173c 100644 --- a/neo4j/data.py +++ b/neo4j/data.py @@ -110,9 +110,9 @@ def get(self, key, default=None): """ Obtain a value from the record by key, returning a default value if the key does not exist. - :param key: - :param default: - :return: + :param key: a key + :param default: default value + :return: a value """ try: index = self.__keys.index(str(key)) @@ -126,8 +126,9 @@ def get(self, key, default=None): def index(self, key): """ Return the index of the given item. - :param key: - :return: + :param key: a key + :return: index + :rtype: int """ if isinstance(key, int): if 0 <= key < len(self.__keys): @@ -146,9 +147,9 @@ def value(self, key=0, default=None): index or key is specified, the first value is returned. If the specified item does not exist, the default value is returned. - :param key: - :param default: - :return: + :param key: an index or key + :param default: default value + :return: a single value """ try: index = self.index(key) @@ -171,6 +172,7 @@ def values(self, *keys): :param keys: indexes or keys of the items to include; if none are provided, all values will be included :return: list of values + :rtype: list """ if keys: d = [] @@ -187,7 +189,8 @@ def values(self, *keys): def items(self, *keys): """ Return the fields of the record as a list of key and value tuples - :return: + :return: a list of value tuples + :rtype: list """ if keys: d = [] diff --git a/neo4j/work/result.py b/neo4j/work/result.py index 4921249b..9231be04 100644 --- a/neo4j/work/result.py +++ b/neo4j/work/result.py @@ -227,6 +227,7 @@ def keys(self): """The keys for the records in this result. :returns: tuple of key names + :rtype: tuple """ return self._keys @@ -249,7 +250,7 @@ def single(self): A warning is generated if more than one record is available but the first of these is still returned. - :returns: the next :class:`.Record` or :const:`None` if none remain + :returns: the next :class:`neo4j.Record` or :const:`None` if none remain :warns: if more than one record is available """ records = list(self) # TODO: exhausts the result with self.consume if there are more records. @@ -277,42 +278,47 @@ def peek(self): return None - # See Record class for available methods. - - # NOT IN THE API - def graph(self): - """Return a Graph instance containing all the graph objects + """Return a :class:`neo4j.graph.Graph` instance containing all the graph objects in the result. After calling this method, the result becomes detached, buffering all remaining records. - :returns: result graph + :returns: a result graph + :rtype: :class:`neo4j.graph.Graph` """ self._buffer_all() return self._hydrant.graph - # def value(self, item=0, default=None): - # """Return the remainder of the result as a list of values. - # - # :param item: field to return for each remaining record - # :param default: default value, used if the index of key is unavailable - # :returns: list of individual values - # """ - # return [record.value(item, default) for record in self._records()] - - # def values(self, *items): - # """Return the remainder of the result as a list of tuples. - # - # :param items: fields to return for each remaining record - # :returns: list of value tuples - # """ - # return [record.values(*items) for record in self._records()] - - # def data(self, *items): - # """Return the remainder of the result as a list of dictionaries. - # - # :param items: fields to return for each remaining record - # :returns: list of dictionaries - # """ - # return [record.data(*items) for record in self] + def value(self, key=0, default=None): + """Helper function that return the remainder of the result as a list of values. + + See :class:`neo4j.Record.value` + + :param key: field to return for each remaining record. Obtain a single value from the record by index or key. + :param default: default value, used if the index of key is unavailable + :returns: list of individual values + :rtype: list + """ + return [record.value(key, default) for record in self] + + def values(self, *keys): + """Helper function that return the remainder of the result as a list of tuples. + See :class:`neo4j.Record.values` + + :param keys: fields to return for each remaining record. Optionally filtering to include only certain values by index or key. + :returns: list of value tuples + :rtype: list + """ + return [record.values(*keys) for record in self] + + def data(self, *keys): + """Helper function that return the remainder of the result as a list of dictionaries. + + See :class:`neo4j.Record.data` + + :param keys: fields to return for each remaining record. Optionally filtering to include only certain values by index or key. + :returns: list of dictionaries + :rtype: list + """ + return [record.data(*keys) for record in self] diff --git a/tests/integration/test_result.py b/tests/integration/test_result.py index f539c4de..250ba8c8 100644 --- a/tests/integration/test_result.py +++ b/tests/integration/test_result.py @@ -291,3 +291,21 @@ def test_single_indexed_values(session): def test_single_keyed_values(session): result = session.run("RETURN 1 AS x, 2 AS y, 3 AS z") assert result.single().values("z", "x") == [3, 1] + + +def test_result_with_helper_function_value(session): + + def f(tx): + result = tx.run("UNWIND range(1, 3) AS n RETURN n") + assert result.value(0) == [1, 2, 3] + + session.read_transaction(f) + + +def test_result_with_helper_function_values(session): + + def f(tx): + result = tx.run("UNWIND range(1, 3) AS n RETURN n, 0") + assert result.values(0, 1) == [[1, 0], [2, 0], [3, 0]] + + session.read_transaction(f) diff --git a/tests/integration/test_result_data.py b/tests/integration/test_result_data.py index 29923ef2..c166c862 100644 --- a/tests/integration/test_result_data.py +++ b/tests/integration/test_result_data.py @@ -25,6 +25,11 @@ def test_data_with_one_key_and_no_records(session): assert data == [] +def test_data_with_one_key_and_no_records_with_helper_function(session): + result = session.run("UNWIND range(1, 0) AS n RETURN n") + assert result.data() == [] + + def test_multiple_data(session): result = session.run("UNWIND range(1, 3) AS n " "RETURN 1 * n AS x, 2 * n AS y, 3 * n AS z") @@ -32,6 +37,12 @@ def test_multiple_data(session): assert data == [{"x": 1, "y": 2, "z": 3}, {"x": 2, "y": 4, "z": 6}, {"x": 3, "y": 6, "z": 9}] +def test_multiple_data_with_helper_function(session): + result = session.run("UNWIND range(1, 3) AS n " + "RETURN 1 * n AS x, 2 * n AS y, 3 * n AS z") + assert result.data() == [{"x": 1, "y": 2, "z": 3}, {"x": 2, "y": 4, "z": 6}, {"x": 3, "y": 6, "z": 9}] + + def test_multiple_indexed_data(session): result = session.run("UNWIND range(1, 3) AS n " "RETURN 1 * n AS x, 2 * n AS y, 3 * n AS z") @@ -39,6 +50,12 @@ def test_multiple_indexed_data(session): assert data == [{"x": 1, "z": 3}, {"x": 2, "z": 6}, {"x": 3, "z": 9}] +def test_multiple_indexed_data_with_helper_function(session): + result = session.run("UNWIND range(1, 3) AS n " + "RETURN 1 * n AS x, 2 * n AS y, 3 * n AS z") + assert result.data(2, 0) == [{"x": 1, "z": 3}, {"x": 2, "z": 6}, {"x": 3, "z": 9}] + + def test_multiple_keyed_data(session): result = session.run("UNWIND range(1, 3) AS n " "RETURN 1 * n AS x, 2 * n AS y, 3 * n AS z") From 0be5f61753cc0319a1dac8392c2ff10dd4e1b3b3 Mon Sep 17 00:00:00 2001 From: martin bendsoe Date: Fri, 3 Jul 2020 16:42:39 +0200 Subject: [PATCH 2/2] updated docs that it is a values lists e.g. [[1,0], [2,0], [3,0]] --- neo4j/work/result.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neo4j/work/result.py b/neo4j/work/result.py index 9231be04..af6a62d2 100644 --- a/neo4j/work/result.py +++ b/neo4j/work/result.py @@ -302,12 +302,12 @@ def value(self, key=0, default=None): return [record.value(key, default) for record in self] def values(self, *keys): - """Helper function that return the remainder of the result as a list of tuples. + """Helper function that return the remainder of the result as a list of values lists. See :class:`neo4j.Record.values` :param keys: fields to return for each remaining record. Optionally filtering to include only certain values by index or key. - :returns: list of value tuples + :returns: list of values lists :rtype: list """ return [record.values(*keys) for record in self]