google-cloud-firestore 2.4.0 → 2.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,7 +24,12 @@ module Google
24
24
  ##
25
25
  # @private Helper module for converting Protobuf values.
26
26
  module Convert
27
- # rubocop:disable all
27
+ # rubocop:disable Metrics/AbcSize
28
+ # rubocop:disable Metrics/BlockLength
29
+ # rubocop:disable Metrics/CyclomaticComplexity
30
+ # rubocop:disable Metrics/MethodLength
31
+ # rubocop:disable Metrics/ModuleLength
32
+ # rubocop:disable Metrics/PerceivedComplexity
28
33
  module ClassMethods
29
34
  def time_to_timestamp time
30
35
  return nil if time.nil?
@@ -32,9 +37,10 @@ module Google
32
37
  # Force the object to be a Time object.
33
38
  time = time.to_time
34
39
 
35
- Google::Protobuf::Timestamp.new \
40
+ Google::Protobuf::Timestamp.new(
36
41
  seconds: time.to_i,
37
- nanos: time.nsec
42
+ nanos: time.nsec
43
+ )
38
44
  end
39
45
 
40
46
  def timestamp_to_time timestamp
@@ -100,9 +106,10 @@ module Google
100
106
  elsif Google::Cloud::Firestore::DocumentReference === obj
101
107
  Google::Cloud::Firestore::V1::Value.new reference_value: obj.path
102
108
  elsif Array === obj
103
- values = obj.map { |o| raw_to_value(o) }
104
- Google::Cloud::Firestore::V1::Value.new(array_value:
105
- Google::Cloud::Firestore::V1::ArrayValue.new(values: values))
109
+ values = obj.map { |o| raw_to_value o }
110
+ Google::Cloud::Firestore::V1::Value.new(
111
+ array_value: Google::Cloud::Firestore::V1::ArrayValue.new(values: values)
112
+ )
106
113
  elsif Hash === obj
107
114
  # keys have been changed to strings before the hash gets here
108
115
  geo_pairs = hash_is_geo_point? obj
@@ -112,8 +119,9 @@ module Google
112
119
  )
113
120
  else
114
121
  fields = hash_to_fields obj
115
- Google::Cloud::Firestore::V1::Value.new(map_value:
116
- Google::Cloud::Firestore::V1::MapValue.new(fields: fields))
122
+ Google::Cloud::Firestore::V1::Value.new(
123
+ map_value: Google::Cloud::Firestore::V1::MapValue.new(fields: fields)
124
+ )
117
125
  end
118
126
  elsif obj.respond_to?(:read) && obj.respond_to?(:rewind)
119
127
  obj.rewind
@@ -129,9 +137,7 @@ module Google
129
137
  return false unless hash.keys.count == 2
130
138
 
131
139
  pairs = hash.map { |k, v| [String(k), v] }.sort
132
- if pairs.map(&:first) == ["latitude", "longitude"]
133
- pairs
134
- end
140
+ pairs if pairs.map(&:first) == ["latitude", "longitude"]
135
141
  end
136
142
 
137
143
  def hash_to_geo_point hash, pairs = nil
@@ -140,47 +146,39 @@ module Google
140
146
  raise ArgumentError, "value is not a geo point" unless pairs
141
147
 
142
148
  Google::Type::LatLng.new(
143
- latitude: pairs.first.last,
144
- longitude: pairs.last.last,
149
+ latitude: pairs.first.last,
150
+ longitude: pairs.last.last
145
151
  )
146
152
  end
147
153
 
148
- def writes_for_create doc_path, data
149
- writes = []
150
-
151
- if is_field_value_nested data, :delete
154
+ def write_for_create doc_path, data
155
+ if field_value_nested? data, :delete
152
156
  raise ArgumentError, "DELETE not allowed on create"
153
157
  end
154
158
  raise ArgumentError, "data is required" unless data.is_a? Hash
155
159
 
156
160
  data, field_paths_and_values = remove_field_value_from data
157
161
 
