google-cloud-datastore 2.11.0 → 2.13.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: f0e7a2aaa0b31449724820d409981bc786ff520231f30e11d3f43fe5cd587e86
4
- data.tar.gz: 3546b3b9d18c0c79c5c73927b1d4b1a3fad4bc523ee075caab61c287cfc5838d
3
+ metadata.gz: 00f4895cedca98c329cdcccad6094e454ba6884afc5f18b2b765660c5df92da6
4
+ data.tar.gz: 500ab2a00f401e8a69da2e4edb838072da922a149340fb56ecd148bf5aabfa1a
5
5
  SHA512:
6
- metadata.gz: 326efcbff7b5b3b3d5982795b1408f87ee5225f5b7a25eedfdc1fe9403302e6bd39957737ff13faa16f438b3f5f32aa6538bddd9deb026844ac3935b40218505
7
- data.tar.gz: cfbfc92c743af8fa804760fb8360c38b3756ea27f49ee60b1090cc4d563074aa6b5844dc5e10983884035993f0ba32490a1b885313fca7978a80a2b7ab8cc1b8
6
+ metadata.gz: 43730b11a7bbd83b69f2b495140fa752d8fee8deb6a729435fc99a7ff9e7d88f81628f209f7a852985d91b77cb3b9ca689edd09595ac9f71a49661bd57e0caef
7
+ data.tar.gz: 5a6d3307d349f0fcfeb115d73ead84a76f053f65b64b4398e943ee2d641a2a6e6dcb58c715bbee563fa48bb2f20e83b6fe71a78125019eac57c017eb5795ae8a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Release History
2
2
 
