@@ -28,23 +28,19 @@ class which can be used to obtain `Driver` instances that are used for
2828
2929from __future__ import division
3030
31- from collections import deque , namedtuple
31+ from collections import deque
3232
33- from .compat import integer , string , urlparse
3433from .bolt import connect , Response , RUN , PULL_ALL
34+ from .compat import integer , string , urlparse
3535from .constants import DEFAULT_PORT , ENCRYPTED_DEFAULT , TRUST_DEFAULT , TRUST_SIGNED_CERTIFICATES
3636from .exceptions import CypherError , ProtocolError , ResultError
3737from .ssl_compat import SSL_AVAILABLE , SSLContext , PROTOCOL_SSLv23 , OP_NO_SSLv2 , CERT_REQUIRED
38+ from .summary import ResultSummary
3839from .types import hydrated
3940
4041
4142DEFAULT_MAX_POOL_SIZE = 50
4243
43- STATEMENT_TYPE_READ_ONLY = "r"
44- STATEMENT_TYPE_READ_WRITE = "rw"
45- STATEMENT_TYPE_WRITE_ONLY = "w"
46- STATEMENT_TYPE_SCHEMA_WRITE = "s"
47-
4844
4945def basic_auth (user , password ):
5046 """ Generate a basic auth token for a given user and password.
@@ -290,172 +286,6 @@ def peek(self):
290286 raise ResultError ("End of stream" )
291287
292288
293- class ResultSummary (object ):
294- """ A summary of execution returned with a :class:`.StatementResult` object.
295- """
296-
297- #: The statement that was executed to produce this result.
298- statement = None
299-
300- #: Dictionary of parameters passed with the statement.
301- parameters = None
302-
303- #: The type of statement (``'r'`` = read-only, ``'rw'`` = read/write).
304- statement_type = None
305-
306- #: A set of statistical information held in a :class:`.Counters` instance.
307- counters = None
308-
309- #: A :class:`.Plan` instance
310- plan = None
311-
312- #: A :class:`.ProfiledPlan` instance
313- profile = None
314-
315- #: Notifications provide extra information for a user executing a statement.
316- #: They can be warnings about problematic queries or other valuable information that can be
317- #: presented in a client.
318- #: Unlike failures or errors, notifications do not affect the execution of a statement.
319- notifications = None
320-
321- def __init__ (self , statement , parameters , ** metadata ):
322- self .statement = statement
323- self .parameters = parameters
324- self .statement_type = metadata .get ("type" )
325- self .counters = SummaryCounters (metadata .get ("stats" , {}))
326- if "plan" in metadata :
327- self .plan = make_plan (metadata ["plan" ])
328- if "profile" in metadata :
329- self .profile = make_plan (metadata ["profile" ])
330- self .plan = self .profile
331- self .notifications = []
332- for notification in metadata .get ("notifications" , []):
333- position = notification .get ("position" )
334- if position is not None :
335- position = Position (position ["offset" ], position ["line" ], position ["column" ])
336- self .notifications .append (Notification (notification ["code" ], notification ["title" ],
337- notification ["description" ], notification ["severity" ], position ))
338-
339-
340- class SummaryCounters (object ):
341- """ Set of statistics from a Cypher statement execution.
342- """
343-
344- #:
345- nodes_created = 0
346-
347- #:
348- nodes_deleted = 0
349-
350- #:
351- relationships_created = 0
352-
353- #:
354- relationships_deleted = 0
355-
356- #:
357- properties_set = 0
358-
359- #:
360- labels_added = 0
361-
362- #:
363- labels_removed = 0
364-
365- #:
366- indexes_added = 0
367-
368- #:
369- indexes_removed = 0
370-
371- #:
372- constraints_added = 0
373-
374- #:
375- constraints_removed = 0
376-
377- def __init__ (self , statistics ):
378- for key , value in dict (statistics ).items ():
379- key = key .replace ("-" , "_" )
380- setattr (self , key , value )
381-
382- def __repr__ (self ):
383- return repr (vars (self ))
384-
385- @property
386- def contains_updates (self ):
387- return bool (self .nodes_created or self .nodes_deleted or \
388- self .relationships_created or self .relationships_deleted or \
389- self .properties_set or self .labels_added or self .labels_removed or \
390- self .indexes_added or self .indexes_removed or \
391- self .constraints_added or self .constraints_removed )
392-
393-
394- #: A plan describes how the database will execute your statement.
395- #:
396- #: operator_type:
397- #: the name of the operation performed by the plan
398- #: identifiers:
399- #: the list of identifiers used by this plan
400- #: arguments:
401- #: a dictionary of arguments used in the specific operation performed by the plan
402- #: children:
403- #: a list of sub-plans
404- Plan = namedtuple ("Plan" , ("operator_type" , "identifiers" , "arguments" , "children" ))
405-
406- #: A profiled plan describes how the database executed your statement.
407- #:
408- #: db_hits:
409- #: the number of times this part of the plan touched the underlying data stores
410- #: rows:
411- #: the number of records this part of the plan produced
412- ProfiledPlan = namedtuple ("ProfiledPlan" , Plan ._fields + ("db_hits" , "rows" ))
413-
414- #: Representation for notifications found when executing a statement. A
415- #: notification can be visualized in a client pinpointing problems or
416- #: other information about the statement.
417- #:
418- #: code:
419- #: a notification code for the discovered issue.
420- #: title:
421- #: a short summary of the notification
422- #: description:
423- #: a long description of the notification
424- #: severity:
425- #: the severity level of the notification
426- #: position:
427- #: the position in the statement where this notification points to, if relevant.
428- Notification = namedtuple ("Notification" , ("code" , "title" , "description" , "severity" , "position" ))
429-
430- #: A position within a statement, consisting of offset, line and column.
431- #:
432- #: offset:
433- #: the character offset referred to by this position; offset numbers start at 0
434- #: line:
435- #: the line number referred to by the position; line numbers start at 1
436- #: column:
437- #: the column number referred to by the position; column numbers start at 1
438- Position = namedtuple ("Position" , ("offset" , "line" , "column" ))
439-
440-
441- def make_plan (plan_dict ):
442- """ Construct a Plan or ProfiledPlan from a dictionary of metadata values.
443-
444- :param plan_dict:
445- :return:
446- """
447- operator_type = plan_dict ["operatorType" ]
448- identifiers = plan_dict .get ("identifiers" , [])
449- arguments = plan_dict .get ("args" , [])
450- children = [make_plan (child ) for child in plan_dict .get ("children" , [])]
451- if "dbHits" in plan_dict or "rows" in plan_dict :
452- db_hits = plan_dict .get ("dbHits" , 0 )
453- rows = plan_dict .get ("rows" , 0 )
454- return ProfiledPlan (operator_type , identifiers , arguments , children , db_hits , rows )
455- else :
456- return Plan (operator_type , identifiers , arguments , children )
457-
458-
459289def run (connection , statement , parameters = None ):
460290 """ Run a Cypher statement on a given connection.
461291
0 commit comments