gcloud 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG.md +26 -0
  3. data/OVERVIEW.md +10 -8
  4. data/lib/gcloud.rb +12 -13
  5. data/lib/gcloud/bigquery/dataset/list.rb +2 -4
  6. data/lib/gcloud/bigquery/job/list.rb +3 -5
  7. data/lib/gcloud/bigquery/table/list.rb +3 -5
  8. data/lib/gcloud/datastore.rb +326 -97
  9. data/lib/gcloud/datastore/commit.rb +73 -56
  10. data/lib/gcloud/datastore/credentials.rb +1 -12
  11. data/lib/gcloud/datastore/cursor.rb +76 -0
  12. data/lib/gcloud/datastore/dataset.rb +337 -134
  13. data/lib/gcloud/datastore/dataset/lookup_results.rb +12 -12
  14. data/lib/gcloud/datastore/dataset/query_results.rb +117 -27
  15. data/lib/gcloud/datastore/entity.rb +159 -93
  16. data/lib/gcloud/datastore/errors.rb +0 -21
  17. data/lib/gcloud/datastore/gql_query.rb +211 -0
  18. data/lib/gcloud/datastore/grpc_utils.rb +131 -0
  19. data/lib/gcloud/datastore/key.rb +74 -65
  20. data/lib/gcloud/datastore/properties.rb +14 -1
  21. data/lib/gcloud/datastore/query.rb +188 -52
  22. data/lib/gcloud/datastore/service.rb +161 -0
  23. data/lib/gcloud/datastore/transaction.rb +175 -60
  24. data/lib/gcloud/dns/change/list.rb +2 -4
  25. data/lib/gcloud/dns/record/list.rb +2 -4
  26. data/lib/gcloud/dns/zone/list.rb +2 -4
  27. data/lib/gcloud/grpc_utils.rb +11 -0
  28. data/lib/gcloud/logging/entry.rb +6 -17
  29. data/lib/gcloud/logging/entry/list.rb +8 -9
  30. data/lib/gcloud/logging/metric/list.rb +4 -5
  31. data/lib/gcloud/logging/resource.rb +1 -12
  32. data/lib/gcloud/logging/resource_descriptor.rb +9 -12
  33. data/lib/gcloud/logging/resource_descriptor/list.rb +4 -5
  34. data/lib/gcloud/logging/sink/list.rb +4 -5
  35. data/lib/gcloud/pubsub/message.rb +1 -3
  36. data/lib/gcloud/pubsub/subscription.rb +5 -7
  37. data/lib/gcloud/pubsub/topic.rb +1 -3
  38. data/lib/gcloud/resource_manager/project/list.rb +2 -4
  39. data/lib/gcloud/translate/api.rb +5 -3
  40. data/lib/gcloud/translate/connection.rb +4 -4
  41. data/lib/gcloud/version.rb +1 -1
  42. metadata +9 -20
  43. data/lib/gcloud/datastore/connection.rb +0 -203
  44. data/lib/gcloud/datastore/proto.rb +0 -266
  45. data/lib/gcloud/proto/datastore_v1.pb.rb +0 -377
  46. data/lib/google/protobuf/any.rb +0 -17
  47. data/lib/google/protobuf/api.rb +0 -31
  48. data/lib/google/protobuf/duration.rb +0 -17
  49. data/lib/google/protobuf/empty.rb +0 -15
  50. data/lib/google/protobuf/field_mask.rb +0 -16
  51. data/lib/google/protobuf/source_context.rb +0 -16
  52. data/lib/google/protobuf/struct.rb +0 -35
  53. data/lib/google/protobuf/timestamp.rb +0 -17
  54. data/lib/google/protobuf/type.rb +0 -79
  55. data/lib/google/protobuf/wrappers.rb +0 -48
@@ -71,6 +71,17 @@ module Gcloud
71
71
  end
72
72
  alias_method :to_hash, :to_h
73
73
 
