google-cloud-firestore 2.11.0 → 2.13.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: c8fe0d4f3e79da21256a4495d0a19da58febfaf27298ea1735fef2042c8c7281
4
- data.tar.gz: 10e4929cd461e369991e153356d3878add4b179c972715880734456b566832ca
3
+ metadata.gz: 99ee040593be1625729cd2eae0d3a8bda03185c53692bec5fdfe18a32c2021f1
4
+ data.tar.gz: 26ff29bf53e07708590e92e9db03955ce1c1c60d671f7cf7fbd4dad52b3b8eab
5
5
  SHA512:
6
- metadata.gz: 7491e2f8033a2e2033e37e77b16e0401f9ecd77e9e357ecf47c72ab55204df6a7b8aa0a8bdf508d58215c3f6e3818a3ffaa7eebd0cc425e9355fe987df1bc478
7
- data.tar.gz: 0f92c886ee8ba0043782aae64166947efd7d5ea1ccd0968fd21fa1bc2e7936f2eba3cb4805853a569d3631e221415fb2649a9c6a5aac101c87cdab1976558472
6
+ metadata.gz: 56a3248b0d03ec14935cc78aa2e0ca6fcf63b810f1800dc96ba3d19b56c1546e914e7449c30cf56b8460d81c1b2e2210bdfaaf035405cf8c7e9909d05d7a9fba
7
+ data.tar.gz: 3cb3a0a89e2ef1d3707e4f30097e2019d62fee21354e6f1575cf29b5bd61121415945a2ff23735c8611af849c5399b6f30f01e58bd1c03f591baa55359f7cd1f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Release History
2
2
 
