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
@@ -28,20 +28,20 @@ module Gcloud
28
28
  # Many common Array methods will return a new Array instance.
29
29
  #
30
30
  # @example
31
- # entities = dataset.find_all key1, key2, key3
32
- # entities.size #=> 3
33
- # entities.deferred #=> []
34
- # entities.missing #=> []
31
+ # tasks = datastore.find_all task_key1, task_key2, task_key3
32
+ # tasks.size #=> 3
33
+ # tasks.deferred #=> []
34
+ # tasks.missing #=> []
35
35
  #
36
36
  # @example Caution, many Array methods will return a new Array instance:
37
- # entities = dataset.find_all key1, key2, key3
38
- # entities.size #=> 3
39
- # entities.deferred #=> []
40
- # entities.missing #=> []
41
- # names = entities.map { |e| e["name"] }
42
- # names.size #=> 3
43
- # names.deferred #=> NoMethodError
44
- # names.missing #=> NoMethodError
37
+ # tasks = datastore.find_all task_key1, task_key2, task_key3
38
+ # tasks.size #=> 3
39
+ # tasks.deferred #=> []
40
+ # tasks.missing #=> []
41
+ # descriptions = tasks.map { |task| task["description"] }
42
+ # descriptions.size #=> 3
43
+ # descriptions.deferred #=> NoMethodError
44
+ # descriptions.missing #=> NoMethodError
45
45
  #
46
46
  class LookupResults < DelegateClass(::Array)
47
47
  ##
@@ -28,21 +28,23 @@ module Gcloud
28
28
  # Many common Array methods will return a new Array instance.
29
29
  #
30
30
  # @example
31
- # entities = dataset.run query
32
- # entities.size #=> 3
33
- # entities.cursor #=> "c3VwZXJhd2Vzb21lIQ"
31
+ # tasks = datastore.run query
32
+ # tasks.size #=> 3
33
+ # tasks.cursor #=> Gcloud::Datastore::Cursor(c3VwZXJhd2Vzb21lIQ)
34
34
  #
35
35
  # @example Caution, many Array methods will return a new Array instance:
36
- # entities = dataset.run query
37
- # entities.size #=> 3
38
- # entities.end_cursor #=> "c3VwZXJhd2Vzb21lIQ"
39
- # names = entities.map { |e| e.name }
40
- # names.size #=> 3
41
- # names.cursor #=> NoMethodError
36
+ # tasks = datastore.run query
37
+ # tasks.size #=> 3
38
+ # tasks.end_cursor #=> Gcloud::Datastore::Cursor(c3VwZXJhd2Vzb21lIQ)
39
+ # descriptions = tasks.map { |task| task["description"] }
40
+ # descriptions.size #=> 3
41
+ # descriptions.cursor #=> NoMethodError
42
42
  #
43
43
  class QueryResults < DelegateClass(::Array)
44
44
  ##
45
45
  # The end_cursor of the QueryResults.
46
+ #
47
+ # @return [Gcloud::Datastore::Cursor]
46
48
  attr_reader :end_cursor
47
49
  alias_method :cursor, :end_cursor
48
50
 
@@ -51,41 +53,129 @@ module Gcloud
51
53
  #
52
54
  # Expected values are:
53
55
  #
54
- # "MORE_RESULTS_AFTER_LIMIT":
55
- # "NOT_FINISHED":
56
- # "NO_MORE_RESULTS":
56
+ # * `:NOT_FINISHED`
57
+ # * `:MORE_RESULTS_AFTER_LIMIT`
58
+ # * `:MORE_RESULTS_AFTER_CURSOR`
59
+ # * `:NO_MORE_RESULTS`
57
60
  attr_reader :more_results
58
61
 
59
62
  ##