74
+ def to_grpc
75
+ Hash[@hash.map { |(k, v)| [k.to_s, GRPCUtils.to_value(v)] }]
76
+ end
77
+
78
+ def self.from_grpc grpc_map
79
+ # For some reason Google::Protobuf::Map#map isn't returning the value.
80
+ # It returns nil every time. COnvert to Hash to get actual objects.
81
+ grpc_hash = GRPCUtils.map_to_hash grpc_map
82
+ new Hash[grpc_hash.map { |(k, v)| [k.to_s, GRPCUtils.from_value(v)] }]
83
+ end
84
+
74
85
  protected
75
86
 
76
87
  ##
@@ -82,7 +93,7 @@ module Gcloud
82
93
  end
83
94
 
84
95
  # rubocop:disable all
85
- # Disabled rubocop because this needs to match Proto.to_proto_value
96
+ # Disabled rubocop because this needs to match GRPCUtils.to_value
86
97
 
87
98
  ##
88
99
  # Ensures the value is a type that can be persisted,
@@ -100,6 +111,8 @@ module Gcloud
100
111
  return value
101
112
  elsif value.respond_to?(:to_time)
102
113
  return value
114
+ elsif value.respond_to?(:to_hash) && value.keys.sort == [:latitude, :longitude]
115
+ return value
103
116
  elsif value.respond_to?(:read) && value.respond_to?(:rewind)
104
117
  # Always convert an IO object to a StringIO when storing.
105
118
  value.rewind
@@ -15,7 +15,6 @@
15
15
 
16
16
  require "gcloud/datastore/entity"
17
17
  require "gcloud/datastore/key"
18
- require "gcloud/datastore/proto"
19
18
 
20
19
  module Gcloud
21
20
  module Datastore
@@ -24,12 +23,19 @@ module Gcloud
24
23
  #
25
24
  # Represents the search criteria against a Datastore.
26
25
  #
26
+ # @see https://cloud.google.com/datastore/docs/concepts/queries Datastore
27
+ # Queries
28
+ # @see https://cloud.google.com/datastore/docs/concepts/metadataqueries
29
+ # Datastore Metadata
30
+ #
27
31
  # @example
28
32
  # query = Gcloud::Datastore::Query.new
29
33
  # query.kind("Task").
30
- # where("completed", "=", true)
34
+ # where("done", "=", false).
35
+ # where("priority", ">=", 4).
36
+ # order("priority", :desc)
31
37
  #
32
- # entities = dataset.run query
38
+ # tasks = datastore.run query
33
39
  #
34
40
  class Query
35
41
  ##
@@ -39,22 +45,28 @@ module Gcloud
39
45
  # query = Gcloud::Datastore::Query.new
40
46
  #
41
47
  def initialize
42
- @_query = Proto::Query.new
48
+ @grpc = Google::Datastore::V1beta3::Query.new
43
49
  end
44
50
 
45
51
  ##
46
52
  # Add the kind of entities to query.
47
53
  #
54
+ # Special entity kinds such as `__namespace__`, `__kind__`, and
55
+ # `__property__` can be used for [metadata
56
+ # queries](https://cloud.google.com/datastore/docs/concepts/metadataqueries).
57
+ #
48
58
  # @example
49
59
  # query = Gcloud::Datastore::Query.new
50
60
  # query.kind "Task"
51
61
  #
52
- # all_tasks = dataset.run query
62
+ # tasks = datastore.run query
53
63
  #
54
64
  def kind *kinds
55
- @_query.kind ||= Proto::KindExpression.new
56
- @_query.kind.name ||= []
57
- @_query.kind.name |= kinds
65
+ kinds.each do |kind|
66
+ grpc_kind = Google::Datastore::V1beta3::KindExpression.new(name: kind)
67
+ @grpc.kind << grpc_kind
68
+ end
69
+
58
70
  self
59
71
  end
60
72
 
@@ -64,21 +76,72 @@ module Gcloud
64
76
  # @example
65
77
  # query = Gcloud::Datastore::Query.new
66
78
  # query.kind("Task").
