Skip to content

Commit 891db8b

Browse files
committed
Merge pull request #31 from neo4j/1.0-cursor-api
Cursor API
2 parents e57aef2 + 2793320 commit 891db8b

File tree

11 files changed

+439
-542
lines changed

11 files changed

+439
-542
lines changed

README.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ Example Usage
2828
driver = GraphDatabase.driver("bolt://localhost")
2929
session = driver.session()
3030
session.run("CREATE (a:Person {name:'Bob'})")
31-
for name, in session.run("MATCH (a:Person) RETURN a.name AS name"):
32-
print(name)
31+
cursor = session.run("MATCH (a:Person) RETURN a.name AS name")
32+
while cursor.next()
33+
print(cursor["name"])
34+
cursor.close()
3335
session.close()
3436
3537

docs/source/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Session API
2626

2727
.. autofunction:: neo4j.v1.record
2828

29-
.. autoclass:: neo4j.v1.Result
29+
.. autoclass:: neo4j.v1.ResultCursor
3030
:members:
3131

3232
.. autoclass:: neo4j.v1.ResultSummary

examples/__init__.py

Whitespace-only changes.

examples/test_examples.py

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#!/usr/bin/env python
2+
# -*- encoding: utf-8 -*-
3+
4+
# Copyright (c) 2002-2016 "Neo Technology,"
5+
# Network Engine for Objects in Lund AB [http://neotechnology.com]
6+
#
7+
# This file is part of Neo4j.
8+
#
9+
# Licensed under the Apache License, Version 2.0 (the "License");
10+
# you may not use this file except in compliance with the License.
11+
# You may obtain a copy of the License at
12+
#
13+
# http://www.apache.org/licenses/LICENSE-2.0
14+
#
15+
# Unless required by applicable law or agreed to in writing, software
16+
# distributed under the License is distributed on an "AS IS" BASIS,
17+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
# See the License for the specific language governing permissions and
19+
# limitations under the License.
20+
21+
22+
from unittest import TestCase
23+
24+
# tag::minimal-example-import[]
25+
from neo4j.v1 import GraphDatabase
26+
# end::minimal-example-import[]
27+
28+
29+
class FreshDatabaseTestCase(TestCase):
30+
31+
def setUp(self):
32+
session = GraphDatabase.driver("bolt://localhost").session()
33+
session.run("MATCH (n) DETACH DELETE n")
34+
session.close()
35+
36+
37+
class MinimalWorkingExampleTestCase(FreshDatabaseTestCase):
38+
39+
def test_minimal_working_example(self):
40+
# tag::minimal-example[]
41+
driver = GraphDatabase.driver("bolt://localhost")
42+
session = driver.session()
43+
44+
session.run("CREATE (neo:Person {name:'Neo', age:23})")
45+
46+
cursor = session.run("MATCH (p:Person) WHERE p.name = 'Neo' RETURN p.age")
47+
while cursor.next():
48+
print("Neo is %d years old." % cursor["p.age"])
49+
50+
session.close()
51+
# end::minimal-example[]
52+
53+
54+
class ExamplesTestCase(FreshDatabaseTestCase):
55+
56+
def test_construct_driver(self):
57+
# tag::construct-driver[]
58+
driver = GraphDatabase.driver("bolt://localhost")
59+
# end::construct-driver[]
60+
return driver
61+
62+
def test_configuration(self):
63+
# tag::configuration[]
64+
driver = GraphDatabase.driver("bolt://localhost", max_pool_size=10)
65+
# end::configuration[]
66+
return driver
67+
68+
def test_tls_require_encryption(self):
69+
# tag::tls-require-encryption[]
70+
# TODO: Unfortunately, this feature is not yet implemented for Python
71+
pass
72+
# end::tls-require-encryption[]
73+
74+
def test_tls_trust_on_first_use(self):
75+
# tag::tls-trust-on-first-use[]
76+
# TODO: Unfortunately, this feature is not yet implemented for Python
77+
pass
78+
# end::tls-trust-on-first-use[]
79+
80+
def test_tls_signed(self):
81+
# tag::tls-signed[]
82+
# TODO: Unfortunately, this feature is not yet implemented for Python
83+
pass
84+
# end::tls-signed[]
85+
86+
def test_statement(self):
87+
driver = GraphDatabase.driver("bolt://localhost")
88+
session = driver.session()
89+
# tag::statement[]
90+
session.run("CREATE (person:Person {name: {name}})", {"name": "Neo"}).close()
91+
# end::statement[]
92+
session.close()
93+
94+
def test_statement_without_parameters(self):
95+
driver = GraphDatabase.driver("bolt://localhost")
96+
session = driver.session()
97+
# tag::statement-without-parameters[]
98+
session.run("CREATE (person:Person {name: 'Neo'})").close()
99+
# end::statement-without-parameters[]
100+
session.close()
101+
102+
def test_result_cursor(self):
103+
driver = GraphDatabase.driver("bolt://localhost")
104+
session = driver.session()
105+
# tag::result-cursor[]
106+
search_term = "hammer"
107+
cursor = session.run("MATCH (tool:Tool) WHERE tool.name CONTAINS {term} "
108+
"RETURN tool.name", {"term": search_term})
109+
print("List of tools called %r:" % search_term)
110+
while cursor.next():
111+
print(cursor["tool.name"])
112+
# end::result-cursor[]
113+
session.close()
114+
115+
def test_cursor_nesting(self):
116+
driver = GraphDatabase.driver("bolt://localhost")
117+
session = driver.session()
118+
# tag::retain-result-query[]
119+
cursor = session.run("MATCH (person:Person) WHERE person.dept = {dept} "
120+
"RETURN id(person) AS minion", {"dept": "IT"})
121+
while cursor.next():
122+
session.run("MATCH (person) WHERE id(person) = {id} "
123+
"MATCH (boss:Person) WHERE boss.name = {boss} "
124+
"CREATE (person)-[:REPORTS_TO]->(boss)", {"id": cursor["minion"], "boss": "Bob"})
125+
# end::retain-result-query[]
126+
session.close()
127+
128+
def test_result_retention(self):
129+
driver = GraphDatabase.driver("bolt://localhost")
130+
session = driver.session()
131+
# tag::retain-result-process[]
132+
cursor = session.run("MATCH (person:Person) WHERE person.dept = {dept} "
133+
"RETURN id(person) AS minion", {"dept": "IT"})
134+
minion_records = list(cursor.stream())
135+
136+
for record in minion_records:
137+
session.run("MATCH (person) WHERE id(person) = {id} "
138+
"MATCH (boss:Person) WHERE boss.name = {boss} "
139+
"CREATE (person)-[:REPORTS_TO]->(boss)", {"id": record["minion"], "boss": "Bob"})
140+
# end::retain-result-process[]
141+
session.close()
142+
143+
def test_transaction_commit(self):
144+
driver = GraphDatabase.driver("bolt://localhost")
145+
session = driver.session()
146+
# tag::transaction-commit[]
147+
tx = session.begin_transaction()
148+
tx.run("CREATE (p:Person {name: 'The One'})")
149+
tx.commit()
150+
# end::transaction-commit[]
151+
cursor = session.run("MATCH (p:Person {name: 'The One'}) RETURN count(p)")
152+
assert cursor.next()
153+
assert cursor["count(p)"] == 1
154+
assert cursor.at_end()
155+
session.close()
156+
157+
def test_transaction_rollback(self):
158+
driver = GraphDatabase.driver("bolt://localhost")
159+
session = driver.session()
160+
# tag::transaction-rollback[]
161+
tx = session.begin_transaction()
162+
tx.run("CREATE (p:Person {name: 'The One'})")
163+
tx.rollback()
164+
# end::transaction-rollback[]
165+
cursor = session.run("MATCH (p:Person {name: 'The One'}) RETURN count(p)")
166+
assert cursor.next()
167+
assert cursor["count(p)"] == 0
168+
assert cursor.at_end()
169+
session.close()
170+
171+
def test_result_summary_query_profile(self):
172+
driver = GraphDatabase.driver("bolt://localhost")
173+
session = driver.session()
174+
# tag::result-summary-query-profile[]
175+
cursor = session.run("PROFILE MATCH (p:Person {name: {name}}) "
176+
"RETURN id(p)", {"name": "The One"})
177+
summary = cursor.summarize()
178+
print(summary.statement_type)
179+
print(summary.profile)
180+
# end::result-summary-query-profile[]
181+
session.close()
182+
183+
def test_result_summary_notifications(self):
184+
driver = GraphDatabase.driver("bolt://localhost")
185+
session = driver.session()
186+
# tag::result-summary-notifications[]
187+
summary = session.run("EXPLAIN MATCH (a), (b) RETURN a,b").summarize()
188+
for notification in summary.notifications:
189+
print(notification)
190+
# end::result-summary-notifications[]
191+
session.close()

neo4j/__main__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,21 @@ def main():
6262
for _ in range(args.times):
6363
for statement in args.statement:
6464
try:
65-
result = session.run(statement, parameters)
65+
cursor = session.run(statement, parameters)
6666
except CypherError as error:
6767
stderr.write("%s: %s\r\n" % (error.code, error.message))
6868
else:
6969
if not args.quiet:
7070
has_results = False
71-
for i, record in enumerate(result):
71+
for i, record in enumerate(cursor.stream()):
7272
has_results = True
7373
if i == 0:
74-
stdout.write("%s\r\n" % "\t".join(record.__keys__))
74+
stdout.write("%s\r\n" % "\t".join(record.keys()))
7575
stdout.write("%s\r\n" % "\t".join(map(repr, record)))
7676
if has_results:
7777
stdout.write("\r\n")
7878
if args.summarize:
79-
summary = result.summarize()
79+
summary = cursor.summarize()
8080
stdout.write("Statement : %r\r\n" % summary.statement)
8181
stdout.write("Parameters : %r\r\n" % summary.parameters)
8282
stdout.write("Statement Type : %r\r\n" % summary.statement_type)

0 commit comments

Comments
 (0)