3
+ ### 2.13.0 (2023-05-10)
4
+
5
+ #### Features
6
+
7
+ * Added support for bulk writer ([#21426](https://github.com/googleapis/google-cloud-ruby/issues/21426))
8
+
9
+ ### 2.12.0 (2023-04-20)
10
+
11
+ #### Features
12
+
13
+ * Add support for OR query ([#20920](https://github.com/googleapis/google-cloud-ruby/issues/20920))
14
+
3
15
  ### 2.11.0 (2023-02-23)
4
16
 
5
17
  #### Features
@@ -0,0 +1,73 @@
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
+ #
21
+ # @private Accumulate write operations to be sent in a batch. Use this for higher
22
+ # volumes (e.g., via `BulkWriter`) and when the order of operations
23
+ # within a given batch is unimportant.
24
+ #
25
+ # Because the order in which individual write operations are applied to the database
26
+ # is not guaranteed, `batch_write` RPCs can never contain multiple operations
27
+ # to the same document. In practice, the BulkWriter class handle this case.
28
+ #
29
+ class BulkCommitBatch
30
+ attr_reader :operations
31
+
32
+ ##
33
+ # Initialize the object
34
+ def initialize service, operations
35
+ @service = service
36
+ @operations = operations
37
+ end
38
+
39
+ ##
40
+ # Updates the operation based on the result received from the API request.
41
+ #
42
+ # @param [Google::Cloud::Firestore::V1::BatchWriteResponse] responses
43
+ #
44
+ # @return [nil]
45
+ #
46
+ def parse_results responses
47
+ @operations.zip responses.write_results, responses.status do |operation, write_result, status|
48
+ begin
49
+ status&.code&.zero? ? operation.on_success(write_result) : operation.on_failure(status)
50
+ rescue StandardError
51
+ # TODO: Log the error while parsing response
52
+ end
53
+ end
54
+ end
55
+
56
+ ##
57
+ # Makes the BatchWrite API request with all the operations in the batch and
58
+ # parses the results for each operation.
59
+ #
60
+ # @return [nil]
61
+ #
62
+ def commit
63
+ begin
64
+ responses = @service.batch_write @operations.map(&:write)
65
+ parse_results responses
66
+ rescue StandardError => e
67
+ raise BulkCommitBatchError, e
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,558 @@
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
+ require "concurrent"
17
+ require "google/cloud/firestore/rate_limiter"
18
+ require "google/cloud/firestore/bulk_commit_batch"
19
+ require "google/cloud/firestore/promise/future"
20
+ require "google/cloud/firestore/bulk_writer_operation"
21
+ require "google/cloud/firestore/bulk_writer_exception"
22
+ require "google/cloud/firestore/bulk_writer_scheduler"
23
+
24
+
25
+ module Google
26
+ module Cloud
27
+ module Firestore
28
+ ##
29
+ # # BulkWriter
30
+ #
31
+ # Accumulate and efficiently sends large amounts of document write
32
+ # operations to the server.
33
+ #
34
+ # BulkWriter can handle large data migrations or updates, buffering records
35
+ # in memory and submitting them to the server in batches of 20.
36
+ #
37
+ # The submission of batches is internally parallelized with a ThreadPoolExecutor.
38
+ #
39
+ # @example Create a BulkWriter and add a write request:
40
+ # require "google/cloud/firestore"
41
+ #
42
+ # firestore = Google::Cloud::Firestore.new
43
+ # bw = firestore.bulk_writer
44
+ #
45
+ # bw.create("cities/NYC", { name: "New York City" })
46
+ #
47
+ # bw.flush
48
+ # bw.close
49
+ #
50
+ class BulkWriter
51
+ MAX_RETRY_ATTEMPTS = 10
52
+
53
+ ##
54
+ # Initialize the attributes and start the schedule_operations job
55
+ #
56
+ def initialize client, service,
57
+ request_threads: nil,
58
+ batch_threads: nil,
59
+ retries: nil
60
+ @client = client
61
+ @service = service
62
+ @closed = false
63
+ @flush = false
64
+ @request_threads = (request_threads || 2).to_i
65
+ @write_thread_pool = Concurrent::ThreadPoolExecutor.new max_threads: @request_threads,
66
+ max_queue: 0
67
+ @mutex = Mutex.new
68
+ @scheduler = BulkWriterScheduler.new client, service, batch_threads
69
+ @doc_refs = Set.new
70
+ @retries = [retries || MAX_RETRY_ATTEMPTS, MAX_RETRY_ATTEMPTS].min
71
+ @request_results = []
72
+ end
73
+
74
+ ##
75
+ # Creates a document with the provided data (fields and values).
76
+ #
77
+ # The operation will fail if the document already exists.
78
+ #
79
+ # @param [String, DocumentReference] doc A string representing the
80
+ # path of the document, or a document reference object.
81
+ # @param [Hash] data The document's fields and values.
82
+ #
83
+ # @return [Google::Cloud::Firestore::Promise::Future] Denoting the future value of
84
+ # write operation.
85
+ #
86
+ # @example Create a document using a document path:
87
+ # require "google/cloud/firestore"
88
+ #
89
+ # firestore = Google::Cloud::Firestore.new
90
+ # bw = firestore.bulk_writer
91
+ #
92
+ # bw.create("cities/NYC", { name: "New York City" })
93
+ #
94
+ # @example Create a document using a document reference:
95
+ # require "google/cloud/firestore"
96
+ #
97
+ # firestore = Google::Cloud::Firestore.new
98
+ # bw = firestore.bulk_writer
99
+ #
100
+ # # Get a document reference
101
+ # nyc_ref = firestore.doc "cities/NYC"
102
+ #
103
+ # bw.create(nyc_ref, { name: "New York City" })
104
+ #
105
+ # @example Create a document and set a field to server_time:
106
+ # require "google/cloud/firestore"
107
+ #
108
+ # firestore = Google::Cloud::Firestore.new
109
+ # bw = firestore.bulk_writer
110
+ #
111
+ # # Get a document reference
112
+ # nyc_ref = firestore.doc "cities/NYC"
113
+ #
114
+ # bw.create(nyc_ref, { name: "New York City",
115
+ # updated_at: firestore.field_server_time })
116
+ #
117
+ # @example Get the value of write operation:
118
+ # require "google/cloud/firestore"
119
+ #
120
+ # firestore = Google::Cloud::Firestore.new
121
+ # bw = firestore.bulk_writer
122
+ #
123
+ # # Get a document reference
124
+ # nyc_ref = firestore.doc "cities/NYC"
125
+ #
126
+ # result = bw.create(nyc_ref, { name: "New York City",
127
+ # updated_at: firestore.field_server_time })
128
+ #
129
+ # bw.close
130
+ #
131
+ # puts result.value
132
+ #
133
+ def create doc, data
134
+ doc_path = coalesce_doc_path_argument doc
135
+ pre_add_operation doc_path
136
+
137
+ write = Convert.write_for_create doc_path, data
138
+
139
+ create_and_enqueue_operation write
140
+ end
141
+
142
+ ##
143
+ # Writes the provided data (fields and values) to the provided document.
144
+ # If the document does not exist, it will be created. By default, the
145
+ # provided data overwrites existing data, but the provided data can be
146
+ # merged into the existing document using the `merge` argument.
147
+ #
148
+ # If you're not sure whether the document exists, use the `merge`
149
+ # argument to merge the new data with any existing document data to
150
+ # avoid overwriting entire documents.
151
+ #
152
+ # @param [String, DocumentReference] doc A string representing the
153
+ # path of the document, or a document reference object.
154
+ # @param [Hash] data The document's fields and values.
155
+ # @param [Boolean, FieldPath, String, Symbol] merge When
156
+ # `true`, all provided data is merged with the existing document data.
157
+ # When the argument is one or more field path, only the data for
158
+ # fields in this argument is merged with the existing document data.
159
+ # The default is to not merge, but to instead overwrite the existing
160
+ # document data.
161
+ #
162
+ # @return [Google::Cloud::Firestore::Promise::Future] Denoting the future value of
163
+ # write operation.
164
+ #
165
+ # @example Set a document using a document path:
166
+ # require "google/cloud/firestore"
167
+ #
168
+ # firestore = Google::Cloud::Firestore.new
169
+ # bw = firestore.bulk_writer
170
+ #
171
+ # # Update a document
172
+ # bw.set("cities/NYC", { name: "New York City" })
173
+ #
174
+ # @example Create a document using a document reference:
175
+ # require "google/cloud/firestore"
176
+ #
177
+ # bw = firestore.bulk_writer
178
+ #
179
+ # # Get a document reference
180
+ # nyc_ref = firestore.doc "cities/NYC"
181
+ #
182
+ # # Update a document
183
+ # bw.set(nyc_ref, { name: "New York City" })
184
+ #
185
+ # @example Set a document and merge all data:
186
+ # require "google/cloud/firestore"
187
+ #
188
+ # firestore = Google::Cloud::Firestore.new
189
+ # bw = firestore.bulk_writer
190
+ #
191
+ # bw.set("cities/NYC", { name: "New York City" }, merge: true)
192
+ #
193
+ # @example Set a document and merge only name:
194
+ # require "google/cloud/firestore"
195
+ #
196
+ # firestore = Google::Cloud::Firestore.new
197
+ # bw = firestore.bulk_writer
198
+ #
199
+ # bw.set("cities/NYC", { name: "New York City" }, merge: :name)
200
+ #
201
+ # @example Set a document and deleting a field using merge:
202
+ # require "google/cloud/firestore"
203
+ #
204
+ # firestore = Google::Cloud::Firestore.new
205
+ # bw = firestore.bulk_writer
206
+ #
207
+ # # Get a document reference
208
+ # nyc_ref = firestore.doc "cities/NYC"
209
+ #
210
+ # nyc_data = { name: "New York City",
211
+ # trash: firestore.field_delete }
212
+ #
213
+ # bw.set(nyc_ref, nyc_data, merge: true)
214
+ #
215
+ # @example Set a document and set a field to server_time:
216
+ # require "google/cloud/firestore"
217
+ #
218
+ # firestore = Google::Cloud::Firestore.new
219
+ # bw = firestore.bulk_writer
220
+ #
221
+ # # Get a document reference
222
+ # nyc_ref = firestore.doc "cities/NYC"
223
+ #
224
+ # nyc_data = { name: "New York City",
225
+ # updated_at: firestore.field_server_time }
226
+ #
227
+ # bw.set(nyc_ref, nyc_data, merge: true)
228
+ #
229
+ # @example Get the value of write operation:
230
+ # require "google/cloud/firestore"
231
+ #
232
+ # firestore = Google::Cloud::Firestore.new
233
+ # bw = firestore.bulk_writer
234
+ #
235
+ # # Get a document reference
236
+ # nyc_ref = firestore.doc "cities/NYC"
237
+ #
238
+ # nyc_data = { name: "New York City",
239
+ # updated_at: firestore.field_server_time }
240
+ #
241
+ # result = bw.set(nyc_ref, nyc_data)
242
+ #
243
+ # bw.close
244
+ #
245
+ # puts result.value
246
+ #
247
+ def set doc, data, merge: nil
248
+ doc_path = coalesce_doc_path_argument doc
249
+ pre_add_operation doc_path
250
+
251
+ write = Convert.write_for_set doc_path, data, merge: merge
252
+
253
+ create_and_enqueue_operation write
254
+ end
255
+
256
+ ##
257
+ # Updates the document with the provided data (fields and values). The
258
+ # provided data is merged into the existing document data.
259
+ #
260
+ # The operation will fail if the document does not exist.
261
+ #
262
+ # @param [String, DocumentReference] doc A string representing the
263
+ # path of the document, or a document reference object.
264
+ # @param [Hash<FieldPath|String|Symbol, Object>] data The document's
265
+ # fields and values.
266
+ #
267
+ # The top-level keys in the data hash are considered field paths, and
268
+ # can either be a FieldPath object, or a string representing the
269
+ # nested fields. In other words the string represents individual
270
+ # fields joined by ".". Fields containing `~`, `*`, `/`, `[`, `]`, and
271
+ # `.` cannot be in a dotted string, and should provided using a
272
+ # {FieldPath} object instead.
273
+ # @param [Time] update_time When set, the document must have been last
274
+ # updated at that time. Optional.
275
+ #
276
+ # @return [Google::Cloud::Firestore::Promise::Future] Denoting the future value of
277
+ # write operation.
278
+ #
279
+ # @example Update a document using a document path:
280
+ # require "google/cloud/firestore"
281
+ #
282
+ # firestore = Google::Cloud::Firestore.new
283
+ # bw = firestore.bulk_writer
284
+ #
285
+ # bw.update("cities/NYC", { name: "New York City" })
286
+ #
287
+ # @example Directly update a deeply-nested field with a `FieldPath`:
288
+ # require "google/cloud/firestore"
289
+ #
290
+ # firestore = Google::Cloud::Firestore.new
291
+ # bw = firestore.bulk_writer
292
+ #
293
+ # nested_field_path = firestore.field_path :favorites, :food
294
+ #
295
+ # bw.update("users/frank", { nested_field_path => "Pasta" })
296
+ #
297
+ # @example Update a document using a document reference:
298
+ # require "google/cloud/firestore"
299
+ #
300
+ # firestore = Google::Cloud::Firestore.new
301
+ # bw = firestore.bulk_writer
302
+ #
303
+ # # Get a document reference
304
+ # nyc_ref = firestore.doc "cities/NYC"
305
+ #
306
+ # bw.update(nyc_ref, { name: "New York City" })
307
+ #
308
+ # @example Update a document using the `update_time` precondition:
309
+ # require "google/cloud/firestore"
310
+ #
311
+ # firestore = Google::Cloud::Firestore.new
312
+ # bw = firestore.bulk_writer
313
+ #
314
+ # last_updated_at = Time.now - 42 # 42 seconds ago
315
+ #
316
+ # bw.update("cities/NYC", { name: "New York City" },
317
+ # update_time: last_updated_at)
318
+ #
319
+ # @example Update a document and deleting a field:
320
+ # require "google/cloud/firestore"
321
+ #
322
+ # firestore = Google::Cloud::Firestore.new
323
+ # bw = firestore.bulk_writer
324
+ #
325
+ # # Get a document reference
326
+ # nyc_ref = firestore.doc "cities/NYC"
327
+ #
328
+ # nyc_data = { name: "New York City",
329
+ # trash: firestore.field_delete }
330
+ #
331
+ # bw.update(nyc_ref, nyc_data)
332
+ #
333
+ # @example Update a document and set a field to server_time:
334
+ # require "google/cloud/firestore"
335
+ #
336
+ # firestore = Google::Cloud::Firestore.new
337
+ # bw = firestore.bulk_writer
338
+ #
339
+ # # Get a document reference
340
+ # nyc_ref = firestore.doc "cities/NYC"
341
+ #
342
+ # nyc_data = { name: "New York City",
343
+ # updated_at: firestore.field_server_time }
344
+ #
345
+ # bw.update(nyc_ref, nyc_data)
346
+ #
347
+ # @example Get the value of write operation:
348
+ # require "google/cloud/firestore"
349
+ #
350
+ # firestore = Google::Cloud::Firestore.new
351
+ # bw = firestore.bulk_writer
352
+ #
353
+ # # Get a document reference
354
+ # nyc_ref = firestore.doc "cities/NYC"
355
+ #
356
+ # nyc_data = { name: "New York City",
357
+ # updated_at: firestore.field_server_time }
358
+ #
359
+ # result = bw.update(nyc_ref, nyc_data)
360
+ #
361
+ # bw.close
362
+ #
363
+ # puts result.value
364
+ #
365
+ def update doc, data, update_time: nil
366
+ doc_path = coalesce_doc_path_argument doc
367
+ pre_add_operation doc_path
368
+
369
+ write = Convert.write_for_update doc_path, data, update_time: update_time
370
+
371
+ create_and_enqueue_operation write
372
+ end
373
+
374
+ ##
375
+ # Deletes a document from the database.
376
+ #
377
+ # @param [String, DocumentReference] doc A string representing the
378
+ # path of the document, or a document reference object.
379
+ # @param [Boolean] exists Whether the document must exist. When `true`,
380
+ # the document must exist or an error is raised. Default is `false`.
381
+ # Optional.
382
+ # @param [Time] update_time When set, the document must have been last
383
+ # updated at that time. Optional.
384
+ #
385
+ # @return [Google::Cloud::Firestore::Promise::Future] Denoting the future value of
386
+ # write operation.
387
+ #
388
+ # @example Delete a document using a document path:
389
+ # require "google/cloud/firestore"
390
+ #
391
+ # firestore = Google::Cloud::Firestore.new
392
+ # bw = firestore.bulk_writer
393
+ #
394
+ # # Delete a document
395
+ # bw.delete "cities/NYC"
396
+ #
397
+ # @example Delete a document using a document reference:
398
+ # require "google/cloud/firestore"
399
+ #
400
+ # firestore = Google::Cloud::Firestore.new
401
+ # bw = firestore.bulk_writer
402
+ #
403
+ # # Get a document reference
404
+ # nyc_ref = firestore.doc "cities/NYC"
405
+ #
406
+ # # Delete a document
407
+ # bw.delete nyc_ref
408
+ #
409
+ # @example Delete a document using `exists`:
410
+ # require "google/cloud/firestore"
411
+ #
412
+ # firestore = Google::Cloud::Firestore.new
413
+ # bw = firestore.bulk_writer
414
+ #
415
+ # # Delete a document
416
+ # bw.delete "cities/NYC", exists: true
417
+ #
418
+ # @example Delete a document using the `update_time` precondition:
419
+ # require "google/cloud/firestore"
420
+ #
421
+ # firestore = Google::Cloud::Firestore.new
422
+ # bw = firestore.bulk_writer
423
+ #
424
+ # last_updated_at = Time.now - 42 # 42 seconds ago
425
+ #
426
+ # # Delete a document
427
+ # bw.delete "cities/NYC", update_time: last_updated_at
428
+ #
429
+ # @example Get the value of write operation:
430
+ # require "google/cloud/firestore"
431
+ #
432
+ # firestore = Google::Cloud::Firestore.new
433
+ # bw = firestore.bulk_writer
434
+ #
435
+ # last_updated_at = Time.now - 42 # 42 seconds ago
436
+ #
437
+ # # Delete a document
438
+ # result = bw.delete "cities/NYC", update_time: last_updated_at
439
+ #
440
+ # bw.close
441
+ #
442
+ # puts result.value
443
+ #
444
+ def delete doc, exists: nil, update_time: nil
445
+ doc_path = coalesce_doc_path_argument doc
446
+ pre_add_operation doc_path
447
+
448
+ write = Convert.write_for_delete doc_path, exists: exists, update_time: update_time
449
+
450
+ create_and_enqueue_operation write
451
+ end
452
+
453
+ ##
454
+ # Flushes all the current operation before enqueuing new operations.
455
+ #
456
+ # @return [nil]
457
+ def flush
458
+ @mutex.synchronize { @flush = true }
459
+ @request_results.each do |result|
460
+ begin
461
+ result.wait!
462
+ rescue StandardError
463
+ # Ignored
464
+ end
465
+ end
466
+ @mutex.synchronize do
467
+ @doc_refs = Set.new
468
+ @flush = false
469
+ end
470
+ end
471
+
472
+ ##
473
+ # Closes the BulkWriter object for new operations.
474
+ # Existing operations will be flushed and the threadpool will shutdown.
475
+ #
476
+ # @return [nil]
477
+ def close
478
+ @mutex.synchronize { @closed = true }
479
+ flush
480
+ @mutex.synchronize do
481
+ @write_thread_pool.shutdown
482
+ @scheduler.close
483
+ end
484
+ end
485
+
486
+ private
487
+
488
+ ##
489
+ # @private The client the Cloud Firestore BulkWriter belongs to.
490
+ #
491
+ # @return [Client] firestore client.
492
+ def firestore
493
+ @client
494
+ end
495
+ alias client firestore
496
+
497
+ ##
498
+ # @private Checks if the BulkWriter is accepting write requests
499
+ def accepting_request?
500
+ unless @closed || @flush
501
+ return true
502
+ end
503
+ false
504
+ end
505
+
506
+ ##
507
+ # @private Sanity checks before adding a write request in the BulkWriter
508
+ def pre_add_operation doc_path
509
+ @mutex.synchronize do
510
+ unless accepting_request?
511
+ raise BulkWriterError, "Not accepting responses for now. Either closed or in flush state"
512
+ end
513
+ if @doc_refs.include? doc_path
514
+ raise BulkWriterError, "Already contains mutations for this document"
515
+ end
516
+ @doc_refs.add doc_path
517
+ end
518
+ end
519
+
520
+ ##
521
+ # @private Creates a BulkWriterOperation
522
+ #
523
+ def create_operation write
524
+ BulkWriterOperation.new write, @retries
525
+ end
526
+
527
+ ##
528
+ # @private Adds a BulkWriterOperation to the scheduler.
529
+ def enqueue_operation operation
530
+ @mutex.synchronize { @scheduler.add_operation operation }
531
+ end
532
+
533
+ ##
534
+ # @private Creates a BulkWriterOperation and adds it in the scheduler.
535
+ #
536
+ def create_and_enqueue_operation write
537
+ operation = create_operation write
538
+ enqueue_operation operation
539
+ future = Concurrent::Promises.future_on @write_thread_pool, operation do |bulk_writer_operation|
540
+ bulk_writer_operation.completion_event.wait
541
+ raise bulk_writer_operation.result if bulk_writer_operation.result.is_a? BulkWriterException
542
+ bulk_writer_operation.result
543
+ end
544
+ @mutex.synchronize { @request_results << future }
545
+ Promise::Future.new future
546
+ end
547
+
548
+ ##
549
+ # @private
550
+ def coalesce_doc_path_argument doc_path
551
+ return doc_path.path if doc_path.respond_to? :path
552
+
553
+ client.doc(doc_path).path
554
+ end
555
+ end
556
+ end
557
+ end
558
+ end
@@ -0,0 +1,40 @@
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
+ # # BulkWriterException
21
+ #
22
+ # A BulkWriterException object refers to the error that will be thrown
23
+ # in case a BulkWriterOperation fails in all the attempts.
24
+ #
25
+ class BulkWriterException < StandardError
26
+ attr_reader :status
27
+ attr_reader :message
28
+ attr_reader :details
29
+
30
+ def initialize status
31
+ @status = status.code
32
+ @message = status.message
33
+ @details = status.details
34
+
35
+ super status.message
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end