67
- # where("completed", "=", true)
79
+ # where("done", "=", false)
80
+ #
81
+ # tasks = datastore.run query
82
+ #
83
+ # @example Add a composite property filter:
84
+ # query = Gcloud::Datastore::Query.new
85
+ # query.kind("Task").
86
+ # where("done", "=", false).
87
+ # where("priority", ">=", 4)
88
+ #
89
+ # tasks = datastore.run query
90
+ #
91
+ # @example Add an inequality filter on a **single** property only:
92
+ # query = Gcloud::Datastore::Query.new
93
+ # query.kind("Task").
94
+ # where("created", ">=", Time.utc(1990, 1, 1)).
95
+ # where("created", "<", Time.utc(2000, 1, 1))
96
+ #
97
+ # tasks = datastore.run query
98
+ #
99
+ # @example Add a composite filter on an array property:
100
+ # query = Gcloud::Datastore::Query.new
101
+ # query.kind("Task").
102
+ # where("tag", "=", "fun").
103
+ # where("tag", "=", "programming")
68
104
  #
69
- # completed_tasks = dataset.run query
105
+ # tasks = datastore.run query
106
+ #
107
+ # @example Add an inequality filter on an array property :
108
+ # query = Gcloud::Datastore::Query.new
109
+ # query.kind("Task").
110
+ # where("tag", ">", "learn").
111
+ # where("tag", "<", "math")
112
+ #
113
+ # tasks = datastore.run query
114
+ #
115
+ # @example Add a key filter using the special property `__key__`:
116
+ # query = Gcloud::Datastore::Query.new
117
+ # query.kind("Task").
118
+ # where("__key__", ">", datastore.key("Task", "someTask"))
119
+ #
120
+ # tasks = datastore.run query
121
+ #
122
+ # @example Add a key filter to a *kindless* query:
123
+ # last_seen_key = datastore.key "Task", "a"
124
+ # query = Gcloud::Datastore::Query.new
125
+ # query.where("__key__", ">", last_seen_key)
126
+ #
127
+ # tasks = datastore.run query
70
128
  #
71
129
  def where name, operator, value
72
- # Initialize filter
73
- @_query.filter ||= Proto.new_filter.tap do |f|
74
- f.composite_filter = Proto.new_composite_filter
75
- end
76
- # Create new property filter
77
- filter = Proto.new_filter.tap do |f|
78
- f.property_filter = Proto.new_property_filter name, operator, value
79
- end
80
- # Add new property filter to the list
81
- @_query.filter.composite_filter.filter << filter
130
+ @grpc.filter ||= Google::Datastore::V1beta3::Filter.new(
131
+ composite_filter: Google::Datastore::V1beta3::CompositeFilter.new(
132
+ op: :AND
133
+ )
134
+ )
135
+ @grpc.filter.composite_filter.filters << \
136
+ Google::Datastore::V1beta3::Filter.new(
137
+ property_filter: Google::Datastore::V1beta3::PropertyFilter.new(
138
+ property: Google::Datastore::V1beta3::PropertyReference.new(
139
+ name: name),
140
+ op: GRPCUtils.to_prop_filter_op(operator),
141
+ value: GRPCUtils.to_value(value)
142
+ )
143
+ )
144
+
82
145
  self
83
146
  end
84
147
  alias_method :filter, :where
@@ -87,11 +150,13 @@ module Gcloud
87
150
  # Add a filter for entities that inherit from a key.
88
151
  #
89
152
  # @example
153
+ # task_list_key = datastore.key "TaskList", "default"
154
+ #
90
155
  # query = Gcloud::Datastore::Query.new
91
156
  # query.kind("Task").
92
- # ancestor(parent.key)
157
+ # ancestor(task_list_key)
93
158
  #
94
- # completed_tasks = dataset.run query
159
+ # tasks = datastore.run query
95
160
  #
96
161
  def ancestor parent
97
162
  # Use key if given an entity
