Class: Gcloud::Datastore::Dataset

Inherits:
Object
  • Object
show all
Defined in:
lib/gcloud/datastore/dataset.rb,
lib/gcloud/datastore/dataset/query_results.rb,
lib/gcloud/datastore/dataset/lookup_results.rb

Overview

# Dataset

Dataset is the data saved in a project’s Datastore. Dataset is analogous to a database in relational database world.

Gcloud::Datastore::Dataset is the main object for interacting with Google Datastore. Entity objects are created, read, updated, and deleted by Gcloud::Datastore::Dataset.

See Gcloud#datastore

Examples:

require "gcloud"

gcloud = Gcloud.new
datastore = gcloud.datastore

query = datastore.query("Task").
  where("done", "=", false)

tasks = datastore.run query

Direct Known Subclasses

Transaction

Defined Under Namespace

Classes: LookupResults, QueryResults

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project, credentials) ⇒ Dataset



63
64
65
66
67
# File 'lib/gcloud/datastore/dataset.rb', line 63

def initialize project, credentials
  project = project.to_s # Always cast to a string
  fail ArgumentError, "project is missing" if project.empty?
  @service = Service.new project, credentials
end

Instance Attribute Details

#serviceObject



57
58
59
# File 'lib/gcloud/datastore/dataset.rb', line 57

def service
  @service
end

Class Method Details

.default_projectObject



87
88
89
90
91
92
93
# File 'lib/gcloud/datastore/dataset.rb', line 87

def self.default_project
  ENV["DATASTORE_DATASET"] ||
    ENV["DATASTORE_PROJECT"] ||
    ENV["GCLOUD_PROJECT"] ||
    ENV["GOOGLE_CLOUD_PROJECT"] ||
    Gcloud::GCE.project_id
end

Instance Method Details

#allocate_ids(incomplete_key, count = 1) ⇒ Array<Gcloud::Datastore::Key>

Generate IDs for a Key before creating an entity.

Examples:

task_key = datastore.key "Task"
task_keys = datastore.allocate_ids task_key, 5

Parameters:

  • incomplete_key (Key)

    A Key without id or name set.

  • count (String) (defaults to: 1)

    The number of new key IDs to create.

Returns:



107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/gcloud/datastore/dataset.rb', line 107

def allocate_ids incomplete_key, count = 1
  if incomplete_key.complete?
    fail Gcloud::Datastore::Error, "An incomplete key must be provided."
  end

  ensure_service!
  incomplete_keys = count.times.map { incomplete_key.to_grpc }
  allocate_res = service.allocate_ids(*incomplete_keys)
  allocate_res.keys.map { |key| Key.from_grpc key }
rescue GRPC::BadStatus => e
  raise Gcloud::Error.from_error(e)
end

#commit {|commit| ... } ⇒ Array<Gcloud::Datastore::Entity>

Make multiple changes in a single commit.

Examples:

gcloud = Gcloud.new
datastore = gcloud.datastore
datastore.commit do |c|
  c.save task3, task4
  c.delete task1, task2
end

Yields:

  • (commit)

    a block for making changes

Yield Parameters:

  • commit (Commit)

    The object that changes are made on

Returns:



263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/gcloud/datastore/dataset.rb', line 263

def commit
  return unless block_given?
  c = Commit.new
  yield c

  ensure_service!
  commit_res = service.commit c.mutations
  entities = c.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
  entities.each { |e| e.key.freeze unless e.persisted? }
  entities
rescue GRPC::BadStatus => e
  raise Gcloud::Error.from_error(e)
end

#delete(*entities_or_keys) ⇒ Boolean

Remove entities from the Datastore.

Examples:

gcloud = Gcloud.new
datastore = gcloud.datastore
datastore.delete task1, task2

Parameters:

  • entities_or_keys (Entity, Key)

    One or more Entity or Key objects to remove.

Returns:

  • (Boolean)

    Returns true if successful



241
242
243
244
# File 'lib/gcloud/datastore/dataset.rb', line 241

def delete *entities_or_keys
  commit { |c| c.delete(*entities_or_keys) }
  true
end

#entity(*key_or_path, project: nil, namespace: nil) {|entity| ... } ⇒ Gcloud::Datastore::Entity

Create a new empty Entity instance. This is a convenience method to make the creation of Entity objects easier.

