Class: Google::Cloud::Spanner::Session

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

Overview

# Session

A session can be used to perform transactions that read and/or modify data in a Cloud Spanner database. Sessions are meant to be reused for many consecutive transactions.

Sessions can only execute one transaction at a time. To execute multiple concurrent read-write/write-only transactions, create multiple sessions. Note that standalone reads and queries use a transaction internally, and count toward the one transaction limit.

Cloud Spanner limits the number of sessions that can exist at any given time; thus, it is a good idea to delete idle and/or unneeded sessions. Aside from explicit deletes, Cloud Spanner can delete sessions for which no operations are sent for more than an hour.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(grpc, service) ⇒ Session

Returns a new instance of Session.



52
53
54
55
# File 'lib/google/cloud/spanner/session.rb', line 52

def initialize grpc, service
  @grpc = grpc
  @service = service
end

Instance Attribute Details

#grpcObject



45
46
47
# File 'lib/google/cloud/spanner/session.rb', line 45

def grpc
  @grpc
end

#serviceObject



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

def service
  @service
end

Class Method Details

.from_grpc(grpc, service) ⇒ Object

Google::Spanner::V1::Session.



642
643
644
# File 'lib/google/cloud/spanner/session.rb', line 642

def self.from_grpc grpc, service
  new grpc, service
end

Instance Method Details

#commit(transaction_id: nil) {|commit| ... } ⇒ Time

Creates changes to be applied to rows in the database.

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

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

db.commit do |c|
  c.update "users", [{ id: 1, name: "Charlie", active: false }]
  c.insert "users", [{ id: 2, name: "Harvey",  active: true }]
end

Parameters:

  • transaction_id (String) (defaults to: nil)

    The identifier of previously-started transaction to be used instead of starting a new transaction. Optional.

Yields:

  • (commit)

    The block for mutating the data.

Yield Parameters:

Returns:

  • (Time)

    The timestamp at which the operation committed.



358
359
360
361
362
363
364
365
366
# File 'lib/google/cloud/spanner/session.rb', line 358

def commit transaction_id: nil
  ensure_service!
  commit = Commit.new
  yield commit
  commit_resp = service.commit path, commit.mutations,
                               transaction_id: transaction_id
  @last_updated_at = Time.now
  Convert.timestamp_to_time commit_resp.commit_timestamp
end

#create_transactionObject

Creates a new transaction object every time.



586
587
588
589
# File 'lib/google/cloud/spanner/session.rb', line 586

def create_transaction
  tx_grpc = service.begin_transaction path
  Transaction.from_grpc(tx_grpc, self)
end

#database_idString

The unique identifier for the database.

Returns:

  • (String)


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

def database_id
  @grpc.name.split("/")[5]
end

#delete(table, keys = [], transaction_id: nil) ⇒ Time

Deletes rows from a table. Succeeds whether or not the specified rows were present.

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

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

db.delete "users", [1, 2, 3]

Parameters:

  • table (String)

    The name of the table in the database to be modified.

  • keys (Object, Array<Object>) (defaults to: [])

    A single, or list of keys or key ranges to match returned data to. Values should have exactly as many elements as there are columns in the primary key.

Returns:

  • (Time)

    The timestamp at which the operation committed.



569
570
571
572
573
# File 'lib/google/cloud/spanner/session.rb', line 569

def delete table, keys = [], transaction_id: nil
  commit transaction_id: transaction_id do |c|
    c.delete table, keys
  end
end

#execute(sql, params: nil, types: nil, transaction: nil, partition_token: nil) ⇒ Google::Cloud::Spanner::Results

Executes a SQL query.

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

Query using query parameters:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

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

results = db.execute "SELECT * FROM users WHERE active = @active",
                     params: { active: true }

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

Query with a SQL STRUCT query parameter as a Hash:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

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

user_hash = { id: 1, name: "Charlie", active: false }

results = db.execute "SELECT * FROM users WHERE " \
                     "ID = @user_struct.id " \
                     "AND name = @user_struct.name " \
                     "AND active = @user_struct.active",
                     params: { user_struct: user_hash }

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

Specify the SQL STRUCT type using Fields object:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

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

user_type = db.fields id: :INT64, name: :STRING, active: :BOOL
user_hash = { id: 1, name: nil, active: false }

results = db.execute "SELECT * FROM users WHERE " \
                     "ID = @user_struct.id " \
                     "AND name = @user_struct.name " \
                     "AND active = @user_struct.active",
                     params: { user_struct: user_hash },
                     types: { user_struct: user_type }

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

Or, query with a SQL STRUCT as a typed Data object:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

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

user_type = db.fields id: :INT64, name: :STRING, active: :BOOL
user_data = user_type.struct id: 1, name: nil, active: false