3
+ ### 2.13.0 (2025-07-24)
4
+
5
+ #### Features
6
+
7
+ * add explain query features to aggregate query in Cloud Datastore ([#30704](https://github.com/googleapis/google-cloud-ruby/issues/30704))
8
+
9
+ ### 2.12.0 (2025-07-15)
10
+
11
+ #### Features
12
+
13
+ * query explanation features for Cloud Datastore ([#30588](https://github.com/googleapis/google-cloud-ruby/issues/30588))
14
+
3
15
  ### 2.11.0 (2025-03-04)
4
16
 
5
17
  #### Features
@@ -40,22 +40,42 @@ module Google
40
40
  #
41
41
  class AggregateQueryResults
42
42
  ##
43
- # @private Object of type [Hash{String => Object}].
44
- #
45
- # String can have the following values:
46
- # - an aggregate literal "sum", "avg", or "count"
47
- # - a custom aggregate alias
48
- # Object can have the following types:
49
- # - Integer
50
- # - Float
43
+ # The result of the aggregation query, returned as a hash of key-value
44
+ # pairs. The key is the alias of the aggregate function, and the value
45
+ # is the result of the aggregation.
46
+ #
47
+ # The alias of the aggregate function can be:
48
+ # - an aggregate literal "sum", "avg", or "count"
49
+ # - a custom aggregate alias
50
+ #
51
+ # @return [Hash{String => Integer, Float}]
51
52
  attr_reader :aggregate_fields
52
53
 
53
54
  ##
54
- # Read timestamp the query was done on the database at.
55
+ # The time when the query was executed.
55
56
  #
56
- # @return Google::Protobuf::Timestamp
57
+ # @return [Google::Protobuf::Timestamp]
57
58
  attr_reader :read_time
58
59
 
60
+ # Query explain metrics. This is only present when the `explain_options`
61
+ # are provided to {Google::Cloud::Datastore::Dataset#run_aggregation}.
62
+ # It is sent only once with the response.
63
+ #
64
+ # @return [Google::Cloud::Datastore::V1::ExplainMetrics, nil]
65
+ attr_reader :explain_metrics
66
+
67
+ ##
68
+ # The options for query explanation.
69
+ #
70
+ # This is a copy of the input parameter supplied to the {Dataset#run_aggregation} function.
71
+ #
72
+ # @return [Google::Cloud::Datastore::V1::ExplainOptions, nil]
73
+ attr_reader :explain_options
74
+
75
+ ##
76
+ # @private
77
+ attr_writer :aggregate_fields, :read_time, :explain_metrics, :explain_options
78
+
59
79
  ##
60
80
  # Retrieves the aggregate data.
61
81
  #
@@ -108,22 +128,33 @@ module Google
108
128
  ##
109
129
  # @private New AggregateQueryResults from a
110
130
  # Google::Cloud::Datastore::V1::RunAggregationQueryResponse object.
111
- def self.from_grpc aggregate_query_response
112
- aggregate_fields = aggregate_query_response
113
- .batch
114
- .aggregation_results[0]
115
- .aggregate_properties
116
- .map do |aggregate_alias, value|
117
- if value.has_integer_value?
118
- [aggregate_alias, value.integer_value]
119
- else
120
- [aggregate_alias, value.double_value]
121
- end
122
- end
131
+ def self.from_grpc aggregate_query_response, explain_options
132
+ # If the aggregate query is run with explain_options and analyze = false,
133
+ # the RunAggregationQueryResponse will not have batch results
134
+ # only explain metrics.
135
+ aggregate_fields = {}
136
+ read_time = nil
137
+
138
+ if aggregate_query_response.batch
139
+ aggregate_fields = aggregate_query_response
140
+ .batch
141
+ .aggregation_results[0]
142
+ .aggregate_properties
143
+ .map do |aggregate_alias, value|
144
+ if value.has_integer_value?
145
+ [aggregate_alias, value.integer_value]
146
+ else
147
+ [aggregate_alias, value.double_value]
148
+ end
149
+ end
150
+ read_time = aggregate_query_response.batch.read_time
151
+ end
123
152
 
124
- new.tap do |s|
125
- s.instance_variable_set :@aggregate_fields, aggregate_fields.to_h
126
- s.instance_variable_set :@read_time, aggregate_query_response.batch.read_time
153
+ new.tap do |aq_result|
154
+ aq_result.explain_options = explain_options
155
+ aq_result.explain_metrics = aggregate_query_response.explain_metrics
156
+ aq_result.aggregate_fields = aggregate_fields.to_h
157
+ aq_result.read_time = read_time
127
158
  end
128
159
  end
129
160
  end
@@ -20,12 +20,12 @@ module Google
20
20
  module Datastore
21
21
  class Dataset
22
22
  ##
23
- # LookupResults is a special case Array with additional values.
24
- # A LookupResults object is returned from Dataset#find_all and
23
+ # {LookupResults} is a special case Array with additional values.
24
+ # A {LookupResults} object is returned from {Dataset#find_all} and
25
25
  # contains the entities as well as the Keys that were deferred from
26
26
  # the results and the Entities that were missing in the dataset.
27
27
  #
28
- # Please be cautious when treating the QueryResults as an Array.
28
+ # Please be cautious when treating the {LookupResults} as an Array.
29
29
  # Many common Array methods will return a new Array instance.
30
30
  #
31
31
  # @example
@@ -55,21 +55,32 @@ module Google
55
55
  class LookupResults < DelegateClass(::Array)
56
56
  ##
57
57
  # The time at which these entities were read or found missing.
58
+ # @return [Google::Protobuf::Timestamp]
58
59
  attr_reader :response_read_time
59
60
 
60
61
  ##
61
62
  # Time at which the entities are being read. This would not be
62
63
  # older than 270 seconds.
64
+ #
65
+ # This is a copy of the input parameter supplied to the {Dataset#find_all} function.
66
+ #
67
+ # @return [Time, nil]
63
68
  attr_reader :read_time
64
69
 
65
70
  ##
66
71
  # Keys that were not looked up due to resource constraints.
72
+ # @return [Array<Google::Cloud::Datastore::Key>]
67
73
  attr_accessor :deferred
68
74
 
69
75
  ##
70
76
  # Entities not found, with only the key populated.
77
+ # @return [Array<Google::Cloud::Datastore::Entity>]
71
78
  attr_accessor :missing
72
79
 
80
+ ##
81
+ # @private
82
+ attr_writer :service, :consistency, :transaction, :response_read_time, :read_time
83
+
73
84
  ##
74
85
  # @private Create a new LookupResults with an array of values.
75
86
  def initialize arr = []
@@ -196,18 +207,19 @@ module Google
196
207
  ##
197
208
  # @private New Dataset::LookupResults from a
198
209
  # Google::Dataset::V1::LookupResponse object.
199
- def self.from_grpc lookup_res, service, consistency = nil, transaction = nil, read_time = nil
200
- entities = to_gcloud_entities lookup_res.found
201
- deferred = to_gcloud_keys lookup_res.deferred
202
- missing = to_gcloud_entities lookup_res.missing
203
- new(entities).tap do |lr|
204
- lr.instance_variable_set :@service, service
205
- lr.instance_variable_set :@consistency, consistency
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
209
- lr.instance_variable_set :@deferred, deferred
210
- lr.instance_variable_set :@missing, missing
210
+ def self.from_grpc lookup_resp, service, consistency = nil, transaction = nil, read_time = nil
211
+ entities = to_gcloud_entities lookup_resp.found
212
+ deferred = to_gcloud_keys lookup_resp.deferred
213
+ missing = to_gcloud_entities lookup_resp.missing
214
+
215
+ new(entities).tap do |lookup_results|
216
+ lookup_results.service = service
217
+ lookup_results.consistency = consistency
218
+ lookup_results.transaction = transaction
219
+ lookup_results.read_time = read_time
220
+ lookup_results.response_read_time = lookup_resp.read_time
221
+ lookup_results.deferred = deferred
222
+ lookup_results.missing = missing
211
223
  end
212
224
  end
213
225
 
@@ -70,6 +70,7 @@ module Google
70
70
  # * `:MORE_RESULTS_AFTER_LIMIT`
71
71
  # * `:MORE_RESULTS_AFTER_CURSOR`
72
72
  # * `:NO_MORE_RESULTS`
73
+ # @return [Symbol]
73
74
  attr_reader :more_results
74
75
 
75
76
  ##
@@ -83,20 +84,45 @@ module Google
83
84
  # is valid for all preceding batches.
84
85
  # This value will not be set for eventually consistent queries in Cloud
85
86
  # Datastore.
87
+ # @return [Google::Protobuf::Timestamp]
86
88
  attr_reader :batch_read_time
87
89
 
90
+ # Query explain metrics. This is only present when the
91
+ # [RunQueryRequest.explain_options][google.datastore.v1.RunQueryRequest.explain_options]
92
+ # is provided, and it is sent only once with or after the last QueryResults batch.
93
+ #
94
+ # To retrieve metrics, iterate over all QueryResults (e.g. with `next`). The explain_metrics
95
+ # field will be set on final QueryResults object.
96
+ #
97
+ # @return [Google::Cloud::Datastore::V1::ExplainMetrics, nil]
98
+ attr_reader :explain_metrics
99
+
88
100
  ##
89
101
  # Time at which the entities are being read. This would not be
90
102
  # older than 270 seconds.
103
+ #
104
+ # This is a copy of the input parameter supplied to the {Dataset#run} function.
105
+ #
106
+ # @return [Time, nil]
91
107
  attr_reader :read_time
92
108
 
109
+ ##
110
+ # The options for query explanation.
111
+ #
112
+ # This is a copy of the input parameter supplied to the {Dataset#run} function.
113
+ #
114
+ # @return [Google::Cloud::Datastore::V1::ExplainOptions, nil]
115
+ attr_reader :explain_options
116
+
93
117
  ##
94
118
  # @private
95
119
  attr_accessor :service, :namespace, :cursors, :query
96
120
 
97
121
  ##
98
122
  # @private
99
- attr_writer :end_cursor, :more_results
123
+ attr_writer :end_cursor, :more_results, :explain_metrics, :read_time, :batch_read_time, :explain_options
124
+
125
+ ##
100
126
 
101
127
  ##
102
128
  # Convenience method for determining if the `more_results` value
@@ -153,6 +179,8 @@ module Google
153
179
  not_finished?
154
180
  end
155
181
 
182
+ # rubocop:disable Metrics/AbcSize
183
+
156
184
  ##
157
185
  # Retrieve the next page of results.
158
186
  #
@@ -180,10 +208,12 @@ module Google
180
208
  # Reduce the limit by the number of entities returned in the current batch
181
209
  query.limit.value -= count
182
210
  end
183
- query_res = service.run_query query, namespace, read_time: read_time
184
- self.class.from_grpc query_res, service, namespace, query, read_time
211
+ query_res = service.run_query query, namespace, read_time: read_time, explain_options: explain_options
212
+ self.class.from_grpc query_res, service, namespace, query, read_time, explain_options
185
213
  end
186
214
 
215
+ # rubocop:enable Metrics/AbcSize
216
+
187
217
  ##
188
218
  # Retrieve the {Cursor} for the provided result.
189
219
  #
@@ -375,27 +405,39 @@ module Google
375
405
  end
376
406
  end
377
407
 
408
+ # rubocop:disable Metrics/AbcSize
409
+
378
410
  ##
379
411
  # @private New Dataset::QueryResults from a
380
412
  # Google::Dataset::V1::RunQueryResponse object.
381
- def self.from_grpc query_res, service, namespace, query, read_time = nil
382
- r, c = Array(query_res.batch.entity_results).map do |result|
383
- [Entity.from_grpc(result.entity), Cursor.from_grpc(result.cursor)]
384
- end.transpose
413
+ def self.from_grpc query_res, service, namespace, query, read_time = nil, explain_options = nil
414
+ if query_res.batch
415
+ r, c = Array(query_res.batch.entity_results).map do |result|
416
+ [Entity.from_grpc(result.entity), Cursor.from_grpc(result.cursor)]
417
+ end.transpose
418
+ end
385
419
  r ||= []
386
420
  c ||= []
421
+
422
+ next_more_results = query_res.batch.more_results if query_res.batch
423
+ next_more_results ||= :NO_MORE_RESULTS
424
+
387
425
  new(r).tap do |qr|
388
426
  qr.cursors = c
389
- qr.end_cursor = Cursor.from_grpc query_res.batch.end_cursor
390
- qr.more_results = query_res.batch.more_results
427
+ qr.explain_metrics = query_res.explain_metrics
428
+ qr.end_cursor = Cursor.from_grpc query_res.batch.end_cursor if query_res.batch
429
+ qr.more_results = next_more_results
430
+ qr.read_time = read_time
431
+ qr.batch_read_time = query_res.batch.read_time if query_res.batch
432
+ qr.explain_options = explain_options
391
433
  qr.service = service
392
434
  qr.namespace = namespace
393
435
  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
396
436
  end
397
437
  end
398
438
 
439
+ # rubocop:enable Metrics/AbcSize
440
+
399
441
  protected
400
442
 
401
443
  ##
@@ -416,7 +416,11 @@ module Google
416
416
  # Datastore](https://cloud.google.com/datastore/docs/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore/#h.tf76fya5nqk8)
417
417
  # for more information.
418
418
  # @param [Time] read_time Reads entities as they were at the given time.
419
- # This may not be older than 270 seconds. Optional
419
+ # This may not be older than 270 seconds. Optional.
420
+ # @param [Hash, Google::Cloud::Datastore::V1::ExplainOptions] explain_options The options for query explanation.
421
+ # Provide this argument to enable explain metrics. If this argument is left unset,
422
+ # the results will not include explain metrics.
423
+ # See {Google::Cloud::Datastore::V1::ExplainOptions} for details. Optional.
420
424
  #
421
425
  # @return [Google::Cloud::Datastore::Dataset::QueryResults]
422
426
  #
@@ -467,16 +471,65 @@ module Google
467
471
  # done: false
468
472
  # tasks = datastore.run gql_query, namespace: "example-ns"
469
473
  #
470
- def run query, namespace: nil, consistency: nil, read_time: nil
474
+ # @example Run the query with explain options to get query plan and execution statistics.
475
+ # require "google/cloud/datastore"
476
+ #
477
+ # datastore = Google::Cloud::Datastore.new
478
+ #
479
+ # query = datastore.query("Task")
480
+ # results = datastore.run query, explain_options: { analyze: true }
481
+ #
482
+ # # The explain_metrics are available on the results object only after
483
+ # # all results have been retrieved. You must iterate through all
484
+ # # pages of results to get the metrics.
485
+ # all_tasks = []
486
+ # loop do
487
+ # results.each { |task| all_tasks << task }
488
+ # break unless results.next?
489
+ # results = results.next
490
+ # end
491
+ #
492
+ # # The `results` object now holds the last page of results,
493
+ # # and contains the explain_metrics.
494
+ # if results.explain_metrics
495
+ # stats = results.explain_metrics.execution_stats
496
+ # puts "Results returned: #{stats.results_returned}"
497
+ # puts "Read operations: #{stats.read_operations}"
498
+ # end
499
+ #
500
+ # @example Run the query with explain options using a `Google::Cloud::Datastore::V1::ExplainOptions` object.
501
+ # require "google/cloud/datastore"
502
+ #
503
+ # datastore = Google::Cloud::Datastore.new
504
+ #
505
+ # query = datastore.query("Task")
506
+ # explain_options = Google::Cloud::Datastore::V1::ExplainOptions.new
507
+ # results = datastore.run query, explain_options: explain_options
508
+ #
509
+ # # You must iterate through all pages of results to get the metrics.
510
+ # loop do
511
+ # break unless results.next?
512
+ # results = results.next
513
+ # end
514
+ #
515
+ # if results.explain_metrics
516
+ # stats = results.explain_metrics.execution_stats
517
+ # puts "Read operations: #{stats.read_operations}"
518
+ # end
519
+ #
520
+ def run query, namespace: nil, consistency: nil, read_time: nil, explain_options: nil
471
521
  ensure_service!
472
522
  unless query.is_a?(Query) || query.is_a?(GqlQuery)
473
523
  raise ArgumentError, "Cannot run a #{query.class} object."
474
524
  end
475
525
  check_consistency! consistency
526
+
476
527
  query_res = service.run_query query.to_grpc, namespace,
477
- consistency: consistency, read_time: read_time
528
+ consistency: consistency, read_time: read_time,
529
+ explain_options: explain_options
530
+
478
531
  QueryResults.from_grpc query_res, service, namespace,
479
- query.to_grpc.dup, read_time
532
+ query.to_grpc.dup, read_time, explain_options
480
533
  end
481
534
  alias run_query run
482
535
 
@@ -496,6 +549,10 @@ module Google
496
549
  # [Eventual Consistency in Google Cloud
497
550
  # Datastore](https://cloud.google.com/datastore/docs/articles/balancing-strong-and-eventual-consistency-with-google-cloud-datastore/#h.tf76fya5nqk8)
498
551
  # for more information.
552
+ # @param [Hash, Google::Cloud::Datastore::V1::ExplainOptions] explain_options The options for query explanation.
553
+ # Provide this argument to enable explain metrics. If this argument is left unset,
554
+ # the results will not include explain metrics.
555
+ # See {Google::Cloud::Datastore::V1::ExplainOptions} for details. Optional.
499
556
  #
500
557
  # @return [Google::Cloud::Datastore::Dataset::AggregateQueryResults]
501
558
  #
@@ -554,15 +611,32 @@ module Google
554
611
  # done: false
555
612
  # res = datastore.run_aggregation gql_query, namespace: "example-ns"
556
613
  #
557
- def run_aggregation aggregate_query, namespace: nil, consistency: nil, read_time: nil
614
+ # @example Run the aggregate query with explain options to get query plan and execution statistics.
615
+ # require "google/cloud/datastore"
616
+ #
617
+ # datastore = Google::Cloud::Datastore.new
618
+ #
619
+ # query = datastore.query("Task")
620
+ # aggregate_query = query.aggregate_query.add_count aggregate_alias: "total"
621
+ # results = datastore.run_aggregation aggregate_query, explain_options: { analyze: true }
622
+ #
623
+ # if results.explain_metrics
624
+ # stats = results.explain_metrics.execution_stats
625
+ # puts "Read operations: #{stats.read_operations}"
626
+ # end
627
+ #
628
+ def run_aggregation aggregate_query, namespace: nil, consistency: nil, read_time: nil, explain_options: nil
558
629
  ensure_service!
559
630
  unless aggregate_query.is_a?(AggregateQuery) || aggregate_query.is_a?(GqlQuery)
560
631
  raise ArgumentError, "Cannot run a #{aggregate_query.class} object."
561
632
  end
562
633
  check_consistency! consistency
563
634
  aggregate_query_res = service.run_aggregation_query aggregate_query.to_grpc, namespace,
564
- consistency: consistency, read_time: read_time
565
- AggregateQueryResults.from_grpc aggregate_query_res
635
+ consistency: consistency,
636
+ read_time: read_time,
637
+ explain_options: explain_options
638
+
639
+ AggregateQueryResults.from_grpc aggregate_query_res, explain_options
566
640
  end
567
641
 
568
642
  ##
@@ -138,8 +138,11 @@ module Google
138
138
  # Retrieve entities specified by a Query. The query is run within the
139
139
  # transaction.
140
140
  #
141
- # @param [Query] query The Query object with the search criteria.
141
+ # @param [Query, GqlQuery] query The query with the search criteria.
142
142
  # @param [String] namespace The namespace the query is to run within.
143
+ # @param [Hash, Google::Cloud::Datastore::V1::ExplainOptions] explain_options
144
+ # The options for query explanation. See {Google::Cloud::Datastore::V1::ExplainOptions}
145
+ # for details. Optional.
143
146
  #
144
147
  # @return [Google::Cloud::Datastore::Dataset::QueryResults]
145
148
  #
@@ -154,15 +157,60 @@ module Google
154
157
  # tasks = tx.run query
155
158
  # end
156
159
  #
157
- def run query, namespace: nil
160
+ # @example Run the query with explain options:
161
+ # require "google/cloud/datastore"
162
+ #
163
+ # datastore = Google::Cloud::Datastore.new
164
+ #
165
+ # datastore.read_only_transaction do |tx|
166
+ # query = tx.query("Task")
167
+ # results = tx.run query, explain_options: { analyze: true }
168
+ #
169
+ # # You must iterate through all pages of results to get the metrics.
170
+ # loop do
171
+ # break unless results.next?
172
+ # results = results.next
173
+ # end
174
+ #
175
+ # if results.explain_metrics
176
+ # stats = results.explain_metrics.execution_stats
177
+ # puts "Read operations: #{stats.read_operations}"
178
+ # end
179
+ # end
180
+ #
181
+ # @example Run the query with explain options using a `Google::Cloud::Datastore::V1::ExplainOptions` object.
182
+ # require "google/cloud/datastore"
183
+ #
184
+ # datastore = Google::Cloud::Datastore.new
185
+ #
186
+ # datastore.read_only_transaction do |tx|
187
+ # query = tx.query("Task")
188
+ # explain_options = Google::Cloud::Datastore::V1::ExplainOptions.new
189
+ # results = tx.run query, explain_options: explain_options
190
+ #
191
+ # # You must iterate through all pages of results to get the metrics.
192
+ # loop do
193
+ # break unless results.next?
194
+ # results = results.next
195
+ # end
196
+ #
197
+ # if results.explain_metrics
198
+ # stats = results.explain_metrics.execution_stats
199
+ # puts "Read operations: #{stats.read_operations}"
200
+ # end
201
+ # end
202
+ #
203
+ def run query, namespace: nil, explain_options: nil
158
204
  ensure_service!
159
205
  unless query.is_a?(Query) || query.is_a?(GqlQuery)
160
206
  raise ArgumentError, "Cannot run a #{query.class} object."
161
207
  end
162
208
  query_res = service.run_query query.to_grpc, namespace,
209
+ explain_options: explain_options,
163
210
  transaction: @id
211
+
164
212
  Dataset::QueryResults.from_grpc query_res, service, namespace,
165
- query.to_grpc.dup
213
+ query.to_grpc.dup, nil, explain_options
166
214
  end
167
215
  alias run_query run
168
216
 
@@ -188,14 +236,34 @@ module Google
188
236
  # .add_count
189
237
  # res = tx.run_aggregation aggregate_query
190
238
  # end
239
+ # @example Run the aggregate query with explain options:
240
+ # require "google/cloud/datastore"
191
241
  #
192
- def run_aggregation aggregate_query, namespace: nil
242
+ # datastore = Google::Cloud::Datastore.new
243
+ #
244
+ # datastore.read_only_transaction do |tx|
245
+ # query = tx.query("Task")
246
+ # aggregate_query = query.aggregate_query.add_count aggregate_alias: "total"
247
+ # results = tx.run_aggregation aggregate_query, explain_options: { analyze: true }
248
+ #
249
+ # if results.explain_metrics
250
+ # stats = results.explain_metrics.execution_stats
251
+ # puts "Read operations: #{stats.read_operations}"
252
+ # end
253
+ # end
254
+ #
255
+ def run_aggregation aggregate_query, namespace: nil, explain_options: nil
193
256
  ensure_service!
194
257
  unless aggregate_query.is_a?(AggregateQuery) || aggregate_query.is_a?(GqlQuery)
195
258
  raise ArgumentError, "Cannot run a #{aggregate_query.class} object."
196
259
  end
197
- aggregate_query_results = service.run_aggregation_query aggregate_query.to_grpc, namespace, transaction: @id
198
- Dataset::AggregateQueryResults.from_grpc aggregate_query_results
260
+
261
+ aggregate_query_results = service.run_aggregation_query aggregate_query.to_grpc,
262
+ namespace,
263
+ transaction: @id,
264
+ explain_options: explain_options
265
+
266
+ Dataset::AggregateQueryResults.from_grpc aggregate_query_results, explain_options
199
267
  end
200
268
 
201
269
  ##
@@ -70,7 +70,12 @@ module Google
70
70
  end
71
71
 
72
72
  # Query for entities.
73
- def run_query query, namespace = nil, consistency: nil, transaction: nil, read_time: nil
73
+ def run_query query, namespace = nil, consistency: nil, transaction: nil, read_time: nil, explain_options: nil
74
+ if explain_options
75
+ explain_options = ::Gapic::Protobuf.coerce(explain_options,
76
+ to: ::Google::Cloud::Datastore::V1::ExplainOptions)
77
+ end
78
+
74
79
  gql_query = nil
75
80
  if query.is_a? Google::Cloud::Datastore::V1::GqlQuery
76
81
  gql_query = query
@@ -88,11 +93,20 @@ module Google
88
93
  partition_id: partition_id,
89
94
  read_options: read_options,
90
95
  query: query,
91
- gql_query: gql_query
96
+ gql_query: gql_query,
97
+ explain_options: explain_options
92
98
  end
93
99
 
94
100
  ## Query for aggregates
95
- def run_aggregation_query query, namespace = nil, consistency: nil, transaction: nil, read_time: nil
101
+ def run_aggregation_query query, namespace = nil, consistency: nil, transaction: nil, read_time: nil,
102
+ explain_options: nil
103
+ if explain_options
104
+ explain_options = ::Gapic::Protobuf.coerce(
105
+ explain_options,
106
+ to: ::Google::Cloud::Datastore::V1::ExplainOptions
107
+ )
108
+ end
109
+
96
110
  gql_query = nil
97
111
  if query.is_a? Google::Cloud::Datastore::V1::GqlQuery
98
112
  gql_query = query
@@ -109,7 +123,8 @@ module Google
109
123
  partition_id: partition_id,
110
124
  read_options: read_options,
111
125
  aggregation_query: query,
112
- gql_query: gql_query
126
+ gql_query: gql_query,
127
+ explain_options: explain_options
113
128
  end
114
129
 
115
130
  ##
@@ -174,6 +189,17 @@ module Google
174
189
  nil
175
190
  end
176
191
 
192
+ ##
193
+ # @private Converts a time-like object to a Google::Protobuf::Timestamp.
194
+ #
195
+ # Any object that responds to `#to_time` is a valid input.
196
+ #
197
+ # @param time [Time, DateTime, Google::Protobuf::Timestamp, nil] The
198
+ # time object to convert. If `nil`, `nil` will be returned.
199
+ #
200
+ # @return [Google::Protobuf::Timestamp, nil] The converted Protobuf timestamp,
201
+ # or `nil` if the input was `nil`.
202
+ #
177
203
  def read_time_to_timestamp time
178
204
  return nil if time.nil?
179
205
 
@@ -225,8 +225,11 @@ module Google
225
225
  # Retrieve entities specified by a Query. The query is run within the
226
226
  # transaction.
227
227
  #
228
- # @param [Query] query The Query object with the search criteria.
228
+ # @param [Query, GqlQuery] query The query with the search criteria.
229
229
  # @param [String] namespace The namespace the query is to run within.
230
+ # @param [Hash, Google::Cloud::Datastore::V1::ExplainOptions] explain_options
231
+ # The options for query explanation. See {Google::Cloud::Datastore::V1::ExplainOptions}
232
+ # for details. Optional.
230
233
  #
231
234
  # @return [Google::Cloud::Datastore::Dataset::QueryResults]
232
235
  #
@@ -251,18 +254,115 @@ module Google
251
254
  # tasks = tx.run query, namespace: "example-ns"
252
255
  # end
253
256
  #
254
- def run query, namespace: nil
257
+ # @example Run the query with explain options:
258
+ # require "google/cloud/datastore"
259
+ #
260
+ # datastore = Google::Cloud::Datastore.new
261
+ #
262
+ # datastore.transaction do |tx|
263
+ # query = datastore.query("Task")
264
+ # results = tx.run query, explain_options: { analyze: true }
265
+ #
266
+ # # You must iterate through all pages of results to get the metrics.
267
+ # loop do
268
+ # break unless results.next?
269
+ # results = results.next
270
+ # end
271
+ #
272
+ # if results.explain_metrics
273
+ # stats = results.explain_metrics.execution_stats
274
+ # puts "Read operations: #{stats.read_operations}"
275
+ # end
276
+ # end
277
+ #
278
+ # @example Run the query with explain options using a `Google::Cloud::Datastore::V1::ExplainOptions` object.
279
+ # require "google/cloud/datastore"
280
+ #
281
+ # datastore = Google::Cloud::Datastore.new
282
+ #
283
+ # datastore.transaction do |tx|
284
+ # query = datastore.query("Task")
285
+ # explain_options = Google::Cloud::Datastore::V1::ExplainOptions.new
286
+ # results = tx.run query, explain_options: explain_options
287
+ #
288
+ # # You must iterate through all pages of results to get the metrics.
289
+ # loop do
290
+ # break unless results.next?
291
+ # results = results.next
292
+ # end
293
+ #
294
+ # if results.explain_metrics
295
+ # stats = results.explain_metrics.execution_stats
296
+ # puts "Read operations: #{stats.read_operations}"
297
+ # end
298
+ # end
299
+ #
300
+ def run query, namespace: nil, explain_options: nil
255
301
  ensure_service!
256
302
  unless query.is_a?(Query) || query.is_a?(GqlQuery)
257
303
  raise ArgumentError, "Cannot run a #{query.class} object."
258
304
  end
259
305
  query_res = service.run_query query.to_grpc, namespace,
306
+ explain_options: explain_options,
260
307
  transaction: @id
261
308
  QueryResults.from_grpc query_res, service, namespace,
262
- query.to_grpc.dup
309
+ query.to_grpc.dup, nil, explain_options
263
310
  end
264
311
  alias run_query run
265
312
 
313
+ ##
314
+ # Retrieve aggregate query results specified by an AggregateQuery. The query is run within the
315
+ # transaction.
316
+ #
317
+ # @param [AggregateQuery, GqlQuery] aggregate_query The Query object
318
+ # with the search criteria.
319
+ # @param [String] namespace The namespace the query is to run within.
320
+ # @param [Hash, Google::Cloud::Datastore::V1::ExplainOptions] explain_options
321
+ # The options for query explanation. See {Google::Cloud::Datastore::V1::ExplainOptions}
322
+ # for details. Optional.
323
+ #
324
+ # @return [Google::Cloud::Datastore::Dataset::AggregateQueryResults]
325
+ #
326
+ # @example
327
+ # require "google/cloud/datastore"
328
+ #
329
+ # datastore = Google::Cloud::Datastore.new
330
+ #
331
+ # datastore.transaction do |tx|
332
+ # query = tx.query("Task")
333
+ # .where("done", "=", false)
334
+ # aggregate_query = query.aggregate_query
335
+ # .add_count
336
+ # res = tx.run_aggregation aggregate_query
337
+ # end
338
+ #
339
+ # @example Run the aggregate query with explain options:
340
+ # require "google/cloud/datastore"
341
+ #
342
+ # datastore = Google::Cloud::Datastore.new
343
+ #
344
+ # datastore.transaction do |tx|
345
+ # query = tx.query("Task")
346
+ # aggregate_query = query.aggregate_query.add_count aggregate_alias: "total"
347
+ # results = tx.run_aggregation aggregate_query, explain_options: { analyze: true }
348
+ #
349
+ # if results.explain_metrics
350
+ # stats = results.explain_metrics.execution_stats
351
+ # puts "Read operations: #{stats.read_operations}"
352
+ # end
353
+ # end
354
+ #
355
+ def run_aggregation aggregate_query, namespace: nil, explain_options: nil
356
+ ensure_service!
357
+ unless aggregate_query.is_a?(AggregateQuery) || aggregate_query.is_a?(GqlQuery)
358
+ raise ArgumentError, "Cannot run a #{aggregate_query.class} object."
359
+ end
360
+ aggregate_query_results = service.run_aggregation_query aggregate_query.to_grpc, namespace,
361
+ transaction: @id,
362
+ explain_options: explain_options
363
+ Dataset::AggregateQueryResults.from_grpc aggregate_query_results, explain_options
364
+ end
365
+
266
366
  ##
267
367
  # Begins a transaction.
268
368
  # This method is run when a new Transaction is created.
@@ -16,7 +16,7 @@
16
16
  module Google
17
17
  module Cloud
18
18
  module Datastore
19
- VERSION = "2.11.0".freeze
19
+ VERSION = "2.13.0".freeze
20
20
  end
21
21
  end
22
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-cloud-datastore
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.11.0
4
+ version: 2.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Moore
8
8
  - Chris Smith
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-04 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: google-cloud-core
@@ -102,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  requirements: []
105
- rubygems_version: 3.6.5
105
+ rubygems_version: 3.6.9
106
106
  specification_version: 4
107
107
  summary: API Client library for Google Cloud Datastore
108
108
  test_files: []