google-cloud-firestore 2.11.0 → 2.13.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: 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