60
- # Convenience method for determining id the more_results value
61
- # is "NOT_FINISHED"
63
+ # @private
64
+ attr_accessor :service, :namespace, :query
65
+
66
+ ##
67
+ # @private
68
+ attr_writer :end_cursor, :more_results
69
+
70
+ ##
71
+ # Convenience method for determining if the `more_results` value
72
+ # is `:NOT_FINISHED`
62
73
  def not_finished?
63
- more_results == Proto.to_more_results_string(
64
- Proto::QueryResultBatch::MoreResultsType::NOT_FINISHED)
74
+ more_results == :NOT_FINISHED
65
75
  end
66
76
 
67
77
  ##
68
- # Convenience method for determining id the more_results value
69
- # is "MORE_RESULTS_AFTER_LIMIT"
78
+ # Convenience method for determining if the `more_results` value
79
+ # is `:MORE_RESULTS_AFTER_LIMIT`
70
80
  def more_after_limit?
71
- more_results == Proto.to_more_results_string(
72
- Proto::QueryResultBatch::MoreResultsType::MORE_RESULTS_AFTER_LIMIT)
81
+ more_results == :MORE_RESULTS_AFTER_LIMIT
82
+ end
83
+
84
+ ##
85
+ # Convenience method for determining if the `more_results` value
86
+ # is `:MORE_RESULTS_AFTER_CURSOR`
87
+ def more_after_cursor?
88
+ more_results == :MORE_RESULTS_AFTER_CURSOR
73
89
  end
74
90
 
75
91
  ##
76
- # Convenience method for determining id the more_results value
77
- # is "NO_MORE_RESULTS"
92
+ # Convenience method for determining if the `more_results` value
93
+ # is `:NO_MORE_RESULTS`
78
94
  def no_more?
79
- more_results == Proto.to_more_results_string(
80
- Proto::QueryResultBatch::MoreResultsType::NO_MORE_RESULTS)
95
+ more_results == :NO_MORE_RESULTS
81
96
  end
82
97
 
83
98
  ##
84
99
  # Create a new QueryResults with an array of values.
85
- def initialize arr = [], end_cursor = nil, more_results = nil
100
+ def initialize arr = []
86
101
  super arr
87
- @end_cursor = end_cursor
88
- @more_results = more_results
102
+ end
103
+
104
+ ##
105
+ # Whether there are more results available.
106
+ def next?
107
+ !no_more?
108
+ end
109
+
110
+ ##
111
+ # Retrieve the next page of results.
112
+ def next
113
+ return nil unless next?
114
+ return nil if end_cursor.nil?
115
+ ensure_service!
116
+ query.start_cursor = cursor.to_grpc # should always be a Cursor...
117
+ query_res = service.run_query query, namespace
118
+ self.class.from_grpc query_res, service, namespace, query
119
+ rescue GRPC::BadStatus => e
120
+ raise Gcloud::Error.from_error(e)
121
+ end
122
+
123
+ ##
124
+ # Retrieves all log entries by repeatedly loading {#next} until
125
+ # {#next?} returns `false`. Returns the list instance for method
126
+ # chaining.
127
+ #
128
+ # This method may make several API calls until all log entries are
129
+ # retrieved. Be sure to use as narrow a search criteria as possible.
130
+ # Please use with caution.
131
+ #
132
+ # @example
133
+ # require "gcloud"
134
+ #
135
+ # gcloud = Gcloud.new
136
+ # logging = gcloud.logging
137
+ # hour_ago = (Time.now - 60*60).utc.strftime('%FT%TZ')
138
+ # recent_errors = "timestamp >= \"#{hour_ago}\" severity >= ERROR"
139
+ # entries = logging.entries(filter: recent_errors).all
140
+ #
141
+ def all
142
+ while next?
143
+ next_records = self.next
144
+ push(*next_records)
145
+ self.end_cursor = next_records.end_cursor
146
+ self.more_results = next_records.more_results
147
+ self.service = next_records.service
148
+ self.namespace = next_records.namespace
149
+ self.query = next_records.query
150
+ end
151
+ self
152
+ end
153
+
154
+ ##
155
+ # @private New Dataset::QueryResults from a
156
+ # Google::Dataset::V1beta3::RunQueryResponse object.
157
+ def self.from_grpc query_res, service, namespace, query
158
+ entities = Array(query_res.batch.entity_results).map do |result|
159
+ # TODO: Make this return an EntityResult with cursor...
160
+ Entity.from_grpc result.entity
161
+ end
162
+ new(entities).tap do |qr|
163
+ qr.end_cursor = Cursor.from_grpc query_res.batch.end_cursor
164
+ qr.more_results = query_res.batch.more_results
165
+ qr.service = service
166
+ qr.namespace = namespace
167
+ qr.query = query_res.query || query
168
+ end
169
+ end
170
+
171
+ protected
172
+
173
+ ##
174
+ # @private Raise an error unless an active connection to the service is
175
+ # available.
176
+ def ensure_service!
177
+ msg = "Must have active connection to datastore service to get next"
178
+ fail msg if @service.nil? || @query.nil?
89
179
  end
