Class: Google::Cloud::Datastore::Transaction

Inherits:
Dataset
  • Object
show all
Defined in:
lib/google/cloud/datastore/transaction.rb

Overview

Transaction

Special Connection instance for running transactions.

See Dataset#transaction

Examples:

Transactional update:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

def transfer_funds from_key, to_key, amount
  datastore.transaction do |tx|
    from = tx.find from_key
    from["balance"] -= amount
    to = tx.find to_key
    to["balance"] += amount
    tx.save from, to
  end
end

See Also:

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Dataset

#allocate_ids, #database_id, #entity, #filter, #gql, #key, #project_id, #query, #read_only_transaction, #transaction

Instance Attribute Details

#idString (readonly)

The identifier of the transaction.

Returns:

  • (String)

    the current value of id



46
47
48
# File 'lib/google/cloud/datastore/transaction.rb', line 46

def id
  @id
end

Instance Method Details

#commit {|commit| ... } ⇒ Object

Commits a transaction.

Examples:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

task = datastore.entity "Task" do |t|
  t["type"] = "Personal"
  t["done"] = false
  t["priority"] = 4
  t["description"] = "Learn Cloud Datastore"
end

tx = datastore.transaction
begin
  if tx.find(task.key).nil?
    tx.save task
  end
  tx.commit
rescue
  tx.rollback
end

Commit can be passed a block, same as Dataset#commit:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

tx = datastore.transaction
begin
  tx.commit do |c|
  c.save task3, task4
  c.delete task1, task2
  end
rescue
  tx.rollback
end

Yields:

  • (commit)

    an optional block for making changes

Yield Parameters:

  • commit (Commit)

    The object that changes are made on



422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
# File 'lib/google/cloud/datastore/transaction.rb', line 422

def commit
  if @id.nil?
    raise TransactionError, "Cannot commit when not in a transaction."
  end

  yield @commit if block_given?

  ensure_service!

  commit_res = service.commit @commit.mutations, transaction: @id
  entities = @commit.entities
  returned_keys = commit_res.mutation_results.map(&:key)
  returned_keys.each_with_index do |key, index|
    next if entities[index].nil?
    entities[index].key = Key.from_grpc key unless key.nil?
  end
  # Make sure all entity keys are frozen so all show as persisted
  entities.each { |e| e.key.freeze unless e.persisted? }
  true
end

#delete(*entities_or_keys) ⇒ Object

Remove entities in a transaction.

Examples:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

datastore.transaction do |tx|
  if tx.find(task_list.key).nil?
    tx.delete task1, task2
  end
end


161
162
163
164
165
# File 'lib/google/cloud/datastore/transaction.rb', line 161

def delete *entities_or_keys
  @commit.delete(*entities_or_keys)
  # Do not delete yet
  true
end

#find(key_or_kind, id_or_name = nil) ⇒ Google::Cloud::Datastore::Entity? Also known as: get

Retrieve an entity by providing key information. The lookup is run within the transaction.

Examples:

Finding an entity with a key:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

task_key = datastore.key "Task", "sampleTask"
task = datastore.find task_key

Finding an entity with a kind and id/name:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

task = datastore.find "Task", "sampleTask"

Parameters:

  • key_or_kind (Key, String)

    A Key object or kind string value.

Returns:



190
191
192
193
194
195
196
# File 'lib/google/cloud/datastore/transaction.rb', line 190

def find key_or_kind, id_or_name = nil
  key = key_or_kind
  unless key.is_a? Google::Cloud::Datastore::Key
    key = Key.new key_or_kind, id_or_name
  end
  find_all(key).first
end

#find_all(*keys) ⇒ Google::Cloud::Datastore::Dataset::LookupResults Also known as: lookup

Retrieve the entities for the provided keys. The lookup is run within the transaction.

Examples:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

task_key1 = datastore.key "Task", 123456
task_key2 = datastore.key "Task", 987654
tasks = datastore.find_all task_key1, task_key2

Parameters:

  • keys (Key)

    One or more Key objects to find records for.

