google-cloud-firestore 2.7.2 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/LOGGING.md +1 -1
- data/lib/google/cloud/firestore/aggregate_query.rb +202 -0
- data/lib/google/cloud/firestore/aggregate_query_snapshot.rb +85 -0
- data/lib/google/cloud/firestore/client.rb +79 -9
- data/lib/google/cloud/firestore/collection_group.rb +20 -4
- data/lib/google/cloud/firestore/collection_reference.rb +17 -2
- data/lib/google/cloud/firestore/collection_reference_list.rb +4 -3
- data/lib/google/cloud/firestore/convert.rb +0 -1
- data/lib/google/cloud/firestore/document_reference/list.rb +5 -3
- data/lib/google/cloud/firestore/document_reference.rb +20 -3
- data/lib/google/cloud/firestore/query.rb +44 -3
- data/lib/google/cloud/firestore/service.rb +49 -15
- data/lib/google/cloud/firestore/transaction.rb +51 -4
- data/lib/google/cloud/firestore/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5c050184924a624eb5f83c42f528334296cc01392d5a9b1d891d81c2b7f4e50
|
4
|
+
data.tar.gz: '085ffdcff90414ab769e585164e331a4d27b1edcfed7341d6c09998aca4a58c6'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5b99c1fa86740df4973731ecf715158cfbb8025fc46833f7b78cf9102d78245106133aed9e92311d5ae0879289054bbc7c832396792141e0df09abc7e6d7357
|
7
|
+
data.tar.gz: 9ccefface707ebaf31f3c8e7a998e7ae7f95713a9ec71df4e691d3be3997eadc528f95dfaf5de8bce00162a2c69856b704b198fd4ccea0376f4804451f1f4c77
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# Release History
|
2
2
|
|
3
|
+
### 2.9.0 (2023-01-26)
|
4
|
+
|
5
|
+
#### Features
|
6
|
+
|
7
|
+
* Added support for read time ([#19851](https://github.com/googleapis/google-cloud-ruby/issues/19851))
|
8
|
+
|
9
|
+
### 2.8.0 (2023-01-05)
|
10
|
+
|
11
|
+
#### Features
|
12
|
+
|
13
|
+
* Support query count for Firestore ([#19457](https://github.com/googleapis/google-cloud-ruby/issues/19457))
|
14
|
+
#### Bug Fixes
|
15
|
+
|
16
|
+
* Add support for merging null field in a document ([#19918](https://github.com/googleapis/google-cloud-ruby/issues/19918))
|
17
|
+
|
3
18
|
### 2.7.2 (2022-08-24)
|
4
19
|
|
5
20
|
#### Documentation
|
data/LOGGING.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
To enable logging for this library, set the logger for the underlying
|
4
4
|
[gRPC](https://github.com/grpc/grpc/tree/master/src/ruby) library. The logger
|
5
5
|
that you set may be a Ruby stdlib
|
6
|
-
[`Logger`](https://ruby-doc.org/
|
6
|
+
[`Logger`](https://ruby-doc.org/current/stdlibs/logger/Logger.html) as
|
7
7
|
shown below, or a
|
8
8
|
[`Google::Cloud::Logging::Logger`](https://googleapis.dev/ruby/google-cloud-logging/latest)
|
9
9
|
that will write logs to [Stackdriver
|
@@ -0,0 +1,202 @@
|
|
1
|
+
# Copyright 2022 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/firestore/v1"
|
16
|
+
require "google/cloud/firestore/aggregate_query_snapshot"
|
17
|
+
|
18
|
+
module Google
|
19
|
+
module Cloud
|
20
|
+
module Firestore
|
21
|
+
##
|
22
|
+
# # AggregateQuery
|
23
|
+
#
|
24
|
+
# An aggregate query can be used to fetch aggregate values (ex: count) for a query
|
25
|
+
#
|
26
|
+
# Instances of this class are immutable. All methods that refine the aggregate query
|
27
|
+
# return new instances.
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# require "google/cloud/firestore"
|
31
|
+
#
|
32
|
+
# firestore = Google::Cloud::Firestore.new
|
33
|
+
#
|
34
|
+
# query = firestore.col "cities"
|
35
|
+
#
|
36
|
+
# # Create an aggregate query
|
37
|
+
# aggregate_query = query.aggregate_query
|
38
|
+
# .add_count
|
39
|
+
#
|
40
|
+
# aggregate_query.get do |aggregate_snapshot|
|
41
|
+
# puts aggregate_snapshot.get('count')
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# @example Alias an aggregate query
|
45
|
+
# require "google/cloud/firestore"
|
46
|
+
#
|
47
|
+
# firestore = Google::Cloud::Firestore.new
|
48
|
+
#
|
49
|
+
# # Create a query
|
50
|
+
# query = firestore.col "cities"
|
51
|
+
#
|
52
|
+
# # Create an aggregate query
|
53
|
+
# aggregate_query = query.aggregate_query
|
54
|
+
# .add_count aggregate_alias: 'total_cities'
|
55
|
+
#
|
56
|
+
# aggregate_query.get do |aggregate_snapshot|
|
57
|
+
# puts aggregate_snapshot.get('total_cities')
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
class AggregateQuery
|
61
|
+
##
|
62
|
+
# @private The firestore client object.
|
63
|
+
attr_accessor :client
|
64
|
+
|
65
|
+
##
|
66
|
+
# @private The type for limit queries.
|
67
|
+
attr_reader :parent_path
|
68
|
+
|
69
|
+
##
|
70
|
+
# @private The Google::Cloud::Firestore::V1::StructuredQuery object.
|
71
|
+
attr_reader :query
|
72
|
+
|
73
|
+
##
|
74
|
+
# @private Array of Google::Cloud::Firestore::V1::StructuredAggregationQuery::Aggregation objects
|
75
|
+
attr_reader :aggregates
|
76
|
+
|
77
|
+
##
|
78
|
+
# @private Creates a new AggregateQuery
|
79
|
+
def initialize query, parent_path, client, aggregates: []
|
80
|
+
@query = query
|
81
|
+
@parent_path = parent_path
|
82
|
+
@aggregates = aggregates
|
83
|
+
@client = client
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# Adds a count aggregate.
|
88
|
+
#
|
89
|
+
# @param [aggregate_alias] Alias to refer to the aggregate. Optional
|
90
|
+
#
|
91
|
+
# @return [AggregateQuery] A new aggregate query with the added count aggregate.
|
92
|
+
#
|
93
|
+
# @example
|
94
|
+
# require "google/cloud/firestore"
|
95
|
+
#
|
96
|
+
# firestore = Google::Cloud::Firestore.new
|
97
|
+
#
|
98
|
+
# query = firestore.col "cities"
|
99
|
+
#
|
100
|
+
# # Create an aggregate query
|
101
|
+
# aggregate_query = query.aggregate_query
|
102
|
+
# .add_count
|
103
|
+
#
|
104
|
+
# aggregate_query.get do |aggregate_snapshot|
|
105
|
+
# puts aggregate_snapshot.get('count')
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
def add_count aggregate_alias: nil
|
109
|
+
aggregate_alias ||= ALIASES[:count]
|
110
|
+
new_aggregates = @aggregates.dup
|
111
|
+
new_aggregates << StructuredAggregationQuery::Aggregation.new(
|
112
|
+
count: StructuredAggregationQuery::Aggregation::Count.new,
|
113
|
+
alias: aggregate_alias
|
114
|
+
)
|
115
|
+
AggregateQuery.start query, new_aggregates, parent_path, client
|
116
|
+
end
|
117
|
+
|
118
|
+
##
|
119
|
+
# Retrieves aggregate snapshot for the query.
|
120
|
+
#
|
121
|
+
# @yield [snapshot] The block for accessing the aggregate query snapshots.
|
122
|
+
# @yieldparam [AggregateQuerySnapshot] An aggregate query snapshot.
|
123
|
+
#
|
124
|
+
# @return [Enumerator<AggregateQuerySnapshot>] A list of aggregate query snapshots.
|
125
|
+
#
|
126
|
+
# @example
|
127
|
+
# require "google/cloud/firestore"
|
128
|
+
#
|
129
|
+
# firestore = Google::Cloud::Firestore.new
|
130
|
+
#
|
131
|
+
# query = firestore.col "cities"
|
132
|
+
#
|
133
|
+
# # Create an aggregate query
|
134
|
+
# aggregate_query = query.aggregate_query
|
135
|
+
# .add_count
|
136
|
+
#
|
137
|
+
# aggregate_query.get do |aggregate_snapshot|
|
138
|
+
# puts aggregate_snapshot.get('count')
|
139
|
+
# end
|
140
|
+
#
|
141
|
+
def get
|
142
|
+
ensure_service!
|
143
|
+
|
144
|
+
return enum_for :get unless block_given?
|
145
|
+
|
146
|
+
responses = service.run_aggregate_query @parent_path, structured_aggregation_query
|
147
|
+
responses.each do |response|
|
148
|
+
next if response.result.nil?
|
149
|
+
yield AggregateQuerySnapshot.from_run_aggregate_query_response response
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# @private Creates a Google::Cloud::Firestore::V1::StructuredAggregationQuery object
|
155
|
+
def structured_aggregation_query
|
156
|
+
StructuredAggregationQuery.new(
|
157
|
+
structured_query: @query,
|
158
|
+
aggregations: @aggregates
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
##
|
163
|
+
# @private Start a new AggregateQuery.
|
164
|
+
def self.start query, aggregates, parent_path, client
|
165
|
+
new query, parent_path, client, aggregates: aggregates
|
166
|
+
end
|
167
|
+
|
168
|
+
protected
|
169
|
+
|
170
|
+
##
|
171
|
+
# @private
|
172
|
+
StructuredAggregationQuery = Google::Cloud::Firestore::V1::StructuredAggregationQuery
|
173
|
+
|
174
|
+
##
|
175
|
+
# @private
|
176
|
+
ALIASES = {
|
177
|
+
count: "count"
|
178
|
+
}.freeze
|
179
|
+
|
180
|
+
##
|
181
|
+
# @private Raise an error unless a database is available.
|
182
|
+
def ensure_client!
|
183
|
+
raise "Must have active connection to service" unless client
|
184
|
+
end
|
185
|
+
|
186
|
+
##
|
187
|
+
# @private Raise an error unless an active connection to the service
|
188
|
+
# is available.
|
189
|
+
def ensure_service!
|
190
|
+
raise "Must have active connection to service" unless service
|
191
|
+
end
|
192
|
+
|
193
|
+
##
|
194
|
+
# @private The Service object.
|
195
|
+
def service
|
196
|
+
ensure_client!
|
197
|
+
client.service
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# Copyright 2022 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
|
+
|
16
|
+
module Google
|
17
|
+
module Cloud
|
18
|
+
module Firestore
|
19
|
+
##
|
20
|
+
# # AggregateQuerySnapshot
|
21
|
+
#
|
22
|
+
# An aggregate query snapshot object is an immutable representation for
|
23
|
+
# an aggregate query result.
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# require "google/cloud/firestore"
|
27
|
+
#
|
28
|
+
# firestore = Google::Cloud::Firestore.new
|
29
|
+
#
|
30
|
+
# query = firestore.col "cities"
|
31
|
+
#
|
32
|
+
# # Create an aggregate query
|
33
|
+
# aggregate_query = query.aggregate_query
|
34
|
+
# .add_count
|
35
|
+
#
|
36
|
+
# aggregate_query.get do |aggregate_snapshot|
|
37
|
+
# puts aggregate_snapshot.get('count')
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
class AggregateQuerySnapshot
|
41
|
+
##
|
42
|
+
# Retrieves the aggregate data.
|
43
|
+
#
|
44
|
+
# @param [String] aggregate_alias The alias used
|
45
|
+
# to access the aggregate value. For count, the
|
46
|
+
# default value is "count".
|
47
|
+
#
|
48
|
+
# @return [Integer] The aggregate value.
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# require "google/cloud/firestore"
|
52
|
+
#
|
53
|
+
# firestore = Google::Cloud::Firestore.new
|
54
|
+
#
|
55
|
+
# query = firestore.col "cities"
|
56
|
+
#
|
57
|
+
# # Create an aggregate query
|
58
|
+
# aggregate_query = query.aggregate_query
|
59
|
+
# .add_count
|
60
|
+
#
|
61
|
+
# aggregate_query.get do |aggregate_snapshot|
|
62
|
+
# puts aggregate_snapshot.get('count')
|
63
|
+
# end
|
64
|
+
def get aggregate_alias
|
65
|
+
@aggregate_fields[aggregate_alias]
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# @private New AggregateQuerySnapshot from a
|
70
|
+
# Google::Cloud::Firestore::V1::RunAggregationQueryResponse object.
|
71
|
+
def self.from_run_aggregate_query_response response
|
72
|
+
aggregate_fields = response
|
73
|
+
.result
|
74
|
+
.aggregate_fields
|
75
|
+
.to_h # convert from protobuf to ruby map
|
76
|
+
.transform_values { |v| v[:integer_value] }
|
77
|
+
|
78
|
+
new.tap do |s|
|
79
|
+
s.instance_variable_set :@aggregate_fields, aggregate_fields
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -85,6 +85,9 @@ module Google
|
|
85
85
|
##
|
86
86
|
# Retrieves an enumerator for the root collections.
|
87
87
|
#
|
88
|
+
# @param [Time] read_time Reads documents as they were at the given time.
|
89
|
+
# This may not be older than 270 seconds. Optional
|
90
|
+
#
|
88
91
|
# @yield [collections] The block for accessing the collections.
|
89
92
|
# @yieldparam [CollectionReference] collection A collection reference object.
|
90
93
|
#
|
@@ -101,10 +104,21 @@ module Google
|
|
101
104
|
# puts col.collection_id
|
102
105
|
# end
|
103
106
|
#
|
104
|
-
|
107
|
+
# @example
|
108
|
+
# require "google/cloud/firestore"
|
109
|
+
#
|
110
|
+
# firestore = Google::Cloud::Firestore.new
|
111
|
+
# read_time = Time.now
|
112
|
+
#
|
113
|
+
# # Get the root collections
|
114
|
+
# firestore.cols(read_time: read_time).each do |col|
|
115
|
+
# puts col.collection_id
|
116
|
+
# end
|
117
|
+
#
|
118
|
+
def cols read_time: nil, &block
|
105
119
|
ensure_service!
|
106
|
-
grpc = service.list_collections "#{path}/documents"
|
107
|
-
cols_enum = CollectionReferenceList.from_grpc(grpc, self, "#{path}/documents").all
|
120
|
+
grpc = service.list_collections "#{path}/documents", read_time: read_time
|
121
|
+
cols_enum = CollectionReferenceList.from_grpc(grpc, self, "#{path}/documents", read_time: read_time).all
|
108
122
|
cols_enum.each(&block) if block_given?
|
109
123
|
cols_enum
|
110
124
|
end
|
@@ -217,6 +231,8 @@ module Google
|
|
217
231
|
# individual fields joined by ".". Fields containing `~`, `*`, `/`,
|
218
232
|
# `[`, `]`, and `.` cannot be in a dotted string, and should provided
|
219
233
|
# using a {FieldPath} object instead. (See {#field_path}.)
|
234
|
+
# @param [Time] read_time Reads documents as they were at the given time.
|
235
|
+
# This may not be older than 270 seconds. Optional
|
220
236
|
#
|
221
237
|
# @yield [documents] The block for accessing the document snapshots.
|
222
238
|
# @yieldparam [DocumentSnapshot] document A document snapshot.
|
@@ -245,11 +261,24 @@ module Google
|
|
245
261
|
# puts "#{city.document_id} has #{city[:population]} residents."
|
246
262
|
# end
|
247
263
|
#
|
248
|
-
|
264
|
+
# @example Get docs using a read_time:
|
265
|
+
# require "google/cloud/firestore"
|
266
|
+
#
|
267
|
+
# firestore = Google::Cloud::Firestore.new
|
268
|
+
#
|
269
|
+
# read_time = Time.now
|
270
|
+
#
|
271
|
+
# # Get and print city documents
|
272
|
+
# cities = ["cities/NYC", "cities/SF", "cities/LA"]
|
273
|
+
# firestore.get_all(cities, read_time: read_time).each do |city|
|
274
|
+
# puts "#{city.document_id} has #{city[:population]} residents."
|
275
|
+
# end
|
276
|
+
#
|
277
|
+
def get_all *docs, field_mask: nil, read_time: nil
|
249
278
|
ensure_service!
|
250
279
|
|
251
280
|
unless block_given?
|
252
|
-
return enum_for :get_all, *docs, field_mask: field_mask
|
281
|
+
return enum_for :get_all, *docs, field_mask: field_mask, read_time: read_time
|
253
282
|
end
|
254
283
|
|
255
284
|
doc_paths = Array(docs).flatten.map do |doc_path|
|
@@ -264,7 +293,7 @@ module Google
|
|
264
293
|
end
|
265
294
|
mask = nil if mask.empty?
|
266
295
|
|
267
|
-
results = service.get_documents doc_paths, mask: mask
|
296
|
+
results = service.get_documents doc_paths, mask: mask, read_time: read_time
|
268
297
|
results.each do |result|
|
269
298
|
next if result.result.nil?
|
270
299
|
yield DocumentSnapshot.from_batch_result result, self
|
@@ -668,13 +697,54 @@ module Google
|
|
668
697
|
end
|
669
698
|
end
|
670
699
|
|
700
|
+
##
|
701
|
+
# Create a transaction to perform multiple reads that are
|
702
|
+
# executed atomically at a single logical point in time in a database.
|
703
|
+
#
|
704
|
+
# All changes are accumulated in memory until the block completes.
|
705
|
+
# Transactions will be automatically retried when documents change
|
706
|
+
# before the transaction is committed. See {Transaction}.
|
707
|
+
#
|
708
|
+
# @see https://firebase.google.com/docs/firestore/manage-data/transactions
|
709
|
+
# Transactions and Batched Writes
|
710
|
+
#
|
711
|
+
# @param [Time] read_time The maximum number of retries for
|
712
|
+
# transactions failed due to errors. Default is 5. Optional.
|
713
|
+
#
|
714
|
+
# @yield [transaction] The block for reading data.
|
715
|
+
# @yieldparam [Transaction] transaction The transaction object for
|
716
|
+
# making changes.
|
717
|
+
#
|
718
|
+
# @return [Object] The return value of the provided
|
719
|
+
# yield block
|
720
|
+
#
|
721
|
+
# @example Read only transaction with read time
|
722
|
+
# require "google/cloud/firestore"
|
723
|
+
#
|
724
|
+
# firestore = Google::Cloud::Firestore.new
|
725
|
+
#
|
726
|
+
# # Get a document reference
|
727
|
+
# nyc_ref = firestore.doc "cities/NYC"
|
728
|
+
#
|
729
|
+
# read_time = Time.now
|
730
|
+
#
|
731
|
+
# firestore.read_only_transaction(read_time: read_time) do |tx|
|
732
|
+
# # Get a document snapshot
|
733
|
+
# nyc_snap = tx.get nyc_ref
|
734
|
+
# end
|
735
|
+
#
|
736
|
+
def read_only_transaction read_time: nil
|
737
|
+
transaction = Transaction.from_client self, read_time: read_time, read_only: true
|
738
|
+
yield transaction
|
739
|
+
end
|
740
|
+
|
671
741
|
# @!endgroup
|
672
742
|
|
673
743
|
# @private
|
674
|
-
def list_documents parent, collection_id, token: nil, max: nil
|
744
|
+
def list_documents parent, collection_id, token: nil, max: nil, read_time: nil
|
675
745
|
ensure_service!
|
676
|
-
grpc = service.list_documents parent, collection_id, token: token, max: max
|
677
|
-
DocumentReference::List.from_grpc grpc, self, parent, collection_id
|
746
|
+
grpc = service.list_documents parent, collection_id, token: token, max: max, read_time: read_time
|
747
|
+
DocumentReference::List.from_grpc grpc, self, parent, collection_id, read_time: read_time
|
678
748
|
end
|
679
749
|
|
680
750
|
protected
|
@@ -48,6 +48,8 @@ module Google
|
|
48
48
|
#
|
49
49
|
# @param [Integer] partition_count The desired maximum number of partition points. The number must be strictly
|
50
50
|
# positive. The actual number of partitions returned may be fewer.
|
51
|
+
# @param [Time] read_time Reads documents as they were at the given time.
|
52
|
+
# This may not be older than 270 seconds. Optional
|
51
53
|
#
|
52
54
|
# @return [Array<QueryPartition>] An ordered array of query partitions.
|
53
55
|
#
|
@@ -62,7 +64,20 @@ module Google
|
|
62
64
|
#
|
63
65
|
# queries = partitions.map(&:to_query)
|
64
66
|
#
|
65
|
-
|
67
|
+
# @example partition with read time
|
68
|
+
# require "google/cloud/firestore"
|
69
|
+
#
|
70
|
+
# firestore = Google::Cloud::Firestore.new
|
71
|
+
#
|
72
|
+
# col_group = firestore.col_group "cities"
|
73
|
+
#
|
74
|
+
# read_time = Time.now
|
75
|
+
#
|
76
|
+
# partitions = col_group.partitions 3, read_time: read_time
|
77
|
+
#
|
78
|
+
# queries = partitions.map(&:to_query)
|
79
|
+
#
|
80
|
+
def partitions partition_count, read_time: nil
|
66
81
|
ensure_service!
|
67
82
|
|
68
83
|
raise ArgumentError, "partition_count must be > 0" unless partition_count.positive?
|
@@ -75,7 +90,7 @@ module Google
|
|
75
90
|
|
76
91
|
grpc_partitions = if partition_count.positive?
|
77
92
|
# Retrieve all pages, since cursor order is not guaranteed and they must be sorted.
|
78
|
-
list_all partition_count, query_with_default_order
|
93
|
+
list_all partition_count, query_with_default_order, read_time
|
79
94
|
else
|
80
95
|
[] # Ensure that a single, empty QueryPartition is returned.
|
81
96
|
end
|
@@ -118,11 +133,12 @@ module Google
|
|
118
133
|
|
119
134
|
protected
|
120
135
|
|
121
|
-
def list_all partition_count, query_with_default_order
|
136
|
+
def list_all partition_count, query_with_default_order, read_time
|
122
137
|
grpc_partitions = []
|
123
138
|
token = nil
|
124
139
|
loop do
|
125
|
-
grpc = service.partition_query parent_path, query_with_default_order.query, partition_count,
|
140
|
+
grpc = service.partition_query parent_path, query_with_default_order.query, partition_count,
|
141
|
+
token: token, read_time: read_time
|
126
142
|
grpc_partitions += Array(grpc.partitions)
|
127
143
|
token = grpc.next_page_token
|
128
144
|
token = nil if token == ""
|
@@ -147,6 +147,8 @@ module Google
|
|
147
147
|
# @param [String] token A previously-returned page token representing
|
148
148
|
# part of the larger set of results to view.
|
149
149
|
# @param [Integer] max Maximum number of results to return.
|
150
|
+
# @param [Time] read_time Reads documents as they were at the given time.
|
151
|
+
# This may not be older than 270 seconds. Optional
|
150
152
|
#
|
151
153
|
# @return [Array<DocumentReference>] An array of document references.
|
152
154
|
#
|
@@ -161,10 +163,23 @@ module Google
|
|
161
163
|
# puts doc_ref.document_id
|
162
164
|
# end
|
163
165
|
#
|
164
|
-
|
166
|
+
# @example List documents with read time
|
167
|
+
# require "google/cloud/firestore"
|
168
|
+
#
|
169
|
+
# firestore = Google::Cloud::Firestore.new
|
170
|
+
#
|
171
|
+
# read_time = Time.now
|
172
|
+
#
|
173
|
+
# col = firestore.col "cities"
|
174
|
+
#
|
175
|
+
# col.list_documents(read_time: read_time).each do |doc_ref|
|
176
|
+
# puts doc_ref.document_id
|
177
|
+
# end
|
178
|
+
#
|
179
|
+
def list_documents token: nil, max: nil, read_time: nil
|
165
180
|
ensure_client!
|
166
181
|
client.list_documents \
|
167
|
-
parent_path, collection_id, token: token, max: max
|
182
|
+
parent_path, collection_id, token: token, max: max, read_time: read_time
|
168
183
|
end
|
169
184
|
|
170
185
|
##
|
@@ -52,8 +52,8 @@ module Google
|
|
52
52
|
def next
|
53
53
|
return nil unless next?
|
54
54
|
ensure_service!
|
55
|
-
grpc = @client.service.list_collections @parent, token: token, max: @max
|
56
|
-
self.class.from_grpc grpc, @client, @parent, max: @max
|
55
|
+
grpc = @client.service.list_collections @parent, token: token, max: @max, read_time: @read_time
|
56
|
+
self.class.from_grpc grpc, @client, @parent, max: @max, read_time: @read_time
|
57
57
|
end
|
58
58
|
|
59
59
|
##
|
@@ -110,7 +110,7 @@ module Google
|
|
110
110
|
##
|
111
111
|
# @private New CollectionReference::List from a `Google::Cloud::Firestore::V1::ListCollectionIdsResponse`
|
112
112
|
# object.
|
113
|
-
def self.from_grpc grpc, client, parent, max: nil
|
113
|
+
def self.from_grpc grpc, client, parent, max: nil, read_time: nil
|
114
114
|
raise ArgumentError, "parent is required" unless parent
|
115
115
|
cols = CollectionReferenceList.new(Array(grpc.collection_ids).map do |collection_id|
|
116
116
|
CollectionReference.from_path "#{parent}/#{collection_id}", client
|
@@ -121,6 +121,7 @@ module Google
|
|
121
121
|
cols.instance_variable_set :@client, client
|
122
122
|
cols.instance_variable_set :@parent, parent
|
123
123
|
cols.instance_variable_set :@max, max
|
124
|
+
cols.instance_variable_set :@read_time, read_time
|
124
125
|
cols
|
125
126
|
end
|
126
127
|
|
@@ -86,8 +86,9 @@ module Google
|
|
86
86
|
def next
|
87
87
|
return nil unless next?
|
88
88
|
ensure_client!
|
89
|
-
grpc = @client.service.list_documents @parent, @collection_id, token: token, max: @max
|
90
|
-
|
89
|
+
grpc = @client.service.list_documents @parent, @collection_id, token: token, max: @max, \
|
90
|
+
read_time: @read_time
|
91
|
+
self.class.from_grpc grpc, @client, @parent, @collection_id, @max, read_time: @read_time
|
91
92
|
end
|
92
93
|
|
93
94
|
##
|
@@ -162,7 +163,7 @@ module Google
|
|
162
163
|
##
|
163
164
|
# @private New DocumentReference::List from a
|
164
165
|
# Google::Cloud::Firestore::V1::ListDocumentsResponse object.
|
165
|
-
def self.from_grpc grpc, client, parent, collection_id, max = nil
|
166
|
+
def self.from_grpc grpc, client, parent, collection_id, max = nil, read_time: nil
|
166
167
|
documents = List.new(Array(grpc.documents).map do |document|
|
167
168
|
DocumentReference.from_path document.name, client
|
168
169
|
end)
|
@@ -173,6 +174,7 @@ module Google
|
|
173
174
|
documents.instance_variable_set :@token, token
|
174
175
|
documents.instance_variable_set :@client, client
|
175
176
|
documents.instance_variable_set :@max, max
|
177
|
+
documents.instance_variable_set :@read_time, read_time
|
176
178
|
documents
|
177
179
|
end
|
178
180
|
|
@@ -73,6 +73,9 @@ module Google
|
|
73
73
|
##
|
74
74
|
# Retrieves an enumerator for the collections nested under the document snapshot.
|
75
75
|
#
|
76
|
+
# @param [Time] read_time Reads documents as they were at the given time.
|
77
|
+
# This may not be older than 270 seconds. Optional
|
78
|
+
#
|
76
79
|
# @yield [collections] The block for accessing the collections.
|
77
80
|
# @yieldparam [CollectionReference] collection A collection reference object.
|
78
81
|
#
|
@@ -91,10 +94,24 @@ module Google
|
|
91
94
|
# puts col.collection_id
|
92
95
|
# end
|
93
96
|
#
|
94
|
-
|
97
|
+
# @example Get collection with read time
|
98
|
+
# require "google/cloud/firestore"
|
99
|
+
#
|
100
|
+
# firestore = Google::Cloud::Firestore.new
|
101
|
+
#
|
102
|
+
# read_time = Time.now
|
103
|
+
#
|
104
|
+
# # Get a document reference
|
105
|
+
# nyc_ref = firestore.doc "cities/NYC"
|
106
|
+
#
|
107
|
+
# nyc_ref.cols(read_time: read_time).each do |col|
|
108
|
+
# puts col.collection_id
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
def cols read_time: nil, &block
|
95
112
|
ensure_service!
|
96
|
-
grpc = service.list_collections path
|
97
|
-
cols_enum = CollectionReferenceList.from_grpc(grpc, client, path).all
|
113
|
+
grpc = service.list_collections path, read_time: read_time
|
114
|
+
cols_enum = CollectionReferenceList.from_grpc(grpc, client, path, read_time: read_time).all
|
98
115
|
cols_enum.each(&block) if block_given?
|
99
116
|
cols_enum
|
100
117
|
end
|
@@ -17,6 +17,7 @@ require "google/cloud/firestore/v1"
|
|
17
17
|
require "google/cloud/firestore/document_snapshot"
|
18
18
|
require "google/cloud/firestore/query_listener"
|
19
19
|
require "google/cloud/firestore/convert"
|
20
|
+
require "google/cloud/firestore/aggregate_query"
|
20
21
|
require "json"
|
21
22
|
|
22
23
|
module Google
|
@@ -903,6 +904,9 @@ module Google
|
|
903
904
|
##
|
904
905
|
# Retrieves document snapshots for the query.
|
905
906
|
#
|
907
|
+
# @param [Time] read_time Reads documents as they were at the given time.
|
908
|
+
# This may not be older than 270 seconds. Optional
|
909
|
+
#
|
906
910
|
# @yield [documents] The block for accessing the document snapshots.
|
907
911
|
# @yieldparam [DocumentSnapshot] document A document snapshot.
|
908
912
|
#
|
@@ -923,12 +927,29 @@ module Google
|
|
923
927
|
# puts "#{city.document_id} has #{city[:population]} residents."
|
924
928
|
# end
|
925
929
|
#
|
926
|
-
|
930
|
+
# @example Get query with read time
|
931
|
+
# require "google/cloud/firestore"
|
932
|
+
#
|
933
|
+
# firestore = Google::Cloud::Firestore.new
|
934
|
+
#
|
935
|
+
# # Get a collection reference
|
936
|
+
# cities_col = firestore.col "cities"
|
937
|
+
#
|
938
|
+
# # Create a query
|
939
|
+
# query = cities_col.select(:population)
|
940
|
+
#
|
941
|
+
# read_time = Time.now
|
942
|
+
#
|
943
|
+
# query.get(read_time: read_time) do |city|
|
944
|
+
# puts "#{city.document_id} has #{city[:population]} residents."
|
945
|
+
# end
|
946
|
+
#
|
947
|
+
def get read_time: nil
|
927
948
|
ensure_service!
|
928
949
|
|
929
|
-
return enum_for :get unless block_given?
|
950
|
+
return enum_for :get, read_time: read_time unless block_given?
|
930
951
|
|
931
|
-
results = service.run_query parent_path, @query
|
952
|
+
results = service.run_query parent_path, @query, read_time: read_time
|
932
953
|
|
933
954
|
# Reverse the results for Query#limit_to_last queries since that method reversed the order_by directions.
|
934
955
|
results = results.to_a.reverse if limit_type == :last
|
@@ -940,6 +961,26 @@ module Google
|
|
940
961
|
end
|
941
962
|
alias run get
|
942
963
|
|
964
|
+
##
|
965
|
+
# Creates an AggregateQuery object for the query.
|
966
|
+
#
|
967
|
+
# @return [AggregateQuery] New empty aggregate query.
|
968
|
+
#
|
969
|
+
# @example
|
970
|
+
# require "google/cloud/firestore"
|
971
|
+
#
|
972
|
+
# firestore = Google::Cloud::Firestore.new
|
973
|
+
#
|
974
|
+
# # Get a collection reference
|
975
|
+
# query = firestore.col "cities"
|
976
|
+
#
|
977
|
+
# # Create an aggregate query
|
978
|
+
# aggregate_query = query.aggregate_query
|
979
|
+
#
|
980
|
+
def aggregate_query
|
981
|
+
AggregateQuery.new query, parent_path, client
|
982
|
+
end
|
983
|
+
|
943
984
|
##
|
944
985
|
# Listen to this query for changes.
|
945
986
|
#
|
@@ -52,7 +52,7 @@ module Google
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
def get_documents document_paths, mask: nil, transaction: nil
|
55
|
+
def get_documents document_paths, mask: nil, transaction: nil, read_time: nil
|
56
56
|
batch_get_req = {
|
57
57
|
database: database_path,
|
58
58
|
documents: document_paths,
|
@@ -63,7 +63,9 @@ module Google
|
|
63
63
|
elsif transaction
|
64
64
|
batch_get_req[:new_transaction] = transaction
|
65
65
|
end
|
66
|
-
|
66
|
+
if read_time
|
67
|
+
batch_get_req[:read_time] = read_time_to_timestamp(read_time)
|
68
|
+
end
|
67
69
|
firestore.batch_get_documents batch_get_req, call_options(parent: database_path)
|
68
70
|
end
|
69
71
|
|
@@ -74,23 +76,25 @@ module Google
|
|
74
76
|
# the showMissing flag to true to support full document traversal. If
|
75
77
|
# there are too many documents, recommendation will be not to call this
|
76
78
|
# method.
|
77
|
-
def list_documents parent, collection_id, token: nil, max: nil
|
79
|
+
def list_documents parent, collection_id, token: nil, max: nil, read_time: nil
|
78
80
|
mask = { field_paths: [] }
|
79
|
-
paged_enum = firestore.list_documents parent:
|
81
|
+
paged_enum = firestore.list_documents parent: parent,
|
80
82
|
collection_id: collection_id,
|
81
|
-
page_size:
|
82
|
-
page_token:
|
83
|
-
mask:
|
84
|
-
show_missing:
|
83
|
+
page_size: max,
|
84
|
+
page_token: token,
|
85
|
+
mask: mask,
|
86
|
+
show_missing: true,
|
87
|
+
read_time: read_time_to_timestamp(read_time)
|
85
88
|
paged_enum.response
|
86
89
|
end
|
87
90
|
|
88
|
-
def list_collections parent, token: nil, max: nil
|
91
|
+
def list_collections parent, token: nil, max: nil, read_time: nil
|
89
92
|
firestore.list_collection_ids(
|
90
93
|
{
|
91
|
-
parent:
|
92
|
-
page_size:
|
93
|
-
page_token: token
|
94
|
+
parent: parent,
|
95
|
+
page_size: max,
|
96
|
+
page_token: token,
|
97
|
+
read_time: read_time_to_timestamp(read_time)
|
94
98
|
},
|
95
99
|
call_options(parent: database_path)
|
96
100
|
)
|
@@ -98,19 +102,20 @@ module Google
|
|
98
102
|
|
99
103
|
##
|
100
104
|
# Returns Google::Cloud::Firestore::V1::PartitionQueryResponse
|
101
|
-
def partition_query parent, query_grpc, partition_count, token: nil, max: nil
|
105
|
+
def partition_query parent, query_grpc, partition_count, token: nil, max: nil, read_time: nil
|
102
106
|
request = Google::Cloud::Firestore::V1::PartitionQueryRequest.new(
|
103
107
|
parent: parent,
|
104
108
|
structured_query: query_grpc,
|
105
109
|
partition_count: partition_count,
|
106
110
|
page_token: token,
|
107
|
-
page_size: max
|
111
|
+
page_size: max,
|
112
|
+
read_time: read_time_to_timestamp(read_time)
|
108
113
|
)
|
109
114
|
paged_enum = firestore.partition_query request
|
110
115
|
paged_enum.response
|
111
116
|
end
|
112
117
|
|
113
|
-
def run_query path, query_grpc, transaction: nil
|
118
|
+
def run_query path, query_grpc, transaction: nil, read_time: nil
|
114
119
|
run_query_req = {
|
115
120
|
parent: path,
|
116
121
|
structured_query: query_grpc
|
@@ -120,10 +125,28 @@ module Google
|
|
120
125
|
elsif transaction
|
121
126
|
run_query_req[:new_transaction] = transaction
|
122
127
|
end
|
128
|
+
if read_time
|
129
|
+
run_query_req[:read_time] = read_time_to_timestamp(read_time)
|
130
|
+
end
|
123
131
|
|
124
132
|
firestore.run_query run_query_req, call_options(parent: database_path)
|
125
133
|
end
|
126
134
|
|
135
|
+
##
|
136
|
+
# Returns Google::Cloud::Firestore::V1::RunAggregationQueryResponse
|
137
|
+
def run_aggregate_query parent, structured_aggregation_query, transaction: nil
|
138
|
+
request = Google::Cloud::Firestore::V1::RunAggregationQueryRequest.new(
|
139
|
+
parent: parent,
|
140
|
+
structured_aggregation_query: structured_aggregation_query
|
141
|
+
)
|
142
|
+
if transaction.is_a? String
|
143
|
+
request.transaction = transaction
|
144
|
+
elsif transaction
|
145
|
+
request.new_transaction = transaction
|
146
|
+
end
|
147
|
+
firestore.run_aggregation_query request
|
148
|
+
end
|
149
|
+
|
127
150
|
def listen enum
|
128
151
|
firestore.listen enum, call_options(parent: database_path)
|
129
152
|
end
|
@@ -172,6 +195,17 @@ module Google
|
|
172
195
|
"#{self.class}(#{@project})"
|
173
196
|
end
|
174
197
|
|
198
|
+
def read_time_to_timestamp read_time
|
199
|
+
return nil if read_time.nil?
|
200
|
+
|
201
|
+
raise TypeError, "read_time is expected to be a Time object" unless read_time.is_a? Time
|
202
|
+
|
203
|
+
Google::Protobuf::Timestamp.new(
|
204
|
+
seconds: read_time.to_i,
|
205
|
+
nanos: read_time.usec * 1000
|
206
|
+
)
|
207
|
+
end
|
208
|
+
|
175
209
|
protected
|
176
210
|
|
177
211
|
def default_headers parent = nil
|
@@ -269,6 +269,45 @@ module Google
|
|
269
269
|
end
|
270
270
|
alias run get
|
271
271
|
|
272
|
+
##
|
273
|
+
# Retrieves aggregate query snapshots for the given value. Valid values can be
|
274
|
+
# a string representing either a document or a collection of documents,
|
275
|
+
# a document reference object, a collection reference object, or a query
|
276
|
+
# to be run.
|
277
|
+
#
|
278
|
+
# @param [AggregateQuery] aggregate_query
|
279
|
+
# An AggregateQuery object
|
280
|
+
#
|
281
|
+
# @yield [documents] The block for accessing the aggregate query snapshot.
|
282
|
+
# @yieldparam [AggregateQuerySnapshot] aggregate_snapshot An aggregate query snapshot.
|
283
|
+
#
|
284
|
+
# @example
|
285
|
+
# require "google/cloud/firestore"
|
286
|
+
#
|
287
|
+
# firestore = Google::Cloud::Firestore.new
|
288
|
+
#
|
289
|
+
# firestore.transaction do |tx|
|
290
|
+
# tx.get_aggregate aq do |aggregate_snapshot|
|
291
|
+
# puts aggregate_snapshot.get('count')
|
292
|
+
# end
|
293
|
+
# end
|
294
|
+
#
|
295
|
+
def get_aggregate aggregate_query
|
296
|
+
ensure_not_closed!
|
297
|
+
ensure_service!
|
298
|
+
|
299
|
+
return enum_for :get_aggregate, aggregate_query unless block_given?
|
300
|
+
|
301
|
+
results = service.run_aggregate_query aggregate_query.parent_path,
|
302
|
+
aggregate_query.structured_aggregation_query,
|
303
|
+
transaction: transaction_or_create
|
304
|
+
results.each do |result|
|
305
|
+
extract_transaction_from_result! result
|
306
|
+
next if result.result.nil?
|
307
|
+
yield AggregateQuerySnapshot.from_run_aggregate_query_response result
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
272
311
|
# @!endgroup
|
273
312
|
|
274
313
|
# @!group Modifications
|
@@ -643,10 +682,12 @@ module Google
|
|
643
682
|
|
644
683
|
##
|
645
684
|
# @private New Transaction reference object from a path.
|
646
|
-
def self.from_client client, previous_transaction: nil
|
685
|
+
def self.from_client client, previous_transaction: nil, read_time: nil, read_only: nil
|
647
686
|
new.tap do |s|
|
648
687
|
s.instance_variable_set :@client, client
|
649
688
|
s.instance_variable_set :@previous_transaction, previous_transaction
|
689
|
+
s.instance_variable_set :@read_time, read_time
|
690
|
+
s.instance_variable_set :@read_only, read_only
|
650
691
|
end
|
651
692
|
end
|
652
693
|
|
@@ -699,6 +740,10 @@ module Google
|
|
699
740
|
##
|
700
741
|
# @private
|
701
742
|
def transaction_opt
|
743
|
+
read_only = \
|
744
|
+
Google::Cloud::Firestore::V1::TransactionOptions::ReadOnly.new \
|
745
|
+
read_time: service.read_time_to_timestamp(@read_time)
|
746
|
+
|
702
747
|
read_write = \
|
703
748
|
Google::Cloud::Firestore::V1::TransactionOptions::ReadWrite.new
|
704
749
|
|
@@ -707,9 +752,11 @@ module Google
|
|
707
752
|
@previous_transaction = nil
|
708
753
|
end
|
709
754
|
|
710
|
-
|
711
|
-
|
712
|
-
|
755
|
+
if @read_only
|
756
|
+
Google::Cloud::Firestore::V1::TransactionOptions.new read_only: read_only
|
757
|
+
else
|
758
|
+
Google::Cloud::Firestore::V1::TransactionOptions.new read_write: read_write
|
759
|
+
end
|
713
760
|
end
|
714
761
|
|
715
762
|
##
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: google-cloud-firestore
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Google Inc
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: google-cloud-core
|
@@ -225,6 +225,8 @@ files:
|
|
225
225
|
- TROUBLESHOOTING.md
|
226
226
|
- lib/google-cloud-firestore.rb
|
227
227
|
- lib/google/cloud/firestore.rb
|
228
|
+
- lib/google/cloud/firestore/aggregate_query.rb
|
229
|
+
- lib/google/cloud/firestore/aggregate_query_snapshot.rb
|
228
230
|
- lib/google/cloud/firestore/batch.rb
|
229
231
|
- lib/google/cloud/firestore/client.rb
|
230
232
|
- lib/google/cloud/firestore/collection_group.rb
|
@@ -272,7 +274,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
272
274
|
- !ruby/object:Gem::Version
|
273
275
|
version: '0'
|
274
276
|
requirements: []
|
275
|
-
rubygems_version: 3.
|
277
|
+
rubygems_version: 3.4.2
|
276
278
|
signing_key:
|
277
279
|
specification_version: 4
|
278
280
|
summary: API Client library for Google Cloud Firestore API
|