google-cloud-datastore 0.20.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 +7 -0
- data/lib/google-cloud-datastore.rb +141 -0
- data/lib/google/cloud/datastore.rb +532 -0
- data/lib/google/cloud/datastore/commit.rb +150 -0
- data/lib/google/cloud/datastore/credentials.rb +38 -0
- data/lib/google/cloud/datastore/cursor.rb +79 -0
- data/lib/google/cloud/datastore/dataset.rb +667 -0
- data/lib/google/cloud/datastore/dataset/lookup_results.rb +222 -0
- data/lib/google/cloud/datastore/dataset/query_results.rb +389 -0
- data/lib/google/cloud/datastore/entity.rb +454 -0
- data/lib/google/cloud/datastore/errors.rb +43 -0
- data/lib/google/cloud/datastore/gql_query.rb +216 -0
- data/lib/google/cloud/datastore/grpc_utils.rb +140 -0
- data/lib/google/cloud/datastore/key.rb +289 -0
- data/lib/google/cloud/datastore/properties.rb +133 -0
- data/lib/google/cloud/datastore/query.rb +351 -0
- data/lib/google/cloud/datastore/service.rb +171 -0
- data/lib/google/cloud/datastore/transaction.rb +365 -0
- data/lib/google/cloud/datastore/version.rb +22 -0
- data/lib/google/datastore/v1/datastore_pb.rb +120 -0
- data/lib/google/datastore/v1/datastore_services_pb.rb +61 -0
- data/lib/google/datastore/v1/entity_pb.rb +63 -0
- data/lib/google/datastore/v1/query_pb.rb +131 -0
- metadata +236 -0
@@ -0,0 +1,133 @@
|
|
1
|
+
# Copyright 2015 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
|
+
require "stringio"
|
17
|
+
|
18
|
+
module Google
|
19
|
+
module Cloud
|
20
|
+
module Datastore
|
21
|
+
##
|
22
|
+
# # Properties
|
23
|
+
#
|
24
|
+
# Hash-like data structure for Datastore properties.
|
25
|
+
#
|
26
|
+
# See {Entity#properties}
|
27
|
+
class Properties
|
28
|
+
def initialize properties = {}
|
29
|
+
@hash = {}
|
30
|
+
properties.each do |key, value|
|
31
|
+
key = ensure_key_type key
|
32
|
+
value = ensure_value_type value
|
33
|
+
@hash[key] = value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def [] key
|
38
|
+
key = ensure_key_type key
|
39
|
+
@hash[key]
|
40
|
+
end
|
41
|
+
alias_method :read, :[]
|
42
|
+
|
43
|
+
def []= key, value
|
44
|
+
key = ensure_key_type key
|
45
|
+
value = ensure_value_type value
|
46
|
+
@hash[key] = value
|
47
|
+
end
|
48
|
+
alias_method :write, :[]=
|
49
|
+
|
50
|
+
def exist? key
|
51
|
+
key = ensure_key_type key
|
52
|
+
@hash.key? key
|
53
|
+
end
|
54
|
+
|
55
|
+
def fetch key, &_block
|
56
|
+
key = ensure_key_type key
|
57
|
+
@hash[key] = yield unless exist? key
|
58
|
+
@hash[key]
|
59
|
+
end
|
60
|
+
|
61
|
+
def each &block
|
62
|
+
@hash.each(&block)
|
63
|
+
end
|
64
|
+
|
65
|
+
def delete key, &block
|
66
|
+
key = ensure_key_type key
|
67
|
+
@hash.delete key, &block
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_h
|
71
|
+
@hash.dup
|
72
|
+
end
|
73
|
+
alias_method :to_hash, :to_h
|
74
|
+
|
75
|
+
def to_grpc
|
76
|
+
Hash[@hash.map { |(k, v)| [k.to_s, Core::GRPCUtils.to_value(v)] }]
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.from_grpc grpc_map
|
80
|
+
# For some reason Google::Protobuf::Map#map isn't returning the value.
|
81
|
+
# It returns nil every time. COnvert to Hash to get actual objects.
|
82
|
+
grpc_hash = Core::GRPCUtils.map_to_hash grpc_map
|
83
|
+
grpc_array = grpc_hash.map do |(k, v)|
|
84
|
+
[k.to_s, Core::GRPCUtils.from_value(v)]
|
85
|
+
end
|
86
|
+
new Hash[grpc_array]
|
87
|
+
end
|
88
|
+
|
89
|
+
protected
|
90
|
+
|
91
|
+
##
|
92
|
+
# Ensures the key is the proper type,
|
93
|
+
# otherwise a PropertyError is raised.
|
94
|
+
def ensure_key_type key
|
95
|
+
return key.to_str if key.respond_to? :to_str
|
96
|
+
fail "Property key #{key} must be a String."
|
97
|
+
end
|
98
|
+
|
99
|
+
# rubocop:disable all
|
100
|
+
# Disabled rubocop because this needs to match Core::GRPCUtils.to_value
|
101
|
+
|
102
|
+
##
|
103
|
+
# Ensures the value is a type that can be persisted,
|
104
|
+
# otherwise a PropertyError is raised.
|
105
|
+
def ensure_value_type value
|
106
|
+
if Google::Cloud::Datastore::Key === value ||
|
107
|
+
Google::Cloud::Datastore::Entity === value ||
|
108
|
+
NilClass === value ||
|
109
|
+
TrueClass === value ||
|
110
|
+
FalseClass === value ||
|
111
|
+
Float === value ||
|
112
|
+
Integer === value ||
|
113
|
+
String === value ||
|
114
|
+
Array === value
|
115
|
+
return value
|
116
|
+
elsif value.respond_to?(:to_time)
|
117
|
+
return value
|
118
|
+
elsif value.respond_to?(:to_hash) && value.keys.sort == [:latitude, :longitude]
|
119
|
+
return value
|
120
|
+
elsif value.respond_to?(:read) && value.respond_to?(:rewind)
|
121
|
+
# Always convert an IO object to a StringIO when storing.
|
122
|
+
value.rewind
|
123
|
+
return StringIO.new(value.read.force_encoding("ASCII-8BIT"))
|
124
|
+
elsif defined?(BigDecimal) && BigDecimal === value
|
125
|
+
return value
|
126
|
+
end
|
127
|
+
fail PropertyError, "A property of type #{value.class} is not supported."
|
128
|
+
end
|
129
|
+
# rubocop:enable all
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,351 @@
|
|
1
|
+
# Copyright 2014 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
|
+
require "google/cloud/datastore/entity"
|
17
|
+
require "google/cloud/datastore/key"
|
18
|
+
|
19
|
+
module Google
|
20
|
+
module Cloud
|
21
|
+
module Datastore
|
22
|
+
##
|
23
|
+
# # Query
|
24
|
+
#
|
25
|
+
# Represents the search criteria against a Datastore.
|
26
|
+
#
|
27
|
+
# @see https://cloud.google.com/datastore/docs/concepts/queries Datastore
|
28
|
+
# Queries
|
29
|
+
# @see https://cloud.google.com/datastore/docs/concepts/metadataqueries
|
30
|
+
# Datastore Metadata
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# query = Google::Cloud::Datastore::Query.new
|
34
|
+
# query.kind("Task").
|
35
|
+
# where("done", "=", false).
|
36
|
+
# where("priority", ">=", 4).
|
37
|
+
# order("priority", :desc)
|
38
|
+
#
|
39
|
+
# tasks = datastore.run query
|
40
|
+
#
|
41
|
+
class Query
|
42
|
+
##
|
43
|
+
# Returns a new query object.
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# query = Google::Cloud::Datastore::Query.new
|
47
|
+
#
|
48
|
+
def initialize
|
49
|
+
@grpc = Google::Datastore::V1::Query.new
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Add the kind of entities to query.
|
54
|
+
#
|
55
|
+
# Special entity kinds such as `__namespace__`, `__kind__`, and
|
56
|
+
# `__property__` can be used for [metadata
|
57
|
+
# queries](https://cloud.google.com/datastore/docs/concepts/metadataqueries).
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
# query = Google::Cloud::Datastore::Query.new
|
61
|
+
# query.kind "Task"
|
62
|
+
#
|
63
|
+
# tasks = datastore.run query
|
64
|
+
#
|
65
|
+
def kind *kinds
|
66
|
+
kinds.each do |kind|
|
67
|
+
grpc_kind = Google::Datastore::V1::KindExpression.new(
|
68
|
+
name: kind)
|
69
|
+
@grpc.kind << grpc_kind
|
70
|
+
end
|
71
|
+
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# Add a property filter to the query.
|
77
|
+
#
|
78
|
+
# @example
|
79
|
+
# query = Google::Cloud::Datastore::Query.new
|
80
|
+
# query.kind("Task").
|
81
|
+
# where("done", "=", false)
|
82
|
+
#
|
83
|
+
# tasks = datastore.run query
|
84
|
+
#
|
85
|
+
# @example Add a composite property filter:
|
86
|
+
# query = Google::Cloud::Datastore::Query.new
|
87
|
+
# query.kind("Task").
|
88
|
+
# where("done", "=", false).
|
89
|
+
# where("priority", ">=", 4)
|
90
|
+
#
|
91
|
+
# tasks = datastore.run query
|
92
|
+
#
|
93
|
+
# @example Add an inequality filter on a **single** property only:
|
94
|
+
# query = Google::Cloud::Datastore::Query.new
|
95
|
+
# query.kind("Task").
|
96
|
+
# where("created", ">=", Time.utc(1990, 1, 1)).
|
97
|
+
# where("created", "<", Time.utc(2000, 1, 1))
|
98
|
+
#
|
99
|
+
# tasks = datastore.run query
|
100
|
+
#
|
101
|
+
# @example Add a composite filter on an array property:
|
102
|
+
# query = Google::Cloud::Datastore::Query.new
|
103
|
+
# query.kind("Task").
|
104
|
+
# where("tag", "=", "fun").
|
105
|
+
# where("tag", "=", "programming")
|
106
|
+
#
|
107
|
+
# tasks = datastore.run query
|
108
|
+
#
|
109
|
+
# @example Add an inequality filter on an array property :
|
110
|
+
# query = Google::Cloud::Datastore::Query.new
|
111
|
+
# query.kind("Task").
|
112
|
+
# where("tag", ">", "learn").
|
113
|
+
# where("tag", "<", "math")
|
114
|
+
#
|
115
|
+
# tasks = datastore.run query
|
116
|
+
#
|
117
|
+
# @example Add a key filter using the special property `__key__`:
|
118
|
+
# query = Google::Cloud::Datastore::Query.new
|
119
|
+
# query.kind("Task").
|
120
|
+
# where("__key__", ">", datastore.key("Task", "someTask"))
|
121
|
+
#
|
122
|
+
# tasks = datastore.run query
|
123
|
+
#
|
124
|
+
# @example Add a key filter to a *kindless* query:
|
125
|
+
# last_seen_key = datastore.key "Task", "a"
|
126
|
+
# query = Google::Cloud::Datastore::Query.new
|
127
|
+
# query.where("__key__", ">", last_seen_key)
|
128
|
+
#
|
129
|
+
# tasks = datastore.run query
|
130
|
+
#
|
131
|
+
def where name, operator, value
|
132
|
+
@grpc.filter ||= Google::Datastore::V1::Filter.new(
|
133
|
+
composite_filter: Google::Datastore::V1::CompositeFilter.new(
|
134
|
+
op: :AND
|
135
|
+
)
|
136
|
+
)
|
137
|
+
@grpc.filter.composite_filter.filters << \
|
138
|
+
Google::Datastore::V1::Filter.new(
|
139
|
+
property_filter: Google::Datastore::V1::PropertyFilter.new(
|
140
|
+
property: Google::Datastore::V1::PropertyReference.new(
|
141
|
+
name: name),
|
142
|
+
op: Core::GRPCUtils.to_prop_filter_op(operator),
|
143
|
+
value: Core::GRPCUtils.to_value(value)
|
144
|
+
)
|
145
|
+
)
|
146
|
+
|
147
|
+
self
|
148
|
+
end
|
149
|
+
alias_method :filter, :where
|
150
|
+
|
151
|
+
##
|
152
|
+
# Add a filter for entities that inherit from a key.
|
153
|
+
#
|
154
|
+
# @example
|
155
|
+
# task_list_key = datastore.key "TaskList", "default"
|
156
|
+
#
|
157
|
+
# query = Google::Cloud::Datastore::Query.new
|
158
|
+
# query.kind("Task").
|
159
|
+
# ancestor(task_list_key)
|
160
|
+
#
|
161
|
+
# tasks = datastore.run query
|
162
|
+
#
|
163
|
+
def ancestor parent
|
164
|
+
# Use key if given an entity
|
165
|
+
parent = parent.key if parent.respond_to? :key
|
166
|
+
where "__key__", "~", parent
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Sort the results by a property name.
|
171
|
+
# By default, an ascending sort order will be used.
|
172
|
+
# To sort in descending order, provide a second argument
|
173
|
+
# of a string or symbol that starts with "d".
|
174
|
+
#
|
175
|
+
# @example With ascending sort order:
|
176
|
+
# query = Google::Cloud::Datastore::Query.new
|
177
|
+
# query.kind("Task").
|
178
|
+
# order("created")
|
179
|
+
#
|
180
|
+
# tasks = datastore.run query
|
181
|
+
#
|
182
|
+
# @example With descending sort order:
|
183
|
+
# query = Google::Cloud::Datastore::Query.new
|
184
|
+
# query.kind("Task").
|
185
|
+
# order("created", :desc)
|
186
|
+
#
|
187
|
+
# tasks = datastore.run query
|
188
|
+
#
|
189
|
+
# @example With multiple sort orders:
|
190
|
+
# query = Google::Cloud::Datastore::Query.new
|
191
|
+
# query.kind("Task").
|
192
|
+
# order("priority", :desc).
|
193
|
+
# order("created")
|
194
|
+
#
|
195
|
+
# tasks = datastore.run query
|
196
|
+
#
|
197
|
+
# @example A property used in inequality filter must be ordered first:
|
198
|
+
# query = Google::Cloud::Datastore::Query.new
|
199
|
+
# query.kind("Task").
|
200
|
+
# where("priority", ">", 3).
|
201
|
+
# order("priority").
|
202
|
+
# order("created")
|
203
|
+
#
|
204
|
+
# tasks = datastore.run query
|
205
|
+
#
|
206
|
+
def order name, direction = :asc
|
207
|
+
@grpc.order << Google::Datastore::V1::PropertyOrder.new(
|
208
|
+
property: Google::Datastore::V1::PropertyReference.new(
|
209
|
+
name: name),
|
210
|
+
direction: prop_order_direction(direction)
|
211
|
+
)
|
212
|
+
|
213
|
+
self
|
214
|
+
end
|
215
|
+
|
216
|
+
##
|
217
|
+
# Set a limit on the number of results to be returned.
|
218
|
+
#
|
219
|
+
# @example
|
220
|
+
# query = Google::Cloud::Datastore::Query.new
|
221
|
+
# query.kind("Task").
|
222
|
+
# limit(5)
|
223
|
+
#
|
224
|
+
# tasks = datastore.run query
|
225
|
+
#
|
226
|
+
def limit num
|
227
|
+
@grpc.limit = Google::Protobuf::Int32Value.new(value: num)
|
228
|
+
|
229
|
+
self
|
230
|
+
end
|
231
|
+
|
232
|
+
##
|
233
|
+
# Set an offset for the results to be returned.
|
234
|
+
#
|
235
|
+
# @example
|
236
|
+
# query = Google::Cloud::Datastore::Query.new
|
237
|
+
# query.kind("Task").
|
238
|
+
# limit(5).
|
239
|
+
# offset(10)
|
240
|
+
#
|
241
|
+
# tasks = datastore.run query
|
242
|
+
#
|
243
|
+
def offset num
|
244
|
+
@grpc.offset = num
|
245
|
+
|
246
|
+
self
|
247
|
+
end
|
248
|
+
|
249
|
+
##
|
250
|
+
# Set the cursor to start the results at.
|
251
|
+
#
|
252
|
+
# @example
|
253
|
+
# query = Google::Cloud::Datastore::Query.new
|
254
|
+
# query.kind("Task").
|
255
|
+
# limit(page_size).
|
256
|
+
# start(page_cursor)
|
257
|
+
#
|
258
|
+
# tasks = datastore.run query
|
259
|
+
#
|
260
|
+
def start cursor
|
261
|
+
if cursor.is_a? Cursor
|
262
|
+
@grpc.start_cursor = cursor.to_grpc
|
263
|
+
elsif cursor.is_a? String
|
264
|
+
@grpc.start_cursor = Core::GRPCUtils.decode_bytes cursor
|
265
|
+
else
|
266
|
+
fail ArgumentError, "Can't set a cursor using a #{cursor.class}."
|
267
|
+
end
|
268
|
+
|
269
|
+
self
|
270
|
+
end
|
271
|
+
alias_method :cursor, :start
|
272
|
+
|
273
|
+
##
|
274
|
+
# Retrieve only select properties from the matched entities.
|
275
|
+
#
|
276
|
+
# @example
|
277
|
+
# query = Google::Cloud::Datastore::Query.new
|
278
|
+
# query.kind("Task").
|
279
|
+
# select("priority", "percent_complete")
|
280
|
+
#
|
281
|
+
# priorities = []
|
282
|
+
# percent_completes = []
|
283
|
+
# datastore.run(query).each do |task|
|
284
|
+
# priorities << task["priority"]
|
285
|
+
# percent_completes << task["percent_complete"]
|
286
|
+
# end
|
287
|
+
#
|
288
|
+
# @example A keys-only query using the special property `__key__`:
|
289
|
+
# query = Google::Cloud::Datastore::Query.new
|
290
|
+
# query.kind("Task").
|
291
|
+
# select("__key__")
|
292
|
+
#
|
293
|
+
# keys = datastore.run(query).map(&:key)
|
294
|
+
#
|
295
|
+
def select *names
|
296
|
+
names.each do |name|
|
297
|
+
grpc_projection = Google::Datastore::V1::Projection.new(
|
298
|
+
property: Google::Datastore::V1::PropertyReference.new(
|
299
|
+
name: name))
|
300
|
+
@grpc.projection << grpc_projection
|
301
|
+
end
|
302
|
+
|
303
|
+
self
|
304
|
+
end
|
305
|
+
alias_method :projection, :select
|
306
|
+
|
307
|
+
##
|
308
|
+
# Group results by a list of properties.
|
309
|
+
#
|
310
|
+
# @example
|
311
|
+
# query = Google::Cloud::Datastore::Query.new
|
312
|
+
# query.kind("Task").
|
313
|
+
# distinct_on("type", "priority").
|
314
|
+
# order("type").
|
315
|
+
# order("priority")
|
316
|
+
#
|
317
|
+
# tasks = datastore.run query
|
318
|
+
#
|
319
|
+
def group_by *names
|
320
|
+
names.each do |name|
|
321
|
+
grpc_property = Google::Datastore::V1::PropertyReference.new(
|
322
|
+
name: name)
|
323
|
+
@grpc.distinct_on << grpc_property
|
324
|
+
end
|
325
|
+
|
326
|
+
self
|
327
|
+
end
|
328
|
+
alias_method :distinct_on, :group_by
|
329
|
+
|
330
|
+
# @private
|
331
|
+
def to_grpc
|
332
|
+
@grpc
|
333
|
+
end
|
334
|
+
|
335
|
+
protected
|
336
|
+
|
337
|
+
##
|
338
|
+
# @private Get the property order direction for a string.
|
339
|
+
def prop_order_direction direction
|
340
|
+
if direction.to_s.downcase.start_with? "a"
|
341
|
+
:ASCENDING
|
342
|
+
elsif direction.to_s.downcase.start_with? "d"
|
343
|
+
:DESCENDING
|
344
|
+
else
|
345
|
+
:DIRECTION_UNSPECIFIED
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|