90
180
  end
91
181
  end
@@ -15,7 +15,6 @@
15
15
 
16
16
  require "gcloud/datastore/key"
17
17
  require "gcloud/datastore/properties"
18
- require "gcloud/datastore/proto"
19
18
 
20
19
  module Gcloud
21
20
  module Datastore
@@ -25,10 +24,35 @@ module Gcloud
25
24
  # Entity represents a Datastore record.
26
25
  # Every Entity has a {Key}, and a list of properties.
27
26
  #
28
- # @example
29
- # entity = Gcloud::Datastore::Entity.new
30
- # entity.key = Gcloud::Datastore::Key.new "User", "heidi@example.com"
31
- # entity["name"] = "Heidi Henderson"
27
+ # Entities in Datastore form a hierarchically structured space similar to
28
+ # the directory structure of a file system. When you create an entity, you
29
+ # can optionally designate another entity as its parent; the new entity is a
30
+ # child of the parent entity.
31
+ #
32
+ # @see https://cloud.google.com/datastore/docs/concepts/entities Entities,
33
+ # Properties, and Keys
34
+ #
35
+ # @example Create a new entity using a block:
36
+ # task = datastore.entity "Task", "sampleTask" do |t|
37
+ # t["type"] = "Personal"
38
+ # t["created"] = Time.now
39
+ # t["done"] = false
40
+ # t["priority"] = 4
41
+ # t["percent_complete"] = 10.0
42
+ # t["description"] = "Learn Cloud Datastore"
43
+ # end
44
+ #
45
+ # @example Create a new entity belonging to an existing parent entity:
46
+ # task_key = datastore.key "Task", "sampleTask"
47
+ # task_key.parent = datastore.key "TaskList", "default"
48
+ #
49
+ # task = Gcloud::Datastore::Entity.new
50
+ # task.key = task_key
51
+ #
52
+ # task["type"] = "Personal"
53
+ # task["done"] = false
54
+ # task["priority"] = 4
55
+ # task["description"] = "Learn Cloud Datastore"
32
56
  #
33
57
  class Entity
34
58
  ##
@@ -48,6 +72,8 @@ module Gcloud
48
72
  #
49
73
  # Property values are converted from the Datastore value type
50
74
  # automatically. Blob properties are returned as StringIO objects.
75
+ # Location properties are returned as a Hash with `:longitude` and
76
+ # `:latitude` keys.
51
77
  #
52
78
  # @param [String, Symbol] prop_name The name of the property.
53
79
  #
@@ -57,28 +83,45 @@ module Gcloud
57
83
  # require "gcloud"
58
84
  #
59
85
  # gcloud = Gcloud.new
60
- # dataset = gcloud.datastore
61
- # user = dataset.find "User", "heidi@example.com"
62
- # user["name"] #=> "Heidi Henderson"
86
+ # datastore = gcloud.datastore
87
+ # task = datastore.find "Task", "sampleTask"
88
+ # task["description"] #=> "Learn Cloud Datastore"
63
89
  #
