3232 "RoutingDriver" ,
3333 "Session" ,
3434 "Transaction" ,
35+ "Statement" ,
3536 "StatementResult" ,
3637 "BoltStatementResult" ,
3738 "BoltStatementResultSummary" ,
7273from warnings import warn
7374
7475
75- from .compat import perf_counter , urlparse
76+ from .compat import perf_counter , urlparse , xstr
7677from .config import *
7778from .meta import version as __version__
7879
@@ -436,30 +437,49 @@ def run(self, statement, parameters=None, **kwparameters):
436437 protocol_version = cx .protocol_version
437438 server = cx .server
438439
439- statement = ustr (statement )
440+ has_transaction = self .has_transaction ()
441+
442+ statement_text = ustr (statement )
443+ statement_metadata = getattr (statement , "metadata" , None )
444+ statement_timeout = getattr (statement , "timeout" , None )
440445 parameters = fix_parameters (dict (parameters or {}, ** kwparameters ), protocol_version ,
441446 supports_bytes = server .supports ("bytes" ))
442447
443448 def fail (_ ):
444449 self ._close_transaction ()
445450
446451 hydrant = PackStreamHydrator (protocol_version )
447- metadata = {
448- "statement" : statement ,
452+ result_metadata = {
453+ "statement" : statement_text ,
449454 "parameters" : parameters ,
450455 "server" : server ,
451456 "protocol_version" : protocol_version ,
452457 }
458+ run_metadata = {
459+ "metadata" : statement_metadata ,
460+ "timeout" : statement_timeout ,
461+ "on_success" : result_metadata .update ,
462+ "on_failure" : fail ,
463+ }
453464
454465 def done (summary_metadata ):
455- metadata .update (summary_metadata )
456- bookmark = metadata .get ("bookmark" )
466+ result_metadata .update (summary_metadata )
467+ bookmark = result_metadata .get ("bookmark" )
457468 if bookmark :
458469 self ._bookmarks_in = tuple ([bookmark ])
459470 self ._bookmark_out = bookmark
460471
461- self ._last_result = result = BoltStatementResult (self , hydrant , metadata )
462- cx .run (statement , parameters , on_success = metadata .update , on_failure = fail )
472+ self ._last_result = result = BoltStatementResult (self , hydrant , result_metadata )
473+
474+ if has_transaction :
475+ if statement_metadata :
476+ raise ValueError ("Metadata can only be attached at transaction level" )
477+ if statement_timeout :
478+ raise ValueError ("Timeouts only apply at transaction level" )
479+ else :
480+ run_metadata ["bookmarks" ] = self ._bookmarks_in
481+
482+ cx .run (statement_text , parameters , ** run_metadata )
463483 cx .pull_all (
464484 on_records = lambda records : result ._records .extend (
465485 hydrant .hydrate_records (result .keys (), records )),
@@ -468,7 +488,7 @@ def done(summary_metadata):
468488 on_summary = lambda : result .detach (sync = False ),
469489 )
470490
471- if not self . has_transaction () :
491+ if not has_transaction :
472492 try :
473493 self ._connection .send ()
474494 self ._connection .fetch ()
@@ -805,6 +825,36 @@ def closed(self):
805825 return self ._closed
806826
807827
828+ class Statement (object ):
829+
830+ def __init__ (self , text , metadata = None , timeout = None ):
831+ self .text = text
832+ try :
833+ self .metadata = metadata
834+ except TypeError :
835+ raise TypeError ("Metadata must be coercible to a dict" )
836+ try :
837+ self .timeout = timeout
838+ except TypeError :
839+ raise TypeError ("Timeout must be specified as a number of seconds" )
840+
841+ def __str__ (self ):
842+ return xstr (self .text )
843+
844+
845+ def fix_parameters (parameters , protocol_version , ** kwargs ):
846+ if not parameters :
847+ return {}
848+ dehydrator = PackStreamDehydrator (protocol_version , ** kwargs )
849+ try :
850+ dehydrated , = dehydrator .dehydrate ([parameters ])
851+ except TypeError as error :
852+ value = error .args [0 ]
853+ raise TypeError ("Parameters of type {} are not supported" .format (type (value ).__name__ ))
854+ else :
855+ return dehydrated
856+
857+
808858class StatementResult (object ):
809859 """ A handler for the result of Cypher statement execution. Instances
810860 of this class are typically constructed and returned by
@@ -1406,19 +1456,6 @@ def custom_auth(principal, credentials, realm, scheme, **parameters):
14061456 return AuthToken (scheme , principal , credentials , realm , ** parameters )
14071457
14081458
1409- def fix_parameters (parameters , protocol_version , ** kwargs ):
1410- if not parameters :
1411- return {}
1412- dehydrator = PackStreamDehydrator (protocol_version , ** kwargs )
1413- try :
1414- dehydrated , = dehydrator .dehydrate ([parameters ])
1415- except TypeError as error :
1416- value = error .args [0 ]
1417- raise TypeError ("Parameters of type {} are not supported" .format (type (value ).__name__ ))
1418- else :
1419- return dehydrated
1420-
1421-
14221459def iter_items (iterable ):
14231460 """ Iterate through all items (key-value pairs) within an iterable
14241461 dictionary-like object. If the object has a `keys` method, this is
0 commit comments