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 and Client#read.

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

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

results = db.execute "SELECT * FROM users"

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

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.execute(service, session_path, sql, params: nil, types: nil, transaction: nil) ⇒ Object



206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/google/cloud/spanner/results.rb', line 206

def self.execute service, session_path, sql, params: nil, types: nil,
                 transaction: nil
  execute_options = { transaction: transaction, params: params,
                      types: types }
  enum = service.streaming_execute_sql session_path, sql,
                                       execute_options
  from_enum(enum, service).tap do |results|
    results.instance_variable_set :@session_path,    session_path
    results.instance_variable_set :@sql,             sql
    results.instance_variable_set :@execute_options, execute_options
  end
end

.from_enum(enum, service) ⇒ Object



195
196
197
198
199
200
201
202
203
# File 'lib/google/cloud/spanner/results.rb', line 195

def self.from_enum enum, service
  grpc = enum.peek
  new.tap do |results|
    results.instance_variable_set :@metadata, grpc.
    results.instance_variable_set :@stats,    grpc.stats
    results.instance_variable_set :@enum,     enum
    results.instance_variable_set :@service,  service
  end
end

.read(service, session_path, table, columns, keys: nil, index: nil, limit: nil, transaction: nil) ⇒ Object



220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/google/cloud/spanner/results.rb', line 220

def self.read service, session_path, table, columns, keys: nil,
              index: nil, limit: nil, transaction: nil
  read_options = { keys: keys, index: index, limit: limit,
                   transaction: transaction }
  enum = service.streaming_read_table \
    session_path, table, columns, read_options
  from_enum(enum, service).tap do |results|
    results.instance_variable_set :@session_path, session_path
    results.instance_variable_set :@table,        table
    results.instance_variable_set :@columns,      columns
    results.instance_variable_set :@read_options, read_options
  end
end

Instance Method Details

#fieldsFields

Returns the field names and types for 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 "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.



71
72
73
# File 'lib/google/cloud/spanner/results.rb', line 71

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

#inspectObject



240
241
242
# File 'lib/google/cloud/spanner/results.rb', line 240

def inspect
  "#<#{self.class.name} #{self}>"
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 "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.



96
97
98
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
# File 'lib/google/cloud/spanner/results.rb', line 96

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

  # 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
      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

        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

        # Flush the buffered responses now that they are all handled
        buffered_responses = []
      end
    rescue GRPC::Unavailable => err
      if resume_token.nil? || resume_token.empty?
        # Re-raise if the resume_token is not a valid value.
        # This can happen if the buffer was flushed.
        raise Google::Cloud::Error.from_error(err)
      end

      # Resume the stream from the last known resume_token
      if @execute_options
        @enum = @service.streaming_execute_sql \
          @session_path, @sql,
          @execute_options.merge(resume_token: resume_token)
      else
        @enum = @service.streaming_read_table \
          @session_path, @table, @columns,
          @read_options.merge(resume_token: resume_token)
      end

      # Flush the buffered responses to reset to the resume_token
      buffered_responses = []
    rescue GRPC::BadStatus => err
      raise Google::Cloud::Error.from_error(err)
    rescue StopIteration
      break
    end
  end

  # clear out any remaining values left over
  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

  # 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.



48
49
50
51
# File 'lib/google/cloud/spanner/results.rb', line 48

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

#to_sObject



235
236
237
# File 'lib/google/cloud/spanner/results.rb', line 235

def to_s
  "(#{fields.inspect} streaming)"
end