@@ -53,5 +53,50 @@ import Foundation
53
53
}
54
54
}
55
55
}
56
+
57
+ /// Executes the given updateBlock and then attempts to commit the changes applied within an atomic
58
+ /// transaction.
59
+ ///
60
+ /// The maximum number of writes allowed in a single transaction is 500, but note that each usage of
61
+ /// `FieldValue.serverTimestamp()`, `FieldValue.arrayUnion()`, `FieldValue.arrayRemove()`, or
62
+ /// `FieldValue.increment()` inside a transaction counts as an additional write.
63
+ ///
64
+ /// In the `updateBlock`, a set of reads and writes can be performed atomically using the
65
+ /// `Transaction` object passed to the block. After the `updateBlock` is run, Firestore will attempt
66
+ /// to apply the changes to the server. If any of the data read has been modified outside of this
67
+ /// transaction since being read, then the transaction will be retried by executing the `updateBlock`
68
+ /// again. If the transaction still fails after 5 retries, then the transaction will fail.
69
+ ///
70
+ /// Since the `updateBlock` may be executed multiple times, it should avoiding doing anything that
71
+ /// would cause side effects.
72
+ ///
73
+ /// Any value maybe be returned from the `updateBlock`. If the transaction is successfully committed,
74
+ /// then the completion block will be passed that value. The `updateBlock` also has an `NSError` out
75
+ /// parameter. If this is set, then the transaction will not attempt to commit, and the given error
76
+ /// will be returned.
77
+ ///
78
+ /// The `Transaction` object passed to the `updateBlock` contains methods for accessing documents
79
+ /// and collections. Unlike other firestore access, data accessed with the transaction will not
80
+ /// reflect local changes that have not been committed. For this reason, it is required that all
81
+ /// reads are performed before any writes. Transactions must be performed while online. Otherwise,
82
+ /// reads will fail, the final commit will fail, and this function will return an error.
83
+ ///
84
+ /// - Parameter updateBlock The block to execute within the transaction context.
85
+ /// - Throws Throws an error if the transaction could not be committed, or if an error was explicitly specified in the `updateBlock` parameter.
86
+ /// - Returns Returns the value returned in the `updateBlock` parameter if no errors occurred.
87
+ func runTransaction( _ updateBlock: @escaping ( Transaction , NSErrorPointer )
88
+ -> Any ? ) async throws -> Any ? {
89
+ // This needs to be wrapped in order to express a nullable return value upon success.
90
+ // See https://github.com/firebase/firebase-ios-sdk/issues/9426 for more details.
91
+ return try await withCheckedThrowingContinuation { continuation in
92
+ self . runTransaction ( updateBlock) { anyValue, error in
93
+ if let err = error {
94
+ continuation. resume ( throwing: err)
95
+ } else {
96
+ continuation. resume ( returning: anyValue)
97
+ }
98
+ }
99
+ }
100
+ }
56
101
}
57
102
#endif
0 commit comments