results = db.execute "SELECT * FROM users WHERE " \
                     "ID = @user_struct.id " \
                     "AND name = @user_struct.name " \
                     "AND active = @user_struct.active",
                     params: { user_struct: user_struct }

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

Parameters:

  • sql (String)

    The SQL query string. See [Query syntax](cloud.google.com/spanner/docs/query-syntax).

    The SQL query string can contain parameter placeholders. A parameter placeholder consists of “@” followed by the parameter name. Parameter names consist of any combination of letters, numbers, and underscores.

  • params (Hash) (defaults to: nil)

    SQL parameters for the query string. The parameter placeholders, minus the “@”, are the the hash keys, and the literal values are the hash values. If the query string contains something like “WHERE id > @msg_id”, then the params must contain something like ‘:msg_id => 1`.

    Ruby types are mapped to Spanner types as follows:

    | Spanner | Ruby | Notes | |————-|—————-|—| | ‘BOOL` | `true`/`false` | | | `INT64` | `Integer` | | | `FLOAT64` | `Float` | | | `STRING` | `String` | | | `DATE` | `Date` | | | `TIMESTAMP` | `Time`, `DateTime` | | | `BYTES` | `File`, `IO`, `StringIO`, or similar | | | `ARRAY` | `Array` | Nested arrays are not supported. | | `STRUCT` | `Hash`, Data | |

    See [Data types](cloud.google.com/spanner/docs/data-definition-language#data_types).

    See [Data Types - Constructing a STRUCT](cloud.google.com/spanner/docs/data-types#constructing-a-struct).

  • types (Hash) (defaults to: nil)

    Types of the SQL parameters in ‘params`. It is not always possible for Cloud Spanner to infer the right SQL type from a value in `params`. In these cases, the `types` hash must be used to specify the SQL type for these values.

    The keys of the hash should be query string parameter placeholders, minus the “@”. The values of the hash should be Cloud Spanner type codes from the following list:

    • ‘:BOOL`

    • ‘:BYTES`

    • ‘:DATE`

    • ‘:FLOAT64`

    • ‘:INT64`

    • ‘:STRING`

    • ‘:TIMESTAMP`

    • ‘Array` - Lists are specified by providing the type code in an array. For example, an array of integers are specified as `[:INT64]`.

    • Fields - Types for STRUCT values (‘Hash`/Data objects) are specified using a Fields object.

    Types are optional.

  • transaction (Google::Spanner::V1::TransactionSelector) (defaults to: nil)

    The transaction selector value to send. Only used for single-use transactions.

Returns:



245
246
247
248
249
250
251
252
253
254
255
# File 'lib/google/cloud/spanner/session.rb', line 245

def execute sql, params: nil, types: nil, transaction: nil,
            partition_token: nil
  ensure_service!

  results = Results.execute service, path, sql,
                            params: params, types: types,
                            transaction: transaction,
                            partition_token: partition_token
  @last_updated_at = Time.now
  results
end

#idle_since?(duration) ⇒ Boolean

Determines if the session has been idle longer than the given duration.

Returns:

  • (Boolean)


634
635
636
637
# File 'lib/google/cloud/spanner/session.rb', line 634

def idle_since? duration
  return true if @last_updated_at.nil?
  Time.now > @last_updated_at + duration
end

#insert(table, *rows, transaction_id: nil) ⇒ Time

Inserts new rows in a table. If any of the rows already exist, the write or request fails with error ‘ALREADY_EXISTS`.

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

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

db.insert "users", [{ id: 1, name: "Charlie", active: false },
                    { id: 2, name: "Harvey",  active: true }]

Parameters:

  • table (String)

    The name of the table in the database to be modified.

  • rows (Array<Hash>)

    One or more hash objects with the hash keys matching the table’s columns, and the hash values matching the table’s values.

    Ruby types are mapped to Spanner types as follows:

    | Spanner | Ruby | Notes | |————-|—————-|—| | ‘BOOL` | `true`/`false` | | | `INT64` | `Integer` | | | `FLOAT64` | `Float` | | | `STRING` | `String` | | | `DATE` | `Date` | | | `TIMESTAMP` | `Time`, `DateTime` | | | `BYTES` | `File`, `IO`, `StringIO`, or similar | | | `ARRAY` | `Array` | Nested arrays are not supported. |

    See [Data types](cloud.google.com/spanner/docs/data-definition-language#data_types).

Returns:

  • (Time)

    The timestamp at which the operation committed.



452
453
454
455
456
# File 'lib/google/cloud/spanner/session.rb', line 452

def insert table, *rows, transaction_id: nil
  commit transaction_id: transaction_id do |c|
    c.insert table, rows
  end
end

#instance_idString

The unique identifier for the instance.

Returns:

  • (String)


65
66
67
# File 'lib/google/cloud/spanner/session.rb', line 65

def instance_id
  @grpc.name.split("/")[3]
end

#keepalive!Object

Keeps the session alive by executing ‘“SELECT 1”`.



611
612
613
614
615
616
617
618
619
620
621
# File 'lib/google/cloud/spanner/session.rb', line 611

def keepalive!
  ensure_service!
  execute "SELECT 1"
  return true
rescue Google::Cloud::NotFoundError
  @grpc = service.create_session \
    Admin::Database::V1::DatabaseAdminClient.database_path(
      project_id, instance_id, database_id
    )
  return false
end

#partition_query(sql, transaction, params: nil, types: nil, partition_size_bytes: nil, max_partitions: nil) ⇒ Object



305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/google/cloud/spanner/session.rb', line 305

def partition_query sql, transaction, params: nil, types: nil,
                    partition_size_bytes: nil, max_partitions: nil
  ensure_service!

  results = service.partition_query \
    path, sql, transaction, params: params, types: types,
                            partition_size_bytes: partition_size_bytes,
                            max_partitions: max_partitions

  @last_updated_at = Time.now

  results
end

#partition_read(table, columns, transaction, keys: nil, index: nil, partition_size_bytes: nil, max_partitions: nil) ⇒ Object



319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/google/cloud/spanner/session.rb', line 319

def partition_read table, columns, transaction, keys: nil,
                   index: nil, partition_size_bytes: nil,
                   max_partitions: nil
  ensure_service!

  results = service.partition_read \
    path, table, columns, transaction,
    keys: keys, index: index,
    partition_size_bytes: partition_size_bytes,
    max_partitions: max_partitions

  @last_updated_at = Time.now

  results
end

#pathString

The full path for the session resource. Values are of the form ‘projects/<project_id>/instances/<instance_id>/databases/<database_id>/sessions/<session_id>`.

Returns:

  • (String)


87
88
89
# File 'lib/google/cloud/spanner/session.rb', line 87

def path
  @grpc.name
end

#project_idString

The unique identifier for the project.

Returns:

  • (String)


59
60
61
# File 'lib/google/cloud/spanner/session.rb', line 59

def project_id
  @grpc.name.split("/")[1]
end

#read(table, columns, keys: nil, index: nil, limit: nil, transaction: nil, partition_token: nil) ⇒ Google::Cloud::Spanner::Results

Read rows from a database table, as a simple alternative to #execute.

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

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

results = db.read "users", [:id, :name]

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

Parameters:

  • table (String)

    The name of the table in the database to be read.

  • columns (Array<String, Symbol>)

    The columns of table to be returned for each row matching this request.

  • keys (Object, Array<Object>) (defaults to: nil)

    A single, or list of keys or key ranges to match returned data to. Values should have exactly as many elements as there are columns in the primary key.

  • index (String) (defaults to: nil)

    The name of an index to use instead of the table’s primary key when interpreting ‘id` and sorting result rows. Optional.

  • limit (Integer) (defaults to: nil)

    If greater than zero, no more than this number of rows will be returned. The default is no limit.

  • transaction (Google::Spanner::V1::TransactionSelector) (defaults to: nil)

    The transaction selector value to send. Only used for single-use transactions.

Returns:



293
294
295
296
297
298
299
300
301
302
303
# File 'lib/google/cloud/spanner/session.rb', line 293

def read table, columns, keys: nil, index: nil, limit: nil,
         transaction: nil, partition_token: nil
  ensure_service!

  results = Results.read service, path, table, columns,
                         keys: keys, index: index, limit: limit,
                         transaction: transaction,
                         partition_token: partition_token
  @last_updated_at = Time.now
  results
end

#release!Object

Permanently deletes the session.



625
626
627
628
# File 'lib/google/cloud/spanner/session.rb', line 625

def release!
  ensure_service!
  service.delete_session path
end

#reload!Object

Reloads the session resource. Useful for determining if the session is still valid on the Spanner API.



594
595
596
597
598
599
600
601
602
603
604
605
606
# File 'lib/google/cloud/spanner/session.rb', line 594

def reload!
  ensure_service!
  @grpc = service.get_session path
  @last_updated_at = Time.now
  return self
rescue Google::Cloud::NotFoundError
  @grpc = service.create_session \
    Admin::Database::V1::DatabaseAdminClient.database_path(
      project_id, instance_id, database_id
    )
  @last_updated_at = Time.now
  return self
end

#replace(table, *rows, transaction_id: nil) ⇒ Time

Inserts or replaces rows in a table. If any of the rows already exist, it is deleted, and the column values provided are inserted instead. Unlike #upsert, this means any values not explicitly written become ‘NULL`.

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

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

db.replace "users", [{ id: 1, name: "Charlie", active: false },
                     { id: 2, name: "Harvey",  active: true }]

Parameters:

  • table (String)

    The name of the table in the database to be modified.

  • rows (Array<Hash>)

    One or more hash objects with the hash keys matching the table’s columns, and the hash values matching the table’s values.

    Ruby types are mapped to Spanner types as follows:

    | Spanner | Ruby | Notes | |————-|—————-|—| | ‘BOOL` | `true`/`false` | | | `INT64` | `Integer` | | | `FLOAT64` | `Float` | | | `STRING` | `String` | | | `DATE` | `Date` | | | `TIMESTAMP` | `Time`, `DateTime` | | | `BYTES` | `File`, `IO`, `StringIO`, or similar | | | `ARRAY` | `Array` | Nested arrays are not supported. |

    See [Data types](cloud.google.com/spanner/docs/data-definition-language#data_types).

Returns:

  • (Time)

    The timestamp at which the operation committed.



542
543
544
545
546
# File 'lib/google/cloud/spanner/session.rb', line 542

def replace table, *rows, transaction_id: nil
  commit transaction_id: transaction_id do |c|
    c.replace table, rows
  end
end

#rollback(transaction_id) ⇒ Object

Rolls back the transaction, releasing any locks it holds.



577
578
579
580
581
# File 'lib/google/cloud/spanner/session.rb', line 577

def rollback transaction_id
  service.rollback path, transaction_id
  @last_updated_at = Time.now
  true
end

#sessionObject



648
649
650
# File 'lib/google/cloud/spanner/session.rb', line 648

def session
  self
end

#session_idString

The unique identifier for the session.

Returns:

  • (String)


77
78
79
# File 'lib/google/cloud/spanner/session.rb', line 77

def session_id
  @grpc.name.split("/")[7]
end

#update(table, *rows, transaction_id: nil) ⇒ Time

Updates existing rows in a table. If any of the rows does not already exist, the request fails with error ‘NOT_FOUND`.

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

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

db.update "users", [{ id: 1, name: "Charlie", active: false },
                    { id: 2, name: "Harvey",  active: true }]

Parameters:

  • table (String)

    The name of the table in the database to be modified.

  • rows (Array<Hash>)

    One or more hash objects with the hash keys matching the table’s columns, and the hash values matching the table’s values.

    Ruby types are mapped to Spanner types as follows:

    | Spanner | Ruby | Notes | |————-|—————-|—| | ‘BOOL` | `true`/`false` | | | `INT64` | `Integer` | | | `FLOAT64` | `Float` | | | `STRING` | `String` | | | `DATE` | `Date` | | | `TIMESTAMP` | `Time`, `DateTime` | | | `BYTES` | `File`, `IO`, `StringIO`, or similar | | | `ARRAY` | `Array` | Nested arrays are not supported. |

    See [Data types](cloud.google.com/spanner/docs/data-definition-language#data_types).

Returns:

  • (Time)

    The timestamp at which the operation committed.



496
497
498
499
500
# File 'lib/google/cloud/spanner/session.rb', line 496

def update table, *rows, transaction_id: nil
  commit transaction_id: transaction_id do |c|
    c.update table, rows
  end
end

#upsert(table, *rows, transaction_id: nil) ⇒ Time Also known as: save

Inserts or updates rows in a table. If any of the rows already exist, then its column values are overwritten with the ones provided. Any column values not explicitly written are preserved.

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

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

db.upsert "users", [{ id: 1, name: "Charlie", active: false },
                    { id: 2, name: "Harvey",  active: true }]

Parameters:

  • table (String)

    The name of the table in the database to be modified.

  • rows (Array<Hash>)

    One or more hash objects with the hash keys matching the table’s columns, and the hash values matching the table’s values.

    Ruby types are mapped to Spanner types as follows:

    | Spanner | Ruby | Notes | |————-|—————-|—| | ‘BOOL` | `true`/`false` | | | `INT64` | `Integer` | | | `FLOAT64` | `Float` | | | `STRING` | `String` | | | `DATE` | `Date` | | | `TIMESTAMP` | `Time`, `DateTime` | | | `BYTES` | `File`, `IO`, `StringIO`, or similar | | | `ARRAY` | `Array` | Nested arrays are not supported. |

    See [Data types](cloud.google.com/spanner/docs/data-definition-language#data_types).

Returns:

  • (Time)

    The timestamp at which the operation committed.



407
408
409
410
411
# File 'lib/google/cloud/spanner/session.rb', line 407

def upsert table, *rows, transaction_id: nil
  commit transaction_id: transaction_id do |c|
    c.upsert table, rows
  end
end