Module: Google::Cloud::Spanner

Defined in:
lib/google/cloud/spanner.rb,
lib/google/cloud/spanner/data.rb,
lib/google/cloud/spanner/pool.rb,
lib/google/cloud/spanner/range.rb,
lib/google/cloud/spanner/client.rb,
lib/google/cloud/spanner/commit.rb,
lib/google/cloud/spanner/errors.rb,
lib/google/cloud/spanner/fields.rb,
lib/google/cloud/spanner/policy.rb,
lib/google/cloud/spanner/status.rb,
lib/google/cloud/spanner/convert.rb,
lib/google/cloud/spanner/project.rb,
lib/google/cloud/spanner/results.rb,
lib/google/cloud/spanner/service.rb,
lib/google/cloud/spanner/session.rb,
lib/google/cloud/spanner/version.rb,
lib/google/cloud/spanner/database.rb,
lib/google/cloud/spanner/instance.rb,
lib/google/cloud/spanner/snapshot.rb,
lib/google/cloud/spanner/partition.rb,
lib/google/cloud/spanner/credentials.rb,
lib/google/cloud/spanner/transaction.rb,
lib/google/cloud/spanner/batch_client.rb,
lib/google/cloud/spanner/column_value.rb,
lib/google/cloud/spanner/database/job.rb,
lib/google/cloud/spanner/instance/job.rb,
lib/google/cloud/spanner/database/list.rb,
lib/google/cloud/spanner/instance/list.rb,
lib/google/cloud/spanner/admin/database.rb,
lib/google/cloud/spanner/admin/instance.rb,
lib/google/cloud/spanner/batch_snapshot.rb,
lib/google/cloud/spanner/v1/credentials.rb,
lib/google/cloud/spanner/instance/config.rb,
lib/google/cloud/spanner/admin/database/v1.rb,
lib/google/cloud/spanner/admin/instance/v1.rb,
lib/google/cloud/spanner/v1/spanner_client.rb,
lib/google/cloud/spanner/instance/config/list.rb,
lib/google/cloud/spanner/admin/database/credentials.rb,
lib/google/cloud/spanner/admin/instance/credentials.rb,
lib/google/cloud/spanner/admin/database/v1/doc/overview.rb,
lib/google/cloud/spanner/admin/instance/v1/doc/overview.rb,
lib/google/cloud/spanner/admin/database/v1/database_admin_client.rb,
lib/google/cloud/spanner/admin/instance/v1/instance_admin_client.rb

Overview

# Cloud Spanner

Cloud Spanner is a fully managed, mission-critical, relational database service that offers transactional consistency at global scale, schemas, SQL (ANSI 2011 with extensions), and automatic, synchronous replication for high availability.

For more information about Cloud Spanner, read the [Cloud Spanner Documentation](cloud.google.com/spanner/docs/).