Examples:

task = datastore.entity

The previous example is equivalent to:

task = Gcloud::Datastore::Entity.new

The key can also be passed in as an object:

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

Or the key values can be passed in as parameters:

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

The previous example is equivalent to:

task_key = Gcloud::Datastore::Key.new "Task", "sampleTask"
task = Gcloud::Datastore::Entity.new
task.key = task_key

The newly created entity can also be configured using a block:

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

The previous example is equivalent to:

task_key = Gcloud::Datastore::Key.new "Task", "sampleTask"
task = Gcloud::Datastore::Entity.new
task.key = task_key
task["type"] = "Personal"
task["done"] = false
task["priority"] = 4
task["description"] = "Learn Cloud Datastore"

Parameters:

  • key_or_path (Key, Array<Array(String,(String|Integer|nil))>)

    An optional list of pairs for the key’s path. Each pair may include the # key’s kind (String) and an id (Integer) or name (String). This is # optional.

  • project (String) (defaults to: nil)

    The project of the Key. This is optional.

  • namespace (String) (defaults to: nil)

    namespace kind of the Key. This is optional.

Yields:

  • (entity)

    a block yielding a new entity

Yield Parameters:

  • entity (Entity)

    the newly created entity object

Returns:



639
640
641
642
643
644
645
646
647
648
649
650
651
652
# File 'lib/gcloud/datastore/dataset.rb', line 639

def entity *key_or_path, project: nil, namespace: nil
  entity = Entity.new

  # Set the key
  if key_or_path.flatten.first.is_a? Gcloud::Datastore::Key
    entity.key = key_or_path.flatten.first
  else
    entity.key = key key_or_path, project: project, namespace: namespace
  end

  yield entity if block_given?

  entity
end

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

Retrieve an entity by key.

Examples:

Finding an entity with a key:

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

Finding an entity with a kind and id/name:

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

Parameters:

Returns:



306
307
308
309
310
311
312
# File 'lib/gcloud/datastore/dataset.rb', line 306

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

#find_all(*keys, consistency: nil) ⇒ Gcloud::Datastore::Dataset::LookupResults Also known as: lookup

Retrieve the entities for the provided keys. The order of results is undefined and has no relation to the order of keys arguments.

Examples:

gcloud = Gcloud.new
datastore = gcloud.datastore

task_key1 = datastore.key "Task", "sampleTask1"
task_key2 = datastore.key "Task", "sampleTask2"
tasks = datastore.find_all task_key1, task_key2

Parameters:

Returns:



339
340
341
342
343
344
345
346
347
# File 'lib/gcloud/datastore/dataset.rb', line 339

def find_all *keys, consistency: nil
  ensure_service!
  check_consistency! consistency
  lookup_res = service.lookup(*Array(keys).flatten.map(&:to_grpc),
                              consistency: consistency)
  LookupResults.from_grpc lookup_res, service, consistency
rescue GRPC::BadStatus => e
  raise Gcloud::Error.from_error(e)
end

#gql(query, bindings = {}) ⇒ Gcloud::Datastore::GqlQuery

Create a new GqlQuery instance. This is a convenience method to make the creation of GqlQuery objects easier.

Examples:

gql_query = datastore.gql "SELECT * FROM Task WHERE done = @done",
                          done: false
tasks = datastore.run gql_query

The previous example is equivalent to:

gql_query = Gcloud::Datastore::GqlQuery.new
gql_query.query_string = "SELECT * FROM Task WHERE done = @done"
gql_query.named_bindings = {done: false}
tasks = datastore.run gql_query