Returns:



216
217
218
219
220
221
# File 'lib/google/cloud/datastore/transaction.rb', line 216

def find_all *keys
  ensure_service!
  lookup_res = service.lookup(*Array(keys).flatten.map(&:to_grpc),
                              transaction: @id)
  LookupResults.from_grpc lookup_res, service, nil, @id
end

#insert(*entities) ⇒ Object

Insert entities in a transaction. An InvalidArgumentError will raised if the entities cannot be inserted.

Examples:

Transactional insert:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

task_key = datastore.key "Task", "sampleTask"

task = nil
datastore.transaction do |tx|
  task = tx.find task_key
  if task.nil?
    task = datastore.entity task_key do |t|
      t["type"] = "Personal"
      t["done"] = false
      t["priority"] = 4
      t["description"] = "Learn Cloud Datastore"
    end
    tx.insert task
  end
end


115
116
117
118
119
# File 'lib/google/cloud/datastore/transaction.rb', line 115

def insert *entities
  @commit.insert(*entities)
  # Do not insert yet
  entities
end

#reset!Object

Reset the transaction. #start must be called afterwards.



480
481
482
483
# File 'lib/google/cloud/datastore/transaction.rb', line 480

def reset!
  @id = nil
  @commit = Commit.new
end

#rollbackObject

Rolls a transaction back.

Examples:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

task = datastore.entity "Task" do |t|
  t["type"] = "Personal"
  t["done"] = false
  t["priority"] = 4
  t["description"] = "Learn Cloud Datastore"
end

tx = datastore.transaction
begin
  if tx.find(task.key).nil?
    tx.save task
  end
  tx.commit
rescue
  tx.rollback
end


467
468
469
470
471
472
473
474
475
# File 'lib/google/cloud/datastore/transaction.rb', line 467

def rollback
  if @id.nil?
    raise TransactionError, "Cannot rollback when not in a transaction."
  end

  ensure_service!
  service.rollback @id
  true
end

#run(query, namespace: nil, explain_options: nil) ⇒ Google::Cloud::Datastore::Dataset::QueryResults Also known as: run_query

Retrieve entities specified by a Query. The query is run within the transaction.

Examples:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

datastore.transaction do |tx|
  query = datastore.query("Task")
  tasks = tx.run query
end

Run the query within a namespace with the namespace option:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

query = Google::Cloud::Datastore::Query.new.kind("Task").
  where("done", "=", false)
datastore.transaction do |tx|
  tasks = tx.run query, namespace: "example-ns"
end

Run the query with explain options:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

datastore.transaction do |tx|
  query = datastore.query("Task")
  results = tx.run query, explain_options: { analyze: true }

  # You must iterate through all pages of results to get the metrics.
  loop do
    break unless results.next?
    results = results.next
  end

  if results.explain_metrics
    stats = results.explain_metrics.execution_stats
    puts "Read operations: #{stats.read_operations}"
  end
end

Run the query with explain options using a Google::Cloud::Datastore::V1::ExplainOptions object.

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

datastore.transaction do |tx|
  query = datastore.query("Task")
  explain_options = Google::Cloud::Datastore::V1::ExplainOptions.new
  results = tx.run query, explain_options: explain_options

  # You must iterate through all pages of results to get the metrics.
  loop do
    break unless results.next?
    results = results.next
  end

  if results.explain_metrics
    stats = results.explain_metrics.execution_stats
    puts "Read operations: #{stats.read_operations}"
  end
end

Parameters:

  • query (Query, GqlQuery)

    The query with the search criteria.

  • namespace (String) (defaults to: nil)

    The namespace the query is to run within.

  • explain_options (Hash, Google::Cloud::Datastore::V1::ExplainOptions) (defaults to: nil)

    The options for query explanation. See V1::ExplainOptions for details. Optional.

Returns:



300
301
302
303
304
305
306
307
308
309
310
# File 'lib/google/cloud/datastore/transaction.rb', line 300