64
90
  # @example Or with a symbol name:
65
91
  # require "gcloud"
66
92
  #
67
93
  # gcloud = Gcloud.new
68
- # dataset = gcloud.datastore
69
- # user = dataset.find "User", "heidi@example.com"
70
- # user[:name] #=> "Heidi Henderson"
94
+ # datastore = gcloud.datastore
95
+ # task = datastore.find "Task", "sampleTask"
96
+ # task[:description] #=> "Learn Cloud Datastore"
97
+ #
98
+ # @example Getting a blob value returns a StringIO object:
99
+ # require "gcloud"
100
+ #
101
+ # gcloud = Gcloud.new
102
+ # datastore = gcloud.datastore
103
+ # user = datastore.find "User", "alice"
104
+ # user["avatar"] #=> StringIO("\x89PNG\r\n\x1A...")
105
+ #
106
+ # @example Getting a geo point value returns a Hash:
107
+ # require "gcloud"
108
+ #
109
+ # gcloud = Gcloud.new
110
+ # datastore = gcloud.datastore
111
+ # user = datastore.find "User", "alice"
112
+ # user["location"] #=> { longitude: -122.0862462,
113
+ # # latitude: 37.4220041 }
71
114
  #
72
115
  # @example Getting a blob value returns a StringIO object:
73
116
  # require "gcloud"
74
117
  #
75
118
  # gcloud = Gcloud.new
76
- # dataset = gcloud.datastore
77
- # user = dataset.find "User", "heidi@example.com"
119
+ # datastore = gcloud.datastore
120
+ # user = datastore.find "User", "alice"
78
121
  # user["avatar"] #=> StringIO("\x89PNG\r\n\x1A...")
79
122
  #
80
123
  def [] prop_name
81
- @properties[prop_name]
124
+ properties[prop_name]
82
125
  end
83
126
 
84
127
  ##
@@ -88,7 +131,8 @@ module Gcloud
88
131
  # automatically. Use an IO-compatible object (File, StringIO, Tempfile) to
89
132
  # indicate the property value should be stored as a Datastore `blob`.
90
133
  # IO-compatible objects are converted to StringIO objects when they are
91
- # set.
134
+ # set. Use a Hash with `:longitude` and `:latitude` keys to indicate the
135
+ # property value should be stored as a Geo Point/LatLng.
92
136
  #
93
137
  # @param [String, Symbol] prop_name The name of the property.
94
138
  # @param [Object] prop_value The value of the property.
@@ -97,29 +141,48 @@ module Gcloud
97
141
  # require "gcloud"
98
142
  #
99
143
  # gcloud = Gcloud.new
100
- # dataset = gcloud.datastore
101
- # user = dataset.find "User", "heidi@example.com"
102
- # user["name"] = "Heidi H. Henderson"
144
+ # datastore = gcloud.datastore
145
+ # task = datastore.find "Task", "sampleTask"
146
+ # task["description"] = "Learn Cloud Datastore"
147
+ # task["tags"] = ["fun", "programming"]
103
148
  #
104
149
  # @example Or with a symbol name:
105
150
  # require "gcloud"
106
151
  #
107
152
  # gcloud = Gcloud.new
108
- # dataset = gcloud.datastore
109
- # user = dataset.find "User", "heidi@example.com"
110
- # user[:name] = "Heidi H. Henderson"
153
+ # datastore = gcloud.datastore
154
+ # task = datastore.find "Task", "sampleTask"
155
+ # task[:description] = "Learn Cloud Datastore"
156
+ # task[:tags] = ["fun", "programming"]
111
157
  #
112
158
  # @example Setting a blob value using an IO:
113
159
  # require "gcloud"
114
160
  #
115
161
  # gcloud = Gcloud.new
