Class: Google::Cloud::Spanner::Results

Inherits:
Object
  • Object
show all
Defined in:
lib/google/cloud/spanner/results.rb

Overview

Results

Represents the result set from an operation returning data.

See Client#execute_query and Client#read.

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

db = spanner.client "my-instance", "my-database"

results = db.execute_query "SELECT * FROM users"

results.fields.pairs.each do |name, type|
  puts "Column #{name} is type #{type}"
end

Constant Summary collapse

RST_STREAM_INTERNAL_ERROR =
"Received RST_STREAM".freeze
EOS_INTERNAL_ERROR =
"Received unexpected EOS on DATA frame from server".freeze

Instance Method Summary collapse

Instance Method Details

#fieldsFields

Returns the configuration object (Fields) of the names and types of the rows in the returned data.

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

db = spanner.client "my-instance", "my-database"

results = db.execute_query "SELECT * FROM users"

results.fields.pairs.each do |name, type|
  puts "Column #{name} is type #{type}"
end

Returns:

  • (Fields)

    The fields of the returned data.


74
75
76
# File 'lib/google/cloud/spanner/results.rb', line 74

def fields
  @fields ||= Fields.from_grpc @metadata.row_type.fields
end

#rows {|row| ... } ⇒ Object

The values returned from the request.

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

db = spanner.client "my-instance", "my-database"

results = db.execute_query "SELECT * FROM users"

results.rows.each do |row|
  puts "User #{row[:id]} is #{row[:name]}"
end

Yields:

  • (row)

    An enumerator for the rows.

Yield Parameters:

  • row (Data)

    object that contains the data values.


99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/google/cloud/spanner/results.rb', line 99

def rows
  return nil if @closed

  unless block_given?
    return enum_for(:rows)
  end

  fields = @metadata.row_type.fields
  values = []
  buffered_responses = []
  buffer_upper_bound = 10
  chunked_value = nil
  resume_token = nil
  should_resume_request = false
  should_retry_request = false

  # Cannot call Enumerator#each because it won't return the first
  # value that was already identified when calling Enumerator#peek.
  # Iterate only using Enumerator#next and break on StopIteration.
  loop do
    begin
      if should_resume_request
        @enum = resume_request(resume_token)
        buffered_responses = []
        should_resume_request = false
      elsif should_retry_request
        @enum = retry_request()
        buffered_responses = []
        should_retry_request = false
      end

      grpc = @enum.next
      # metadata should be set before the first iteration...
      @metadata ||= grpc.
      @stats ||= grpc.stats

      buffered_responses << grpc

      if (grpc.resume_token && grpc.resume_token != "") ||
        buffered_responses.size >= buffer_upper_bound
        # This can set the resume_token to nil
        resume_token = grpc.resume_token

        if fields.count > 0
          buffered_responses.each do |resp|
            if chunked_value
              resp.values.unshift merge(chunked_value, resp.values.shift)
              chunked_value = nil
            end
            to_iterate = values + Array(resp.values)
            chunked_value = to_iterate.pop if resp.chunked_value
            values = to_iterate.pop(to_iterate.count % fields.count)
            to_iterate.each_slice(fields.count) do |slice|
              yield Data.from_grpc(slice, fields)
            end
          end
        end

        # Flush the buffered responses now that they are all handled
        buffered_responses = []
      end
    # TODO: once the generated client throws only Google Cloud errors, remove
    # the GRPC errors from the rescue block
    rescue GRPC::Aborted,
      GRPC::Cancelled,
      GRPC::DeadlineExceeded,
      GRPC::Internal,
      GRPC::ResourceExhausted,
      GRPC::Unauthenticated,
      GRPC::Unavailable,
      GRPC::Core::CallError,
      Google::Cloud::AbortedError,
      Google::Cloud::CanceledError,
      Google::Cloud::DeadlineExceededError,
      Google::Cloud::InternalError,
      Google::Cloud::ResourceExhaustedError,
      Google::Cloud::UnauthenticatedError,
      Google::Cloud::UnavailableError => err

      if resumable?(resume_token)
        should_resume_request = true
      elsif retryable?(err)
        should_retry_request = true
      elsif err.is_a?(Google::Cloud::Error)
        raise err
      else
        raise Google::Cloud::Error.from_error(err)
      end

    # TODO: once the generated client throws only Google Cloud errors, remove
    # this rescue block (for GRPC::BadStatus)
    rescue GRPC::BadStatus => err
      raise Google::Cloud::Error.from_error(err)
    rescue StopIteration
      break
    end
  end

  # clear out any remaining values left over
  if fields.count > 0
    buffered_responses.each do |resp|
      if chunked_value
        resp.values.unshift merge(chunked_value, resp.values.shift)
        chunked_value = nil
      end
      to_iterate = values + Array(resp.values)
      chunked_value = to_iterate.pop if resp.chunked_value
      values = to_iterate.pop(to_iterate.count % fields.count)
      to_iterate.each_slice(fields.count) do |slice|
        yield Data.from_grpc(slice, fields)
      end
    end
    values.each_slice(fields.count) do |slice|
      yield Data.from_grpc(slice, fields)
    end
  end

  # If we get this far then we can release the session
  @closed = true
  nil
end

#timestampTime

The read timestamp chosen for single-use snapshots (read-only transactions).

Returns:

  • (Time)

    The chosen timestamp.


50
51
52
53
# File 'lib/google/cloud/spanner/results.rb', line 50

def timestamp
  return nil if @metadata.nil? || @metadata.transaction.nil?
  Convert.timestamp_to_time @metadata.transaction.read_timestamp
end