gcloud 0.8.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/CHANGELOG.md +26 -0
- data/OVERVIEW.md +10 -8
- data/lib/gcloud.rb +12 -13
- data/lib/gcloud/bigquery/dataset/list.rb +2 -4
- data/lib/gcloud/bigquery/job/list.rb +3 -5
- data/lib/gcloud/bigquery/table/list.rb +3 -5
- data/lib/gcloud/datastore.rb +326 -97
- data/lib/gcloud/datastore/commit.rb +73 -56
- data/lib/gcloud/datastore/credentials.rb +1 -12
- data/lib/gcloud/datastore/cursor.rb +76 -0
- data/lib/gcloud/datastore/dataset.rb +337 -134
- data/lib/gcloud/datastore/dataset/lookup_results.rb +12 -12
- data/lib/gcloud/datastore/dataset/query_results.rb +117 -27
- data/lib/gcloud/datastore/entity.rb +159 -93
- data/lib/gcloud/datastore/errors.rb +0 -21
- data/lib/gcloud/datastore/gql_query.rb +211 -0
- data/lib/gcloud/datastore/grpc_utils.rb +131 -0
- data/lib/gcloud/datastore/key.rb +74 -65
- data/lib/gcloud/datastore/properties.rb +14 -1
- data/lib/gcloud/datastore/query.rb +188 -52
- data/lib/gcloud/datastore/service.rb +161 -0
- data/lib/gcloud/datastore/transaction.rb +175 -60
- data/lib/gcloud/dns/change/list.rb +2 -4
- data/lib/gcloud/dns/record/list.rb +2 -4
- data/lib/gcloud/dns/zone/list.rb +2 -4
- data/lib/gcloud/grpc_utils.rb +11 -0
- data/lib/gcloud/logging/entry.rb +6 -17
- data/lib/gcloud/logging/entry/list.rb +8 -9
- data/lib/gcloud/logging/metric/list.rb +4 -5
- data/lib/gcloud/logging/resource.rb +1 -12
- data/lib/gcloud/logging/resource_descriptor.rb +9 -12
- data/lib/gcloud/logging/resource_descriptor/list.rb +4 -5
- data/lib/gcloud/logging/sink/list.rb +4 -5
- data/lib/gcloud/pubsub/message.rb +1 -3
- data/lib/gcloud/pubsub/subscription.rb +5 -7
- data/lib/gcloud/pubsub/topic.rb +1 -3
- data/lib/gcloud/resource_manager/project/list.rb +2 -4
- data/lib/gcloud/translate/api.rb +5 -3
- data/lib/gcloud/translate/connection.rb +4 -4
- data/lib/gcloud/version.rb +1 -1
- metadata +9 -20
- data/lib/gcloud/datastore/connection.rb +0 -203
- data/lib/gcloud/datastore/proto.rb +0 -266
- data/lib/gcloud/proto/datastore_v1.pb.rb +0 -377
- data/lib/google/protobuf/any.rb +0 -17
- data/lib/google/protobuf/api.rb +0 -31
- data/lib/google/protobuf/duration.rb +0 -17
- data/lib/google/protobuf/empty.rb +0 -15
- data/lib/google/protobuf/field_mask.rb +0 -16
- data/lib/google/protobuf/source_context.rb +0 -16
- data/lib/google/protobuf/struct.rb +0 -35
- data/lib/google/protobuf/timestamp.rb +0 -17
- data/lib/google/protobuf/type.rb +0 -79
- data/lib/google/protobuf/wrappers.rb +0 -48
@@ -22,21 +22,23 @@ module Gcloud
|
|
22
22
|
# in a single commit.
|
23
23
|
#
|
24
24
|
# @example
|
25
|
-
#
|
25
|
+
# gcloud = Gcloud.new
|
26
|
+
# datastore = gcloud.datastore
|
27
|
+
# datastore.commit do |c|
|
26
28
|
# c.save task1, task2
|
27
29
|
# c.delete entity1, entity2
|
28
30
|
# end
|
29
31
|
#
|
30
|
-
#
|
31
|
-
# {Gcloud::Datastore::Transaction#commit}
|
32
|
-
#
|
32
|
+
# @see {Gcloud::Datastore::Dataset#commit}
|
33
|
+
# @see {Gcloud::Datastore::Transaction#commit}
|
33
34
|
class Commit
|
34
35
|
##
|
35
36
|
# @private Create a new Commit object.
|
36
37
|
def initialize
|
37
|
-
@
|
38
|
-
@
|
39
|
-
@
|
38
|
+
@shared_upserts = []
|
39
|
+
@shared_inserts = []
|
40
|
+
@shared_updates = []
|
41
|
+
@shared_deletes = []
|
40
42
|
end
|
41
43
|
|
42
44
|
##
|
@@ -46,19 +48,56 @@ module Gcloud
|
|
46
48
|
#
|
47
49
|
# @example
|
48
50
|
# gcloud = Gcloud.new
|
49
|
-
#
|
50
|
-
#
|
51
|
+
# datastore = gcloud.datastore
|
52
|
+
# datastore.commit do |c|
|
51
53
|
# c.save task1, task2
|
52
54
|
# end
|
53
55
|
#
|
54
56
|
def save *entities
|
55
|
-
entities
|
56
|
-
|
57
|
-
shared_entities << entity
|
58
|
-
end
|
57
|
+
entities = Array(entities).flatten
|
58
|
+
@shared_upserts += entities unless entities.empty?
|
59
59
|
# Do not save yet
|
60
60
|
entities
|
61
61
|
end
|
62
|
+
alias_method :upsert, :save
|
63
|
+
|
64
|
+
##
|
65
|
+
# Inserts entities to the Datastore.
|
66
|
+
#
|
67
|
+
# @param [Entity] entities One or more Entity objects to insert.
|
68
|
+
#
|
69
|
+
# @example
|
70
|
+
# gcloud = Gcloud.new
|
71
|
+
# datastore = gcloud.datastore
|
72
|
+
# datastore.commit do |c|
|
73
|
+
# c.insert task1, task2
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
def insert *entities
|
77
|
+
entities = Array(entities).flatten
|
78
|
+
@shared_inserts += entities unless entities.empty?
|
79
|
+
# Do not insert yet
|
80
|
+
entities
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Updates entities to the Datastore.
|
85
|
+
#
|
86
|
+
# @param [Entity] entities One or more Entity objects to update.
|
87
|
+
#
|
88
|
+
# @example
|
89
|
+
# gcloud = Gcloud.new
|
90
|
+
# datastore = gcloud.datastore
|
91
|
+
# datastore.commit do |c|
|
92
|
+
# c.update task1, task2
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
def update *entities
|
96
|
+
entities = Array(entities).flatten
|
97
|
+
@shared_updates += entities unless entities.empty?
|
98
|
+
# Do not update yet
|
99
|
+
entities
|
100
|
+
end
|
62
101
|
|
63
102
|
##
|
64
103
|
# Remove entities from the Datastore.
|
@@ -68,63 +107,41 @@ module Gcloud
|
|
68
107
|
#
|
69
108
|
# @example
|
70
109
|
# gcloud = Gcloud.new
|
71
|
-
#
|
72
|
-
#
|
73
|
-
# c.delete
|
110
|
+
# datastore = gcloud.datastore
|
111
|
+
# datastore.commit do |c|
|
112
|
+
# c.delete task1, task2
|
74
113
|
# end
|
75
114
|
#
|
76
115
|
def delete *entities_or_keys
|
77
|
-
keys = entities_or_keys.map do |e_or_k|
|
116
|
+
keys = Array(entities_or_keys).flatten.map do |e_or_k|
|
78
117
|
e_or_k.respond_to?(:key) ? e_or_k.key : e_or_k
|
79
118
|
end
|
80
|
-
|
119
|
+
@shared_deletes += keys unless keys.empty?
|
81
120
|
# Do not delete yet
|
82
121
|
true
|
83
122
|
end
|
84
123
|
|
85
|
-
# @private
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
m.delete = shared_deletes.map(&:to_proto)
|
124
|
+
# @private Mutations object to be committed.
|
125
|
+
def mutations
|
126
|
+
mutations = []
|
127
|
+
mutations += @shared_upserts.map do |entity|
|
128
|
+
Google::Datastore::V1beta3::Mutation.new upsert: entity.to_grpc
|
91
129
|
end
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
130
|
+
mutations += @shared_inserts.map do |entity|
|
131
|
+
Google::Datastore::V1beta3::Mutation.new insert: entity.to_grpc
|
132
|
+
end
|
133
|
+
mutations += @shared_updates.map do |entity|
|
134
|
+
Google::Datastore::V1beta3::Mutation.new update: entity.to_grpc
|
135
|
+
end
|
136
|
+
mutations += @shared_deletes.map do |key|
|
137
|
+
Google::Datastore::V1beta3::Mutation.new delete: key.to_grpc
|
138
|
+
end
|
139
|
+
mutations
|
97
140
|
end
|
98
141
|
|
99
142
|
# @private All entities saved in the commit.
|
100
143
|
def entities
|
101
|
-
|
102
|
-
end
|
103
|
-
|
104
|
-
protected
|
105
|
-
|
106
|
-
##
|
107
|
-
# @private List of Entity objects to be saved.
|
108
|
-
def shared_entities
|
109
|
-
@shared_entities
|
110
|
-
end
|
111
|
-
|
112
|
-
##
|
113
|
-
# @private List of Entity objects that need auto_ids
|
114
|
-
def shared_auto_ids
|
115
|
-
@shared_auto_ids
|
116
|
-
end
|
117
|
-
|
118
|
-
##
|
119
|
-
# @private List of Entity objects to be saved.
|
120
|
-
def shared_upserts
|
121
|
-
shared_entities - shared_auto_ids
|
122
|
-
end
|
123
|
-
|
124
|
-
##
|
125
|
-
# @private List of Key objects to be deleted.
|
126
|
-
def shared_deletes
|
127
|
-
@shared_deletes
|
144
|
+
@shared_upserts + @shared_inserts + @shared_updates
|
128
145
|
end
|
129
146
|
end
|
130
147
|
end
|
@@ -26,21 +26,10 @@ module Gcloud
|
|
26
26
|
#
|
27
27
|
# @see https://developers.google.com/accounts/docs/application-default-credentials
|
28
28
|
class Credentials < Gcloud::Credentials
|
29
|
-
SCOPE = ["https://www.googleapis.com/auth/datastore"
|
30
|
-
"https://www.googleapis.com/auth/userinfo.email"]
|
29
|
+
SCOPE = ["https://www.googleapis.com/auth/datastore"]
|
31
30
|
PATH_ENV_VARS = %w(DATASTORE_KEYFILE GCLOUD_KEYFILE GOOGLE_CLOUD_KEYFILE)
|
32
31
|
JSON_ENV_VARS = %w(DATASTORE_KEYFILE_JSON GCLOUD_KEYFILE_JSON
|
33
32
|
GOOGLE_CLOUD_KEYFILE_JSON)
|
34
|
-
|
35
|
-
##
|
36
|
-
# Sign OAuth 2.0 API calls.
|
37
|
-
def sign_http_request request
|
38
|
-
if @client
|
39
|
-
@client.fetch_access_token! if @client.expires_within? 30
|
40
|
-
@client.generate_authenticated_request request: request
|
41
|
-
end
|
42
|
-
request
|
43
|
-
end
|
44
33
|
end
|
45
34
|
end
|
46
35
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Copyright 2016 Google Inc. All rights reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
module Gcloud
|
17
|
+
module Datastore
|
18
|
+
##
|
19
|
+
# # Cursor
|
20
|
+
#
|
21
|
+
# Cursor is a point in query results. Cursors are returned in QueryResults.
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# require "gcloud"
|
25
|
+
#
|
26
|
+
# gcloud = Gcloud.new
|
27
|
+
# datastore = gcloud.datastore
|
28
|
+
#
|
29
|
+
# query = datastore.query("Task").
|
30
|
+
# where("done", "=", false)
|
31
|
+
#
|
32
|
+
# tasks = datastore.run query
|
33
|
+
# tasks.cursor #=> Cursor
|
34
|
+
#
|
35
|
+
class Cursor
|
36
|
+
# Base64 encoded array of bytes
|
37
|
+
def initialize cursor
|
38
|
+
@cursor = cursor
|
39
|
+
end
|
40
|
+
|
41
|
+
# Base64 encoded array of bytes
|
42
|
+
def to_s
|
43
|
+
@cursor
|
44
|
+
end
|
45
|
+
|
46
|
+
# @private
|
47
|
+
def inspect
|
48
|
+
"#{self.class}(#{@cursor})"
|
49
|
+
end
|
50
|
+
|
51
|
+
# @private
|
52
|
+
def == other
|
53
|
+
return false unless other.is_a? Cursor
|
54
|
+
@cursor == other.to_s
|
55
|
+
end
|
56
|
+
|
57
|
+
# @private
|
58
|
+
def <=> other
|
59
|
+
return -1 unless other.is_a? Cursor
|
60
|
+
@cursor <=> other.to_s
|
61
|
+
end
|
62
|
+
|
63
|
+
# @private byte array as a string
|
64
|
+
def to_grpc
|
65
|
+
GRPCUtils.decode_bytes(@cursor)
|
66
|
+
end
|
67
|
+
|
68
|
+
# @private byte array as a string
|
69
|
+
def self.from_grpc grpc
|
70
|
+
grpc = String grpc
|
71
|
+
return nil if grpc.empty?
|
72
|
+
new GRPCUtils.encode_bytes(grpc)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -14,12 +14,15 @@
|
|
14
14
|
|
15
15
|
|
16
16
|
require "gcloud/gce"
|
17
|
-
require "gcloud/datastore/
|
17
|
+
require "gcloud/datastore/grpc_utils"
|
18
18
|
require "gcloud/datastore/credentials"
|
19
|
+
require "gcloud/datastore/service"
|
19
20
|
require "gcloud/datastore/commit"
|
20
21
|
require "gcloud/datastore/entity"
|
21
22
|
require "gcloud/datastore/key"
|
22
23
|
require "gcloud/datastore/query"
|
24
|
+
require "gcloud/datastore/gql_query"
|
25
|
+
require "gcloud/datastore/cursor"
|
23
26
|
require "gcloud/datastore/dataset/lookup_results"
|
24
27
|
require "gcloud/datastore/dataset/query_results"
|
25
28
|
|
@@ -41,16 +44,17 @@ module Gcloud
|
|
41
44
|
# require "gcloud"
|
42
45
|
#
|
43
46
|
# gcloud = Gcloud.new
|
44
|
-
#
|
47
|
+
# datastore = gcloud.datastore
|
45
48
|
#
|
46
|
-
# query =
|
47
|
-
# where("
|
49
|
+
# query = datastore.query("Task").
|
50
|
+
# where("done", "=", false)
|
48
51
|
#
|
49
|
-
# tasks =
|
52
|
+
# tasks = datastore.run query
|
50
53
|
#
|
51
54
|
class Dataset
|
52
|
-
|
53
|
-
|
55
|
+
##
|
56
|
+
# @private The gRPC Service object.
|
57
|
+
attr_accessor :service
|
54
58
|
|
55
59
|
##
|
56
60
|
# @private Creates a new Dataset instance.
|
@@ -59,7 +63,7 @@ module Gcloud
|
|
59
63
|
def initialize project, credentials
|
60
64
|
project = project.to_s # Always cast to a string
|
61
65
|
fail ArgumentError, "project is missing" if project.empty?
|
62
|
-
@
|
66
|
+
@service = Service.new project, credentials
|
63
67
|
end
|
64
68
|
|
65
69
|
##
|
@@ -71,11 +75,11 @@ module Gcloud
|
|
71
75
|
# gcloud = Gcloud.new "my-todo-project",
|
72
76
|
# "/path/to/keyfile.json"
|
73
77
|
#
|
74
|
-
#
|
75
|
-
#
|
78
|
+
# datastore = gcloud.datastore
|
79
|
+
# datastore.project #=> "my-todo-project"
|
76
80
|
#
|
77
81
|
def project
|
78
|
-
|
82
|
+
service.project
|
79
83
|
end
|
80
84
|
|
81
85
|
##
|
@@ -97,19 +101,20 @@ module Gcloud
|
|
97
101
|
# @return [Array<Gcloud::Datastore::Key>]
|
98
102
|
#
|
99
103
|
# @example
|
100
|
-
#
|
101
|
-
# task_keys =
|
104
|
+
# task_key = datastore.key "Task"
|
105
|
+
# task_keys = datastore.allocate_ids task_key, 5
|
102
106
|
#
|
103
107
|
def allocate_ids incomplete_key, count = 1
|
104
108
|
if incomplete_key.complete?
|
105
109
|
fail Gcloud::Datastore::Error, "An incomplete key must be provided."
|
106
110
|
end
|
107
111
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
112
|
+
ensure_service!
|
113
|
+
incomplete_keys = count.times.map { incomplete_key.to_grpc }
|
114
|
+
allocate_res = service.allocate_ids(*incomplete_keys)
|
115
|
+
allocate_res.keys.map { |key| Key.from_grpc key }
|
116
|
+
rescue GRPC::BadStatus => e
|
117
|
+
raise Gcloud::Error.from_error(e)
|
113
118
|
end
|
114
119
|
|
115
120
|
##
|
@@ -119,12 +124,106 @@ module Gcloud
|
|
119
124
|
#
|
120
125
|
# @return [Array<Gcloud::Datastore::Entity>]
|
121
126
|
#
|
122
|
-
# @example
|
123
|
-
#
|
127
|
+
# @example Insert a new entity:
|
128
|
+
# task = datastore.entity "Task" do |t|
|
129
|
+
# t["type"] = "Personal"
|
130
|
+
# t["done"] = false
|
131
|
+
# t["priority"] = 4
|
132
|
+
# t["description"] = "Learn Cloud Datastore"
|
133
|
+
# end
|
134
|
+
# task.key.id #=> nil
|
135
|
+
# datastore.save task
|
136
|
+
# task.key.id #=> 123456
|
137
|
+
#
|
138
|
+
# @example Insert multiple new entities in a batch:
|
139
|
+
# task1 = datastore.entity "Task" do |t|
|
140
|
+
# t["type"] = "Personal"
|
141
|
+
# t["done"] = false
|
142
|
+
# t["priority"] = 4
|
143
|
+
# t["description"] = "Learn Cloud Datastore"
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
# task2 = datastore.entity "Task" do |t|
|
147
|
+
# t["type"] = "Personal"
|
148
|
+
# t["done"] = false
|
149
|
+
# t["priority"] = 5
|
150
|
+
# t["description"] = "Integrate Cloud Datastore"
|
151
|
+
# end
|
152
|
+
#
|
153
|
+
# task_key1, task_key2 = datastore.save(task1, task2).map(&:key)
|
154
|
+
#
|
155
|
+
# @example Update an existing entity:
|
156
|
+
# task = datastore.find "Task", "sampleTask"
|
157
|
+
# task["priority"] = 5
|
158
|
+
# datastore.save task
|
124
159
|
#
|
125
160
|
def save *entities
|
126
161
|
commit { |c| c.save(*entities) }
|
127
162
|
end
|
163
|
+
alias_method :upsert, :save
|
164
|
+
|
165
|
+
##
|
166
|
+
# Insert one or more entities to the Datastore. An InvalidArgumentError
|
167
|
+
# will raised if the entities cannot be inserted.
|
168
|
+
#
|
169
|
+
# @param [Entity] entities One or more entity objects to be inserted.
|
170
|
+
#
|
171
|
+
# @return [Array<Gcloud::Datastore::Entity>]
|
172
|
+
#
|
173
|
+
# @example Insert a new entity:
|
174
|
+
# task = datastore.entity "Task" do |t|
|
175
|
+
# t["type"] = "Personal"
|
176
|
+
# t["done"] = false
|
177
|
+
# t["priority"] = 4
|
178
|
+
# t["description"] = "Learn Cloud Datastore"
|
179
|
+
# end
|
180
|
+
# task.key.id #=> nil
|
181
|
+
# datastore.insert task
|
182
|
+
# task.key.id #=> 123456
|
183
|
+
#
|
184
|
+
# @example Insert multiple new entities in a batch:
|
185
|
+
# task1 = datastore.entity "Task" do |t|
|
186
|
+
# t["type"] = "Personal"
|
187
|
+
# t["done"] = false
|
188
|
+
# t["priority"] = 4
|
189
|
+
# t["description"] = "Learn Cloud Datastore"
|
190
|
+
# end
|
191
|
+
#
|
192
|
+
# task2 = datastore.entity "Task" do |t|
|
193
|
+
# t["type"] = "Personal"
|
194
|
+
# t["done"] = false
|
195
|
+
# t["priority"] = 5
|
196
|
+
# t["description"] = "Integrate Cloud Datastore"
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
# task_key1, task_key2 = datastore.insert(task1, task2).map(&:key)
|
200
|
+
#
|
201
|
+
def insert *entities
|
202
|
+
commit { |c| c.insert(*entities) }
|
203
|
+
end
|
204
|
+
|
205
|
+
##
|
206
|
+
# Update one or more entities to the Datastore. An InvalidArgumentError
|
207
|
+
# will raised if the entities cannot be updated.
|
208
|
+
#
|
209
|
+
# @param [Entity] entities One or more entity objects to be updated.
|
210
|
+
#
|
211
|
+
# @return [Array<Gcloud::Datastore::Entity>]
|
212
|
+
#
|
213
|
+
# @example Update an existing entity:
|
214
|
+
# task = datastore.find "Task", "sampleTask"
|
215
|
+
# task["done"] = true
|
216
|
+
# datastore.save task
|
217
|
+
#
|
218
|
+
# @example update multiple new entities in a batch:
|
219
|
+
# query = datastore.query("Task").where("done", "=", false)
|
220
|
+
# tasks = datastore.run query
|
221
|
+
# tasks.each { |t| t["done"] = true }
|
222
|
+
# datastore.update tasks
|
223
|
+
#
|
224
|
+
def update *entities
|
225
|
+
commit { |c| c.update(*entities) }
|
226
|
+
end
|
128
227
|
|
129
228
|
##
|
130
229
|
# Remove entities from the Datastore.
|
@@ -136,8 +235,8 @@ module Gcloud
|
|
136
235
|
#
|
137
236
|
# @example
|
138
237
|
# gcloud = Gcloud.new
|
139
|
-
#
|
140
|
-
#
|
238
|
+
# datastore = gcloud.datastore
|
239
|
+
# datastore.delete task1, task2
|
141
240
|
#
|
142
241
|
def delete *entities_or_keys
|
143
242
|
commit { |c| c.delete(*entities_or_keys) }
|
@@ -154,26 +253,34 @@ module Gcloud
|
|
154
253
|
# persisted.
|
155
254
|
#
|
156
255
|
# @example
|
157
|
-
#
|
158
|
-
#
|
159
|
-
#
|
256
|
+
# gcloud = Gcloud.new
|
257
|
+
# datastore = gcloud.datastore
|
258
|
+
# datastore.commit do |c|
|
259
|
+
# c.save task3, task4
|
260
|
+
# c.delete task1, task2
|
160
261
|
# end
|
161
262
|
#
|
162
263
|
def commit
|
163
264
|
return unless block_given?
|
164
265
|
c = Commit.new
|
165
266
|
yield c
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
# Make sure all entity keys are frozen so all show as persisted
|
267
|
+
|
268
|
+
ensure_service!
|
269
|
+
commit_res = service.commit c.mutations
|
170
270
|
entities = c.entities
|
271
|
+
returned_keys = commit_res.mutation_results.map(&:key)
|
272
|
+
returned_keys.each_with_index do |key, index|
|
273
|
+
next if entities[index].nil?
|
274
|
+
entities[index].key = Key.from_grpc(key) unless key.nil?
|
275
|
+
end
|
171
276
|
entities.each { |e| e.key.freeze unless e.persisted? }
|
172
277
|
entities
|
278
|
+
rescue GRPC::BadStatus => e
|
279
|
+
raise Gcloud::Error.from_error(e)
|
173
280
|
end
|
174
281
|
|
175
282
|
##
|
176
|
-
# Retrieve an entity by
|
283
|
+
# Retrieve an entity by key.
|
177
284
|
#
|
178
285
|
# @param [Key, String] key_or_kind A Key object or `kind` string value.
|
179
286
|
# @param [Integer, String, nil] id_or_name The Key's `id` or `name` value
|
@@ -190,11 +297,11 @@ module Gcloud
|
|
190
297
|
# @return [Gcloud::Datastore::Entity, nil]
|
191
298
|
#
|
192
299
|
# @example Finding an entity with a key:
|
193
|
-
#
|
194
|
-
# task =
|
300
|
+
# task_key = datastore.key "Task", "sampleTask"
|
301
|
+
# task = datastore.find task_key
|
195
302
|
#
|
196
303
|
# @example Finding an entity with a `kind` and `id`/`name`:
|
197
|
-
# task =
|
304
|
+
# task = datastore.find "Task", "sampleTask"
|
198
305
|
#
|
199
306
|
def find key_or_kind, id_or_name = nil, consistency: nil
|
200
307
|
key = key_or_kind
|
@@ -206,7 +313,8 @@ module Gcloud
|
|
206
313
|
alias_method :get, :find
|
207
314
|
|
208
315
|
##
|
209
|
-
# Retrieve the entities for the provided keys.
|
316
|
+
# Retrieve the entities for the provided keys. The order of results is
|
317
|
+
# undefined and has no relation to the order of `keys` arguments.
|
210
318
|
#
|
211
319
|
# @param [Key] keys One or more Key objects to find records for.
|
212
320
|
# @param [Symbol] consistency The non-transactional read consistency to
|
@@ -222,26 +330,30 @@ module Gcloud
|
|
222
330
|
#
|
223
331
|
# @example
|
224
332
|
# gcloud = Gcloud.new
|
225
|
-
#
|
226
|
-
#
|
227
|
-
#
|
228
|
-
#
|
333
|
+
# datastore = gcloud.datastore
|
334
|
+
#
|
335
|
+
# task_key1 = datastore.key "Task", "sampleTask1"
|
336
|
+
# task_key2 = datastore.key "Task", "sampleTask2"
|
337
|
+
# tasks = datastore.find_all task_key1, task_key2
|
229
338
|
#
|
230
339
|
def find_all *keys, consistency: nil
|
340
|
+
ensure_service!
|
231
341
|
check_consistency! consistency
|
232
|
-
|
233
|
-
|
234
|
-
entities = to_gcloud_entities
|
235
|
-
deferred = to_gcloud_keys
|
236
|
-
missing = to_gcloud_entities
|
342
|
+
lookup_res = service.lookup(*keys.map(&:to_grpc),
|
343
|
+
consistency: consistency)
|
344
|
+
entities = to_gcloud_entities lookup_res.found
|
345
|
+
deferred = to_gcloud_keys lookup_res.deferred
|
346
|
+
missing = to_gcloud_entities lookup_res.missing
|
237
347
|
LookupResults.new entities, deferred, missing
|
348
|
+
rescue GRPC::BadStatus => e
|
349
|
+
raise Gcloud::Error.from_error(e)
|
238
350
|
end
|
239
351
|
alias_method :lookup, :find_all
|
240
352
|
|
241
353
|
##
|
242
354
|
# Retrieve entities specified by a Query.
|
243
355
|
#
|
244
|
-
# @param [Query] query The
|
356
|
+
# @param [Query, GqlQuery] query The object with the search criteria.
|
245
357
|
# @param [String] namespace The namespace the query is to run within.
|
246
358
|
# @param [Symbol] consistency The non-transactional read consistency to
|
247
359
|
# use. Cannot be set to `:strong` for global queries. Accepted values
|
@@ -255,24 +367,43 @@ module Gcloud
|
|
255
367
|
# @return [Gcloud::Datastore::Dataset::QueryResults]
|
256
368
|
#
|
257
369
|
# @example
|
258
|
-
# query =
|
259
|
-
# where("
|
260
|
-
# tasks =
|
370
|
+
# query = datastore.query("Task").
|
371
|
+
# where("done", "=", false)
|
372
|
+
# tasks = datastore.run query
|
373
|
+
#
|
374
|
+
# @example Run an ancestor query with eventual consistency:
|
375
|
+
# task_list_key = datastore.key "TaskList", "default"
|
376
|
+
# query.kind("Task").
|
377
|
+
# ancestor(task_list_key)
|
378
|
+
#
|
379
|
+
# tasks = datastore.run query, consistency: :eventual
|
261
380
|
#
|
262
381
|
# @example Run the query within a namespace with the `namespace` option:
|
263
|
-
# query =
|
264
|
-
# where("
|
265
|
-
# tasks =
|
382
|
+
# query = datastore.query("Task").
|
383
|
+
# where("done", "=", false)
|
384
|
+
# tasks = datastore.run query, namespace: "ns~todo-project"
|
385
|
+
#
|
386
|
+
# @example Run the query with a GQL string.
|
387
|
+
# gql_query = datastore.gql "SELECT * FROM Task WHERE done = @done",
|
388
|
+
# done: false
|
389
|
+
# tasks = datastore.run gql_query
|
390
|
+
#
|
391
|
+
# @example Run the GQL query within a namespace with `namespace` option:
|
392
|
+
# gql_query = datastore.gql "SELECT * FROM Task WHERE done = @done",
|
393
|
+
# done: false
|
394
|
+
# tasks = datastore.run gql_query, namespace: "ns~todo-project"
|
266
395
|
#
|
267
396
|
def run query, namespace: nil, consistency: nil
|
268
|
-
|
397
|
+
ensure_service!
|
398
|
+
unless query.is_a?(Query) || query.is_a?(GqlQuery)
|
399
|
+
fail ArgumentError, "Cannot run a #{query.class} object."
|
400
|
+
end
|
269
401
|
check_consistency! consistency
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
QueryResults.new entities, cursor, more_results
|
402
|
+
query_res = service.run_query query.to_grpc, namespace,
|
403
|
+
consistency: consistency
|
404
|
+
QueryResults.from_grpc query_res, service, namespace, query.to_grpc.dup
|
405
|
+
rescue GRPC::BadStatus => e
|
406
|
+
raise Gcloud::Error.from_error(e)
|
276
407
|
end
|
277
408
|
alias_method :run_query, :run
|
278
409
|
|
@@ -286,16 +417,18 @@ module Gcloud
|
|
286
417
|
# require "gcloud"
|
287
418
|
#
|
288
419
|
# gcloud = Gcloud.new
|
289
|
-
#
|
420
|
+
# datastore = gcloud.datastore
|
290
421
|
#
|
291
|
-
#
|
292
|
-
#
|
293
|
-
#
|
422
|
+
# task = datastore.entity "Task", "sampleTask" do |t|
|
423
|
+
# t["type"] = "Personal"
|
424
|
+
# t["done"] = false
|
425
|
+
# t["priority"] = 4
|
426
|
+
# t["description"] = "Learn Cloud Datastore"
|
294
427
|
# end
|
295
428
|
#
|
296
|
-
#
|
297
|
-
# if tx.find(
|
298
|
-
# tx.save
|
429
|
+
# datastore.transaction do |tx|
|
430
|
+
# if tx.find(task.key).nil?
|
431
|
+
# tx.save task
|
299
432
|
# end
|
300
433
|
# end
|
301
434
|
#
|
@@ -303,17 +436,19 @@ module Gcloud
|
|
303
436
|
# require "gcloud"
|
304
437
|
#
|
305
438
|
# gcloud = Gcloud.new
|
306
|
-
#
|
439
|
+
# datastore = gcloud.datastore
|
307
440
|
#
|
308
|
-
#
|
309
|
-
#
|
310
|
-
#
|
441
|
+
# task = datastore.entity "Task", "sampleTask" do |t|
|
442
|
+
# t["type"] = "Personal"
|
443
|
+
# t["done"] = false
|
444
|
+
# t["priority"] = 4
|
445
|
+
# t["description"] = "Learn Cloud Datastore"
|
311
446
|
# end
|
312
447
|
#
|
313
|
-
# tx =
|
448
|
+
# tx = datastore.transaction
|
314
449
|
# begin
|
315
|
-
# if tx.find(
|
316
|
-
# tx.save
|
450
|
+
# if tx.find(task.key).nil?
|
451
|
+
# tx.save task
|
317
452
|
# end
|
318
453
|
# tx.commit
|
319
454
|
# rescue
|
@@ -321,7 +456,7 @@ module Gcloud
|
|
321
456
|
# end
|
322
457
|
#
|
323
458
|
def transaction
|
324
|
-
tx = Transaction.new
|
459
|
+
tx = Transaction.new service
|
325
460
|
return tx unless block_given?
|
326
461
|
|
327
462
|
begin
|
@@ -348,15 +483,15 @@ module Gcloud
|
|
348
483
|
# @return [Gcloud::Datastore::Query]
|
349
484
|
#
|
350
485
|
# @example
|
351
|
-
# query =
|
352
|
-
# where("
|
353
|
-
# tasks =
|
486
|
+
# query = datastore.query("Task").
|
487
|
+
# where("done", "=", false)
|
488
|
+
# tasks = datastore.run query
|
354
489
|
#
|
355
490
|
# @example The previous example is equivalent to:
|
356
491
|
# query = Gcloud::Datastore::Query.new.
|
357
492
|
# kind("Task").
|
358
|
-
# where("
|
359
|
-
# tasks =
|
493
|
+
# where("done", "=", false)
|
494
|
+
# tasks = datastore.run query
|
360
495
|
#
|
361
496
|
def query *kinds
|
362
497
|
query = Query.new
|
@@ -364,77 +499,155 @@ module Gcloud
|
|
364
499
|
query
|
365
500
|
end
|
366
501
|
|
502
|
+
##
|
503
|
+
# Create a new GqlQuery instance. This is a convenience method to make the
|
504
|
+
# creation of GqlQuery objects easier.
|
505
|
+
#
|
506
|
+
# @param [String] query The GQL query string.
|
507
|
+
# @param [Hash] bindings Named bindings for the GQL query string, each
|
508
|
+
# key must match regex `[A-Za-z_$][A-Za-z_$0-9]*`, must not match regex
|
509
|
+
# `__.*__`, and must not be `""`. The value must be an `Object` that can
|
510
|
+
# be stored as an Entity property value, or a `Cursor`.
|
511
|
+
#
|
512
|
+
# @return [Gcloud::Datastore::GqlQuery]
|
513
|
+
#
|
514
|
+
# @example
|
515
|
+
# gql_query = datastore.gql "SELECT * FROM Task WHERE done = @done",
|
516
|
+
# done: false
|
517
|
+
# tasks = datastore.run gql_query
|
518
|
+
#
|
519
|
+
# @example The previous example is equivalent to:
|
520
|
+
# gql_query = Gcloud::Datastore::GqlQuery.new
|
521
|
+
# gql_query.query_string = "SELECT * FROM Task WHERE done = @done"
|
522
|
+
# gql_query.named_bindings = {done: false}
|
523
|
+
# tasks = datastore.run gql_query
|
524
|
+
#
|
525
|
+
def gql query, bindings = {}
|
526
|
+
gql = GqlQuery.new
|
527
|
+
gql.query_string = query
|
528
|
+
gql.named_bindings = bindings unless bindings.empty?
|
529
|
+
gql
|
530
|
+
end
|
531
|
+
|
367
532
|
##
|
368
533
|
# Create a new Key instance. This is a convenience method to make the
|
369
534
|
# creation of Key objects easier.
|
370
535
|
#
|
371
|
-
# @param [String]
|
372
|
-
#
|
373
|
-
# optional.
|
536
|
+
# @param [Array<Array(String,(String|Integer|nil))>] path An optional list
|
537
|
+
# of pairs for the key's path. Each pair may include the key's kind
|
538
|
+
# (String) and an id (Integer) or name (String). This is optional.
|
539
|
+
# @param [String] project The project of the Key. This is optional.
|
540
|
+
# @param [String] namespace namespace kind of the Key. This is optional.
|
374
541
|
#
|
375
542
|
# @return [Gcloud::Datastore::Key]
|
376
543
|
#
|
377
544
|
# @example
|
378
|
-
#
|
545
|
+
# task_key = datastore.key "Task", "sampleTask"
|
379
546
|
#
|
380
547
|
# @example The previous example is equivalent to:
|
381
|
-
#
|
382
|
-
#
|
383
|
-
|
384
|
-
|
548
|
+
# task_key = Gcloud::Datastore::Key.new "Task", "sampleTask"
|
549
|
+
#
|
550
|
+
# @example Create an empty key:
|
551
|
+
# key = datastore.key
|
552
|
+
#
|
553
|
+
# @example Create an incomplete key:
|
554
|
+
# key = datastore.key "User"
|
555
|
+
#
|
556
|
+
# @example Create a key with a parent:
|
557
|
+
# key = datastore.key [["TaskList", "default"], ["Task", "sampleTask"]]
|
558
|
+
# key.path #=> [["TaskList", "default"], ["Task", "sampleTask"]]
|
559
|
+
#
|
560
|
+
# @example Create a key with multi-level ancestry:
|
561
|
+
# key = datastore.key([
|
562
|
+
# ["User", "alice"],
|
563
|
+
# ["TaskList", "default"],
|
564
|
+
# ["Task", "sampleTask"]
|
565
|
+
# ])
|
566
|
+
# key.path #=> [["User", "alice"], ["TaskList", "default"], [ ... ]]
|
567
|
+
#
|
568
|
+
# @example Create an incomplete key with a parent:
|
569
|
+
# key = datastore.key "TaskList", "default", "Task"
|
570
|
+
# key.path #=> [["TaskList", "default"], ["Task", nil]]
|
571
|
+
#
|
572
|
+
# @example Create a key with a project and namespace:
|
573
|
+
# key = datastore.key ["TaskList", "default"], ["Task", "sampleTask"],
|
574
|
+
# project: "my-todo-project",
|
575
|
+
# namespace: "ns~todo-project"
|
576
|
+
# key.path #=> [["TaskList", "default"], ["Task", "sampleTask"]]
|
577
|
+
# key.project #=> "my-todo-project",
|
578
|
+
# key.namespace #=> "ns~todo-project"
|
579
|
+
#
|
580
|
+
def key *path, project: nil, namespace: nil
|
581
|
+
path = path.flatten.each_slice(2).to_a # group in pairs
|
582
|
+
kind, id_or_name = path.pop
|
583
|
+
Key.new(kind, id_or_name).tap do |k|
|
584
|
+
k.project = project
|
585
|
+
k.namespace = namespace
|
586
|
+
unless path.empty?
|
587
|
+
k.parent = key path, project: project, namespace: namespace
|
588
|
+
end
|
589
|
+
end
|
385
590
|
end
|
386
591
|
|
387
592
|
##
|
388
593
|
# Create a new empty Entity instance. This is a convenience method to make
|
389
594
|
# the creation of Entity objects easier.
|
390
595
|
#
|
391
|
-
# @param [Key, String,
|
392
|
-
#
|
393
|
-
#
|
394
|
-
#
|
596
|
+
# @param [Key, Array<Array(String,(String|Integer|nil))>] key_or_path An
|
597
|
+
# optional list of pairs for the key's path. Each pair may include the #
|
598
|
+
# key's kind (String) and an id (Integer) or name (String). This is #
|
599
|
+
# optional.
|
600
|
+
# @param [String] project The project of the Key. This is optional.
|
601
|
+
# @param [String] namespace namespace kind of the Key. This is optional.
|
395
602
|
# @yield [entity] a block yielding a new entity
|
396
603
|
# @yieldparam [Entity] entity the newly created entity object
|
397
604
|
#
|
398
605
|
# @return [Gcloud::Datastore::Entity]
|
399
606
|
#
|
400
607
|
# @example
|
401
|
-
#
|
608
|
+
# task = datastore.entity
|
402
609
|
#
|
403
610
|
# @example The previous example is equivalent to:
|
404
|
-
#
|
611
|
+
# task = Gcloud::Datastore::Entity.new
|
405
612
|
#
|
406
613
|
# @example The key can also be passed in as an object:
|
407
|
-
#
|
408
|
-
#
|
614
|
+
# task_key = datastore.key "Task", "sampleTask"
|
615
|
+
# task = datastore.entity task_key
|
409
616
|
#
|
410
617
|
# @example Or the key values can be passed in as parameters:
|
411
|
-
#
|
618
|
+
# task = datastore.entity "Task", "sampleTask"
|
412
619
|
#
|
413
620
|
# @example The previous example is equivalent to:
|
414
|
-
#
|
415
|
-
#
|
416
|
-
#
|
621
|
+
# task_key = Gcloud::Datastore::Key.new "Task", "sampleTask"
|
622
|
+
# task = Gcloud::Datastore::Entity.new
|
623
|
+
# task.key = task_key
|
417
624
|
#
|
418
625
|
# @example The newly created entity can also be configured using a block:
|
419
|
-
#
|
420
|
-
#
|
421
|
-
#
|
626
|
+
# task = datastore.entity "Task", "sampleTask" do |t|
|
627
|
+
# t["type"] = "Personal"
|
628
|
+
# t["done"] = false
|
629
|
+
# t["priority"] = 4
|
630
|
+
# t["description"] = "Learn Cloud Datastore"
|
631
|
+
# end
|
422
632
|
#
|
423
633
|
# @example The previous example is equivalent to:
|
424
|
-
#
|
425
|
-
#
|
426
|
-
#
|
427
|
-
#
|
428
|
-
#
|
429
|
-
|
634
|
+
# task_key = Gcloud::Datastore::Key.new "Task", "sampleTask"
|
635
|
+
# task = Gcloud::Datastore::Entity.new
|
636
|
+
# task.key = task_key
|
637
|
+
# task["type"] = "Personal"
|
638
|
+
# task["done"] = false
|
639
|
+
# task["priority"] = 4
|
640
|
+
# task["description"] = "Learn Cloud Datastore"
|
641
|
+
#
|
642
|
+
def entity *key_or_path, project: nil, namespace: nil
|
430
643
|
entity = Entity.new
|
431
644
|
|
432
645
|
# Set the key
|
433
|
-
|
434
|
-
|
435
|
-
|
646
|
+
if key_or_path.flatten.first.is_a? Gcloud::Datastore::Key
|
647
|
+
entity.key = key_or_path.flatten.first
|
648
|
+
else
|
649
|
+
entity.key = key key_or_path, project: project, namespace: namespace
|
436
650
|
end
|
437
|
-
entity.key = key
|
438
651
|
|
439
652
|
yield entity if block_given?
|
440
653
|
|
@@ -444,37 +657,27 @@ module Gcloud
|
|
444
657
|
protected
|
445
658
|
|
446
659
|
##
|
447
|
-
#
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
Entity.from_proto result.entity
|
452
|
-
end
|
660
|
+
# @private Raise an error unless an active connection to the service is
|
661
|
+
# available.
|
662
|
+
def ensure_service!
|
663
|
+
fail "Must have active connection to service" unless service
|
453
664
|
end
|
454
665
|
|
455
666
|
##
|
456
|
-
#
|
457
|
-
def
|
458
|
-
#
|
459
|
-
Array(
|
460
|
-
|
667
|
+
# Convenience method to convert GRPC entities to Gcloud entities.
|
668
|
+
def to_gcloud_entities grpc_entity_results
|
669
|
+
# Entities are nested in an object.
|
670
|
+
Array(grpc_entity_results).map do |result|
|
671
|
+
# TODO: Make this return an EntityResult with cursor...
|
672
|
+
Entity.from_grpc result.entity
|
461
673
|
end
|
462
674
|
end
|
463
675
|
|
464
676
|
##
|
465
|
-
#
|
466
|
-
def
|
467
|
-
|
468
|
-
|
469
|
-
entity.key = Key.from_proto key
|
470
|
-
end
|
471
|
-
end
|
472
|
-
|
473
|
-
def optional_partition_id namespace = nil
|
474
|
-
return nil if namespace.nil?
|
475
|
-
Proto::PartitionId.new.tap do |p|
|
476
|
-
p.namespace = namespace
|
477
|
-
end
|
677
|
+
# Convenience method to convert GRPC keys to Gcloud keys.
|
678
|
+
def to_gcloud_keys grpc_keys
|
679
|
+
# Keys are not nested in an object like entities are.
|
680
|
+
Array(grpc_keys).map { |key| Key.from_grpc key }
|
478
681
|
end
|
479
682
|
|
480
683
|
def check_consistency! consistency
|