116
- # dataset = gcloud.datastore
117
- # user = dataset.find "User", "heidi@example.com"
118
- # user["avatar"] = File.open "/avatars/heidi.png"
162
+ # datastore = gcloud.datastore
163
+ # user = datastore.find "User", "alice"
164
+ # user["avatar"] = File.open "/avatars/alice.png"
165
+ # user["avatar"] #=> StringIO("\x89PNG\r\n\x1A...")
166
+ #
167
+ # @example Setting a geo point value using a Hash:
168
+ # require "gcloud"
169
+ #
170
+ # gcloud = Gcloud.new
171
+ # datastore = gcloud.datastore
172
+ # user = datastore.find "User", "alice"
173
+ # user["location"] = { longitude: -122.0862462, latitude: 37.4220041 }
174
+ #
175
+ # @example Setting a blob value using an IO:
176
+ # require "gcloud"
177
+ #
178
+ # gcloud = Gcloud.new
179
+ # datastore = gcloud.datastore
180
+ # user = datastore.find "User", "alice"
181
+ # user["avatar"] = File.open "/avatars/alice.png"
119
182
  # user["avatar"] #=> StringIO("\x89PNG\r\n\x1A...")
120
183
  #
121
184
  def []= prop_name, prop_value
122
- @properties[prop_name] = prop_value
185
+ properties[prop_name] = prop_value
123
186
  end
124
187
 
125
188
  ##
@@ -129,52 +192,52 @@ module Gcloud
129
192
  # @return [Gcloud::Datastore::Properties]
130
193
  #
131
194
  # @example
132
- # entity.properties[:name] = "Heidi H. Henderson"
133
- # entity.properties["name"] #=> "Heidi H. Henderson"
195
+ # task.properties[:description] = "Learn Cloud Datastore"
196
+ # task.properties["description"] #=> "Learn Cloud Datastore"
134
197
  #
135
- # entity.properties.each do |name, value|
198
+ # task.properties.each do |name, value|
136
199
  # puts "property #{name} has a value of #{value}"
137
200
  # end
138
201
  #
139
202
  # @example A property's existence can be determined by calling `exist?`:
140
- # entity.properties.exist? :name #=> true
141
- # entity.properties.exist? "name" #=> true
142
- # entity.properties.exist? :expiration #=> false
203
+ # task.properties.exist? :description #=> true
204
+ # task.properties.exist? "description" #=> true
205
+ # task.properties.exist? :expiration #=> false
143
206
  #
144
207
  # @example A property can be removed from the entity:
145
- # entity.properties.delete :name
146
- # entity.save
208
+ # task.properties.delete :description
209
+ # task.save
147
210
  #
148
211
  # @example The properties can be converted to a hash:
149
- # prop_hash = entity.properties.to_h
212
+ # prop_hash = task.properties.to_h
150
213
  #
151
214
  attr_reader :properties
152
215
 
153
216
  ##
154
- # Sets the Key that identifies the entity.
217
+ # Sets the {Gcloud::Datastore::Key} that identifies the entity.
155
218
  #
156
219
  # Once the entity is saved, the key is frozen and immutable. Trying to set
157
220
  # a key when immutable will raise a `RuntimeError`.
158
221
  #
159
- # @example The Key can be set before the entity is saved:
222
+ # @example The key can be set before the entity is saved:
160
223
  # require "gcloud"
161
224
  #
162
225
  # gcloud = Gcloud.new
163
- # dataset = gcloud.datastore
164
- # entity = Gcloud::Datastore::Entity.new
165
- # entity.key = Gcloud::Datastore::Key.new "User"
166
- # dataset.save entity
226
+ # datastore = gcloud.datastore
227
+ # task = Gcloud::Datastore::Entity.new
228
+ # task.key = datastore.key "Task"
229
+ # datastore.save task
167
230
  #
168
231
  # @example Once the entity is saved, the key is frozen and immutable:
169
232
  # require "gcloud"
170
233
  #
171
234
  # gcloud = Gcloud.new
172
- # dataset = gcloud.datastore
173
- # entity = dataset.find "User", "heidi@example.com"
174
- # entity.persisted? #=> true
175
- # entity.key = Gcloud::Datastore::Key.new "User" #=> RuntimeError
176
- # entity.key.frozen? #=> true
177
- # entity.key.id = 9876543221 #=> RuntimeError
235
+ # datastore = gcloud.datastore
236
+ # task = datastore.find "Task", "sampleTask"
237
+ # task.persisted? #=> true
238
+ # task.key = datastore.key "Task" #=> RuntimeError
239
+ # task.key.frozen? #=> true
240
+ # task.key.id = 9876543221 #=> RuntimeError
178
241
  #
179
242
  def key= new_key
180
243
  fail "This entity's key is immutable." if persisted?
@@ -188,13 +251,13 @@ module Gcloud
188
251
  # require "gcloud"
189
252
  #
190
253
  # gcloud = Gcloud.new
191
- # dataset = gcloud.datastore
254
+ # datastore = gcloud.datastore
192
255
  #
193
- # new_entity = Gcloud::Datastore::Entity.new
194
- # new_entity.persisted? #=> false
256
+ # task = Gcloud::Datastore::Entity.new
257
+ # task.persisted? #=> false
195
258
  #
196
- # found_entity = dataset.find "User", "heidi@example.com"
197
- # found_entity.persisted? #=> true
259
+ # task = datastore.find "Task", "sampleTask"
260
+ # task.persisted? #=> true
198
261
  #
199
262
  def persisted?
200
263
  @key && @key.frozen?
@@ -217,14 +280,14 @@ module Gcloud
217
280
  # Unindexed properties
218
281
  #
219
282
  # @example Single property values will return a single flag setting:
220
- # entity["age"] = 21
221
- # entity.exclude_from_indexes? "age" #=> false
283
+ # task["priority"] = 4
284
+ # task.exclude_from_indexes? "priority" #=> false
222
285
  #
223
286
  # @example A multi-valued property will return an array of flag settings:
224
- # entity["tags"] = ["ruby", "code"]
225
- # entity.exclude_from_indexes! "tags", [true, false]
287
+ # task["tags"] = ["fun", "programming"]
288
+ # task.exclude_from_indexes! "tags", [true, false]
226
289
  #
227
- # entity.exclude_from_indexes? "tags" #=> [true, false]
290
+ # task.exclude_from_indexes? "tags" #=> [true, false]
228
291
  #
229
292
  def exclude_from_indexes? name
230
293
  value = self[name]
@@ -260,21 +323,21 @@ module Gcloud
260
323
  # Unindexed properties
261
324
  #
262
325
  # @example
263
- # entity["age"] = 21
264
- # entity.exclude_from_indexes! "age", true
326
+ # entity["priority"] = 4
327
+ # entity.exclude_from_indexes! "priority", true
265
328
  #
266
329
  # @example Multi-valued properties can be given multiple exclude flags:
267
- # entity["tags"] = ["ruby", "code"]
330
+ # entity["tags"] = ["fun", "programming"]
268
331
  # entity.exclude_from_indexes! "tags", [true, false]
269
332
  #
270
333
  # @example Or, a single flag can be applied to all values in a property:
271
- # entity["tags"] = ["ruby", "code"]
334
+ # entity["tags"] = ["fun", "programming"]
272
335
  # entity.exclude_from_indexes! "tags", true
273
336
  #
274
337
  # @example Flags can also be set with a block:
275
- # entity["age"] = 21
276
- # entity.exclude_from_indexes! "age" do |age|
277
- # age > 18
338
+ # entity["priority"] = 4
339
+ # entity.exclude_from_indexes! "priority" do |priority|
340
+ # priority > 4
278
341
  # end
