google-cloud-datastore 2.5.0 → 2.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ded45a15f44ec5a2e095ef0369db26c2a4a65e59c2af1e08bb8f6028736062ea
4
- data.tar.gz: 8d7321547294a1c1ab492df132e19300a0466f252e74f9c7122fb7941bbaeac7
3
+ metadata.gz: b372b670c25604994c20b79779906b9a7c00b21bdf3ada9a23eb2cbb5968d053
4
+ data.tar.gz: 2cb8cac3d2de7b1b631d1c9ee7332b7391a73a720968bf09dc0608430de2a472
5
5
  SHA512:
6
- metadata.gz: 8a4039bbc1c34698507c3b7a1e2c22b011f4df3ea66a57927c7dd147c4468d97c85f15b49efa6c06dcb124815ad5fc4098eeaa8e6f54d23570489e6da0d8dbf3
7
- data.tar.gz: af0981ba4ea2bd054ba35ddd372399addbbb5e0d0c8e4032f518b48ab03065771af8a6185dea29483a9948ae42147011c0f6a100c747dd08100736780a5cb286
6
+ metadata.gz: dba07c333a2230e08f4c315dce2b8e28c748a082561c0692d9e419ba47565496b4b47463912e6cebea34ca3c33732df257ec6b4bcd9419b664cc16a4338b9b76
7
+ data.tar.gz: e817d031036cefd768ccf202a291435c6a710f69292ea61f2349bd5456732b3e0253ce94c75006abbcbc231c6c6e664bd4340dd2836f20978542dc2bb30b3b45
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Release History
2
2
 