The goal of google-cloud is to provide an API that is comfortable to Rubyists. Your authentication credentials are detected automatically in Google Cloud Platform environments such as Google Compute Engine, Google App Engine and Google Kubernetes Engine. In other environments you can configure authentication easily, either directly in your code or via environment variables. Read more about the options for connecting in the [Authentication Guide](googlecloudplatform.github.io/google-cloud-ruby/#/docs/guides/authentication).

## Enabling Logging

To enable logging for this library, set the logger for the underlying [gRPC](github.com/grpc/grpc/tree/master/src/ruby) library. The logger that you set may be a Ruby stdlib [‘Logger`](ruby-doc.org/stdlib-2.5.0/libdoc/logger/rdoc/Logger.html) as shown below, or a [`Google::Cloud::Logging::Logger`](googlecloudplatform.github.io/google-cloud-ruby/#/docs/google-cloud-logging/latest/google/cloud/logging/logger) that will write logs to [Stackdriver Logging](cloud.google.com/logging/). See [grpc/logconfig.rb](github.com/grpc/grpc/blob/master/src/ruby/lib/grpc/logconfig.rb) and the gRPC [spec_helper.rb](github.com/grpc/grpc/blob/master/src/ruby/spec/spec_helper.rb) for additional information.

Configuring a Ruby stdlib logger:

“‘ruby require “logger”

module MyLogger

LOGGER = Logger.new $stderr, level: Logger::WARN
def logger
  LOGGER
end

end

# Define a gRPC module-level logger method before grpc/logconfig.rb loads. module GRPC

extend MyLogger

end “‘

## Creating instances

When you first use Cloud Spanner, you must create an instance, which is an allocation of resources that are used by Cloud Spanner databases. When you create an instance, you choose where your data is stored and how many nodes are used for your data. (For more information, see [Instance Configuration](cloud.google.com/spanner/docs/instance-configuration)).

Use Project#create_instance to create an instance:

“‘ruby require “google/cloud/spanner”

spanner = Google::Cloud::Spanner.new

job = spanner.create_instance “my-instance”,

name: "My Instance",
config: "regional-us-central1",
nodes: 5,
labels: { production: :env }

job.done? #=> false job.reload! # API call job.done? #=> true

if job.error?

status = job.error

else

instance = job.instance

end “‘

## Creating databases

Now that you have created an instance, you can create a database. Cloud Spanner databases hold the tables and indexes that allow you to read and write data. You may create multiple databases in an instance.

Use Project#create_database (or Instance#create_database) to create a database:

“‘ruby require “google/cloud/spanner”

spanner = Google::Cloud::Spanner.new

job = spanner.create_database “my-instance”, “my-database”

job.done? #=> false job.reload! # API call job.done? #=> true

if job.error?

status = job.error

else

database = job.database

end “‘

## Updating database schemas

Cloud Spanner supports schema updates to a database while the database continues to serve traffic. Schema updates do not require taking the database offline and they do not lock entire tables or columns; you can continue writing data to the database during the schema update.

Use Database#update to execute one or more statements in Cloud Spanner’s Data Definition Language (DDL):

“‘ruby require “google/cloud/spanner”

spanner = Google::Cloud::Spanner.new

database = spanner.database “my-instance”, “my-database”

add_users_table_sql = %q(

CREATE TABLE users (
  id INT64 NOT NULL,
  username STRING(25) NOT NULL,
  name STRING(45) NOT NULL,
  email STRING(128),
) PRIMARY KEY(id)

)

database.update statements: [add_users_table_sql] “‘

## Creating clients

In order to read and/or write data, you must create a database client. You can think of a client as a database connection: All of your interactions with Cloud Spanner data must go through a client. Typically you create a client when your application starts up, then you re-use that client to read, write, and execute transactions.

Use Project#client to create a client:

“‘ruby require “google/cloud/spanner”

spanner = Google::Cloud::Spanner.new

db = spanner.client “my-instance”, “my-database”

results = db.execute “SELECT 1”

results.rows.each do |row|

puts row

end “‘

## Writing data

You write data using your client object. The client object supports various mutation operations, as well as combinations of inserts, updates, deletes, etc., that can be applied atomically to different rows and/or tables in a database.

Use Client#commit to execute various mutations atomically at a single logical point in time. All changes are accumulated in memory until the block completes. Unlike Client#transaction, which can also perform reads, this operation accepts only mutations and makes a single API request.

“‘ruby 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, username: "charlie94", name: "Charlie" }]
c.insert "users", [{ id: 2, username: "harvey00", name: "Harvey" }]

end “‘

## Querying data using SQL

Cloud Spanner supports a native SQL interface for reading data that is available through Client#execute:

“‘ruby 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 “‘

## Reading data using the read method

In addition to Cloud Spanner’s SQL interface, Cloud Spanner also supports a read interface. Use the Client#read method to read rows from the database, and use its ‘keys` option to pass unique identifiers as both lists and ranges:

“‘ruby require “google/cloud/spanner”

spanner = Google::Cloud::Spanner.new

db = spanner.client “my-instance”, “my-database”

results = db.read “users”, [:id, :name], keys: 1..5

results.rows.each do |row|

puts "User #{row[:id]} is #{row[:name]}"

end “‘

## Using read-write transactions

When an operation might write data depending on values it reads, you should use a read-write transaction to perform the reads and writes atomically.

Suppose that sales of ‘Albums(1, 1)` are lower than expected and you want to move $200,000 from the marketing budget of `Albums(2, 2)` to it, but only if the budget of `Albums(2, 2)` is at least $300,000.

Use Client#transaction to execute both reads and writes atomically at a single logical point in time. All changes are accumulated in memory until the block completes. Transactions will be automatically retried when possible. This operation makes separate API requests to begin and commit the transaction.

“‘ruby require “google/cloud/spanner”

spanner = Google::Cloud::Spanner.new

db = spanner.client “my-instance”, “my-database”

db.transaction do |tx|

# Read the second album budget.
second_album_result = tx.read "Albums", ["marketing_budget"],
                              keys: [[2, 2]], limit: 1
second_album_row = second_album_result.rows.first
second_album_budget = second_album_row.values.first

transfer_amount = 200000

if second_album_budget < 300000
  # Raising an exception will automatically roll back the transaction.
  raise "The second album doesn't have enough funds to transfer"
end

# Read the first album's budget.
first_album_result = tx.read "Albums", ["marketing_budget"],
                              keys: [[1, 1]], limit: 1
first_album_row = first_album_result.rows.first
first_album_budget = first_album_row.values.first

# Update the budgets.
second_album_budget -= transfer_amount
first_album_budget += transfer_amount
puts "Setting first album's budget to #{first_album_budget} and the " \
     "second album's budget to #{second_album_budget}."

# Update the rows.
rows = [
  {singer_id: 1, album_id: 1, marketing_budget: first_album_budget},
  {singer_id: 2, album_id: 2, marketing_budget: second_album_budget}
]
tx.update "Albums", rows

end “‘

## Using read-only transactions

Suppose you want to execute more than one read at the same timestamp. Read-only transactions observe a consistent prefix of the transaction commit history, so your application always gets consistent data. Because read-only transactions are much faster than locking read-write transactions, we strongly recommend that you do all of your transaction reads in read-only transactions if possible.

Use a Snapshot object to execute statements in a read-only transaction. The snapshot object is available via a block provided to Client#snapshot:

“‘ruby require “google/cloud/spanner”

spanner = Google::Cloud::Spanner.new

db = spanner.client “my-instance”, “my-database”

db.snapshot do |snp|

results_1 = snp.execute "SELECT * FROM users"
results_1.rows.each do |row|
  puts "User #{row[:id]} is #{row[:name]}"
end

# Perform another read using the `read` method. Even if the data
# is updated in-between the reads, the snapshot ensures that both
# return the same data.
results_2 = db.read "users", [:id, :name]
results_2.rows.each do |row|
  puts "User #{row[:id]} is #{row[:name]}"
end

end “‘

## Deleting databases

Use Database#drop to delete a database:

“‘ruby require “google/cloud/spanner”

spanner = Google::Cloud::Spanner.new

database = spanner.database “my-instance”, “my-database”

database.drop “‘

## Deleting instances

When you delete an instance, all databases within it are automatically deleted. (If you only delete databases and not your instance, you will still incur charges for the instance.) Use Instance#delete to delete an instance:

“‘ruby require “google/cloud/spanner”

spanner = Google::Cloud::Spanner.new

instance = spanner.instance “my-instance”

instance.delete ““

Defined Under Namespace

Modules: Admin, Convert, V1 Classes: BatchClient, BatchSnapshot, Client, ClientClosedError, ColumnValue, Commit, Credentials, Data, Database, DuplicateNameError, Fields, Instance, Partition, Policy, Pool, Project, Range, Results, Rollback, Service, Session, SessionLimitError, Snapshot, Status, Transaction

Constant Summary collapse

VERSION =
"1.6.1".freeze

Class Method Summary collapse

Class Method Details

.configure {|Google::Cloud.configure.spanner| ... } ⇒ Google::Cloud::Config

Configure the Google Cloud Spanner library.

The following Spanner configuration parameters are supported:

  • ‘project_id` - (String) Identifier for a Spanner project. (The parameter `project` is considered deprecated, but may also be used.)

  • ‘credentials` - (String, Hash, Google::Auth::Credentials) The path to the keyfile as a String, the contents of the keyfile as a Hash, or a Google::Auth::Credentials object. (See Credentials) (The parameter `keyfile` is considered deprecated, but may also be used.)

  • ‘scope` - (String, Array<String>) The OAuth 2.0 scopes controlling the set of resources and operations that the connection can access.

  • ‘timeout` - (Integer) Default timeout to use in requests.

  • ‘client_config` - (Hash) A hash of values to override the default behavior of the API client.

Yields:

Returns:

  • (Google::Cloud::Config)

    The configuration object the Google::Cloud::Spanner library uses.



459
460
461
462
463
# File 'lib/google/cloud/spanner.rb', line 459

def self.configure
  yield Google::Cloud.configure.spanner if block_given?

  Google::Cloud.configure.spanner
end

.default_credentials(scope: nil) ⇒ Object



475
476
477
478
479
# File 'lib/google/cloud/spanner.rb', line 475

def self.default_credentials scope: nil
  Google::Cloud.configure.spanner.credentials ||
    Google::Cloud.configure.credentials ||
    Spanner::Credentials.default(scope: scope)
end

.default_project_idObject



467
468
469
470
471
# File 'lib/google/cloud/spanner.rb', line 467

def self.default_project_id
  Google::Cloud.configure.spanner.project_id ||
    Google::Cloud.configure.project_id ||
    Google::Cloud.env.project_id
end

.new(project_id: nil, credentials: nil, scope: nil, timeout: nil, client_config: nil, project: nil, keyfile: nil) ⇒ Google::Cloud::Spanner::Project

Creates a new object for connecting to the Spanner service. Each call creates a new connection.

For more information on connecting to Google Cloud see the [Authentication Guide](googlecloudplatform.github.io/google-cloud-ruby/#/docs/guides/authentication).

Examples:

require "google/cloud/spanner"

spanner = Google::Cloud::Spanner.new

Parameters:

  • project_id (String) (defaults to: nil)

    Project identifier for the Spanner service you are connecting to. If not present, the default project for the credentials is used.

  • credentials (String, Hash, Google::Auth::Credentials) (defaults to: nil)

    The path to the keyfile as a String, the contents of the keyfile as a Hash, or a Google::Auth::Credentials object. (See Credentials)

  • scope (String, Array<String>) (defaults to: nil)

    The OAuth 2.0 scopes controlling the set of resources and operations that the connection can access. See [Using OAuth 2.0 to Access Google APIs](developers.google.com/identity/protocols/OAuth2).

    The default scopes are:

  • timeout (Integer) (defaults to: nil)

    Default timeout to use in requests. Optional.

  • client_config (Hash) (defaults to: nil)

    A hash of values to override the default behavior of the API client. Optional.

  • project (String) (defaults to: nil)

    Alias for the ‘project_id` argument. Deprecated.

  • keyfile (String) (defaults to: nil)

    Alias for the ‘credentials` argument. Deprecated.

Returns:

Raises:

  • (ArgumentError)


417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
# File 'lib/google/cloud/spanner.rb', line 417

def self.new project_id: nil, credentials: nil, scope: nil, timeout: nil,
             client_config: nil, project: nil, keyfile: nil
  project_id ||= (project || default_project_id)
  project_id = project_id.to_s # Always cast to a string
  raise ArgumentError, "project_id is missing" if project_id.empty?

  scope ||= configure.scope
  timeout ||= configure.timeout
  client_config ||= configure.client_config
  credentials ||= (keyfile || default_credentials(scope: scope))
  unless credentials.is_a? Google::Auth::Credentials
    credentials = Spanner::Credentials.new credentials, scope: scope
  end

  Spanner::Project.new(
    Spanner::Service.new(
      project_id, credentials, timeout: timeout,
                               client_config: client_config
    )
  )
end