@@ -105,20 +170,44 @@ module Gcloud
105
170
  # To sort in descending order, provide a second argument
106
171
  # of a string or symbol that starts with "d".
107
172
  #
108
- # @example
173
+ # @example With ascending sort order:
174
+ # query = Gcloud::Datastore::Query.new
175
+ # query.kind("Task").
176
+ # order("created")
177
+ #
178
+ # tasks = datastore.run query
179
+ #
180
+ # @example With descending sort order:
181
+ # query = Gcloud::Datastore::Query.new
182
+ # query.kind("Task").
183
+ # order("created", :desc)
184
+ #
185
+ # tasks = datastore.run query
186
+ #
187
+ # @example With multiple sort orders:
188
+ # query = Gcloud::Datastore::Query.new
189
+ # query.kind("Task").
190
+ # order("priority", :desc).
191
+ # order("created")
192
+ #
193
+ # tasks = datastore.run query
194
+ #
195
+ # @example A property used in an inequality filter must be ordered first:
109
196
  # query = Gcloud::Datastore::Query.new
110
197
  # query.kind("Task").
111
- # order("due", :desc)
198
+ # where("priority", ">", 3).
199
+ # order("priority").
200
+ # order("created")
112
201
  #
113
- # sorted_tasks = dataset.run query
202
+ # tasks = datastore.run query
114
203
  #
115
204
  def order name, direction = :asc
116
- @_query.order ||= []
117
- po = Proto::PropertyOrder.new
118
- po.property = Proto::PropertyReference.new
119
- po.property.name = name
120
- po.direction = Proto.to_prop_order_direction direction
121
- @_query.order << po
205
+ @grpc.order << Google::Datastore::V1beta3::PropertyOrder.new(
206
+ property: Google::Datastore::V1beta3::PropertyReference.new(
207
+ name: name),
208
+ direction: prop_order_direction(direction)
209
+ )
210
+
122
211
  self
123
212
  end
124
213
 
@@ -128,12 +217,13 @@ module Gcloud
128
217
  # @example
129
218
  # query = Gcloud::Datastore::Query.new
130
219
  # query.kind("Task").
131
- # limit(10)
220
+ # limit(5)
132
221
  #
133
- # paginated_tasks = dataset.run query
222
+ # tasks = datastore.run query
134
223
  #
135
224
  def limit num
136
- @_query.limit = num
225
+ @grpc.limit = Google::Protobuf::Int32Value.new(value: num)
226
+
137
227
  self
138
228
  end
139
229
 
@@ -143,13 +233,14 @@ module Gcloud
143
233
  # @example
144
234
  # query = Gcloud::Datastore::Query.new
145
235
  # query.kind("Task").
146
- # limit(10).
147
- # offset(20)
236
+ # limit(5).
237
+ # offset(10)
148
238
  #
149
- # paginated_tasks = dataset.run query
239
+ # tasks = datastore.run query
150
240
  #
151
241
  def offset num
152
- @_query.offset = num
242
+ @grpc.offset = num
243
+
153
244
  self
154
245
  end
155
246
 
@@ -159,13 +250,20 @@ module Gcloud
159
250
  # @example
160
251
  # query = Gcloud::Datastore::Query.new
161
252
  # query.kind("Task").
162
- # limit(10).
163
- # cursor(task_cursor)
253
+ # limit(page_size).
254
+ # start(page_cursor)
164
255
  #
165
- # paginated_tasks = dataset.run query
256
+ # tasks = datastore.run query
166
257
  #
167
258
  def start cursor
168
- @_query.start_cursor = Proto.decode_cursor cursor
259
+ if cursor.is_a? Cursor
260
+ @grpc.start_cursor = cursor.to_grpc
261
+ elsif cursor.is_a? String
262
+ @grpc.start_cursor = GRPCUtils.decode_bytes cursor
263
+ else
264
+ fail ArgumentError, "Can't set a cursor using a #{cursor.class}."
265
+ end
266
+
169
267
  self
170
268
  end
171
269
  alias_method :cursor, :start
