Class: Neo4j::Driver::Result

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/neo4j/driver/result.rb

Overview

Represents the result of running a Cypher statement.

Records arrive through a Bolt::RecordBuffer that the connection's dedicated reader fills (via the StreamHandler the RUN's PULL registered). The cursor shifts from that buffer and, as it drains past the low watermark, issues the next PULL — so the reader keeps a batch or two ahead (watermark prefetch). The terminal SUCCESS's metadata becomes the Summary; a stream FAILURE is re-raised (classified) on the next read.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connection, keys = [], buffer:, handler:, query_text: nil, parameters: {}, run_metadata: {}, fetch_size: 1000, qid: nil, terminated_error: nil, on_summary: nil, on_release: nil) ⇒ Result

Returns a new instance of Result.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/neo4j/driver/result.rb', line 16

def initialize(connection, keys = [], buffer:, handler:, query_text: nil, parameters: {},
               run_metadata: {}, fetch_size: 1000, qid: nil, terminated_error: nil,
               on_summary: nil, on_release: nil)
  @connection = connection
  @keys = keys
  @buffer = buffer # Bolt::RecordBuffer, filled by the reader
  @handler = handler # the StreamHandler registered for this result's PULLs
  @query_text = query_text
  @parameters = parameters
  @run_metadata = 
  @fetch_size = fetch_size
  # Bolt query id (explicit-tx RUN reply). A PULL/DISCARD targets the *last*
  # opened query when qid is omitted, so we only send it once this result is
  # no longer the transaction's current one — see #demote! and #request_more.
  @qid = qid
  @demoted = false
  # Callable returning the error that terminated the owning transaction
  # (a failure in a *sibling* result or a tx method), or nil. Once set,
  # this result must raise it on access rather than pull — a terminated tx
  # leaves the connection FAILED, so more wire traffic is invalid. nil for
  # auto-commit results (no enclosing transaction).
  @terminated_error = terminated_error
  @failure = nil # this result's own classified stream failure, if any
  @on_summary = on_summary # called with the built Summary when the stream ends in SUCCESS
  @on_release = on_release # called once when the connection is no longer needed
  @records = [] # records pulled into memory by #buffer (not by iteration)
  @had_record = false # any RECORD arrived on this stream — drives the GQL outcome status
  @summary = nil
  @consumed = false # stream fully drained (terminal seen)
  @discarded = false # records explicitly released; further access raises
  @failed = false # stream ended with a server FAILURE; connection needs RESET
  @cancelling = false # consume(): abandon the rest — DISCARD the next batch instead of PULL
  @list_mode = false # to_a/list: pull all remaining in one PULL {n: -1}, ignoring fetch_size
  @peeked_record = nil
end

Instance Attribute Details

#connectionObject (readonly)

Returns the value of attribute connection.



52
53
54
# File 'lib/neo4j/driver/result.rb', line 52

def connection
  @connection
end

#failureObject (readonly)

This result's own classified stream failure (nil unless it failed). The transaction reads it to surface the terminating error to sibling results.



164
165
166
# File 'lib/neo4j/driver/result.rb', line 164

def failure
  @failure
end

#keysObject (readonly)

Returns the value of attribute keys.



52
53
54
# File 'lib/neo4j/driver/result.rb', line 52

def keys
  @keys
end

Instance Method Details

#bufferObject

Pull all remaining records into memory so the underlying connection can be reused for another query. Unlike #consume, records stay accessible.



141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/neo4j/driver/result.rb', line 141

def buffer
  return if @consumed

  if @peeked_record
    @records << @peeked_record
    @peeked_record = nil
  end

  while (record = next_record)
    @records << record
  end
end

#consumeObject



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/neo4j/driver/result.rb', line 120

def consume
  return @summary if @discarded

  @peeked_record = nil
  # Abandon the rest: the watermark path (request_more) now DISCARDs instead
  # of PULLing the next batch, so the server stops shipping records and the
  # stream ends on its terminating SUCCESS. We must still drain the records
  # already in flight (dropping them) so the connection is left clean.
  @cancelling = true
  begin
    nil while next_record unless @consumed
  ensure
    @records.clear
    @discarded = true
  end

  @summary
end

#demote!Object

A later RUN in the same transaction made another query current; from now on this result's PULL/DISCARD must name its qid explicitly (see #request_more). Called by Transaction#run when it opens the next result.



169
# File 'lib/neo4j/driver/result.rb', line 169

def demote! = @demoted = true

#discard!Object

Mark this result as released without touching the wire — the connection is being returned/reset by the caller. Callers drain (consume/buffer) or RESET before this, so the stream is already finished; further access raises.



174
175
176
177
178
# File 'lib/neo4j/driver/result.rb', line 174

def discard!
  @peeked_record = nil
  @discarded = true
  release_connection
end

#eachObject



101
102
103
104
105
106
# File 'lib/neo4j/driver/result.rb', line 101

def each(&)
  raise Exceptions::ResultConsumedException if @discarded
  return to_enum(:each) unless block_given?

  yield(self.next) while has_next?
end

#failed?Boolean

Returns:

  • (Boolean)


158
159
160
# File 'lib/neo4j/driver/result.rb', line 158

def failed?
  @failed
end

#has_next?Boolean

Returns:

  • (Boolean)

Raises:



54
55
56
57
58
59
60
61
62
# File 'lib/neo4j/driver/result.rb', line 54

def has_next?
  raise Exceptions::ResultConsumedException if @discarded
  return true if @records.any?
  return true if @peeked_record
  return false if @consumed

  @peeked_record = next_record
  !@peeked_record.nil?
end

#nextObject



64
65
66
67
68
69
70
71
72
# File 'lib/neo4j/driver/result.rb', line 64

def next
  raise Exceptions::ResultConsumedException if @discarded
  return @records.shift if @records.any?
  raise Exceptions::NoSuchRecordException, 'No more records' unless has_next?

  record = @peeked_record
  @peeked_record = nil
  record
end

#none?Boolean

Returns:

  • (Boolean)


154
155
156
# File 'lib/neo4j/driver/result.rb', line 154

def none?
  !has_next?
end

#peekObject



74
75
76
77
78
79
80
# File 'lib/neo4j/driver/result.rb', line 74

def peek
  raise Exceptions::ResultConsumedException if @discarded
  return @records.first if @records.any?
  raise Exceptions::NoSuchRecordException, 'No more records' unless has_next?

  @peeked_record
end

#singleObject



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/neo4j/driver/result.rb', line 82

def single
  raise Exceptions::ResultConsumedException if @discarded

  unless has_next?
    raise Exceptions::NoSuchRecordException,
          'Cannot retrieve a single record, because this result is empty.'
  end

  record = self.next

  if has_next?
    raise Exceptions::NoSuchRecordException,
          'Expected a result with a single record, but this result contains at least one more. ' \
          'Ensure your query returns only one record.'
  end

  record
end

#to_aObject



108
109
110
111
112
113
114
115
116
117
118
# File 'lib/neo4j/driver/result.rb', line 108

def to_a
  raise Exceptions::ResultConsumedException if @discarded

  # Result.list ignores the configured fetch size: pull everything still on
  # the server in a single PULL {n: -1} instead of paging (Optimization:
  # ResultListFetchAll). The next watermark pull picks this up.
  @list_mode = true
  records = []
  records << self.next while has_next?
  records
end