Files
firebase-ios-sdk/Firestore/Swift/Tests/API/BasicCompileTests.swift
T

484 lines
13 KiB
Swift
Raw Normal View History

2017-10-03 08:55:22 -07:00
/*
* Copyright 2017 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// These aren't tests in the usual sense--they just verify that the Objective-C to Swift translation
// results in the right names.
2017-10-03 08:55:22 -07:00
import Foundation
import XCTest
// The Firebase pod is only available on iOS. On other platforms, import
// Firestore directly and disable any tests that inspect types at the Firebase
// level.
#if os(iOS)
import Firebase
#else
import FirebaseFirestore
#endif
2017-10-03 08:55:22 -07:00
class BasicCompileTests: XCTestCase {
func testCompiled() {
XCTAssertTrue(true)
}
}
2017-10-03 08:55:22 -07:00
func main() {
2018-02-26 10:51:58 -08:00
let db = initializeDb()
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
let (collectionRef, documentRef) = makeRefs(database: db)
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
let query = makeQuery(collection: collectionRef)
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
writeDocument(at: documentRef)
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
writeDocuments(at: documentRef, database: db)
2018-02-26 10:51:58 -08:00
addDocument(to: collectionRef)
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
readDocument(at: documentRef)
readDocumentWithSource(at: documentRef)
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
readDocuments(matching: query)
readDocumentsWithSource(matching: query)
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
listenToDocument(at: documentRef)
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
listenToDocuments(matching: query)
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
enableDisableNetwork(database: db)
2017-12-18 18:50:08 -08:00
2019-06-05 16:25:09 -07:00
clearPersistence(database: db)
2018-02-26 10:51:58 -08:00
types()
waitForPendingWrites(database: db)
2019-09-30 16:36:51 -07:00
addSnapshotsInSyncListener(database: db)
terminateDb(database: db)
2017-10-03 08:55:22 -07:00
}
func initializeDb() -> Firestore {
2018-02-26 10:51:58 -08:00
// Initialize with ProjectID.
let firestore = Firestore.firestore()
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
// Apply settings
let settings = FirestoreSettings()
settings.host = "localhost"
settings.isPersistenceEnabled = true
2018-11-26 14:33:28 -08:00
settings.cacheSizeBytes = FirestoreCacheSizeUnlimited
2018-02-26 10:51:58 -08:00
firestore.settings = settings
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
return firestore
2017-10-03 08:55:22 -07:00
}
func makeRefs(database db: Firestore) -> (CollectionReference, DocumentReference) {
2018-02-26 10:51:58 -08:00
var collectionRef = db.collection("my-collection")
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
var documentRef: DocumentReference
documentRef = collectionRef.document("my-doc")
// or
documentRef = db.document("my-collection/my-doc")
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
// deeper collection (my-collection/my-doc/some/deep/collection)
collectionRef = documentRef.collection("some/deep/collection")
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
// parent doc (my-collection/my-doc/some/deep)
documentRef = collectionRef.parent!
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
// print paths.
print("Collection: \(collectionRef.path), document: \(documentRef.path)")
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
return (collectionRef, documentRef)
2017-10-03 08:55:22 -07:00
}
func makeQuery(collection collectionRef: CollectionReference) -> Query {
2019-04-09 20:50:58 -07:00
var query = collectionRef.whereField(FieldPath(["name"]), isEqualTo: "Fred")
2018-02-26 10:51:58 -08:00
.whereField("age", isGreaterThanOrEqualTo: 24)
.whereField("tags", arrayContains: "active")
.whereField(FieldPath(["tags"]), arrayContains: "active")
2019-10-29 14:13:02 -07:00
.whereField("tags", arrayContainsAny: ["active", "squat"])
.whereField(FieldPath(["tags"]), arrayContainsAny: ["active", "squat"])
.whereField("tags", in: ["active", "squat"])
.whereField(FieldPath(["tags"]), in: ["active", "squat"])
2018-02-26 10:51:58 -08:00
.whereField(FieldPath.documentID(), isEqualTo: "fred")
.order(by: FieldPath(["age"]))
.order(by: "name", descending: true)
.limit(to: 10)
2017-10-03 08:55:22 -07:00
2019-04-09 20:50:58 -07:00
query = collectionRef.firestore.collectionGroup("collection")
2019-03-08 13:37:00 -08:00
2018-02-26 10:51:58 -08:00
return query
2017-10-03 08:55:22 -07:00
}
func writeDocument(at docRef: DocumentReference) {
2018-02-26 10:51:58 -08:00
let setData = [
"foo": 42,
"bar": [
"baz": "Hello world!",
],
] as [String: Any]
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
let updateData = [
"bar.baz": 42,
FieldPath(["foobar"]): 42,
2018-04-13 14:22:41 -07:00
"server_timestamp": FieldValue.serverTimestamp(),
"array_union": FieldValue.arrayUnion(["a", "b"]),
"array_remove": FieldValue.arrayRemove(["a", "b"]),
2018-04-13 14:22:41 -07:00
"field_delete": FieldValue.delete(),
2018-02-26 10:51:58 -08:00
] as [AnyHashable: Any]
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
docRef.setData(setData)
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
// Completion callback (via trailing closure syntax).
docRef.setData(setData) { error in
if let error = error {
print("Uh oh! \(error)")
return
2017-10-03 08:55:22 -07:00
}
2018-02-26 10:51:58 -08:00
print("Set complete!")
}
2017-10-03 08:55:22 -07:00
// merge
docRef.setData(setData, merge: true)
docRef.setData(setData, merge: true) { error in
if let error = error {
print("Uh oh! \(error)")
return
}
print("Set complete!")
}
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
docRef.updateData(updateData)
docRef.delete()
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
docRef.delete { error in
if let error = error {
print("Uh oh! \(error)")
return
2017-10-03 08:55:22 -07:00
}
2018-02-26 10:51:58 -08:00
print("Set complete!")
}
2017-10-03 08:55:22 -07:00
}
2017-12-18 21:05:07 -08:00
func enableDisableNetwork(database db: Firestore) {
2018-02-26 10:51:58 -08:00
// closure syntax
db.disableNetwork(completion: { error in
if let e = error {
print("Uh oh! \(e)")
return
2017-12-18 18:50:08 -08:00
}
2018-02-26 10:51:58 -08:00
})
// trailing block syntax
db.enableNetwork { error in
if let e = error {
print("Uh oh! \(e)")
return
}
}
2017-12-18 18:50:08 -08:00
}
2019-06-05 16:25:09 -07:00
func clearPersistence(database db: Firestore) {
db.clearPersistence { error in
if let e = error {
print("Uh oh! \(e)")
return
}
}
}
func writeDocuments(at docRef: DocumentReference, database db: Firestore) {
2018-02-26 10:51:58 -08:00
var batch: WriteBatch
2018-02-26 10:51:58 -08:00
batch = db.batch()
batch.setData(["a": "b"], forDocument: docRef)
batch.setData(["a": "b"], forDocument: docRef, merge: true)
2018-02-26 10:51:58 -08:00
batch.setData(["c": "d"], forDocument: docRef)
// commit without completion callback.
2018-02-26 10:51:58 -08:00
batch.commit()
print("Batch write without completion complete!")
2018-02-26 10:51:58 -08:00
batch = db.batch()
batch.setData(["a": "b"], forDocument: docRef)
batch.setData(["c": "d"], forDocument: docRef)
// commit with completion callback via trailing closure syntax.
2018-02-26 10:51:58 -08:00
batch.commit { error in
if let error = error {
2018-02-26 10:51:58 -08:00
print("Uh oh! \(error)")
return
}
2018-02-26 10:51:58 -08:00
print("Batch write callback complete!")
}
2018-02-26 10:51:58 -08:00
print("Batch write with completion complete!")
}
2017-10-03 08:55:22 -07:00
func addDocument(to collectionRef: CollectionReference) {
2019-06-19 10:00:17 -04:00
_ = collectionRef.addDocument(data: ["foo": 42])
2018-02-26 10:51:58 -08:00
// or
collectionRef.document().setData(["foo": 42])
2017-10-03 08:55:22 -07:00
}
func readDocument(at docRef: DocumentReference) {
2018-02-26 10:51:58 -08:00
// Trailing closure syntax.
docRef.getDocument { document, error in
if let document = document {
// Note that both document and document.data() is nullable.
if let data = document.data() {
print("Read document: \(data)")
}
if let data = document.data(with: .estimate) {
2018-02-26 10:51:58 -08:00
print("Read document: \(data)")
}
if let foo = document.get("foo") {
print("Field: \(foo)")
}
if let foo = document.get("foo", serverTimestampBehavior: .previous) {
2018-02-26 10:51:58 -08:00
print("Field: \(foo)")
}
// Fields can also be read via subscript notation.
if let foo = document["foo"] {
print("Field: \(foo)")
}
} else {
// TODO(mikelehen): There may be a better way to do this, but it at least demonstrates
// the swift error domain / enum codes are renamed appropriately.
if let errorCode = error.flatMap({
($0._domain == FirestoreErrorDomain) ? FirestoreErrorCode(rawValue: $0._code) : nil
}) {
switch errorCode {
case .unavailable:
print("Can't read document due to being offline!")
case _:
print("Failed to read.")
2017-10-03 08:55:22 -07:00
}
2018-02-26 10:51:58 -08:00
} else {
print("Unknown error!")
}
2017-10-03 08:55:22 -07:00
}
2018-02-26 10:51:58 -08:00
}
2017-10-03 08:55:22 -07:00
}
func readDocumentWithSource(at docRef: DocumentReference) {
docRef.getDocument(source: FirestoreSource.default) { document, error in
}
docRef.getDocument(source: .server) { document, error in
}
docRef.getDocument(source: FirestoreSource.cache) { document, error in
}
}
2017-10-03 08:55:22 -07:00
func readDocuments(matching query: Query) {
2018-02-26 10:51:58 -08:00
query.getDocuments { querySnapshot, error in
// TODO(mikelehen): Figure out how to make "for..in" syntax work
// directly on documentSet.
for document in querySnapshot!.documents {
print(document.data())
2017-10-03 08:55:22 -07:00
}
2018-02-26 10:51:58 -08:00
}
2017-10-03 08:55:22 -07:00
}
func readDocumentsWithSource(matching query: Query) {
query.getDocuments(source: FirestoreSource.default) { querySnapshot, error in
}
query.getDocuments(source: .server) { querySnapshot, error in
}
query.getDocuments(source: FirestoreSource.cache) { querySnapshot, error in
}
}
2017-10-03 08:55:22 -07:00
func listenToDocument(at docRef: DocumentReference) {
2018-02-26 10:51:58 -08:00
let listener = docRef.addSnapshotListener { document, error in
2017-12-18 21:05:07 -08:00
if let error = error {
print("Uh oh! Listen canceled: \(error)")
return
2017-10-03 08:55:22 -07:00
}
2017-12-18 21:05:07 -08:00
if let document = document {
// Note that document.data() is nullable.
2018-02-26 10:51:58 -08:00
if let data: [String: Any] = document.data() {
print("Current document: \(data)")
2017-12-18 21:05:07 -08:00
}
if document.metadata.isFromCache {
print("From Cache")
} else {
print("From Server")
}
}
}
// Unsubscribe.
2018-02-26 10:51:58 -08:00
listener.remove()
2017-10-03 08:55:22 -07:00
}
func listenToDocumentWithMetadataChanges(at docRef: DocumentReference) {
let listener = docRef.addSnapshotListener(includeMetadataChanges: true) { document, error in
if let document = document {
if document.metadata.hasPendingWrites {
print("Has pending writes")
}
}
}
// Unsubscribe.
listener.remove()
}
2017-10-03 08:55:22 -07:00
func listenToDocuments(matching query: Query) {
2018-02-26 10:51:58 -08:00
let listener = query.addSnapshotListener { snap, error in
if let error = error {
print("Uh oh! Listen canceled: \(error)")
return
2017-10-03 08:55:22 -07:00
}
2018-02-26 10:51:58 -08:00
if let snap = snap {
print("NEW SNAPSHOT (empty=\(snap.isEmpty) count=\(snap.count)")
// TODO(mikelehen): Figure out how to make "for..in" syntax work
// directly on documentSet.
for document in snap.documents {
// Note that document.data() is not nullable.
let data: [String: Any] = document.data()
print("Doc: ", data)
}
}
}
// Unsubscribe
listener.remove()
2017-10-03 08:55:22 -07:00
}
func listenToQueryDiffs(onQuery query: Query) {
2018-02-26 10:51:58 -08:00
let listener = query.addSnapshotListener { snap, error in
if let snap = snap {
for change in snap.documentChanges {
2018-02-26 10:51:58 -08:00
switch change.type {
case .added:
print("New document: \(change.document.data())")
case .modified:
print("Modified document: \(change.document.data())")
case .removed:
print("Removed document: \(change.document.data())")
2017-10-03 08:55:22 -07:00
}
2018-02-26 10:51:58 -08:00
}
2017-10-03 08:55:22 -07:00
}
2018-02-26 10:51:58 -08:00
}
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
// Unsubscribe
listener.remove()
2017-10-03 08:55:22 -07:00
}
func listenToQueryDiffsWithMetadata(onQuery query: Query) {
let listener = query.addSnapshotListener(includeMetadataChanges: true) { snap, error in
if let snap = snap {
for change in snap.documentChanges(includeMetadataChanges: true) {
switch change.type {
case .added:
print("New document: \(change.document.data())")
case .modified:
print("Modified document: \(change.document.data())")
case .removed:
print("Removed document: \(change.document.data())")
}
}
}
}
// Unsubscribe
listener.remove()
}
2017-10-03 08:55:22 -07:00
func transactions() {
2018-02-26 10:51:58 -08:00
let db = Firestore.firestore()
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
let collectionRef = db.collection("cities")
let accA = collectionRef.document("accountA")
let accB = collectionRef.document("accountB")
let amount = 20.0
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
db.runTransaction({ (transaction, errorPointer) -> Any? in
do {
let balanceA = try transaction.getDocument(accA)["balance"] as! Double
let balanceB = try transaction.getDocument(accB)["balance"] as! Double
2017-10-03 08:55:22 -07:00
2018-02-26 10:51:58 -08:00
if balanceA < amount {
errorPointer?.pointee = NSError(domain: "Foo", code: 123, userInfo: nil)
return nil
}
transaction.updateData(["balance": balanceA - amount], forDocument: accA)
transaction.updateData(["balance": balanceB + amount], forDocument: accB)
} catch let error as NSError {
print("Uh oh! \(error)")
2017-10-03 08:55:22 -07:00
}
2018-02-26 10:51:58 -08:00
return 0
}) { result, error in
// handle result.
}
2017-10-03 08:55:22 -07:00
}
func types() {
2018-02-26 10:51:58 -08:00
let _: CollectionReference
let _: DocumentChange
let _: DocumentReference
let _: DocumentSnapshot
let _: FieldPath
let _: FieldValue
let _: Firestore
let _: FirestoreSettings
let _: GeoPoint
#if os(iOS)
let _: Firebase.GeoPoint
#endif
2019-03-20 08:38:37 -07:00
let _: FirebaseFirestore.GeoPoint
let _: Timestamp
#if os(iOS)
let _: Firebase.Timestamp
#endif
2019-03-20 08:38:37 -07:00
let _: FirebaseFirestore.Timestamp
2018-02-26 10:51:58 -08:00
let _: ListenerRegistration
let _: Query
let _: QuerySnapshot
let _: SnapshotMetadata
let _: Transaction
let _: WriteBatch
2017-10-03 08:55:22 -07:00
}
func waitForPendingWrites(database db: Firestore) {
db.waitForPendingWrites { error in
if let e = error {
print("Uh oh! \(e)")
return
}
}
}
2019-09-30 16:36:51 -07:00
func addSnapshotsInSyncListener(database db: Firestore) {
let listener = db.addSnapshotsInSyncListener {}
// Unsubscribe
listener.remove()
}
func terminateDb(database db: Firestore) {
db.terminate { error in
if let e = error {
print("Uh oh! \(e)")
return
}
}
}