google-cloud-firestore 2.8.0 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 389203f8e3c58b6e61e856d294ae723f1b9101119d36172a5a503408bab5e629
4
- data.tar.gz: e1cfa1b4c701550f80da65ee573e83bea391cd1fd1cb7e605b215b91facbba05
3
+ metadata.gz: c5c050184924a624eb5f83c42f528334296cc01392d5a9b1d891d81c2b7f4e50
4
+ data.tar.gz: '085ffdcff90414ab769e585164e331a4d27b1edcfed7341d6c09998aca4a58c6'
5
5
  SHA512:
6
- metadata.gz: adcda0a3707c9e0c1055fef937e46c6080db4960ac86a9572780d495722c9a0cdfb39ab07c0d6134c51584c18e43661e06d7c167b1bcf03c773adfdf52bda85a
7
- data.tar.gz: 9649e1d619412c0e7786f2e78e47dcb0913c0bd989ca95bab358c9c0a8bd8bd7a1047abba62268a4114a6a2b935446f69987ba86bbf922a8b30193d7ea165d3a
6
+ metadata.gz: d5b99c1fa86740df4973731ecf715158cfbb8025fc46833f7b78cf9102d78245106133aed9e92311d5ae0879289054bbc7c832396792141e0df09abc7e6d7357
7
+ data.tar.gz: 9ccefface707ebaf31f3c8e7a998e7ae7f95713a9ec71df4e691d3be3997eadc528f95dfaf5de8bce00162a2c69856b704b198fd4ccea0376f4804451f1f4c77
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
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
+
3
9
  ### 2.8.0 (2023-01-05)
4
10
 
5
11
  #### Features
@@ -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
- def cols &block
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
- def get_all *docs, field_mask: nil
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
- def partitions partition_count
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, token: token
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
- def list_documents token: nil, max: nil
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
- self.class.from_grpc grpc, @client, @parent, @collection_id, @max
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
- def cols &block
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
@@ -904,6 +904,9 @@ module Google
904
904
  ##
905
905
  # Retrieves document snapshots for the query.
906
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
+ #
907
910
  # @yield [documents] The block for accessing the document snapshots.
908
911
  # @yieldparam [DocumentSnapshot] document A document snapshot.
909
912
  #
@@ -924,12 +927,29 @@ module Google
924
927
  # puts "#{city.document_id} has #{city[:population]} residents."
925
928
  # end
926
929
  #
927
- def get
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
928
948
  ensure_service!
929
949
 
930
- return enum_for :get unless block_given?
950
+ return enum_for :get, read_time: read_time unless block_given?
931
951
 
932
- results = service.run_query parent_path, @query
952
+ results = service.run_query parent_path, @query, read_time: read_time
933
953
 
934
954
  # Reverse the results for Query#limit_to_last queries since that method reversed the order_by directions.
935
955
  results = results.to_a.reverse if limit_type == :last
@@ -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: parent,
81
+ paged_enum = firestore.list_documents parent: parent,
80
82
  collection_id: collection_id,
81
- page_size: max,
82
- page_token: token,
83
- mask: mask,
84
- show_missing: true
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: parent,
92
- page_size: max,
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,6 +125,9 @@ 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
@@ -187,6 +195,17 @@ module Google
187
195
  "#{self.class}(#{@project})"
188
196
  end
189
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
+
190
209
  protected
191
210
 
192
211
  def default_headers parent = nil
@@ -682,10 +682,12 @@ module Google
682
682
 
683
683
  ##
684
684
  # @private New Transaction reference object from a path.
685
- def self.from_client client, previous_transaction: nil
685
+ def self.from_client client, previous_transaction: nil, read_time: nil, read_only: nil
686
686
  new.tap do |s|
687
687
  s.instance_variable_set :@client, client
688
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
689
691
  end
690
692
  end
691
693
 
@@ -738,6 +740,10 @@ module Google
738
740
  ##
739
741
  # @private
740
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
+
741
747
  read_write = \
742
748
  Google::Cloud::Firestore::V1::TransactionOptions::ReadWrite.new
743
749
 
@@ -746,9 +752,11 @@ module Google
746
752
  @previous_transaction = nil
747
753
  end
748
754
 
749
- Google::Cloud::Firestore::V1::TransactionOptions.new(
750
- read_write: read_write
751
- )
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
752
760
  end
753
761
 
754
762
  ##
@@ -16,7 +16,7 @@
16
16
  module Google
17
17
  module Cloud
18
18
  module Firestore
19
- VERSION = "2.8.0".freeze
19
+ VERSION = "2.9.0".freeze
20
20
  end
21
21
  end
22
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-cloud-firestore
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.0
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: 2023-01-06 00:00:00.000000000 Z
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
@@ -274,7 +274,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
274
274
  - !ruby/object:Gem::Version
275
275
  version: '0'
276
276
  requirements: []
277
- rubygems_version: 3.3.14
277
+ rubygems_version: 3.4.2
278
278
  signing_key:
279
279
  specification_version: 4
280
280
  summary: API Client library for Google Cloud Firestore API