279
342
  #
280
343
  def exclude_from_indexes! name, flag = nil, &block
@@ -288,30 +351,34 @@ module Gcloud
288
351
  end
289
352
 
290
353
  ##
291
- # @private Convert the Entity to a protocol buffer object.
292
- def to_proto
293
- entity = Proto::Entity.new.tap do |e|
294
- e.key = @key.to_proto
295
- e.property = Proto.to_proto_properties @properties.to_h
296
- end
297
- update_properties_indexed! entity
298
- entity
354
+ # @private Convert the Entity to a Google::Datastore::V1beta3::Entity
355
+ # object.
356
+ def to_grpc
357
+ grpc = Google::Datastore::V1beta3::Entity.new(
358
+ key: @key.to_grpc,
359
+ properties: @properties.to_grpc
360
+ )
361
+ update_properties_indexed! grpc.properties
362
+ grpc
299
363
  end
300
364
 
301
365
  ##
302
- # @private Create a new Entity from a protocol buffer object.
303
- def self.from_proto proto
366
+ # @private Create a new Entity from a Google::Datastore::V1beta3::Key
367
+ # object.
368
+ def self.from_grpc grpc
304
369
  entity = Entity.new
305
- entity.key = Key.from_proto proto.key
306
- Array(proto.property).each do |p|
307
- entity[p.name] = Proto.from_proto_value p.value
308
- end
309
- entity.send :update_exclude_indexes!, proto
370
+ entity.key = Key.from_grpc grpc.key
371
+ entity.send :properties=, Properties.from_grpc(grpc.properties)
372
+ entity.send :update_exclude_indexes!, grpc.properties
310
373
  entity
311
374
  end
312
375
 
313
376
  protected
314
377
 
378
+ ##
379
+ # @private Allow friendly objects to set Properties object.
380
+ attr_writer :properties
381
+
315
382
  # rubocop:disable all
316
383
  # Disabled rubocop because this is intentionally complex.
317
384
 
@@ -342,31 +409,30 @@ module Gcloud
342
409
 
343
410
  ##
344
411
  # @private Update the exclude data after a new object is created.
345
- def update_exclude_indexes! entity
412
+ def update_exclude_indexes! grpc_map
346
413
  @_exclude_indexes = {}
347
- Array(entity.property).each do |property|
348
- @_exclude_indexes[property.name] = !property.value.indexed
349
- unless property.value.list_value.nil?
350
- exclude = Array(property.value.list_value).map{|v| !v.indexed}
351
- @_exclude_indexes[property.name] = exclude
414
+ grpc_map.each do |name, value|
415
+ next if value.nil?
416
+ @_exclude_indexes[name] = value.exclude_from_indexes
417
+ unless value.array_value.nil?
418
+ exclude = value.array_value.values.map &:exclude_from_indexes
419
+ @_exclude_indexes[name] = exclude
352
420
  end
353
421
  end
354
422
  end
355
423
 
356
424
  ##
357
425
  # @private Update the indexed values before the object is saved.
358
- def update_properties_indexed! entity
359
- Array(entity.property).each do |property|
360
- excluded = exclude_from_indexes? property.name
426
+ def update_properties_indexed! grpc_map
427
+ grpc_map.each do |name, value|
428
+ next if value.nil?
429
+ excluded = exclude_from_indexes? name
361
430
  if excluded.is_a? Array
362
- # Lists must not set indexed, or this error will happen:
363
- # "A Value containing a list_value cannot specify indexed."
364
- property.value.indexed = nil
365
- property.value.list_value.each_with_index do |value, index|
366
- value.indexed = !excluded[index]
431
+ value.array_value.values.each_with_index do |v, i|
432
+ v.exclude_from_indexes = excluded[i]
367
433
  end
368
434
  else
369
- property.value.indexed = !excluded
435
+ value.exclude_from_indexes = excluded
370
436
  end
371
437
  end
372
438
  end