Parameters:

  • query (String)

    The GQL query string.

  • bindings (Hash) (defaults to: {})

    Named bindings for the GQL query string, each key must match regex ‘[A-Za-z_$]*`, must not match regex `__.*__`, and must not be `“”`. The value must be an Object that can be stored as an Entity property value, or a Cursor.

Returns:



522
523
524
525
526
527
# File 'lib/gcloud/datastore/dataset.rb', line 522

def gql query, bindings = {}
  gql = GqlQuery.new
  gql.query_string = query
  gql.named_bindings = bindings unless bindings.empty?
  gql
end

#insert(*entities) ⇒ Array<Gcloud::Datastore::Entity>

Insert one or more entities to the Datastore. An InvalidArgumentError will raised if the entities cannot be inserted.

Examples:

Insert a new entity:

task = datastore.entity "Task" do |t|
  t["type"] = "Personal"
  t["done"] = false
  t["priority"] = 4
  t["description"] = "Learn Cloud Datastore"
end
task.key.id #=> nil
datastore.insert task
task.key.id #=> 123456

Insert multiple new entities in a batch:

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

task2 = datastore.entity "Task" do |t|
  t["type"] = "Personal"
  t["done"] = false
  t["priority"] = 5
  t["description"] = "Integrate Cloud Datastore"
end

task_key1, task_key2 = datastore.insert(task1, task2).map(&:key)

Parameters:

  • entities (Entity)

    One or more entity objects to be inserted.

Returns:



201
202
203
# File 'lib/gcloud/datastore/dataset.rb', line 201

def insert *entities
  commit { |c| c.insert(*entities) }
end

#key(*path, project: nil, namespace: nil) ⇒ Gcloud::Datastore::Key

Create a new Key instance. This is a convenience method to make the creation of Key objects easier.

Examples:

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

The previous example is equivalent to:

task_key = Gcloud::Datastore::Key.new "Task", "sampleTask"

Create an empty key:

key = datastore.key

Create an incomplete key:

key = datastore.key "User"

Create a key with a parent:

key = datastore.key [["TaskList", "default"], ["Task", "sampleTask"]]
key.path #=> [["TaskList", "default"], ["Task", "sampleTask"]]

Create a key with multi-level ancestry:

key = datastore.key([
  ["User", "alice"],
  ["TaskList", "default"],
  ["Task", "sampleTask"]
])
key.path #=> [["User", "alice"], ["TaskList", "default"], [ ... ]]

Create an incomplete key with a parent:

key = datastore.key "TaskList", "default", "Task"
key.path #=> [["TaskList", "default"], ["Task", nil]]

Create a key with a project and namespace:

key = datastore.key ["TaskList", "default"], ["Task", "sampleTask"],
                    project: "my-todo-project",
                    namespace: "ns~todo-project"
key.path #=> [["TaskList", "default"], ["Task", "sampleTask"]]
key.project #=> "my-todo-project",
key.namespace #=> "ns~todo-project"

Parameters:

  • path (Array<Array(String,(String|Integer|nil))>)

    An optional list of pairs for the key’s path. Each pair may include the key’s kind (String) and an id (Integer) or name (String). This is optional.

  • project (String) (defaults to: nil)

    The project of the Key. This is optional.

  • namespace (String) (defaults to: nil)

    namespace kind of the Key. This is optional.

Returns:



577
578
579
580
581
582
583
584
585
586
587
# File 'lib/gcloud/datastore/dataset.rb', line 577

def key *path, project: nil, namespace: nil
  path = path.flatten.each_slice(2).to_a # group in pairs
  kind, id_or_name = path.pop
  Key.new(kind, id_or_name).tap do |k|
    k.project = project
    k.namespace = namespace
    unless path.empty?
      k.parent = key path, project: project, namespace: namespace
    end
  end
end

#projectObject

The Datastore project connected to.

Examples:

require "gcloud"

gcloud = Gcloud.new "my-todo-project",
                    "/path/to/keyfile.json"

datastore = gcloud.datastore
datastore.project #=> "my-todo-project"


81
82
83
# File 'lib/gcloud/datastore/dataset.rb', line 81

def project
  service.project
end

#query(*kinds) ⇒ Gcloud::Datastore::Query

Create a new Query instance. This is a convenience method to make the creation of Query objects easier.

Examples:

query = datastore.query("Task").
  where("done", "=", false)
tasks = datastore.run query

The previous example is equivalent to:

query = Gcloud::Datastore::Query.new.
  kind("Task").
  where("done", "=", false)
tasks = datastore.run query

Parameters:

  • kinds (String)

    The kind of entities to query. This is optional.

Returns:



493
494
495
496
497
# File 'lib/gcloud/datastore/dataset.rb', line 493

def query *kinds
  query = Query.new
  query.kind(*kinds) unless kinds.empty?
  query
end

#run(query, namespace: nil, consistency: nil) ⇒ Gcloud::Datastore::Dataset::QueryResults Also known as: run_query

Retrieve entities specified by a Query.

Examples:

query = datastore.query("Task").
  where("done", "=", false)
tasks = datastore.run query

Run an ancestor query with eventual consistency:

task_list_key = datastore.key "TaskList", "default"
query.kind("Task").
  ancestor(task_list_key)

tasks = datastore.run query, consistency: :eventual

Run the query within a namespace with the namespace option:

query = datastore.query("Task").
  where("done", "=", false)
tasks = datastore.run query, namespace: "ns~todo-project"

Run the query with a GQL string.

gql_query = datastore.gql "SELECT * FROM Task WHERE done = @done",
                          done: false
tasks = datastore.run gql_query

Run the GQL query within a namespace with namespace option:

gql_query = datastore.gql "SELECT * FROM Task WHERE done = @done",
                          done: false
tasks = datastore.run gql_query, namespace: "ns~todo-project"

Parameters:

Returns:



393
394
395
396
397
398
399
400
401
402
403
404
# File 'lib/gcloud/datastore/dataset.rb', line 393

def run query, namespace: nil, consistency: nil
  ensure_service!
  unless query.is_a?(Query) || query.is_a?(GqlQuery)
    fail ArgumentError, "Cannot run a #{query.class} object."
  end
  check_consistency! consistency
  query_res = service.run_query query.to_grpc, namespace,
                                consistency: consistency
  QueryResults.from_grpc query_res, service, namespace, query.to_grpc.dup
rescue GRPC::BadStatus => e
  raise Gcloud::Error.from_error(e)
end

#save(*entities) ⇒ Array<Gcloud::Datastore::Entity> Also known as: upsert

Persist one or more entities to the Datastore.

Examples:

Insert a new entity:

task = datastore.entity "Task" do |t|
  t["type"] = "Personal"
  t["done"] = false
  t["priority"] = 4
  t["description"] = "Learn Cloud Datastore"
end
task.key.id #=> nil
datastore.save task
task.key.id #=> 123456

Insert multiple new entities in a batch:

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

task2 = datastore.entity "Task" do |t|
  t["type"] = "Personal"
  t["done"] = false
  t["priority"] = 5
  t["description"] = "Integrate Cloud Datastore"
end

task_key1, task_key2 = datastore.save(task1, task2).map(&:key)

Update an existing entity:

task = datastore.find "Task", "sampleTask"
task["priority"] = 5
datastore.save task

Parameters:

  • entities (Entity)

    One or more entity objects to be saved.

Returns:



160
161
162
# File 'lib/gcloud/datastore/dataset.rb', line 160

def save *entities
  commit { |c| c.save(*entities) }
end

#transaction {|tx| ... } ⇒ Object

Creates a Datastore Transaction.

Examples:

Runs the given block in a database transaction:

require "gcloud"

gcloud = Gcloud.new
datastore = gcloud.datastore

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

datastore.transaction do |tx|
  if tx.find(task.key).nil?
    tx.save task
  end
end

If no block is given, a Transaction object is returned:

require "gcloud"

gcloud = Gcloud.new
datastore = gcloud.datastore

task = datastore.entity "Task", "sampleTask" 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

Yields:

  • (tx)

    a block yielding a new transaction

Yield Parameters:



455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
# File 'lib/gcloud/datastore/dataset.rb', line 455

def transaction
  tx = Transaction.new service
  return tx unless block_given?

  begin
    yield tx
    tx.commit
  rescue => e
    begin
      tx.rollback
    rescue => re
      msg = "Transaction failed to commit and rollback."
      raise TransactionError.new(msg, commit_error: e, rollback_error: re)
    end
    raise TransactionError.new("Transaction failed to commit.",
                               commit_error: e)
  end
end

#update(*entities) ⇒ Array<Gcloud::Datastore::Entity>

Update one or more entities to the Datastore. An InvalidArgumentError will raised if the entities cannot be updated.

Examples:

Update an existing entity:

task = datastore.find "Task", "sampleTask"
task["done"] = true
datastore.save task

update multiple new entities in a batch:

query = datastore.query("Task").where("done", "=", false)
tasks = datastore.run query
tasks.each { |t| t["done"] = true }
datastore.update tasks

Parameters:

  • entities (Entity)

    One or more entity objects to be updated.

Returns:



224
225
226
# File 'lib/gcloud/datastore/dataset.rb', line 224

def update *entities
  commit { |c| c.update(*entities) }
end