DocumentReference+ReadDecodable.swift 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. #if SWIFT_PACKAGE
  18. @_exported import FirebaseFirestoreInternalWrapper
  19. #else
  20. @_exported import FirebaseFirestoreInternal
  21. #endif // SWIFT_PACKAGE
  22. public extension DocumentReference {
  23. /// Fetches and decodes the document referenced by this `DocumentReference`.
  24. ///
  25. /// This allows users to retrieve a Firestore document and have it decoded to
  26. /// an instance of caller-specified type as follows:
  27. /// ```swift
  28. /// ref.getDocument(as: Book.self) { result in
  29. /// do {
  30. /// let book = try result.get()
  31. /// } catch {
  32. /// // Handle error
  33. /// }
  34. /// }
  35. /// ```
  36. ///
  37. /// This method attempts to provide up-to-date data when possible by waiting
  38. /// for data from the server, but it may return cached data or fail if you are
  39. /// offline and the server cannot be reached. If `T` denotes an optional
  40. /// type, the method returns a successful status with a value of `nil` for
  41. /// non-existing documents.
  42. ///
  43. /// - Parameters:
  44. /// - as: A `Decodable` type to convert the document fields to.
  45. /// - serverTimestampBehavior: Configures how server timestamps that have
  46. /// not yet been set to their final value are returned from the snapshot.
  47. /// - decoder: The decoder to use to convert the document. Defaults to use
  48. /// the default decoder.
  49. /// - source: Indicates whether the results should be fetched from the cache only
  50. /// (`Source.cache`), the server only (`Source.server`), or to attempt the
  51. /// server and fall back to the cache (`Source.default`).
  52. /// - completion: The closure to call when the document snapshot has been
  53. /// fetched and decoded.
  54. func getDocument<T: Decodable>(as type: T.Type,
  55. with serverTimestampBehavior: ServerTimestampBehavior =
  56. .none,
  57. decoder: Firestore.Decoder = .init(),
  58. source: FirestoreSource = .default,
  59. completion: @escaping (Result<T, Error>) -> Void) {
  60. getDocument(source: source) { snapshot, error in
  61. guard let snapshot = snapshot else {
  62. /**
  63. * Force unwrapping here is fine since this logic corresponds to the auto-synthesized
  64. * async/await wrappers for Objective-C functions with callbacks taking an object and an error
  65. * parameter. The API should (and does) guarantee that either object or error is set, but never both.
  66. * For more details see:
  67. * https://github.com/firebase/firebase-ios-sdk/pull/9101#discussion_r809117034
  68. */
  69. completion(.failure(error!))
  70. return
  71. }
  72. let result = Result {
  73. try snapshot.data(as: T.self,
  74. with: serverTimestampBehavior,
  75. decoder: decoder)
  76. }
  77. completion(result)
  78. }
  79. }
  80. /// Fetches and decodes the document referenced by this `DocumentReference`.
  81. ///
  82. /// This allows users to retrieve a Firestore document and have it decoded
  83. /// to an instance of caller-specified type as follows:
  84. /// ```swift
  85. /// do {
  86. /// let book = try await ref.getDocument(as: Book.self)
  87. /// } catch {
  88. /// // Handle error
  89. /// }
  90. /// ```
  91. ///
  92. /// This method attempts to provide up-to-date data when possible by waiting
  93. /// for data from the server, but it may return cached data or fail if you
  94. /// are offline and the server cannot be reached. If `T` denotes
  95. /// an optional type, the method returns a successful status with a value
  96. /// of `nil` for non-existing documents.
  97. ///
  98. /// - Parameters:
  99. /// - as: A `Decodable` type to convert the document fields to.
  100. /// - serverTimestampBehavior: Configures how server timestamps that have
  101. /// not yet been set to their final value are returned from the
  102. /// snapshot.
  103. /// - decoder: The decoder to use to convert the document. Defaults to use
  104. /// the default decoder.
  105. /// - source: Indicates whether the results should be fetched from the cache only
  106. /// (`Source.cache`), the server only (`Source.server`), or to attempt the
  107. /// server and fall back to the cache (`Source.default`).
  108. /// - Returns: This instance of the supplied `Decodable` type `T`.
  109. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  110. func getDocument<T: Decodable>(as type: T.Type,
  111. with serverTimestampBehavior: ServerTimestampBehavior =
  112. .none,
  113. decoder: Firestore.Decoder = .init(),
  114. source: FirestoreSource = .default) async throws -> T {
  115. let snapshot = try await getDocument(source: source)
  116. return try snapshot.data(as: T.self,
  117. with: serverTimestampBehavior,
  118. decoder: decoder)
  119. }
  120. }