3
+ ### 2.7.0 (2023-04-12)
4
+
5
+ #### Features
6
+
7
+ * Support OR filter ([#21002](https://github.com/googleapis/google-cloud-ruby/issues/21002))
8
+
9
+ ### 2.6.0 (2023-02-13)
10
+
11
+ #### Features
12
+
13
+ * Added support for snapshot read ([#19422](https://github.com/googleapis/google-cloud-ruby/issues/19422))
14
+
3
15
  ### 2.5.0 (2023-02-09)
4
16
 
5
17
  #### Features
@@ -53,6 +53,15 @@ module Google
53
53
  # descriptions.missing #=> raise NoMethodError
54
54
  #
55
55
  class LookupResults < DelegateClass(::Array)
56
+ ##
57
+ # The time at which these entities were read or found missing.
58
+ attr_reader :response_read_time
59
+
60
+ ##
61
+ # Time at which the entities are being read. This would not be
62
+ # older than 270 seconds.
63
+ attr_reader :read_time
64
+
56
65
  ##
57
66
  # Keys that were not looked up due to resource constraints.
58
67
  attr_accessor :deferred
@@ -110,9 +119,9 @@ module Google
110
119
  ensure_service!
111
120
  lookup_res = @service.lookup(
112
121
  *Array(@deferred).flatten.map(&:to_grpc),
113
- consistency: @consistency, transaction: @transaction
122
+ consistency: @consistency, transaction: @transaction, read_time: @read_time
114
123
  )
115
- self.class.from_grpc lookup_res, @service, @consistency
124
+ self.class.from_grpc lookup_res, @service, @consistency, nil, @read_time
116
125
  end
117
126
 
118
127
  ##
@@ -187,7 +196,7 @@ module Google
187
196
  ##
188
197
  # @private New Dataset::LookupResults from a
189
198
  # Google::Dataset::V1::LookupResponse object.
190
- def self.from_grpc lookup_res, service, consistency = nil, transaction = nil
199
+ def self.from_grpc lookup_res, service, consistency = nil, transaction = nil, read_time = nil
191
200
  entities = to_gcloud_entities lookup_res.found
192
201
  deferred = to_gcloud_keys lookup_res.deferred
193
202
  missing = to_gcloud_entities lookup_res.missing
@@ -195,6 +204,8 @@ module Google
195
204
  lr.instance_variable_set :@service, service
196
205
  lr.instance_variable_set :@consistency, consistency
197
206
  lr.instance_variable_set :@transaction, transaction
207
+ lr.instance_variable_set :@read_time, read_time
208
+ lr.instance_variable_set :@response_read_time, lookup_res.read_time
198
209
  lr.instance_variable_set :@deferred, deferred
199
210
  lr.instance_variable_set :@missing, missing
200
211
  end
@@ -72,6 +72,24 @@ module Google
72
72
  # * `:NO_MORE_RESULTS`
73
73
  attr_reader :more_results
74
74
 
75
+ ##
76
+ # Read timestamp this batch was returned from.
77
+ # This applies to the range of results from the query's `start_cursor` (or
78
+ # the beginning of the query if no cursor was given) to this batch's
79
+ # `end_cursor` (not the query's `end_cursor`).
80
+ #
81
+ # In a single transaction, subsequent query result batches for the same query
82
+ # can have a greater timestamp. Each batch's read timestamp
83
+ # is valid for all preceding batches.
84
+ # This value will not be set for eventually consistent queries in Cloud
85
+ # Datastore.
86
+ attr_reader :batch_read_time
87
+
88
+ ##
89
+ # Time at which the entities are being read. This would not be
90
+ # older than 270 seconds.
91
+ attr_reader :read_time
92
+
75
93
  ##
76
94
  # @private
77
95
  attr_accessor :service, :namespace, :cursors, :query
@@ -162,8 +180,8 @@ module Google
162
180
  # Reduce the limit by the number of entities returned in the current batch
163
181
  query.limit.value -= count
164
182
  end
165
- query_res = service.run_query query, namespace
166
- self.class.from_grpc query_res, service, namespace, query
183
+ query_res = service.run_query query, namespace, read_time: read_time
184
+ self.class.from_grpc query_res, service, namespace, query, read_time
167
185
  end
168
186
 
169
187
  ##
@@ -360,7 +378,7 @@ module Google
360
378
  ##
361
379
  # @private New Dataset::QueryResults from a
362
380
  # Google::Dataset::V1::RunQueryResponse object.
363
- def self.from_grpc query_res, service, namespace, query
381
+ def self.from_grpc query_res, service, namespace, query, read_time = nil
364
382
  r, c = Array(query_res.batch.entity_results).map do |result|
365
383
  [Entity.from_grpc(result.entity), Cursor.from_grpc(result.cursor)]
366
384
  end.transpose
@@ -373,6 +391,8 @@ module Google
373
391
  qr.service = service
374
392
  qr.namespace = namespace
375
393
  qr.query = query_res.query || query
394
+ qr.instance_variable_set :@read_time, read_time
395
+ qr.instance_variable_set :@batch_read_time, query_res.batch.read_time
376
396
  end
377
397
  end
378
398
 
@@ -337,6 +337,8 @@ module Google
337
337
  # [Eventual Consistency in Google Cloud
338
338
  # Datastore](https://cloud.google.com/datastore/docs/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore/#h.tf76fya5nqk8)
339
339
  # for more information.
340
+ # @param [Time] read_time Reads entities as they were at the given time.
341
+ # This may not be older than 270 seconds. Optional
340
342
  #
341
343
  # @return [Google::Cloud::Datastore::Entity, nil]
342
344
  #
@@ -355,12 +357,12 @@ module Google
355
357
  #
356
358
  # task = datastore.find "Task", "sampleTask"
357
359
  #
358
- def find key_or_kind, id_or_name = nil, consistency: nil
360
+ def find key_or_kind, id_or_name = nil, consistency: nil, read_time: nil
359
361
  key = key_or_kind
360
362
  unless key.is_a? Google::Cloud::Datastore::Key
361
363
  key = Key.new key_or_kind, id_or_name
362
364
  end
363
- find_all(key, consistency: consistency).first
365
+ find_all(key, consistency: consistency, read_time: read_time).first
364
366
  end
365
367
  alias get find
366
368
 
@@ -377,6 +379,8 @@ module Google
377
379
  # [Eventual Consistency in Google Cloud
378
380
  # Datastore](https://cloud.google.com/datastore/docs/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore/#h.tf76fya5nqk8)
379
381
  # for more information.
382
+ # @param [Time] read_time Reads entities as they were at the given time.
383
+ # This may not be older than 270 seconds. Optional
380
384
  #
381
385
  # @return [Google::Cloud::Datastore::Dataset::LookupResults]
382
386
  #
@@ -389,12 +393,12 @@ module Google
389
393
  # task_key2 = datastore.key "Task", "sampleTask2"
390
394
  # tasks = datastore.find_all task_key1, task_key2
391
395
  #
392
- def find_all *keys, consistency: nil
396
+ def find_all *keys, consistency: nil, read_time: nil
393
397
  ensure_service!
394
398
  check_consistency! consistency
395
399
  lookup_res = service.lookup(*Array(keys).flatten.map(&:to_grpc),
396
- consistency: consistency)
397
- LookupResults.from_grpc lookup_res, service, consistency
400
+ consistency: consistency, read_time: read_time)
401
+ LookupResults.from_grpc lookup_res, service, consistency, nil, read_time
398
402
  end
399
403
  alias lookup find_all
400
404
 
@@ -411,6 +415,8 @@ module Google
411
415
  # [Eventual Consistency in Google Cloud
412
416
  # Datastore](https://cloud.google.com/datastore/docs/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore/#h.tf76fya5nqk8)
413
417
  # for more information.
418
+ # @param [Time] read_time Reads entities as they were at the given time.
419
+ # This may not be older than 270 seconds. Optional
414
420
  #
415
421
  # @return [Google::Cloud::Datastore::Dataset::QueryResults]
416
422
  #
@@ -461,16 +467,16 @@ module Google
461
467
  # done: false
462
468
  # tasks = datastore.run gql_query, namespace: "example-ns"
463
469
  #
464
- def run query, namespace: nil, consistency: nil
470
+ def run query, namespace: nil, consistency: nil, read_time: nil
465
471
  ensure_service!
466
472
  unless query.is_a?(Query) || query.is_a?(GqlQuery)
467
473
  raise ArgumentError, "Cannot run a #{query.class} object."
468
474
  end
469
475
  check_consistency! consistency
470
476
  query_res = service.run_query query.to_grpc, namespace,
471
- consistency: consistency
477
+ consistency: consistency, read_time: read_time
472
478
  QueryResults.from_grpc query_res, service, namespace,
473
- query.to_grpc.dup
479
+ query.to_grpc.dup, read_time
474
480
  end
475
481
  alias run_query run
476
482
 
@@ -482,6 +488,8 @@ module Google
482
488
  # @param [Symbol] consistency The non-transactional read consistency to
483
489
  # use. Cannot be set to `:strong` for global queries. Accepted values
484
490
  # are `:eventual` and `:strong`.
491
+ # @param [Time] read_time Reads entities as they were at the given time.
492
+ # This may not be older than 270 seconds. Optional
485
493
  #
486
494
  # The default consistency depends on the type of query used. See
487
495
  # [Eventual Consistency in Google Cloud
@@ -545,14 +553,14 @@ module Google
545
553
  # done: false
546
554
  # res = datastore.run_aggregation gql_query, namespace: "example-ns"
547
555
  #
548
- def run_aggregation aggregate_query, namespace: nil, consistency: nil
556
+ def run_aggregation aggregate_query, namespace: nil, consistency: nil, read_time: nil
549
557
  ensure_service!
550
558
  unless aggregate_query.is_a?(AggregateQuery) || aggregate_query.is_a?(GqlQuery)
551
559
  raise ArgumentError, "Cannot run a #{aggregate_query.class} object."
552
560
  end
553
561
  check_consistency! consistency
554
562
  aggregate_query_res = service.run_aggregation_query aggregate_query.to_grpc, namespace,
555
- consistency: consistency
563
+ consistency: consistency, read_time: read_time
556
564
  AggregateQueryResults.from_grpc aggregate_query_res
557
565
  end
558
566
 
@@ -677,6 +685,9 @@ module Google
677
685
  # @see https://cloud.google.com/datastore/docs/concepts/transactions
678
686
  # Transactions
679
687
  #
688
+ # @param [Time] read_time Reads entities at the given time.
689
+ # This may not be older than 60 seconds. Optional
690
+ #
680
691
  # @yield [tx] a block yielding a new transaction
681
692
  # @yieldparam [ReadOnlyTransaction] tx the transaction object
682
693
  #
@@ -698,8 +709,8 @@ module Google
698
709
  # end
699
710
  # end
700
711
  #
701
- def read_only_transaction
702
- tx = ReadOnlyTransaction.new service
712
+ def read_only_transaction read_time: nil
713
+ tx = ReadOnlyTransaction.new service, read_time: read_time
703
714
  return tx unless block_given?
704
715
 
705
716
  begin
@@ -970,6 +981,38 @@ module Google
970
981
  entity
971
982
  end
972
983
 
984
+ ##
985
+ # Create a new Filter instance. This is a convenience method to make the
986
+ # creation of Filter objects easier.
987
+ #
988
+ # @param name [String] The property to filter by.
989
+ # @param operator [String] The operator to filter by. Defaults to nil.
990
+ # @param value The value to compare the property to. Defaults to nil.
991
+ # Possible values are:
992
+ # - Integer
993
+ # - Float/BigDecimal
994
+ # - String
995
+ # - Boolean
996
+ # - Array
997
+ # - Date/Time
998
+ # - StringIO
999
+ # - Google::Cloud::Datastore::Key
1000
+ # - Google::Cloud::Datastore::Entity
1001
+ # - nil
1002
+ #
1003
+ # @return [Google::Cloud::Datastore::Filter]
1004
+ #
1005
+ # @example
1006
+ # require "google/cloud/datastore"
1007
+ #
1008
+ # datastore = Google::Cloud::Datastore.new
1009
+ #
1010
+ # filter = datastore.filter("done", "=", false)
1011
+ #
1012
+ def filter name, operator, value
1013
+ Filter.new name, operator, value
1014
+ end
1015
+
973
1016
  protected
974
1017
 
975
1018
  ##
@@ -0,0 +1,222 @@
1
+ # Copyright 2023 Google LLC
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
+ # https://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
+ require "google/cloud/datastore/v1"
16
+
17
+ module Google
18
+ module Cloud
19
+ module Datastore
20
+ ##
21
+ # Filter
22
+ #
23
+ # Represents the filter criteria for a datastore query.
24
+ #
25
+ # @example Run a query with a simple property filter.
26
+ # require "google/cloud/datastore"
27
+ #
28
+ # datastore = Google::Cloud::Datastore.new
29
+ #
30
+ # filter = Google::Cloud::Datastore::Filter.new("done", "=", "false")
31
+ #
32
+ # query = Google::Cloud::Datastore::Query.new
33
+ # query.kind("Task")
34
+ # .where(filter)
35
+ #
36
+ # tasks = datastore.run query
37
+ #
38
+ # @example Construct a composite filter with a logical OR.
39
+ # require "google/cloud/datastore"
40
+ #
41
+ # datastore = Google::Cloud::Datastore.new
42
+ #
43
+ # filter = Google::Cloud::Datastore::Filter.new("done", "=", "false")
44
+ # .or("priority", ">=", "4")
45
+ #
46
+ # query = Google::Cloud::Datastore::Query.new
47
+ # query.kind("Task")
48
+ # .where(filter)
49
+ #
50
+ # tasks = datastore.run query
51
+ #
52
+ # @example Construct a composite filter by combining multiple filters.
53
+ # require "google/cloud/datastore"
54
+ #
55
+ # datastore = Google::Cloud::Datastore.new
56
+ #
57
+ # filter_1 = Google::Cloud::Datastore::Filter.new("done", "=", "false")
58
+ # filter_2 = Google::Cloud::Datastore::Filter.new("priority", ">=", "4")
59
+ # filter = filter_1.or(filter_2)
60
+ #
61
+ # query = Google::Cloud::Datastore::Query.new
62
+ # query.kind("Task")
63
+ # .where(filter)
64
+ #
65
+ # tasks = datastore.run query
66
+ #
67
+ class Filter
68
+ ##
69
+ # @private Object of type
70
+ # Google::Cloud::Datastore::V1::Filter
71
+ attr_accessor :grpc
72
+
73
+ ##
74
+ # Creates a new Filter.
75
+ #
76
+ # @example
77
+ # require "google/cloud/datastore"
78
+ #
79
+ # filter = Google::Cloud::Datastore::Filter.new("done", "=", "false")
80
+ #
81
+ def initialize name, operator, value
82
+ @grpc = create_property_filter name, operator, value
83
+ end
84
+
85
+ ##
86
+ # Joins two filters with an AND operator.
87
+ #
88
+ # @overload and(name, operator, value)
89
+ # Joins the filter with a property filter
90
+ # @param name [String]
91
+ # @param operator [String]
92
+ # @param value
93
+ #
94
+ # @overload and(filter)
95
+ # Joins the filter with a Filter object
96
+ # @param filter [Filter]
97
+ #
98
+ # @example Join the filter with a property filter
99
+ # require "google/cloud/datastore"
100
+ #
101
+ # datastore = Google::Cloud::Datastore.new
102
+ #
103
+ # filter = Google::Cloud::Filter.new("done", "=", false)
104
+ # .and("priority", ">=", 4)
105
+ #
106
+ # @example Join the filter with a filter object
107
+ # require "google/cloud/datastore"
108
+ #
109
+ # datastore = Google::Cloud::Datastore.new
110
+ #
111
+ # filter_1 = Google::Cloud::Filter.new("done", "=", false)
112
+ # filter_2 = Google::Cloud::Filter.new("priority", ">=", 4)
113
+ #
114
+ # filter = filter_1.and(filter_2)
115
+ #
116
+ def and name_or_filter, operator = nil, value = nil
117
+ combine_filters composite_filter_and, name_or_filter, operator, value
118
+ end
119
+
120
+ ##
121
+ # Joins two filters with an OR operator.
122
+ #
123
+ # @overload or(name, operator, value)
124
+ # Joins the filter with a property filter
125
+ # @param name [String] The property to filter by.
126
+ # @param operator [String] The operator to filter by. Defaults to nil.
127
+ # @param value [Object] The value to compare the property to. Defaults to nil.
128
+ # Possible values are:
129
+ # - Integer
130
+ # - Float/BigDecimal
131
+ # - String
132
+ # - Boolean
133
+ # - Array
134
+ # - Date/Time
135
+ # - StringIO
136
+ # - Google::Cloud::Datastore::Key
137
+ # - Google::Cloud::Datastore::Entity
138
+ # - nil
139
+ #
140
+ # @overload or(filter)
141
+ # Joins the filter with a Filter object
142
+ # @param flter [Filter]
143
+ #
144
+ # @example Join the filter with a property filter
145
+ # require "google/cloud/datastore"
146
+ #
147
+ # datastore = Google::Cloud::Datastore.new
148
+ #
149
+ # filter = Google::Cloud::Filter.new("done", "=", false)
150
+ # .or("priority", ">=", 4)
151
+ #
152
+ # @example Join the filter with a filter object
153
+ # require "google/cloud/datastore"
154
+ #
155
+ # datastore = Google::Cloud::Datastore.new
156
+ #
157
+ # filter_1 = Google::Cloud::Filter.new("done", "=", false)
158
+ # filter_2 = Google::Cloud::Filter.new("priority", ">=", 4)
159
+ #
160
+ # filter = filter_1.or(filter_2)
161
+ #
162
+ def or name_or_filter, operator = nil, value = nil
163
+ combine_filters composite_filter_or, name_or_filter, operator, value
164
+ end
165
+
166
+ # @private
167
+ def to_grpc
168
+ @grpc
169
+ end
170
+
171
+ protected
172
+
173
+ ##
174
+ # @private
175
+ #
176
+ # Combines self.grpc and (name_or_filter, operator, value)
177
+ # into the new_filter object with the specified AND/OR operator
178
+ def combine_filters new_filter, name_or_filter, operator, value
179
+ new_filter.composite_filter.filters << to_grpc
180
+ new_filter.composite_filter.filters << if name_or_filter.is_a? Google::Cloud::Datastore::Filter
181
+ name_or_filter.to_grpc
182
+ else
183
+ create_property_filter name_or_filter, operator, value
184
+ end
185
+ dup.tap do |f|
186
+ f.grpc = new_filter
187
+ end
188
+ end
189
+
190
+ ##
191
+ # @private
192
+ def composite_filter_and
193
+ Google::Cloud::Datastore::V1::Filter.new(
194
+ composite_filter: Google::Cloud::Datastore::V1::CompositeFilter.new(op: :AND)
195
+ )
196
+ end
197
+
198
+ ##
199
+ # @private
200
+ def composite_filter_or
201
+ Google::Cloud::Datastore::V1::Filter.new(
202
+ composite_filter: Google::Cloud::Datastore::V1::CompositeFilter.new(op: :OR)
203
+ )
204
+ end
205
+
206
+ ##
207
+ # @private
208
+ def create_property_filter name, operator, value
209
+ Google::Cloud::Datastore::V1::Filter.new(
210
+ property_filter: Google::Cloud::Datastore::V1::PropertyFilter.new(
211
+ property: Google::Cloud::Datastore::V1::PropertyReference.new(
212
+ name: name
213
+ ),
214
+ op: Convert.to_prop_filter_op(operator),
215
+ value: Convert.to_value(value)
216
+ )
217
+ )
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
@@ -16,6 +16,7 @@
16
16
  require "google/cloud/datastore/entity"
17
17
  require "google/cloud/datastore/key"
18
18
  require "google/cloud/datastore/aggregate_query"
19
+ require "google/cloud/datastore/filter"
19
20
 
20
21
  module Google
21
22
  module Cloud
@@ -96,6 +97,27 @@ module Google
96
97
  ##
97
98
  # Add a property filter to the query.
98
99
  #
100
+ # @overload and(name, operator, value)
101
+ # Joins the filter with a property filter
102
+ # @param name [String] The property to filter by.
103
+ # @param operator [String] The operator to filter by. Defaults to nil.
104
+ # @param value [Object] The value to compare the property to. Defaults to nil.
105
+ # Possible values are:
106
+ # - Integer
107
+ # - Float/BigDecimal
108
+ # - String
109
+ # - Boolean
110
+ # - Array
111
+ # - Date/Time
112
+ # - StringIO
113
+ # - Google::Cloud::Datastore::Key
114
+ # - Google::Cloud::Datastore::Entity
115
+ # - nil
116
+ #
117
+ # @overload and(filter)
118
+ # Joins the filter with a Filter object
119
+ # @param filter [Filter]
120
+ #
99
121
  # @example
100
122
  # require "google/cloud/datastore"
101
123
  #
@@ -119,6 +141,34 @@ module Google
119
141
  #
120
142
  # tasks = datastore.run query
121
143
  #
144
+ # @example Add a composite "AND" filter:
145
+ # require "google/cloud/datastore"
146
+ #
147
+ # datastore = Google::Cloud::Datastore.new
148
+ #
149
+ # filter = Google::Cloud::Filter.new("done", "=", false)
150
+ # .and("priority", ">=", 4)
151
+ #
152
+ # query = Google::Cloud::Datastore::Query.new
153
+ # query.kind("Task")
154
+ # .where(filter)
155
+ #
156
+ # tasks = datastore.run query
157
+ #
158
+ # @example Add a composite "OR" filter:
159
+ # require "google/cloud/datastore"
160
+ #
161
+ # datastore = Google::Cloud::Datastore.new
162
+ #
163
+ # filter = Google::Cloud::Filter.new("done", "=", false)
164
+ # .or("priority", ">=", 4)
165
+ #
166
+ # query = Google::Cloud::Datastore::Query.new
167
+ # query.kind("Task")
168
+ # .where(filter)
169
+ #
170
+ # tasks = datastore.run query
171
+ #
122
172
  # @example Add an inequality filter on a **single** property only:
123
173
  # require "google/cloud/datastore"
124
174
  #
@@ -177,22 +227,18 @@ module Google
177
227
  #
178
228
  # tasks = datastore.run query
179
229
  #
180
- def where name, operator, value
230
+ def where name_or_filter, operator = nil, value = nil
181
231
  @grpc.filter ||= Google::Cloud::Datastore::V1::Filter.new(
182
232
  composite_filter: Google::Cloud::Datastore::V1::CompositeFilter.new(
183
233
  op: :AND
184
234
  )
185
235
  )
186
- @grpc.filter.composite_filter.filters << \
187
- Google::Cloud::Datastore::V1::Filter.new(
188
- property_filter: Google::Cloud::Datastore::V1::PropertyFilter.new(
189
- property: Google::Cloud::Datastore::V1::PropertyReference.new(
190
- name: name
191
- ),
192
- op: Convert.to_prop_filter_op(operator),
193
- value: Convert.to_value(value)
194
- )
195
- )
236
+ if name_or_filter.is_a? Google::Cloud::Datastore::Filter
237
+ @grpc.filter.composite_filter.filters << name_or_filter.to_grpc
238
+ else
239
+ @grpc.filter.composite_filter.filters << \
240
+ Google::Cloud::Datastore::Filter.new(name_or_filter, operator, value).to_grpc
241
+ end
196
242
 
197
243
  self
198
244
  end
@@ -59,13 +59,22 @@ module Google
59
59
  # @private The Service object.
60
60
  attr_accessor :service
61
61
 
62
+ ##
63
+ # Reads entities at the given time.
64
+ # This may not be older than 60 seconds.
65
+ attr_reader :read_time
66
+
62
67
  ##
63
68
  # @private Creates a new ReadOnlyTransaction instance.
64
69
  # Takes a Service instead of project and Credentials.
65
70
  #
66
- def initialize service
71
+ # @param [Time] read_time Reads documents as they were at the given time.
72
+ # This may not be older than 270 seconds. Optional
73
+ #
74
+ def initialize service, read_time: nil
67
75
  @service = service
68
76
  reset!
77
+ @read_time = read_time
69
78
  start
70
79
  end
71
80
 
@@ -194,9 +203,8 @@ module Google
194
203
  #
195
204
  def start
196
205
  raise TransactionError, "Transaction already opened." unless @id.nil?
197
-
198
206
  ensure_service!
199
- tx_res = service.begin_transaction read_only: true
207
+ tx_res = service.begin_transaction read_only: true, read_time: @read_time
200
208
  @id = tx_res.transaction
201
209
  end
202
210
  alias begin_transaction start
@@ -52,6 +52,7 @@ module Google
52
52
  config.metadata = { "google-cloud-resource-prefix": "projects/#{@project}/databases/#{database}" }
53
53
  end
54
54
  end
55
+
55
56
  attr_accessor :mocked_service
56
57
 
57
58
  ##
@@ -63,20 +64,19 @@ module Google
63
64
 
64
65
  ##
65
66
  # Look up entities by keys.
66
- def lookup *keys, consistency: nil, transaction: nil
67
- read_options = generate_read_options consistency, transaction
68
-
67
+ def lookup *keys, consistency: nil, transaction: nil, read_time: nil
68
+ read_options = generate_read_options consistency, transaction, read_time
69
69
  service.lookup project_id: project, database_id: database, keys: keys, read_options: read_options
70
70
  end
71
71
 
72
72
  # Query for entities.
73
- def run_query query, namespace = nil, consistency: nil, transaction: nil
73
+ def run_query query, namespace = nil, consistency: nil, transaction: nil, read_time: nil
74
74
  gql_query = nil
75
75
  if query.is_a? Google::Cloud::Datastore::V1::GqlQuery
76
76
  gql_query = query
77
77
  query = nil
78
78
  end
79
- read_options = generate_read_options consistency, transaction
79
+ read_options = generate_read_options consistency, transaction, read_time
80
80
  if namespace
81
81
  partition_id = Google::Cloud::Datastore::V1::PartitionId.new(
82
82
  namespace_id: namespace
@@ -92,13 +92,13 @@ module Google
92
92
  end
93
93
 
94
94
  ## Query for aggregates
95
- def run_aggregation_query query, namespace = nil, consistency: nil, transaction: nil
95
+ def run_aggregation_query query, namespace = nil, consistency: nil, transaction: nil, read_time: nil
96
96
  gql_query = nil
97
97
  if query.is_a? Google::Cloud::Datastore::V1::GqlQuery
98
98
  gql_query = query
99
99
  query = nil
100
100
  end
101
- read_options = generate_read_options consistency, transaction
101
+ read_options = generate_read_options consistency, transaction, read_time
102
102
  if namespace
103
103
  partition_id = Google::Cloud::Datastore::V1::PartitionId.new(
104
104
  namespace_id: namespace
@@ -114,11 +114,13 @@ module Google
114
114
 
115
115
  ##
116
116
  # Begin a new transaction.
117
- def begin_transaction read_only: nil, previous_transaction: nil
117
+ def begin_transaction read_only: nil, previous_transaction: nil, read_time: nil
118
118
  if read_only
119
119
  transaction_options = Google::Cloud::Datastore::V1::TransactionOptions.new
120
120
  transaction_options.read_only = \
121
- Google::Cloud::Datastore::V1::TransactionOptions::ReadOnly.new
121
+ Google::Cloud::Datastore::V1::TransactionOptions::ReadOnly.new \
122
+ read_time: read_time_to_timestamp(read_time)
123
+
122
124
  end
123
125
  if previous_transaction
124
126
  transaction_options ||= \
@@ -152,7 +154,7 @@ module Google
152
154
 
153
155
  protected
154
156
 
155
- def generate_read_options consistency, transaction
157
+ def generate_read_options consistency, transaction, read_time
156
158
  if consistency == :eventual
157
159
  return Google::Cloud::Datastore::V1::ReadOptions.new(
158
160
  read_consistency: :EVENTUAL
@@ -165,9 +167,25 @@ module Google
165
167
  return Google::Cloud::Datastore::V1::ReadOptions.new(
166
168
  transaction: transaction
167
169
  )
170
+ elsif read_time
171
+ return Google::Cloud::Datastore::V1::ReadOptions.new(
172
+ read_time: read_time_to_timestamp(read_time)
173
+ )
168
174
  end
169
175
  nil
170
176
  end
177
+
178
+ def read_time_to_timestamp time
179
+ return nil if time.nil?
180
+
181
+ # Force the object to be a Time object.
182
+ time = time.to_time.utc
183
+
184
+ Google::Protobuf::Timestamp.new(
185
+ seconds: time.to_i,
186
+ nanos: time.usec * 1000
187
+ )
188
+ end
171
189
  end
172
190
  end
173
191
  end
@@ -16,7 +16,7 @@
16
16
  module Google
17
17
  module Cloud
18
18
  module Datastore
19
- VERSION = "2.5.0".freeze
19
+ VERSION = "2.7.0".freeze
20
20
  end
21
21
  end
22
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-cloud-datastore
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Moore
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-02-09 00:00:00.000000000 Z
12
+ date: 2023-04-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: google-cloud-core
@@ -210,6 +210,7 @@ files:
210
210
  - lib/google/cloud/datastore/dataset/query_results.rb
211
211
  - lib/google/cloud/datastore/entity.rb
212
212
  - lib/google/cloud/datastore/errors.rb
213
+ - lib/google/cloud/datastore/filter.rb
213
214
  - lib/google/cloud/datastore/gql_query.rb
214
215
  - lib/google/cloud/datastore/key.rb
215
216
  - lib/google/cloud/datastore/properties.rb