158
- if data.any? || field_paths_and_values.empty?
159
- write = Google::Cloud::Firestore::V1::Write.new(
160
- update: Google::Cloud::Firestore::V1::Document.new(
161
- name: doc_path,
162
- fields: hash_to_fields(data)),
163
- current_document: Google::Cloud::Firestore::V1::Precondition.new(
164
- exists: false)
165
- )
166
- writes << write
167
- end
168
-
169
- if field_paths_and_values.any?
170
- transform_write = transform_write doc_path, field_paths_and_values
171
-
172
- if data.empty?
173
- transform_write.current_document = \
174
- Google::Cloud::Firestore::V1::Precondition.new(exists: false)
175
- end
176
-
177
- writes << transform_write
178
- end
162
+ doc = Google::Cloud::Firestore::V1::Document.new(
163
+ name: doc_path,
164
+ fields: hash_to_fields(data)
165
+ )
166
+ precondition = Google::Cloud::Firestore::V1::Precondition.new exists: false
167
+ Google::Cloud::Firestore::V1::Write.new(
168
+ update: doc,
169
+ current_document: precondition,
170
+ update_transforms: field_transforms(field_paths_and_values)
171
+ )
172
+ end
179
173
 
180
- writes
174
+ def field_transforms paths
175
+ return nil if paths.empty?
176
+ paths.map do |field_path, field_value|
177
+ to_field_transform field_path, field_value
178
+ end.to_a
181
179
  end
182
180
 
183
- def writes_for_set doc_path, data, merge: nil
181
+ def write_for_set doc_path, data, merge: nil
184
182
  raise ArgumentError, "data is required" unless data.is_a? Hash
185
183
 
186
184
  if merge
@@ -195,11 +193,9 @@ module Google
195
193
  end
196
194
  allow_empty = false
197
195
  end
198
- return writes_for_set_merge doc_path, data, field_paths, allow_empty
196
+ return write_for_set_merge doc_path, data, field_paths, allow_empty
199
197
  end
200
198
 
201
- writes = []
202
-
203
199
  data, delete_paths = remove_field_value_from data, :delete
204
200
  if delete_paths.any?
205
201
  raise ArgumentError, "DELETE not allowed on set"
@@ -207,30 +203,25 @@ module Google
207
203
 
208
204
  data, field_paths_and_values = remove_field_value_from data
209
205
 