@@ -176,13 +274,30 @@ module Gcloud
176
274
  # @example
177
275
  # query = Gcloud::Datastore::Query.new
178
276
  # query.kind("Task").
179
- # select("completed", "due")
277
+ # select("priority", "percent_complete")
278
+ #
279
+ # priorities = []
280
+ # percent_completes = []
281
+ # datastore.run(query).each do |task|
282
+ # priorities << task["priority"]
283
+ # percent_completes << task["percent_complete"]
284
+ # end
285
+ #
286
+ # @example A keys-only query using the special property `__key__`:
287
+ # query = Gcloud::Datastore::Query.new
288
+ # query.kind("Task").
289
+ # select("__key__")
180
290
  #
181
- # partial_tasks = dataset.run query
291
+ # keys = datastore.run(query).map(&:key)
182
292
  #
183
293
  def select *names
184
- @_query.projection ||= []
185
- @_query.projection += Proto.new_property_expressions(*names)
294
+ names.each do |name|
295
+ grpc_projection = Google::Datastore::V1beta3::Projection.new(
296
+ property: Google::Datastore::V1beta3::PropertyReference.new(
297
+ name: name))
298
+ @grpc.projection << grpc_projection
299
+ end
300
+
186
301
  self
187
302
  end
188
303
  alias_method :projection, :select
@@ -193,19 +308,40 @@ module Gcloud
193
308
  # @example
194
309
  # query = Gcloud::Datastore::Query.new
195
310
  # query.kind("Task").
196
- # group_by("completed")
311
+ # distinct_on("type", "priority").
312
+ # order("type").
313
+ # order("priority")
197
314
  #
198
- # grouped_tasks = dataset.run query
315
+ # tasks = datastore.run query
199
316
  #
200
317
  def group_by *names
201
- @_query.group_by ||= []
202
- @_query.group_by += Proto.new_property_references(*names)
318
+ names.each do |name|
319
+ grpc_property = Google::Datastore::V1beta3::PropertyReference.new(
320
+ name: name)
321
+ @grpc.distinct_on << grpc_property
322
+ end
323
+
203
324
  self
204
325
  end
326
+ alias_method :distinct_on, :group_by
205
327
 
206
328
  # @private
207
- def to_proto
208
- @_query
329
+ def to_grpc
330
+ @grpc
331
+ end
332
+
333
+ protected
334
+
335
+ ##
336
+ # @private Get the property order direction for a string.
337
+ def prop_order_direction direction
338
+ if direction.to_s.downcase.start_with? "a"
339
+ :ASCENDING
340
+ elsif direction.to_s.downcase.start_with? "d"
341
+ :DESCENDING
342
+ else
343
+ :DIRECTION_UNSPECIFIED
344
+ end
209
345
  end
210
346
  end
211
347
  end
