google-cloud-firestore 2.6.0 → 2.10.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 +4 -4
- data/AUTHENTICATION.md +2 -1
- data/CHANGELOG.md +85 -0
- data/CONTRIBUTING.md +346 -115
- data/EMULATOR.md +10 -8
- data/LOGGING.md +1 -1
- data/OVERVIEW.md +1 -1
- data/lib/google/cloud/firestore/aggregate_query.rb +202 -0
- data/lib/google/cloud/firestore/aggregate_query_snapshot.rb +120 -0
- data/lib/google/cloud/firestore/client.rb +99 -19
- 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 +10 -8
- 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/field_path.rb +3 -7
- data/lib/google/cloud/firestore/query.rb +44 -3
- data/lib/google/cloud/firestore/service.rb +57 -21
- data/lib/google/cloud/firestore/transaction.rb +57 -4
- data/lib/google/cloud/firestore/version.rb +1 -1
- data/lib/google/cloud/firestore/watch/inventory.rb +1 -1
- data/lib/google/cloud/firestore.rb +14 -6
- data/lib/google-cloud-firestore.rb +20 -8
- metadata +10 -8
data/EMULATOR.md
CHANGED
|
@@ -2,19 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
To develop and test your application locally, you can use the [Google Cloud
|
|
4
4
|
Firestore
|
|
5
|
-
Emulator](https://cloud.google.com/
|
|
6
|
-
which provides local emulation of the production Google Cloud Firestore
|
|
7
|
-
environment. You can start the Google Cloud Firestore emulator using
|
|
8
|
-
|
|
5
|
+
Emulator](https://cloud.google.com/sdk/gcloud/reference/beta/emulators/firestore/),
|
|
6
|
+
which provides local emulation of the production Google Cloud Firestore
|
|
7
|
+
environment. You can start the Google Cloud Firestore emulator using
|
|
8
|
+
the `gcloud` command-line tool.
|
|
9
|
+
|
|
10
|
+
`gcloud beta emulators firestore start --host-port=0.0.0.0:8080`
|
|
9
11
|
|
|
10
12
|
When you run the Cloud Firestore emulator you will see a message similar to the
|
|
11
13
|
following printed:
|
|
12
14
|
|
|
13
15
|
```
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
If you are using a library that supports the FIRESTORE_EMULATOR_HOST
|
|
17
|
+
environment variable, run:
|
|
18
|
+
|
|
19
|
+
export FIRESTORE_EMULATOR_HOST=localhost:8080
|
|
18
20
|
```
|
|
19
21
|
|
|
20
22
|
Now you can connect to the emulator using the `FIRESTORE_EMULATOR_HOST`
|
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
|
data/OVERVIEW.md
CHANGED
|
@@ -108,7 +108,7 @@ and it can't contain other collections. You do not need to "create" or "delete"
|
|
|
108
108
|
collections. After you create the first document in a collection, the collection
|
|
109
109
|
exists. If you delete all of the documents in a collection, it no longer exists.
|
|
110
110
|
(For more information, see [Cloud Firestore Data
|
|
111
|
-
Model](https://cloud.google.com/firestore/docs/data-model).
|
|
111
|
+
Model](https://cloud.google.com/firestore/docs/data-model).)
|
|
112
112
|
|
|
113
113
|
Use {Google::Cloud::Firestore::Client#cols Client#cols} to list the root-level
|
|
114
114
|
collections:
|
|
@@ -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
|
|
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
|
|
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
|
|
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,120 @@
|
|
|
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
|
|
38
|
+
# end
|
|
39
|
+
# @return [Integer] The aggregate value.
|
|
40
|
+
#
|
|
41
|
+
# @example Alias an aggregate query
|
|
42
|
+
# require "google/cloud/firestore"
|
|
43
|
+
#
|
|
44
|
+
# firestore = Google::Cloud::Firestore.new
|
|
45
|
+
#
|
|
46
|
+
# query = firestore.col "cities"
|
|
47
|
+
#
|
|
48
|
+
# # Create an aggregate query
|
|
49
|
+
# aggregate_query = query.aggregate_query
|
|
50
|
+
# .add_count aggregate_alias: 'total'
|
|
51
|
+
#
|
|
52
|
+
# aggregate_query.get do |aggregate_snapshot|
|
|
53
|
+
# puts aggregate_snapshot.get('total')
|
|
54
|
+
# end
|
|
55
|
+
class AggregateQuerySnapshot
|
|
56
|
+
##
|
|
57
|
+
# Retrieves the aggregate data.
|
|
58
|
+
#
|
|
59
|
+
# @param aggregate_alias [String] The alias used to access
|
|
60
|
+
# the aggregate value. For an AggregateQuery with a
|
|
61
|
+
# single aggregate field, this parameter can be omitted.
|
|
62
|
+
#
|
|
63
|
+
# @return [Integer] The aggregate value.
|
|
64
|
+
#
|
|
65
|
+
# @example
|
|
66
|
+
# require "google/cloud/firestore"
|
|
67
|
+
#
|
|
68
|
+
# firestore = Google::Cloud::Firestore.new
|
|
69
|
+
#
|
|
70
|
+
# query = firestore.col "cities"
|
|
71
|
+
#
|
|
72
|
+
# # Create an aggregate query
|
|
73
|
+
# aggregate_query = query.aggregate_query
|
|
74
|
+
# .add_count
|
|
75
|
+
#
|
|
76
|
+
# aggregate_query.get do |aggregate_snapshot|
|
|
77
|
+
# puts aggregate_snapshot.get
|
|
78
|
+
# end
|
|
79
|
+
# @return [Integer] The aggregate value.
|
|
80
|
+
#
|
|
81
|
+
# @example Alias an aggregate query
|
|
82
|
+
# require "google/cloud/firestore"
|
|
83
|
+
#
|
|
84
|
+
# firestore = Google::Cloud::Firestore.new
|
|
85
|
+
#
|
|
86
|
+
# query = firestore.col "cities"
|
|
87
|
+
#
|
|
88
|
+
# # Create an aggregate query
|
|
89
|
+
# aggregate_query = query.aggregate_query
|
|
90
|
+
# .add_count aggregate_alias: 'total'
|
|
91
|
+
#
|
|
92
|
+
# aggregate_query.get do |aggregate_snapshot|
|
|
93
|
+
# puts aggregate_snapshot.get('total')
|
|
94
|
+
# end
|
|
95
|
+
def get aggregate_alias = nil
|
|
96
|
+
if @aggregate_fields.count > 1 && aggregate_alias.nil?
|
|
97
|
+
raise ArgumentError, "Required param aggregate_alias for AggregateQuery with multiple aggregate fields"
|
|
98
|
+
end
|
|
99
|
+
aggregate_alias ||= @aggregate_fields.keys.first
|
|
100
|
+
@aggregate_fields[aggregate_alias]
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
##
|
|
104
|
+
# @private New AggregateQuerySnapshot from a
|
|
105
|
+
# Google::Cloud::Firestore::V1::RunAggregationQueryResponse object.
|
|
106
|
+
def self.from_run_aggregate_query_response response
|
|
107
|
+
aggregate_fields = response
|
|
108
|
+
.result
|
|
109
|
+
.aggregate_fields
|
|
110
|
+
.to_h # convert from protobuf to ruby map
|
|
111
|
+
.transform_values { |v| v[:integer_value] }
|
|
112
|
+
|
|
113
|
+
new.tap do |s|
|
|
114
|
+
s.instance_variable_set :@aggregate_fields, aggregate_fields
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -69,7 +69,7 @@ module Google
|
|
|
69
69
|
#
|
|
70
70
|
# @return [String] database identifier.
|
|
71
71
|
def database_id
|
|
72
|
-
|
|
72
|
+
service.database
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
##
|
|
@@ -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
|
|
@@ -164,8 +178,7 @@ module Google
|
|
|
164
178
|
#
|
|
165
179
|
def col_group collection_id
|
|
166
180
|
if collection_id.include? "/"
|
|
167
|
-
raise ArgumentError, "Invalid collection_id: '#{collection_id}', "
|
|
168
|
-
"must not contain '/'."
|
|
181
|
+
raise ArgumentError, "Invalid collection_id: '#{collection_id}', must not contain '/'."
|
|
169
182
|
end
|
|
170
183
|
|
|
171
184
|
CollectionGroup.from_collection_id service.documents_path, collection_id, self
|
|
@@ -218,6 +231,8 @@ module Google
|
|
|
218
231
|
# individual fields joined by ".". Fields containing `~`, `*`, `/`,
|
|
219
232
|
# `[`, `]`, and `.` cannot be in a dotted string, and should provided
|
|
220
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
|
|
221
236
|
#
|
|
222
237
|
# @yield [documents] The block for accessing the document snapshots.
|
|
223
238
|
# @yieldparam [DocumentSnapshot] document A document snapshot.
|
|
@@ -246,11 +261,24 @@ module Google
|
|
|
246
261
|
# puts "#{city.document_id} has #{city[:population]} residents."
|
|
247
262
|
# end
|
|
248
263
|
#
|
|
249
|
-
|
|
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
|
|
250
278
|
ensure_service!
|
|
251
279
|
|
|
252
280
|
unless block_given?
|
|
253
|
-
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
|
|
254
282
|
end
|
|
255
283
|
|
|
256
284
|
doc_paths = Array(docs).flatten.map do |doc_path|
|
|
@@ -265,7 +293,7 @@ module Google
|
|
|
265
293
|
end
|
|
266
294
|
mask = nil if mask.empty?
|
|
267
295
|
|
|
268
|
-
results = service.get_documents doc_paths, mask: mask
|
|
296
|
+
results = service.get_documents doc_paths, mask: mask, read_time: read_time
|
|
269
297
|
results.each do |result|
|
|
270
298
|
next if result.result.nil?
|
|
271
299
|
yield DocumentSnapshot.from_batch_result result, self
|
|
@@ -628,7 +656,24 @@ module Google
|
|
|
628
656
|
commit_return = transaction.commit
|
|
629
657
|
# Conditional return value, depending on truthy commit_response
|
|
630
658
|
commit_response ? commit_return : transaction_return
|
|
631
|
-
rescue Google::Cloud::
|
|
659
|
+
rescue Google::Cloud::AbortedError,
|
|
660
|
+
Google::Cloud::CanceledError,
|
|
661
|
+
Google::Cloud::UnknownError,
|
|
662
|
+
Google::Cloud::DeadlineExceededError,
|
|
663
|
+
Google::Cloud::InternalError,
|
|
664
|
+
Google::Cloud::UnauthenticatedError,
|
|
665
|
+
Google::Cloud::ResourceExhaustedError,
|
|
666
|
+
Google::Cloud::UnavailableError,
|
|
667
|
+
Google::Cloud::InvalidArgumentError => e
|
|
668
|
+
|
|
669
|
+
if e.instance_of? Google::Cloud::InvalidArgumentError
|
|
670
|
+
# Return if a previous call was retried but ultimately succeeded
|
|
671
|
+
return nil if backoff[:current].positive?
|
|
672
|
+
# The Firestore backend uses "INVALID_ARGUMENT" for transaction IDs that have expired.
|
|
673
|
+
# While INVALID_ARGUMENT is generally not retryable, we retry this specific case.
|
|
674
|
+
raise e unless e.message =~ /transaction has expired/
|
|
675
|
+
end
|
|
676
|
+
|
|
632
677
|
# Re-raise if retried more than the max
|
|
633
678
|
raise e if backoff[:current] > backoff[:max]
|
|
634
679
|
|
|
@@ -643,12 +688,6 @@ module Google
|
|
|
643
688
|
transaction = Transaction.from_client \
|
|
644
689
|
self, previous_transaction: transaction.transaction_id
|
|
645
690
|
retry
|
|
646
|
-
rescue Google::Cloud::InvalidArgumentError => e
|
|
647
|
-
# Return if a previous call was retried but ultimately succeeded
|
|
648
|
-
return nil if backoff[:current].positive?
|
|
649
|
-
|
|
650
|
-
# Re-raise error.
|
|
651
|
-
raise e
|
|
652
691
|
rescue StandardError => e
|
|
653
692
|
# Rollback transaction when handling unexpected error
|
|
654
693
|
transaction.rollback rescue nil
|
|
@@ -658,13 +697,54 @@ module Google
|
|
|
658
697
|
end
|
|
659
698
|
end
|
|
660
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
|
+
|
|
661
741
|
# @!endgroup
|
|
662
742
|
|
|
663
743
|
# @private
|
|
664
|
-
def list_documents parent, collection_id, token: nil, max: nil
|
|
744
|
+
def list_documents parent, collection_id, token: nil, max: nil, read_time: nil
|
|
665
745
|
ensure_service!
|
|
666
|
-
grpc = service.list_documents parent, collection_id, token: token, max: max
|
|
667
|
-
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
|
|
668
748
|
end
|
|
669
749
|
|
|
670
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
|
|