DocumentReference+ReadDecodable.swift 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /*
  2. * Copyright 2021 Google LLC
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import Foundation
  17. import FirebaseFirestore
  18. public extension DocumentReference {
  19. /// Fetches and decodes the document referenced by this `DocumentReference`.
  20. ///
  21. /// This allows users to retrieve a Firestore document and have it decoded to
  22. /// an instance of caller-specified type as follows:
  23. /// ```swift
  24. /// ref.getDocument(as: Book.self) { result in
  25. /// do {
  26. /// let book = try result.get()
  27. /// } catch {
  28. /// // Handle error
  29. /// }
  30. /// }
  31. /// ```
  32. ///
  33. /// This method attempts to provide up-to-date data when possible by waiting
  34. /// for data from the server, but it may return cached data or fail if you are
  35. /// offline and the server cannot be reached. If `T` denotes an optional
  36. /// type, the method returns a successful status with a value of `nil` for
  37. /// non-existing documents.
  38. ///
  39. /// - Parameters:
  40. /// - as: A `Decodable` type to convert the document fields to.
  41. /// - serverTimestampBehavior: Configures how server timestamps that have
  42. /// not yet been set to their final value are returned from the snapshot.
  43. /// - decoder: The decoder to use to convert the document. Defaults to use
  44. /// the default decoder.
  45. /// - completion: The closure to call when the document snapshot has been
  46. /// fetched and decoded.
  47. func getDocument<T: Decodable>(as type: T.Type,
  48. with serverTimestampBehavior: ServerTimestampBehavior =
  49. .none,
  50. decoder: Firestore.Decoder = .init(),
  51. completion: @escaping (Result<T, Error>) -> Void) {
  52. getDocument { snapshot, error in
  53. guard let snapshot = snapshot else {
  54. /**
  55. * Force unwrapping here is fine since this logic corresponds to the auto-synthesized
  56. * async/await wrappers for Objective-C functions with callbacks taking an object and an error
  57. * parameter. The API should (and does) guarantee that either object or error is set, but never both.
  58. * For more details see:
  59. * https://github.com/firebase/firebase-ios-sdk/pull/9101#discussion_r809117034
  60. */
  61. completion(.failure(error!))
  62. return
  63. }
  64. let result = Result {
  65. try snapshot.data(as: T.self,
  66. with: serverTimestampBehavior,
  67. decoder: decoder)
  68. }
  69. completion(result)
  70. }
  71. }
  72. #if compiler(>=5.5.2) && canImport(_Concurrency)
  73. /// Fetches and decodes the document referenced by this `DocumentReference`.
  74. ///
  75. /// This allows users to retrieve a Firestore document and have it decoded
  76. /// to an instance of caller-specified type as follows:
  77. /// ```swift
  78. /// do {
  79. /// let book = try await ref.getDocument(as: Book.self)
  80. /// } catch {
  81. /// // Handle error
  82. /// }
  83. /// ```
  84. ///
  85. /// This method attempts to provide up-to-date data when possible by waiting
  86. /// for data from the server, but it may return cached data or fail if you
  87. /// are offline and the server cannot be reached. If `T` denotes
  88. /// an optional type, the method returns a successful status with a value
  89. /// of `nil` for non-existing documents.
  90. ///
  91. /// - Parameters:
  92. /// - as: A `Decodable` type to convert the document fields to.
  93. /// - serverTimestampBehavior: Configures how server timestamps that have
  94. /// not yet been set to their final value are returned from the
  95. /// snapshot.
  96. /// - decoder: The decoder to use to convert the document. Defaults to use
  97. /// the default decoder.
  98. /// - Returns: This instance of the supplied `Decodable` type `T`.
  99. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  100. func getDocument<T: Decodable>(as type: T.Type,
  101. with serverTimestampBehavior: ServerTimestampBehavior =
  102. .none,
  103. decoder: Firestore.Decoder = .init()) async throws -> T {
  104. let snapshot = try await getDocument()
  105. return try snapshot.data(as: T.self,
  106. with: serverTimestampBehavior,
  107. decoder: decoder)
  108. }
  109. #endif
  110. }