Skip to content

Commit 5001806

Browse files
Add async/await helper for CollectionReference.add()/Firestore.loadBundle() (#9130)
1 parent c7456c9 commit 5001806

File tree

7 files changed

+215
-1
lines changed

7 files changed

+215
-1
lines changed

Firestore/Example/Firestore.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
056542AD1D0F78E29E22EFA9 /* grpc_connection_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B6D9649021544D4F00EB9CFB /* grpc_connection_test.cc */; };
3535
0575F3004B896D94456A74CE /* status_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3CAA33F964042646FDDAF9F9 /* status_testing.cc */; };
3636
05D99904EA713414928DD920 /* query_listener_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7C3F995E040E9E9C5E8514BB /* query_listener_test.cc */; };
37+
062072B72773A055001655D7 /* AsyncAwaitIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 062072B62773A055001655D7 /* AsyncAwaitIntegrationTests.swift */; };
38+
062072B82773A055001655D7 /* AsyncAwaitIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 062072B62773A055001655D7 /* AsyncAwaitIntegrationTests.swift */; };
39+
062072B92773A055001655D7 /* AsyncAwaitIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 062072B62773A055001655D7 /* AsyncAwaitIntegrationTests.swift */; };
3740
06485D6DA8F64757D72636E1 /* leveldb_target_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = E76F0CDF28E5FA62D21DE648 /* leveldb_target_cache_test.cc */; };
3841
06A3926F89C847846BE4D6BE /* http.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE9720B89AAC00B5BCE7 /* http.pb.cc */; };
3942
06BCEB9C65DFAA142F3D3F0B /* view_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = A5466E7809AD2871FFDE6C76 /* view_testing.cc */; };
@@ -1319,6 +1322,7 @@
13191322
01D10113ECC5B446DB35E96D /* byte_stream_cpp_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = byte_stream_cpp_test.cc; sourceTree = "<group>"; };
13201323
045D39C4A7D52AF58264240F /* remote_document_cache_test.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = remote_document_cache_test.h; sourceTree = "<group>"; };
13211324
0473AFFF5567E667A125347B /* ordered_code_benchmark.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = ordered_code_benchmark.cc; sourceTree = "<group>"; };
1325+
062072B62773A055001655D7 /* AsyncAwaitIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncAwaitIntegrationTests.swift; sourceTree = "<group>"; };
13221326
0840319686A223CC4AD3FAB1 /* leveldb_remote_document_cache_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = leveldb_remote_document_cache_test.cc; sourceTree = "<group>"; };
13231327
0EE5300F8233D14025EF0456 /* string_apple_test.mm */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.objcpp; path = string_apple_test.mm; sourceTree = "<group>"; };
13241328
11984BA0A99D7A7ABA5B0D90 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.release.xcconfig"; sourceTree = "<group>"; };
@@ -1792,6 +1796,7 @@
17921796
124C932A22C1635300CA8C2D /* Integration */ = {
17931797
isa = PBXGroup;
17941798
children = (
1799+
062072B62773A055001655D7 /* AsyncAwaitIntegrationTests.swift */,
17951800
124C932B22C1642C00CA8C2D /* CodableIntegrationTests.swift */,
17961801
);
17971802
path = Integration;
@@ -3783,6 +3788,7 @@
37833788
isa = PBXSourcesBuildPhase;
37843789
buildActionMask = 2147483647;
37853790
files = (
3791+
062072B92773A055001655D7 /* AsyncAwaitIntegrationTests.swift in Sources */,
37863792
733AFC467B600967536BD70F /* BasicCompileTests.swift in Sources */,
37873793
79987AF2DF1FCE799008B846 /* CodableGeoPointTests.swift in Sources */,
37883794
1C79AE3FBFC91800E30D092C /* CodableIntegrationTests.swift in Sources */,
@@ -3986,6 +3992,7 @@
39863992
isa = PBXSourcesBuildPhase;
39873993
buildActionMask = 2147483647;
39883994
files = (
3995+
062072B82773A055001655D7 /* AsyncAwaitIntegrationTests.swift in Sources */,
39893996
B896E5DE1CC27347FAC009C3 /* BasicCompileTests.swift in Sources */,
39903997
722F9A798F39F7D1FE7CF270 /* CodableGeoPointTests.swift in Sources */,
39913998
CF5DE1ED21DD0A9783383A35 /* CodableIntegrationTests.swift in Sources */,
@@ -4408,6 +4415,7 @@
44084415
isa = PBXSourcesBuildPhase;
44094416
buildActionMask = 2147483647;
44104417
files = (
4418+
062072B72773A055001655D7 /* AsyncAwaitIntegrationTests.swift in Sources */,
44114419
F731A0CCD0220B370BC1BE8B /* BasicCompileTests.swift in Sources */,
44124420
7C5E017689012489AAB7718D /* CodableGeoPointTests.swift in Sources */,
44134421
54C3242322D3B627000FE6DD /* CodableIntegrationTests.swift in Sources */,

Firestore/Swift/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Unreleased
2+
- [added] Added async wrapper for `CollectionReference.addDocument()` and
3+
`Firestore.loadBundle()`.
4+
15
# v8.9.0
26
- [added] Added `@FirestoreQuery` property wrapper for querying data from a
37
Firestore collection.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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+
17+
import FirebaseFirestore
18+
import Foundation
19+
20+
#if compiler(>=5.5) && canImport(_Concurrency)
21+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
22+
public extension CollectionReference {
23+
/// Adds a new document to this collection with the specified data, assigning it a document ID
24+
/// automatically.
25+
/// - Parameter data: A `Dictionary` containing the data for the new document.
26+
/// - Throws: `Error` if the backend rejected the write.
27+
/// - Returns: A `DocumentReference` pointing to the newly created document.
28+
func addDocument(data: [String: Any]) async throws -> DocumentReference {
29+
return try await withCheckedThrowingContinuation { continuation in
30+
var document: DocumentReference?
31+
document = self.addDocument(data: data) { error in
32+
if let err = error {
33+
continuation.resume(throwing: err)
34+
} else {
35+
// Our callbacks guarantee that we either return an error or a document.
36+
continuation.resume(returning: document!)
37+
}
38+
}
39+
}
40+
}
41+
}
42+
#endif
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
17+
import FirebaseFirestore
18+
import Foundation
19+
20+
#if compiler(>=5.5) && canImport(_Concurrency)
21+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
22+
public extension Firestore {
23+
/// Loads a Firestore bundle into the local cache.
24+
/// - Parameter bundleData: Data from the bundle to be loaded.
25+
/// - Throws: `Error` if the bundle data cannot be parsed.
26+
/// - Returns: The final `LoadBundleTaskProgress` that contains the total number of documents loaded.
27+
func loadBundle(_ bundleData: Data) async throws -> LoadBundleTaskProgress {
28+
return try await withCheckedThrowingContinuation { continuation in
29+
self.loadBundle(bundleData) { progress, error in
30+
if let err = error {
31+
continuation.resume(throwing: err)
32+
} else {
33+
// Our callbacks guarantee that we either return an error or a progress event.
34+
continuation.resume(returning: progress!)
35+
}
36+
}
37+
}
38+
}
39+
40+
/// Loads a Firestore bundle into the local cache.
41+
/// - Parameter bundleStream: An input stream from which the bundle can be read.
42+
/// - Throws: `Error` if the bundle stream cannot be parsed.
43+
/// - Returns: The final `LoadBundleTaskProgress` that contains the total number of documents loaded.
44+
func loadBundle(_ bundleStream: InputStream) async throws -> LoadBundleTaskProgress {
45+
return try await withCheckedThrowingContinuation { continuation in
46+
self.loadBundle(bundleStream) { progress, error in
47+
if let err = error {
48+
continuation.resume(throwing: err)
49+
} else {
50+
// Our callbacks guarantee that we either return an error or a progress event.
51+
continuation.resume(returning: progress!)
52+
}
53+
}
54+
}
55+
}
56+
}
57+
#endif

Firestore/Swift/Tests/API/BasicCompileTests.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,3 +472,37 @@ func terminateDb(database db: Firestore) {
472472
}
473473
}
474474
}
475+
476+
#if swift(>=5.5)
477+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
478+
func testAsyncAwait(database db: Firestore) async throws {
479+
try await db.enableNetwork()
480+
try await db.disableNetwork()
481+
try await db.waitForPendingWrites()
482+
try await db.clearPersistence()
483+
try await db.terminate()
484+
try await db.runTransaction { _, _ in
485+
0
486+
}
487+
488+
let batch = db.batch()
489+
try await batch.commit()
490+
491+
_ = await db.getQuery(named: "foo")
492+
_ = try await db.loadBundle(Data())
493+
494+
let collection = db.collection("coll")
495+
try await collection.getDocuments()
496+
try await collection.getDocuments(source: FirestoreSource.default)
497+
498+
let document = try await collection.addDocument(data: [:])
499+
500+
try await document.setData([:])
501+
try await document.setData([:], merge: true)
502+
try await document.setData([:], mergeFields: [])
503+
try await document.updateData([:])
504+
try await document.delete()
505+
try await document.getDocument()
506+
try await document.getDocument(source: FirestoreSource.default)
507+
}
508+
#endif
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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+
17+
import FirebaseFirestore
18+
import FirebaseFirestoreSwift
19+
import Foundation
20+
21+
let emptyBundle = """
22+
{\
23+
"metadata":{\
24+
"id":"test",\
25+
"createTime":{\
26+
"seconds":0,\
27+
"nanos":0\
28+
},\
29+
"version":1,\
30+
"totalDocuments":0,\
31+
"totalBytes":0\
32+
}\
33+
}
34+
"""
35+
36+
#if swift(>=5.5)
37+
@available(iOS 15, tvOS 15, macOS 12, watchOS 8, *)
38+
class AsyncAwaitIntegrationTests: FSTIntegrationTestCase {
39+
func testAddData() async throws {
40+
let collection = collectionRef()
41+
let document = try await collection.addDocument(data: [:])
42+
let snapshot = try await document.getDocument()
43+
XCTAssertTrue(snapshot.exists)
44+
}
45+
46+
func testLoadBundleFromData() async throws {
47+
let bundle = "\(emptyBundle.count)\(emptyBundle)"
48+
let bundleProgress = try await db.loadBundle(Data(bundle.utf8))
49+
XCTAssertEqual(LoadBundleTaskState.success, bundleProgress.state)
50+
}
51+
52+
func testLoadBundleFromEmptyDataFails() async throws {
53+
do {
54+
_ = try await db.loadBundle(Data())
55+
XCTFail("Bundle loading should have failed")
56+
} catch {
57+
XCTAssertEqual((error as NSError).domain, FirestoreErrorDomain)
58+
XCTAssertEqual((error as NSError).code, FirestoreErrorCode.unknown.rawValue)
59+
}
60+
}
61+
62+
func testLoadBundleFromStream() async throws {
63+
let bundle = "\(emptyBundle.count)\(emptyBundle)"
64+
let bundleProgress = try await db
65+
.loadBundle(InputStream(data: bundle.data(using: String.Encoding.utf8)!))
66+
XCTAssertEqual(LoadBundleTaskState.success, bundleProgress.state)
67+
}
68+
}
69+
#endif

SwiftDashboard.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ tasks for additional Swift improvements.
1111
| :--- | :--- | :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: | :----: |
1212
| **Swift Library** |||||||||| 1 ||||||||
1313
| **API Tests** |||||||| 3 | 2 || 2 || 2 | 2 ||||
14-
| **async/await** || n/a |||||| 3 | |||||||||
14+
| **async/await** || n/a |||||| 3 | |||||||||
1515
| **Swift Errors** ||||| 4 |||||||||||| 5 |
1616
| **Codable** | n/a | n/a | n/a |n/a | n/a | n/a |n/a ||| 1 | n/a | n/a || n/a | n/a ||n/a |
1717
| **SwiftUI Lifecycle** | n/a || n/a ||| n/a |n/a | n/a | n/a | n/a | n/a | n/a || n/a | n/a | n/a |n/a |

0 commit comments

Comments
 (0)