def run query, namespace: nil, explain_options: nil
  ensure_service!
  unless query.is_a?(Query) || query.is_a?(GqlQuery)
    raise ArgumentError, "Cannot run a #{query.class} object."
  end
  query_res = service.run_query query.to_grpc, namespace,
                                explain_options: explain_options,
                                transaction: @id
  QueryResults.from_grpc query_res, service, namespace,
                         query.to_grpc.dup, nil, explain_options
end

#run_aggregation(aggregate_query, namespace: nil, explain_options: nil) ⇒ Google::Cloud::Datastore::Dataset::AggregateQueryResults

Retrieve aggregate query results specified by an AggregateQuery. The query is run within the transaction.

Examples:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

datastore.transaction do |tx|
  query = tx.query("Task")
            .where("done", "=", false)
  aggregate_query = query.aggregate_query
                         .add_count
  res = tx.run_aggregation aggregate_query
end

Run the aggregate query with explain options:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

datastore.transaction do |tx|
  query = tx.query("Task")
  aggregate_query = query.aggregate_query.add_count aggregate_alias: "total"
  results = tx.run_aggregation aggregate_query, explain_options: { analyze: true }

  if results.explain_metrics
    stats = results.explain_metrics.execution_stats
    puts "Read operations: #{stats.read_operations}"
  end
end

Parameters:

  • aggregate_query (AggregateQuery, GqlQuery)

    The Query object with the search criteria.

  • namespace (String) (defaults to: nil)

    The namespace the query is to run within.

  • explain_options (Hash, Google::Cloud::Datastore::V1::ExplainOptions) (defaults to: nil)

    The options for query explanation. See V1::ExplainOptions for details. Optional.

Returns:



355
356
357
358
359
360
361
362
363
364
# File 'lib/google/cloud/datastore/transaction.rb', line 355

def run_aggregation aggregate_query, namespace: nil, explain_options: nil
  ensure_service!
  unless aggregate_query.is_a?(AggregateQuery) || aggregate_query.is_a?(GqlQuery)
    raise ArgumentError, "Cannot run a #{aggregate_query.class} object."
  end
  aggregate_query_results = service.run_aggregation_query aggregate_query.to_grpc, namespace,
                                                          transaction: @id,
                                                          explain_options: explain_options
  Dataset::AggregateQueryResults.from_grpc aggregate_query_results, explain_options
end

#save(*entities) ⇒ Object Also known as: upsert

Persist entities in a transaction.

Examples:

Transactional get or create:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

task_key = datastore.key "Task", "sampleTask"

task = nil
datastore.transaction do |tx|
  task = tx.find task_key
  if task.nil?
    task = datastore.entity task_key do |t|
      t["type"] = "Personal"
      t["done"] = false
      t["priority"] = 4
      t["description"] = "Learn Cloud Datastore"
    end
    tx.save task
  end
end


83
84
85
86
87
# File 'lib/google/cloud/datastore/transaction.rb', line 83

def save *entities
  @commit.save(*entities)
  # Do not save yet
  entities
end

#startObject Also known as: begin_transaction

Begins a transaction. This method is run when a new Transaction is created.

Raises:



369
370
371
372
373
374
375
376
# File 'lib/google/cloud/datastore/transaction.rb', line 369

def start
  raise TransactionError, "Transaction already opened." unless @id.nil?

  ensure_service!
  tx_res = service.begin_transaction \
    previous_transaction: @previous_transaction
  @id = tx_res.transaction
end

#update(*entities) ⇒ Object

Update entities in a transaction. An InvalidArgumentError will raised if the entities cannot be updated.

Examples:

Transactional update:

require "google/cloud/datastore"

datastore = Google::Cloud::Datastore.new

task_key = datastore.key "Task", "sampleTask"

task = nil
datastore.transaction do |tx|
  task = tx.find task_key
  if task
    task["done"] = true
    tx.update task
  end
end


141
142
143
144
145
# File 'lib/google/cloud/datastore/transaction.rb', line 141

def update *entities
  @commit.update(*entities)
  # Do not update yet
  entities
end