google-cloud-firestore 2.8.0 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
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