google-cloud-firestore 2.7.2 → 2.15.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 +8 -26
- data/CHANGELOG.md +69 -0
- data/LOGGING.md +1 -1
- data/lib/google/cloud/firestore/aggregate_query.rb +285 -0
- data/lib/google/cloud/firestore/aggregate_query_snapshot.rb +145 -0
- data/lib/google/cloud/firestore/bulk_commit_batch.rb +73 -0
- data/lib/google/cloud/firestore/bulk_writer.rb +558 -0
- data/lib/google/cloud/firestore/bulk_writer_exception.rb +40 -0
- data/lib/google/cloud/firestore/bulk_writer_operation.rb +126 -0
- data/lib/google/cloud/firestore/bulk_writer_scheduler.rb +164 -0
- data/lib/google/cloud/firestore/client.rb +161 -10
- 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 +6 -7
- 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/document_snapshot.rb +1 -1
- data/lib/google/cloud/firestore/errors.rb +60 -0
- data/lib/google/cloud/firestore/filter.rb +326 -0
- data/lib/google/cloud/firestore/promise/future.rb +97 -0
- data/lib/google/cloud/firestore/query.rb +112 -89
- data/lib/google/cloud/firestore/rate_limiter.rb +80 -0
- data/lib/google/cloud/firestore/service.rb +74 -23
- data/lib/google/cloud/firestore/transaction.rb +57 -4
- data/lib/google/cloud/firestore/version.rb +1 -1
- data/lib/google/cloud/firestore.rb +17 -7
- data/lib/google-cloud-firestore.rb +45 -8
- metadata +17 -146
@@ -17,6 +17,8 @@ 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"
|
21
|
+
require "google/cloud/firestore/filter"
|
20
22
|
require "json"
|
21
23
|
|
22
24
|
module Google
|
@@ -209,29 +211,48 @@ module Google
|
|
209
211
|
end
|
210
212
|
|
211
213
|
##
|
212
|
-
#
|
213
|
-
#
|
214
|
-
# @
|
215
|
-
#
|
216
|
-
#
|
217
|
-
#
|
218
|
-
#
|
219
|
-
#
|
220
|
-
#
|
221
|
-
#
|
222
|
-
#
|
223
|
-
#
|
224
|
-
#
|
225
|
-
#
|
226
|
-
#
|
227
|
-
#
|
228
|
-
#
|
229
|
-
#
|
230
|
-
#
|
231
|
-
#
|
232
|
-
#
|
233
|
-
#
|
234
|
-
#
|
214
|
+
# Adds filter to the where clause
|
215
|
+
#
|
216
|
+
# @overload where(filter)
|
217
|
+
# Pass Firestore::Filter to `where` via field_or_filter argument.
|
218
|
+
#
|
219
|
+
# @param filter [::Google::Cloud::Firestore::Filter]
|
220
|
+
#
|
221
|
+
# @overload where(field, operator, value)
|
222
|
+
# Pass arguments to `where` via positional arguments.
|
223
|
+
#
|
224
|
+
# @param field [FieldPath, String, Symbol] A field path to filter
|
225
|
+
# results with.
|
226
|
+
# If a {FieldPath} object is not provided then the field will be
|
227
|
+
# treated as a dotted string, meaning the string represents individual
|
228
|
+
# fields joined by ".". Fields containing `~`, `*`, `/`, `[`, `]`, and
|
229
|
+
# `.` cannot be in a dotted string, and should provided using a
|
230
|
+
# {FieldPath} object instead.
|
231
|
+
#
|
232
|
+
# @param operator [String, Symbol] The operation to compare the field
|
233
|
+
# to. Acceptable values include:
|
234
|
+
# * less than: `<`, `lt`
|
235
|
+
# * less than or equal: `<=`, `lte`
|
236
|
+
# * greater than: `>`, `gt`
|
237
|
+
# * greater than or equal: `>=`, `gte`
|
238
|
+
# * equal: `=`, `==`, `eq`, `eql`, `is`
|
239
|
+
# * not equal: `!=`
|
240
|
+
# * in: `in`
|
241
|
+
# * not in: `not-in`, `not_in`
|
242
|
+
# * array contains: `array-contains`, `array_contains`
|
243
|
+
#
|
244
|
+
# @param value [Object] The value to compare the property to. Defaults to nil.
|
245
|
+
# Possible values are:
|
246
|
+
# * Integer
|
247
|
+
# * Float/BigDecimal
|
248
|
+
# * String
|
249
|
+
# * Boolean
|
250
|
+
# * Array
|
251
|
+
# * Date/Time
|
252
|
+
# * StringIO
|
253
|
+
# * Google::Cloud::Datastore::Key
|
254
|
+
# * Google::Cloud::Datastore::Entity
|
255
|
+
# * nil
|
235
256
|
#
|
236
257
|
# @return [Query] New query with `where` called on it.
|
237
258
|
#
|
@@ -250,7 +271,25 @@ module Google
|
|
250
271
|
# puts "#{city.document_id} has #{city[:population]} residents."
|
251
272
|
# end
|
252
273
|
#
|
253
|
-
|
274
|
+
# @example
|
275
|
+
# require "google/cloud/firestore"
|
276
|
+
#
|
277
|
+
# firestore = Google::Cloud::Firestore.new
|
278
|
+
#
|
279
|
+
# # Get a collection reference
|
280
|
+
# cities_col = firestore.col "cities"
|
281
|
+
#
|
282
|
+
# # Create a filter
|
283
|
+
# filter = Filter.create(:population, :>=, 1000000)
|
284
|
+
#
|
285
|
+
# # Add filter to where clause
|
286
|
+
# query = query.where filter
|
287
|
+
#
|
288
|
+
# query.get do |city|
|
289
|
+
# puts "#{city.document_id} has #{city[:population]} residents."
|
290
|
+
# end
|
291
|
+
#
|
292
|
+
def where filter_or_field = nil, operator = nil, value = nil
|
254
293
|
if query_has_cursors?
|
255
294
|
raise "cannot call where after calling " \
|
256
295
|
"start_at, start_after, end_before, or end_at"
|
@@ -259,10 +298,12 @@ module Google
|
|
259
298
|
new_query = @query.dup
|
260
299
|
new_query ||= StructuredQuery.new
|
261
300
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
301
|
+
if filter_or_field.is_a? Google::Cloud::Firestore::Filter
|
302
|
+
new_query.where = filter_or_field.filter
|
303
|
+
else
|
304
|
+
new_filter = Google::Cloud::Firestore::Filter.new filter_or_field, operator, value
|
305
|
+
add_filters_to_query new_query, new_filter.filter
|
306
|
+
end
|
266
307
|
|
267
308
|
Query.start new_query, parent_path, client, limit_type: limit_type
|
268
309
|
end
|
@@ -903,6 +944,9 @@ module Google
|
|
903
944
|
##
|
904
945
|
# Retrieves document snapshots for the query.
|
905
946
|
#
|
947
|
+
# @param [Time] read_time Reads documents as they were at the given time.
|
948
|
+
# This may not be older than 270 seconds. Optional
|
949
|
+
#
|
906
950
|
# @yield [documents] The block for accessing the document snapshots.
|
907
951
|
# @yieldparam [DocumentSnapshot] document A document snapshot.
|
908
952
|
#
|
@@ -923,12 +967,29 @@ module Google
|
|
923
967
|
# puts "#{city.document_id} has #{city[:population]} residents."
|
924
968
|
# end
|
925
969
|
#
|
926
|
-
|
970
|
+
# @example Get query with read time
|
971
|
+
# require "google/cloud/firestore"
|
972
|
+
#
|
973
|
+
# firestore = Google::Cloud::Firestore.new
|
974
|
+
#
|
975
|
+
# # Get a collection reference
|
976
|
+
# cities_col = firestore.col "cities"
|
977
|
+
#
|
978
|
+
# # Create a query
|
979
|
+
# query = cities_col.select(:population)
|
980
|
+
#
|
981
|
+
# read_time = Time.now
|
982
|
+
#
|
983
|
+
# query.get(read_time: read_time) do |city|
|
984
|
+
# puts "#{city.document_id} has #{city[:population]} residents."
|
985
|
+
# end
|
986
|
+
#
|
987
|
+
def get read_time: nil
|
927
988
|
ensure_service!
|
928
989
|
|
929
|
-
return enum_for :get unless block_given?
|
990
|
+
return enum_for :get, read_time: read_time unless block_given?
|
930
991
|
|
931
|
-
results = service.run_query parent_path, @query
|
992
|
+
results = service.run_query parent_path, @query, read_time: read_time
|
932
993
|
|
933
994
|
# Reverse the results for Query#limit_to_last queries since that method reversed the order_by directions.
|
934
995
|
results = results.to_a.reverse if limit_type == :last
|
@@ -940,6 +1001,26 @@ module Google
|
|
940
1001
|
end
|
941
1002
|
alias run get
|
942
1003
|
|
1004
|
+
##
|
1005
|
+
# Creates an AggregateQuery object for the query.
|
1006
|
+
#
|
1007
|
+
# @return [AggregateQuery] New empty aggregate query.
|
1008
|
+
#
|
1009
|
+
# @example
|
1010
|
+
# require "google/cloud/firestore"
|
1011
|
+
#
|
1012
|
+
# firestore = Google::Cloud::Firestore.new
|
1013
|
+
#
|
1014
|
+
# # Get a collection reference
|
1015
|
+
# query = firestore.col "cities"
|
1016
|
+
#
|
1017
|
+
# # Create an aggregate query
|
1018
|
+
# aggregate_query = query.aggregate_query
|
1019
|
+
#
|
1020
|
+
def aggregate_query
|
1021
|
+
AggregateQuery.new self, parent_path, client
|
1022
|
+
end
|
1023
|
+
|
943
1024
|
##
|
944
1025
|
# Listen to this query for changes.
|
945
1026
|
#
|
@@ -1046,34 +1127,6 @@ module Google
|
|
1046
1127
|
# @private
|
1047
1128
|
StructuredQuery = Google::Cloud::Firestore::V1::StructuredQuery
|
1048
1129
|
|
1049
|
-
##
|
1050
|
-
# @private
|
1051
|
-
FILTER_OPS = {
|
1052
|
-
"<" => :LESS_THAN,
|
1053
|
-
"lt" => :LESS_THAN,
|
1054
|
-
"<=" => :LESS_THAN_OR_EQUAL,
|
1055
|
-
"lte" => :LESS_THAN_OR_EQUAL,
|
1056
|
-
">" => :GREATER_THAN,
|
1057
|
-
"gt" => :GREATER_THAN,
|
1058
|
-
">=" => :GREATER_THAN_OR_EQUAL,
|
1059
|
-
"gte" => :GREATER_THAN_OR_EQUAL,
|
1060
|
-
"=" => :EQUAL,
|
1061
|
-
"==" => :EQUAL,
|
1062
|
-
"eq" => :EQUAL,
|
1063
|
-
"eql" => :EQUAL,
|
1064
|
-
"is" => :EQUAL,
|
1065
|
-
"!=" => :NOT_EQUAL,
|
1066
|
-
"array_contains" => :ARRAY_CONTAINS,
|
1067
|
-
"array-contains" => :ARRAY_CONTAINS,
|
1068
|
-
"include" => :ARRAY_CONTAINS,
|
1069
|
-
"include?" => :ARRAY_CONTAINS,
|
1070
|
-
"has" => :ARRAY_CONTAINS,
|
1071
|
-
"in" => :IN,
|
1072
|
-
"not_in" => :NOT_IN,
|
1073
|
-
"not-in" => :NOT_IN,
|
1074
|
-
"array_contains_any" => :ARRAY_CONTAINS_ANY,
|
1075
|
-
"array-contains-any" => :ARRAY_CONTAINS_ANY
|
1076
|
-
}.freeze
|
1077
1130
|
##
|
1078
1131
|
# @private
|
1079
1132
|
INEQUALITY_FILTERS = [
|
@@ -1097,36 +1150,6 @@ module Google
|
|
1097
1150
|
value_nil?(value) || value_nan?(value)
|
1098
1151
|
end
|
1099
1152
|
|
1100
|
-
def filter name, op_key, value
|
1101
|
-
field = StructuredQuery::FieldReference.new field_path: name.to_s
|
1102
|
-
operator = FILTER_OPS[op_key.to_s.downcase]
|
1103
|
-
raise ArgumentError, "unknown operator #{op_key}" if operator.nil?
|
1104
|
-
|
1105
|
-
if value_unary? value
|
1106
|
-
operator = case operator
|
1107
|
-
when :EQUAL
|
1108
|
-
value_nan?(value) ? :IS_NAN : :IS_NULL
|
1109
|
-
when :NOT_EQUAL
|
1110
|
-
value_nan?(value) ? :IS_NOT_NAN : :IS_NOT_NULL
|
1111
|
-
else
|
1112
|
-
raise ArgumentError, "can only perform '==' and '!=' comparisons on #{value} values"
|
1113
|
-
end
|
1114
|
-
|
1115
|
-
return StructuredQuery::Filter.new(
|
1116
|
-
unary_filter: StructuredQuery::UnaryFilter.new(
|
1117
|
-
field: field, op: operator
|
1118
|
-
)
|
1119
|
-
)
|
1120
|
-
end
|
1121
|
-
|
1122
|
-
value = Convert.raw_to_value value
|
1123
|
-
StructuredQuery::Filter.new(
|
1124
|
-
field_filter: StructuredQuery::FieldFilter.new(
|
1125
|
-
field: field, op: operator, value: value
|
1126
|
-
)
|
1127
|
-
)
|
1128
|
-
end
|
1129
|
-
|
1130
1153
|
def composite_filter
|
1131
1154
|
StructuredQuery::Filter.new(
|
1132
1155
|
composite_filter: StructuredQuery::CompositeFilter.new(op: :AND)
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# Copyright 2023 Google LLC
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
module Google
|
17
|
+
module Cloud
|
18
|
+
module Firestore
|
19
|
+
##
|
20
|
+
# @private Implements 5/5/5 ramp-up via Token Bucket algorithm.
|
21
|
+
#
|
22
|
+
# 5/5/5 is a ramp up strategy that starts with a budget of 500 operations per
|
23
|
+
# second. Additionally, every 5 minutes, the maximum budget can increase by
|
24
|
+
# 50%. Thus, at 5:01 into a long bulk-writing process, the maximum budget
|
25
|
+
# becomes 750 operations per second. At 10:01, the budget becomes 1,125
|
26
|
+
# operations per second.
|
27
|
+
#
|
28
|
+
class RateLimiter
|
29
|
+
DEFAULT_STARTING_MAXIMUM_OPS_PER_SECOND = 500.0
|
30
|
+
DEFAULT_PHASE_LENGTH = 300.0
|
31
|
+
|
32
|
+
attr_reader :bandwidth
|
33
|
+
|
34
|
+
##
|
35
|
+
# Initialize the object
|
36
|
+
def initialize starting_ops: nil, phase_length: nil
|
37
|
+
@start_time = time
|
38
|
+
@last_fetched = time
|
39
|
+
@bandwidth = (starting_ops || DEFAULT_STARTING_MAXIMUM_OPS_PER_SECOND).to_f
|
40
|
+
@phase_length = phase_length || DEFAULT_PHASE_LENGTH
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Wait till the number of tokens is available
|
45
|
+
# Assumes that the bandwidth is distributed evenly across the entire second.
|
46
|
+
#
|
47
|
+
# Example - If the limit is 500 qps, then it has been further broken down to 2e+6 nsec
|
48
|
+
# per query
|
49
|
+
#
|
50
|
+
# @return [nil]
|
51
|
+
def wait_for_tokens size
|
52
|
+
available_time = @last_fetched + (size / @bandwidth)
|
53
|
+
waiting_time = [0, available_time - time].max
|
54
|
+
sleep waiting_time
|
55
|
+
@last_fetched = time
|
56
|
+
increase_bandwidth
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
##
|
62
|
+
# Returns time elapsed since epoch.
|
63
|
+
#
|
64
|
+
# @return [Float] Float denoting time elapsed since epoch
|
65
|
+
def time
|
66
|
+
Time.now.to_f
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Increase the bandwidth as per 555 rule
|
71
|
+
#
|
72
|
+
# @return [nil]
|
73
|
+
def increase_bandwidth
|
74
|
+
intervals = (time - @start_time) / @phase_length
|
75
|
+
@bandwidth = (DEFAULT_STARTING_MAXIMUM_OPS_PER_SECOND * (1.5**intervals.floor)).to_f
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -30,29 +30,34 @@ module Google
|
|
30
30
|
attr_accessor :credentials
|
31
31
|
attr_accessor :timeout
|
32
32
|
attr_accessor :host
|
33
|
+
attr_accessor :database
|
33
34
|
|
34
35
|
##
|
35
36
|
# Creates a new Service instance.
|
36
|
-
def initialize project, credentials, host: nil, timeout: nil
|
37
|
+
def initialize project, credentials, host: nil, timeout: nil, database: nil, transport: :grpc
|
37
38
|
@project = project
|
38
39
|
@credentials = credentials
|
39
40
|
@host = host
|
40
41
|
@timeout = timeout
|
42
|
+
@database = database
|
43
|
+
@transport = transport
|
41
44
|
end
|
42
45
|
|
43
46
|
def firestore
|
44
|
-
@firestore ||=
|
45
|
-
V1::Firestore::Client
|
47
|
+
@firestore ||= begin
|
48
|
+
client_class = @transport == :rest ? V1::Firestore::Rest::Client : V1::Firestore::Client
|
49
|
+
client_class.new do |config|
|
46
50
|
config.credentials = credentials if credentials
|
47
51
|
config.timeout = timeout if timeout
|
48
52
|
config.endpoint = host if host
|
49
53
|
config.lib_name = "gccl"
|
50
54
|
config.lib_version = Google::Cloud::Firestore::VERSION
|
51
|
-
config.metadata = { "google-cloud-resource-prefix": "projects/#{@project}/databases
|
55
|
+
config.metadata = { "google-cloud-resource-prefix": "projects/#{@project}/databases/#{@database}" }
|
52
56
|
end
|
57
|
+
end
|
53
58
|
end
|
54
59
|
|
55
|
-
def get_documents document_paths, mask: nil, transaction: nil
|
60
|
+
def get_documents document_paths, mask: nil, transaction: nil, read_time: nil
|
56
61
|
batch_get_req = {
|
57
62
|
database: database_path,
|
58
63
|
documents: document_paths,
|
@@ -63,7 +68,9 @@ module Google
|
|
63
68
|
elsif transaction
|
64
69
|
batch_get_req[:new_transaction] = transaction
|
65
70
|
end
|
66
|
-
|
71
|
+
if read_time
|
72
|
+
batch_get_req[:read_time] = read_time_to_timestamp(read_time)
|
73
|
+
end
|
67
74
|
firestore.batch_get_documents batch_get_req, call_options(parent: database_path)
|
68
75
|
end
|
69
76
|
|
@@ -74,23 +81,25 @@ module Google
|
|
74
81
|
# the showMissing flag to true to support full document traversal. If
|
75
82
|
# there are too many documents, recommendation will be not to call this
|
76
83
|
# method.
|
77
|
-
def list_documents parent, collection_id, token: nil, max: nil
|
84
|
+
def list_documents parent, collection_id, token: nil, max: nil, read_time: nil
|
78
85
|
mask = { field_paths: [] }
|
79
|
-
paged_enum = firestore.list_documents parent:
|
86
|
+
paged_enum = firestore.list_documents parent: parent,
|
80
87
|
collection_id: collection_id,
|
81
|
-
page_size:
|
82
|
-
page_token:
|
83
|
-
mask:
|
84
|
-
show_missing:
|
88
|
+
page_size: max,
|
89
|
+
page_token: token,
|
90
|
+
mask: mask,
|
91
|
+
show_missing: true,
|
92
|
+
read_time: read_time_to_timestamp(read_time)
|
85
93
|
paged_enum.response
|
86
94
|
end
|
87
95
|
|
88
|
-
def list_collections parent, token: nil, max: nil
|
96
|
+
def list_collections parent, token: nil, max: nil, read_time: nil
|
89
97
|
firestore.list_collection_ids(
|
90
98
|
{
|
91
|
-
parent:
|
92
|
-
page_size:
|
93
|
-
page_token: token
|
99
|
+
parent: parent,
|
100
|
+
page_size: max,
|
101
|
+
page_token: token,
|
102
|
+
read_time: read_time_to_timestamp(read_time)
|
94
103
|
},
|
95
104
|
call_options(parent: database_path)
|
96
105
|
)
|
@@ -98,19 +107,20 @@ module Google
|
|
98
107
|
|
99
108
|
##
|
100
109
|
# Returns Google::Cloud::Firestore::V1::PartitionQueryResponse
|
101
|
-
def partition_query parent, query_grpc, partition_count, token: nil, max: nil
|
110
|
+
def partition_query parent, query_grpc, partition_count, token: nil, max: nil, read_time: nil
|
102
111
|
request = Google::Cloud::Firestore::V1::PartitionQueryRequest.new(
|
103
112
|
parent: parent,
|
104
113
|
structured_query: query_grpc,
|
105
114
|
partition_count: partition_count,
|
106
115
|
page_token: token,
|
107
|
-
page_size: max
|
116
|
+
page_size: max,
|
117
|
+
read_time: read_time_to_timestamp(read_time)
|
108
118
|
)
|
109
119
|
paged_enum = firestore.partition_query request
|
110
120
|
paged_enum.response
|
111
121
|
end
|
112
122
|
|
113
|
-
def run_query path, query_grpc, transaction: nil
|
123
|
+
def run_query path, query_grpc, transaction: nil, read_time: nil
|
114
124
|
run_query_req = {
|
115
125
|
parent: path,
|
116
126
|
structured_query: query_grpc
|
@@ -120,10 +130,28 @@ module Google
|
|
120
130
|
elsif transaction
|
121
131
|
run_query_req[:new_transaction] = transaction
|
122
132
|
end
|
133
|
+
if read_time
|
134
|
+
run_query_req[:read_time] = read_time_to_timestamp(read_time)
|
135
|
+
end
|
123
136
|
|
124
137
|
firestore.run_query run_query_req, call_options(parent: database_path)
|
125
138
|
end
|
126
139
|
|
140
|
+
##
|
141
|
+
# Returns Google::Cloud::Firestore::V1::RunAggregationQueryResponse
|
142
|
+
def run_aggregate_query parent, structured_aggregation_query, transaction: nil
|
143
|
+
request = Google::Cloud::Firestore::V1::RunAggregationQueryRequest.new(
|
144
|
+
parent: parent,
|
145
|
+
structured_aggregation_query: structured_aggregation_query
|
146
|
+
)
|
147
|
+
if transaction.is_a? String
|
148
|
+
request.transaction = transaction
|
149
|
+
elsif transaction
|
150
|
+
request.new_transaction = transaction
|
151
|
+
end
|
152
|
+
firestore.run_aggregation_query request
|
153
|
+
end
|
154
|
+
|
127
155
|
def listen enum
|
128
156
|
firestore.listen enum, call_options(parent: database_path)
|
129
157
|
end
|
@@ -158,18 +186,41 @@ module Google
|
|
158
186
|
)
|
159
187
|
end
|
160
188
|
|
161
|
-
|
189
|
+
##
|
190
|
+
# Makes the BatchWrite API call. Contains the list of write operations to be processed.
|
191
|
+
#
|
192
|
+
# @return [::Google::Cloud::Firestore::V1::BatchWriteResponse]
|
193
|
+
def batch_write writes
|
194
|
+
batch_write_req = {
|
195
|
+
database: database_path,
|
196
|
+
writes: writes
|
197
|
+
}
|
198
|
+
firestore.batch_write batch_write_req, call_options(parent: database_path)
|
199
|
+
end
|
200
|
+
|
201
|
+
def database_path project_id: project, database_id: database
|
162
202
|
# Originally used V1::FirestoreClient.database_root_path until it was removed in #5405.
|
163
203
|
"projects/#{project_id}/databases/#{database_id}"
|
164
204
|
end
|
165
205
|
|
166
|
-
def documents_path project_id: project, database_id:
|
206
|
+
def documents_path project_id: project, database_id: database
|
167
207
|
# Originally used V1::FirestoreClient.document_root_path until it was removed in #5405.
|
168
208
|
"projects/#{project_id}/databases/#{database_id}/documents"
|
169
209
|
end
|
170
210
|
|
171
211
|
def inspect
|
172
|
-
"#{self.class}(#{@project})"
|
212
|
+
"#{self.class}(#{@project})(#{@database})"
|
213
|
+
end
|
214
|
+
|
215
|
+
def read_time_to_timestamp read_time
|
216
|
+
return nil if read_time.nil?
|
217
|
+
|
218
|
+
raise TypeError, "read_time is expected to be a Time object" unless read_time.is_a? Time
|
219
|
+
|
220
|
+
Google::Protobuf::Timestamp.new(
|
221
|
+
seconds: read_time.to_i,
|
222
|
+
nanos: read_time.usec * 1000
|
223
|
+
)
|
173
224
|
end
|
174
225
|
|
175
226
|
protected
|
@@ -183,7 +234,7 @@ module Google
|
|
183
234
|
Gapic::CallOptions.new(**{
|
184
235
|
metadata: default_headers(parent),
|
185
236
|
page_token: token
|
186
|
-
}.
|
237
|
+
}.compact)
|
187
238
|
end
|
188
239
|
|
189
240
|
def document_mask mask
|
@@ -269,6 +269,51 @@ 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
|
+
# query = firestore.col "cities"
|
290
|
+
#
|
291
|
+
# # Create an aggregate query
|
292
|
+
# aq = query.aggregate_query
|
293
|
+
# .add_count
|
294
|
+
#
|
295
|
+
# firestore.transaction do |tx|
|
296
|
+
# tx.get_aggregate aq do |aggregate_snapshot|
|
297
|
+
# puts aggregate_snapshot.get
|
298
|
+
# end
|
299
|
+
# end
|
300
|
+
#
|
301
|
+
def get_aggregate aggregate_query
|
302
|
+
ensure_not_closed!
|
303
|
+
ensure_service!
|
304
|
+
|
305
|
+
return enum_for :get_aggregate, aggregate_query unless block_given?
|
306
|
+
|
307
|
+
results = service.run_aggregate_query aggregate_query.parent_path,
|
308
|
+
aggregate_query.to_grpc,
|
309
|
+
transaction: transaction_or_create
|
310
|
+
results.each do |result|
|
311
|
+
extract_transaction_from_result! result
|
312
|
+
next if result.result.nil?
|
313
|
+
yield AggregateQuerySnapshot.from_run_aggregate_query_response result
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
272
317
|
# @!endgroup
|
273
318
|
|
274
319
|
# @!group Modifications
|
@@ -643,10 +688,12 @@ module Google
|
|
643
688
|
|
644
689
|
##
|
645
690
|
# @private New Transaction reference object from a path.
|
646
|
-
def self.from_client client, previous_transaction: nil
|
691
|
+
def self.from_client client, previous_transaction: nil, read_time: nil, read_only: nil
|
647
692
|
new.tap do |s|
|
648
693
|
s.instance_variable_set :@client, client
|
649
694
|
s.instance_variable_set :@previous_transaction, previous_transaction
|
695
|
+
s.instance_variable_set :@read_time, read_time
|
696
|
+
s.instance_variable_set :@read_only, read_only
|
650
697
|
end
|
651
698
|
end
|
652
699
|
|
@@ -699,6 +746,10 @@ module Google
|
|
699
746
|
##
|
700
747
|
# @private
|
701
748
|
def transaction_opt
|
749
|
+
read_only = \
|
750
|
+
Google::Cloud::Firestore::V1::TransactionOptions::ReadOnly.new \
|
751
|
+
read_time: service.read_time_to_timestamp(@read_time)
|
752
|
+
|
702
753
|
read_write = \
|
703
754
|
Google::Cloud::Firestore::V1::TransactionOptions::ReadWrite.new
|
704
755
|
|
@@ -707,9 +758,11 @@ module Google
|
|
707
758
|
@previous_transaction = nil
|
708
759
|
end
|
709
760
|
|
710
|
-
|
711
|
-
|
712
|
-
|
761
|
+
if @read_only
|
762
|
+
Google::Cloud::Firestore::V1::TransactionOptions.new read_only: read_only
|
763
|
+
else
|
764
|
+
Google::Cloud::Firestore::V1::TransactionOptions.new read_write: read_write
|
765
|
+
end
|
713
766
|
end
|
714
767
|
|
715
768
|
##
|