@@ -0,0 +1,161 @@
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
+ require "gcloud/datastore/credentials"
17
+ require "google/datastore/v1beta3/datastore_services"
18
+ require "gcloud/backoff"
19
+
20
+ module Gcloud
21
+ module Datastore
22
+ ##
23
+ # @private Represents the gRPC Datastore service, including all the API
24
+ # methods.
25
+ class Service
26
+ attr_accessor :project, :credentials, :host
27
+
28
+ ##
29
+ # Creates a new Service instance.
30
+ def initialize project, credentials
31
+ @project = project
32
+ @credentials = credentials
33
+ @host = "datastore.googleapis.com"
34
+ end
35
+
36
+ def creds
37
+ return credentials if insecure?
38
+ GRPC::Core::ChannelCredentials.new.compose \
39
+ GRPC::Core::CallCredentials.new credentials.client.updater_proc
40
+ end
41
+
42
+ def datastore
43
+ return mocked_datastore if mocked_datastore
44
+ @datastore ||= Google::Datastore::V1beta3::Datastore::Stub.new(
45
+ host, creds)
46
+ end
47
+ attr_accessor :mocked_datastore
48
+
49
+ def insecure?
50
+ credentials == :this_channel_is_insecure
51
+ end
52
+
53
+ ##
54
+ # Allocate IDs for incomplete keys.
55
+ # (This is useful for referencing an entity before it is inserted.)
56
+ def allocate_ids *incomplete_keys
57
+ allocate_req = Google::Datastore::V1beta3::AllocateIdsRequest.new(
58
+ project_id: project,
59
+ keys: incomplete_keys
60
+ )
61
+
62
+ backoff { datastore.allocate_ids allocate_req }
63
+ end
64
+
65
+ ##
66
+ # Look up entities by keys.
67
+ def lookup *keys, consistency: nil, transaction: nil
68
+ lookup_req = Google::Datastore::V1beta3::LookupRequest.new(
69
+ project_id: project,
70
+ keys: keys
71
+ )
72
+ lookup_req.read_options = generate_read_options consistency, transaction
73
+
74
+ backoff { datastore.lookup lookup_req }
75
+ end
76
+
77
+ # Query for entities.
78
+ def run_query query, namespace = nil, consistency: nil, transaction: nil
79
+ run_req = Google::Datastore::V1beta3::RunQueryRequest.new(
80
+ project_id: project)
81
+ if query.is_a? Google::Datastore::V1beta3::Query
82
+ run_req["query"] = query
83
+ elsif query.is_a? Google::Datastore::V1beta3::GqlQuery
84
+ run_req["gql_query"] = query
85
+ else
86
+ fail ArgumentError, "Unable to query with a #{query.class} object."
87
+ end
88
+ run_req.read_options = generate_read_options consistency, transaction
89
+
90
+ run_req.partition_id = Google::Datastore::V1beta3::PartitionId.new(
91
+ namespace_id: namespace) if namespace
92
+
93
+ backoff { datastore.run_query run_req }
94
+ end
95
+
96
+ ##
97
+ # Begin a new transaction.
98
+ def begin_transaction
99
+ tx_req = Google::Datastore::V1beta3::BeginTransactionRequest.new(
100
+ project_id: project
101
+ )
102
+
103
+ backoff { datastore.begin_transaction tx_req }
104
+ end
105
+
106
+ ##
107
+ # Commit a transaction, optionally creating, deleting or modifying
108
+ # some entities.
109
+ def commit mutations, transaction: nil
110
+ commit_req = Google::Datastore::V1beta3::CommitRequest.new(
111
+ project_id: project,
112
+ mode: :NON_TRANSACTIONAL,
113
+ mutations: mutations
114
+ )
115
+ if transaction
116
+ commit_req.mode = :TRANSACTIONAL
117
+ commit_req.transaction = transaction
118
+ end
119
+
120
+ backoff { datastore.commit commit_req }
121
+ end
122
+
123
+ ##
124
+ # Roll back a transaction.
125
+ def rollback transaction
126
+ rb_req = Google::Datastore::V1beta3::RollbackRequest.new(
127
+ project_id: project,
128
+ transaction: transaction
129
+ )
130
+
131
+ backoff { datastore.rollback rb_req }
132
+ end
133
+
134
+ def inspect
135
+ "#{self.class}(#{@project})"
136
+ end
137
+
138
+ def backoff options = {}
139
+ Gcloud::Backoff.new(options).execute_grpc do
140
+ yield
141
+ end
142
+ end
143
+
144
+ protected
145
+
146
+ def generate_read_options consistency, transaction
147
+ if consistency == :eventual
148
+ return Google::Datastore::V1beta3::ReadOptions.new(
149
+ read_consistency: :EVENTUAL)
150
+ elsif consistency == :strong
151
+ return Google::Datastore::V1beta3::ReadOptions.new(
152
+ read_consistency: :STRONG)
153
+ elsif transaction
154
+ return Google::Datastore::V1beta3::ReadOptions.new(
155
+ transaction: transaction)
156
+ end
157
+ nil
158
+ end
159
+ end
160
+ end
161
+ end