210
- writes << Google::Cloud::Firestore::V1::Write.new(
211
- update: Google::Cloud::Firestore::V1::Document.new(
212
- name: doc_path,
213
- fields: hash_to_fields(data))
206
+ doc = Google::Cloud::Firestore::V1::Document.new(
207
+ name: doc_path,
208
+ fields: hash_to_fields(data)
209
+ )
210
+ Google::Cloud::Firestore::V1::Write.new(
211
+ update: doc,
212
+ update_transforms: field_transforms(field_paths_and_values)
214
213
  )
215
-
216
- if field_paths_and_values.any?
217
- writes << transform_write(doc_path, field_paths_and_values)
218
- end
219
-
220
- writes
221
214
  end
222
215
 
223
- def writes_for_set_merge doc_path, data, field_paths, allow_empty
216
+ def write_for_set_merge doc_path, data, field_paths, allow_empty
224
217
  raise ArgumentError, "data is required" unless data.is_a? Hash
225
218
 
226
219
  validate_field_paths! field_paths
227
220
 
228
- writes = []
229
-
230
221
  # Ensure provided field paths are valid.
231
222
  all_valid = identify_leaf_nodes data
232
223
  all_valid_check = field_paths.map do |verify_path|
233
- if all_valid.include?(verify_path)
224
+ if all_valid.include? verify_path
234
225
  true
235
226
  else
236
227
  found_in_all_valid = all_valid.select do |fp|
@@ -271,32 +262,25 @@ module Google
271
262
  # Restore delete paths
272
263
  field_paths += delete_field_paths_and_values.keys
273
264
 
274
- if data.empty? && !allow_empty
275
- if field_paths_and_values.empty? && delete_field_paths_and_values.empty?
276
- raise ArgumentError, "data required for set with merge"
277
- end
265
+ if data.empty? && !allow_empty && field_paths_and_values.empty? && delete_field_paths_and_values.empty?
266
+ raise ArgumentError, "data required for set with merge"
278
267
  end
279
268
 
280
- if data.any? || field_paths.any? || (allow_empty && field_paths_and_values.empty?)
281
- writes << Google::Cloud::Firestore::V1::Write.new(
282
- update: Google::Cloud::Firestore::V1::Document.new(
283
- name: doc_path,
284
- fields: hash_to_fields(data)),
285
- update_mask: Google::Cloud::Firestore::V1::DocumentMask.new(
286
- field_paths: field_paths.map(&:formatted_string).sort)
287
- )
288
- end
289
-
290
- if field_paths_and_values.any?
291
- writes << transform_write(doc_path, field_paths_and_values)
292
- end
293
-
294
- writes
269
+ doc = Google::Cloud::Firestore::V1::Document.new(
270
+ name: doc_path,
271
+ fields: hash_to_fields(data)
272
+ )
273
+ doc_mask = Google::Cloud::Firestore::V1::DocumentMask.new(
274
+ field_paths: field_paths.map(&:formatted_string).sort
275
+ )
276
+ Google::Cloud::Firestore::V1::Write.new(
277
+ update: doc,
278
+ update_mask: doc_mask,
279
+ update_transforms: field_transforms(field_paths_and_values)
280
+ )
295
281
  end
296
282
 
297
- def writes_for_update doc_path, data, update_time: nil
298
- writes = []
299
-
283
+ def write_for_update doc_path, data, update_time: nil
300
284
  raise ArgumentError, "data is required" unless data.is_a? Hash
301
285
 
302
286
  # Convert data to use FieldPath
@@ -308,11 +292,11 @@ module Google
308
292
  # Duplicate field paths check
309
293
  validate_field_paths! new_data_pairs.map(&:first)
310
294
 
311
- delete_paths, new_data_pairs = new_data_pairs.partition do |field_path, value|
295
+ delete_paths, new_data_pairs = new_data_pairs.partition do |_field_path, value|
312
296
  value.is_a?(FieldValue) && value.type == :delete
313
297
  end
314
298
 
315
- root_field_paths_and_values, new_data_pairs = new_data_pairs.partition do |field_path, value|
299
+ root_field_paths_and_values, new_data_pairs = new_data_pairs.partition do |_field_path, value|
316
300
  value.is_a? FieldValue
317
301
  end
318
302
 
@@ -325,7 +309,7 @@ module Google
325
309
  data, nested_deletes = remove_field_value_from data, :delete
326
310
  raise ArgumentError, "DELETE cannot be nested" if nested_deletes.any?
327
311
 
328
- data, nested_field_paths_and_values = remove_field_value_from data
312
+ data, nested_field_paths_and_values = remove_field_value_from data
329
313
 
330
314
  field_paths_and_values = root_field_paths_and_values.merge nested_field_paths_and_values
331
315
 
@@ -338,34 +322,31 @@ module Google
338
322
  raise ArgumentError, "data is required"
339
323
  end
340
324
 
325
+ write = Google::Cloud::Firestore::V1::Write.new(
326
+ update: Google::Cloud::Firestore::V1::Document.new(name: doc_path),
327
+ update_mask: Google::Cloud::Firestore::V1::DocumentMask.new,
328
+ current_document: Google::Cloud::Firestore::V1::Precondition.new(exists: true)
329
+ )
330
+
341
331
  if data.any? || delete_paths.any?
342
- write = Google::Cloud::Firestore::V1::Write.new(
343
- update: Google::Cloud::Firestore::V1::Document.new(
344
- name: doc_path,
345
- fields: hash_to_fields(data)),
346
- update_mask: Google::Cloud::Firestore::V1::DocumentMask.new(
347
- field_paths: (field_paths).map(&:formatted_string).sort),
348
- current_document: Google::Cloud::Firestore::V1::Precondition.new(
349
- exists: true)
350
- )
332
+ htf = hash_to_fields data
333
+ htf.each_pair do |k, v|
334
+ write.update.fields[k] = v
335
+ end
336
+ write.update_mask.field_paths += field_paths.map(&:formatted_string).sort
337
+
351
338
  if update_time
352
- write.current_document = \
353
- Google::Cloud::Firestore::V1::Precondition.new(
354
- update_time: time_to_timestamp(update_time))
339
+ write.current_document = Google::Cloud::Firestore::V1::Precondition.new(
340
+ update_time: time_to_timestamp(update_time)
341
+ )
355
342
  end
356
- writes << write
357
343
  end
358
344
 
359
345
  if field_paths_and_values.any?
360
- transform_write = transform_write doc_path, field_paths_and_values
361
- if data.empty?
362
- transform_write.current_document = \
363
- Google::Cloud::Firestore::V1::Precondition.new(exists: true)
364
- end
365
- writes << transform_write
346
+ write.update_transforms += field_transforms field_paths_and_values
366
347
  end
367
348
 
368
- writes
349
+ write
369
350
  end
370
351
 
371
352
  def write_for_delete doc_path, exists: nil, update_time: nil
@@ -387,13 +368,20 @@ module Google
387
368
  write
388
369
  end
389
370
 
390
- def is_field_value_nested obj, field_value_type = nil
371
+ def field_value_nested? obj, field_value_type = nil
391
372
  return obj if obj.is_a?(FieldValue) && (field_value_type.nil? || obj.type == field_value_type)
392
373
 
393
- if obj.is_a? Array
394
- obj.each { |o| val = is_field_value_nested o, field_value_type; return val if val }
395
- elsif obj.is_a? Hash
396
- obj.each { |_k, v| val = is_field_value_nested v, field_value_type; return val if val }
374
+ case obj
375
+ when Array
376
+ obj.each do |o|
377
+ val = field_value_nested? o, field_value_type
378
+ return val if val
379
+ end
380
+ when Hash
381
+ obj.each do |_k, v|
382
+ val = field_value_nested? v, field_value_type
383
+ return val if val
384
+ end
397
385
  end
398
386
  nil
399
387
  end
@@ -406,35 +394,33 @@ module Google
406
394
  if value.is_a?(FieldValue) && (field_value_type.nil? || value.type == field_value_type)
407
395
  paths << [FieldPath.new(*key), value]
408
396
  nil # will be removed by calling compact
409
- else
410
- if value.is_a? Hash
411
- unless value.empty?
412
- nested_hash, nested_paths = remove_field_value_from value, field_value_type
413
- if nested_paths.any?
414
- nested_paths.each do |nested_field_path, nested_field_value|
415
- updated_field_paths = ([key] + nested_field_path.fields).flatten
416
- updated_field_path = FieldPath.new *updated_field_paths
417
- paths << [updated_field_path, nested_field_value]
418
- end
419
- end
420
- if nested_hash.empty?
421
- nil # will be removed by calling compact
422
- else
423
- [String(key), nested_hash]
397
+ elsif value.is_a? Hash
398
+ if value.empty?
399
+ [String(key), value]
400
+ else
401
+ nested_hash, nested_paths = remove_field_value_from value, field_value_type
402
+ if nested_paths.any?
403
+ nested_paths.each do |nested_field_path, nested_field_value|
404
+ updated_field_paths = ([key] + nested_field_path.fields).flatten
405
+ updated_field_path = FieldPath.new(*updated_field_paths)
406
+ paths << [updated_field_path, nested_field_value]
424
407
  end
408
+ end
409
+ if nested_hash.empty?
410
+ nil # will be removed by calling compact
425
411
  else
426
- [String(key), value]
412
+ [String(key), nested_hash]
427
413
  end
428
- else
429
- if value.is_a? Array
430
- nested_field_value = is_field_value_nested value, field_value_type
431
- if nested_field_value
432
- raise ArgumentError, "cannot nest #{nested_field_value.type} under arrays"
433
- end
414
+ end
415
+ else
416
+ if value.is_a? Array
417
+ nested_field_value = field_value_nested? value, field_value_type
418
+ if nested_field_value
419
+ raise ArgumentError, "cannot nest #{nested_field_value.type} under arrays"
434
420
  end
435
-
436
- [String(key), value]
437
421
  end
422
+
423
+ [String(key), value]
438
424
  end
439
425
  end
440
426
 
@@ -449,14 +435,14 @@ module Google
449
435
  if value.is_a? Hash
450
436
  nested_paths = identify_leaf_nodes value
451
437
  nested_paths.each do |nested_path|
452
- paths << (([key] + nested_path.fields).flatten)
438
+ paths << ([key] + nested_path.fields).flatten
453
439
  end
454
440
  else
455
441
  paths << [key]
456
442
  end
457
443
  end
458
444
 
459
- paths.map { |path| FieldPath.new *path }
445
+ paths.map { |path| FieldPath.new(*path) }
460
446
  end
461
447
 
462
448
  def identify_all_file_paths hash
@@ -465,15 +451,14 @@ module Google
465
451
  hash.map do |key, value|
466
452
  paths << [key]
467
453
 
468
- if value.is_a? Hash
469
- nested_paths = identify_all_file_paths value
470
- nested_paths.each do |nested_path|
471
- paths << (([key] + nested_path.fields).flatten)
472
- end
454
+ next unless value.is_a? Hash
455
+ nested_paths = identify_all_file_paths value
456
+ nested_paths.each do |nested_path|
457
+ paths << ([key] + nested_path.fields).flatten
473
458
  end
474
459
  end
475
460
 
476
- paths.map { |path| FieldPath.new *path }
461
+ paths.map { |path| FieldPath.new(*path) }
477
462
  end
478
463
 
479
464
  def select_by_field_paths hash, field_paths
@@ -533,19 +518,19 @@ module Google
533
518
  right_hash.each_pair do |key, right_value|
534
519
  left_value = left_hash[key]
535
520
 
536
- if left_value.is_a?(Hash) && right_value.is_a?(Hash)
537
- left_hash[key] = deep_merge_hashes left_value, right_value
538
- else
539
- left_hash[key] = right_value
540
- end
521
+ left_hash[key] = if left_value.is_a?(Hash) && right_value.is_a?(Hash)
522
+ deep_merge_hashes left_value, right_value
523
+ else
524
+ right_value
525
+ end
541
526
  end
542
527
 
543
528
  left_hash
544
529
  end
545
530
 
546
- START_FIELD_PATH_CHARS = /\A[a-zA-Z_]/
547
- INVALID_FIELD_PATH_CHARS = /[\~\*\/\[\]]/
548
- ESCAPED_FIELD_PATH = /\A\`(.*)\`\z/
531
+ START_FIELD_PATH_CHARS = /\A[a-zA-Z_]/.freeze
532
+ INVALID_FIELD_PATH_CHARS = %r{[~*/\[\]]}.freeze
533
+ ESCAPED_FIELD_PATH = /\A`(.*)`\z/.freeze
549
534
 
550
535
  def build_hash_from_field_paths_and_values pairs
551
536
  pairs.each do |field_path, _value|
@@ -579,59 +564,52 @@ module Google
579
564
  "`#{str}`"
580
565
  end
581
566
 
582
- def transform_write doc_path, paths
583
- field_transforms = paths.map do |field_path, field_value|
584
- to_field_transform field_path, field_value
585
- end
586
-
587
- Google::Cloud::Firestore::V1::Write.new(
588
- transform: Google::Cloud::Firestore::V1::DocumentTransform.new(
589
- document: doc_path,
590
- field_transforms: field_transforms
591
- )
592
- )
593
- end
594
-
595
567
  def to_field_transform field_path, field_value
596
- if field_value.type == :server_time
568
+ case field_value.type
569
+ when :server_time
597
570
  Google::Cloud::Firestore::V1::DocumentTransform::FieldTransform.new(
598
- field_path: field_path.formatted_string,
571
+ field_path: field_path.formatted_string,
599
572
  set_to_server_value: :REQUEST_TIME
600
573
  )
601
- elsif field_value.type == :array_union
574
+ when :array_union
602
575
  Google::Cloud::Firestore::V1::DocumentTransform::FieldTransform.new(
603
- field_path: field_path.formatted_string,
576
+ field_path: field_path.formatted_string,
604
577
  append_missing_elements: raw_to_value(Array(field_value.value)).array_value
605
578
  )
606
- elsif field_value.type == :array_delete
579
+ when :array_delete
607
580
  Google::Cloud::Firestore::V1::DocumentTransform::FieldTransform.new(
608
- field_path: field_path.formatted_string,
581
+ field_path: field_path.formatted_string,
609
582
  remove_all_from_array: raw_to_value(Array(field_value.value)).array_value
610
583
  )
611
- elsif field_value.type == :increment
584
+ when :increment
612
585
  Google::Cloud::Firestore::V1::DocumentTransform::FieldTransform.new(
613
586
  field_path: field_path.formatted_string,
614
- increment: raw_to_value(field_value.value)
587
+ increment: raw_to_value(field_value.value)
615
588
  )
616
- elsif field_value.type == :maximum
589
+ when :maximum
617
590
  Google::Cloud::Firestore::V1::DocumentTransform::FieldTransform.new(
618
591
  field_path: field_path.formatted_string,
619
- maximum: raw_to_value(field_value.value)
592
+ maximum: raw_to_value(field_value.value)
620
593
  )
621
- elsif field_value.type == :minimum
594
+ when :minimum
622
595
  Google::Cloud::Firestore::V1::DocumentTransform::FieldTransform.new(
623
596
  field_path: field_path.formatted_string,
624
- minimum: raw_to_value(field_value.value)
597
+ minimum: raw_to_value(field_value.value)
625
598
  )
626
599
  else
627
600
  raise ArgumentError, "unknown field transform #{field_value.type}"
628
601
  end
629
602
  end
630
603
  end
631
- # rubocop:enable all
632
604
 
633
605
  extend ClassMethods
634
606
  end
607
+ # rubocop:enable Metrics/AbcSize
608
+ # rubocop:enable Metrics/BlockLength
609
+ # rubocop:enable Metrics/CyclomaticComplexity
610
+ # rubocop:enable Metrics/MethodLength
611
+ # rubocop:enable Metrics/ModuleLength
612
+ # rubocop:enable Metrics/PerceivedComplexity
635
613
  end
636
614
  end
637
615
  end