Skip to content
This repository was archived by the owner on Jan 2, 2025. It is now read-only.

Commit 8a10f51

Browse files
authored
Merge pull request #1 from space-squad/develop
Develop
2 parents b5afcc0 + ad41a47 commit 8a10f51

15 files changed

+597
-6
lines changed

.github/README.md

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# FirebaseManager Package
2+
3+
This repository contains all utility functions that simplify transactions with Firebase products like Cloud Firestore, Cloud Storage or Authentication, wrapped in a Swift Package.
4+
5+
It is made by **[SPACE SQUAD](https://www.spacesquad.de)**! We make great software with ♥️ in Berlin.
6+
7+
<img src="assets/README-spacesquad_logo_full.png" width="120">
8+
9+
---
10+
11+
## Content
12+
- [Features](#features)
13+
- [Installation](#installation)
14+
- [How to Use](#how-to-use)
15+
16+
17+
## Features
18+
- [x] CRUD-Transactions for collections and documents stored in Firebase Cloud Firestore
19+
- [x] CR-Transactions for documents stored in Firebase Cloud Storage
20+
- [ ] Handling Authentication and Authorization using SignInWithApple and Password
21+
22+
---
23+
24+
## Installation
25+
##### Requirements
26+
- iOS 14.0+ / macOS 10.14+
27+
- Xcode 13+
28+
- Swift 5+
29+
30+
##### Swift Package Manager
31+
In Xcode, go to `File > Add Packages` and add `https://github.com/space-squad/swift-firebase-manager`. Add the package to all your targets.
32+
33+
34+
## How to Use
35+
36+
The package is separated into three targets and you need to import the one that fits your needs:
37+
38+
### FirebaseFirestoreManager
39+
Target for all transactions with the Firebase Cloud Firestore.
40+
41+
42+
##### Status
43+
- [x] CRUD-Transactions for collections and documents
44+
- [x] Error Handling
45+
- [ ] Support for nested collections
46+
- [ ] Snapshot Listeners
47+
48+
49+
In the first step you need to define your collections by implementing the ReferenceProtocol.
50+
51+
Example definition for two top-level collections (countries, notes), where every country-document has a cities-collection associated:
52+
```Swift
53+
import FirebaseFirestoreManager
54+
55+
enum FirestoreReference: String, ReferenceProtocol {
56+
case country = "countries", city = "cities", notes
57+
}
58+
```
59+
Next you need to define all your model classes, conforming to Codable-protocol.
60+
61+
Example:
62+
```Swift
63+
public struct City: Codable {
64+
65+
let name: String
66+
let state: String?
67+
let country: String?
68+
let isCapital: Bool?
69+
let population: Int64?
70+
71+
enum CodingKeys: String, CodingKey {
72+
case name
73+
case state
74+
case country
75+
case isCapital = "capital"
76+
case population
77+
}
78+
79+
}
80+
```
81+
82+
Afterwards you can use all FirebaseFirestoreManager-classes for creating, reading, updating or deleting data.
83+
84+
Example:
85+
```Swift
86+
// Create new document
87+
let country = Country(....)
88+
FirestoreManager.createDocument(country, reference: FirestoreReference.country) { _ in }
89+
90+
// Read all documents from a collection
91+
FirestoreManager.fetchCollection(FirestoreReference.country) { (result: Result<[Country], FirestoreError>) in
92+
switch result {
93+
case .success(let countries):
94+
// Here you can use the fetched countries!
95+
print(countries)
96+
case .failure(let error):
97+
print(error.localizedDescription)
98+
}
99+
}
100+
101+
// Update document
102+
country.name = "USA"
103+
FirestoreManager.updateDocument(country, reference: FirestoreReference.country, with: country.id) { _ in }
104+
105+
// Delete document
106+
FirestoreManager.deleteDocument(reference: FirestoreReference.country, with: country.id)
107+
```
108+
109+
### FirebaseStorageManager
110+
Target for all transactions with the Firebase Cloud Storage, using the Combine-framework.
111+
112+
##### Status
113+
- [x] Create files
114+
- [x] Read files
115+
- [ ] Delete files
116+
- [x] Error Handling
117+
- [ ] Hierarchical Organization
118+
- [ ] Multiple Buckets
119+
- [ ] Support more file types
120+
121+
Example:
122+
```Swift
123+
// Create new file in bucket in folder "directory"
124+
125+
let data = Data(base64Encoded: someString)!
126+
FirebaseStorageManager.uploadData(data: data, path: "directory", fileName: "fileName", fileType: .csv)
127+
.sink { _ in }
128+
receiveValue: { url in
129+
print(url.absoluteURL)
130+
}
131+
132+
133+
// Read File from bucket
134+
FirebaseStorageManager.fetchFile(path: "directory", fileName: "fileName", fileType: .csv)
135+
.tryMap { url in
136+
try String(contentsOf: url)
137+
}
138+
.replaceError(with: "Error")
139+
.sink { print($0) }
140+
```
141+
142+
143+
144+
### FirebaseAuthenticationManager
145+
To be completed.
47.8 KB
Loading

.gitignore

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ playground.xcworkspace
3737
# Swift Package Manager
3838
#
3939
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40-
# Packages/
41-
# Package.pins
42-
# Package.resolved
43-
# *.xcodeproj
40+
Packages/
41+
Package.pins
42+
Package.resolved
43+
*.xcodeproj
4444
#
4545
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
4646
# hence it is not needed unless you have added a package configuration file to your project
47-
# .swiftpm
47+
.swiftpm
4848

4949
.build/
5050

Package.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// swift-tools-version:5.5
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "FirebaseManager",
8+
platforms: [
9+
.iOS(.v14),
10+
.macOS(.v10_14)
11+
],
12+
products: [
13+
.library(
14+
name: "FirebaseManagerPackage",
15+
targets: [
16+
"FirebaseStorageManager"
17+
])
18+
],
19+
dependencies: [
20+
.package(url: "https://github.com/firebase/firebase-ios-sdk.git", .upToNextMajor(from: "9.0.0"))
21+
],
22+
targets: [
23+
.target(
24+
name: "FirebaseFirestoreManager",
25+
dependencies: [
26+
.product(name: "FirebaseFirestoreSwift", package: "firebase-ios-sdk")
27+
],
28+
path: "Sources/FirestoreManager"
29+
),
30+
.target(
31+
name: "FirebaseStorageManager",
32+
dependencies: [
33+
.product(name: "FirebaseStorage", package: "firebase-ios-sdk")
34+
],
35+
path: "Sources/StorageManager"
36+
)
37+
]
38+
)

README.md

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//
2+
// FirestoreManager+Create.swift
3+
//
4+
//
5+
// Created by Anna Münster on 26.08.21.
6+
//
7+
8+
import Foundation
9+
10+
extension FirestoreManager {
11+
/**
12+
Create a document in Firebase.
13+
14+
- Parameter object: Codable object to be uploaded
15+
- Parameter reference: The collection name
16+
- Parameter id: ID to be set for the document, if nil it is created by Firebase
17+
- Parameter completion: If creating was successful, the documentId is returned, otherwise the error
18+
*/
19+
public static func createDocument<T: Encodable>(_ object: T,
20+
reference: ReferenceProtocol,
21+
with id: String? = nil,
22+
completion: @escaping(Result<String, FirestoreError>) -> Void) {
23+
do {
24+
if let id = id {
25+
try reference.reference().document(id).setData(from: object)
26+
completion(.success(id))
27+
} else {
28+
let reference = try reference.reference().addDocument(from: object)
29+
completion(.success(reference.documentID))
30+
}
31+
} catch {
32+
completion(.failure(FirestoreError.create(error: error)))
33+
}
34+
}
35+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// FirestoreManager+Delete.swift
3+
//
4+
//
5+
// Created by Anna Münster on 26.08.21.
6+
//
7+
8+
import Foundation
9+
10+
extension FirestoreManager {
11+
/**
12+
Delete a document in Firebase.
13+
14+
- Parameter reference: The collection name
15+
- Parameter id: ID to be set for the document
16+
*/
17+
public static func deleteDocument(reference: ReferenceProtocol, with id: String, completion: ((FirestoreError?) -> Void)? = nil) {
18+
reference.reference().document(id).delete { error in
19+
if let error = error {
20+
completion?(FirestoreError.delete(error: error))
21+
} else {
22+
completion?(nil)
23+
}
24+
}
25+
}
26+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//
2+
// FirestoreManager+Fetch.swift
3+
//
4+
//
5+
// Created by Anna Münster on 26.08.21.
6+
//
7+
8+
import Foundation
9+
import FirebaseFirestore
10+
11+
extension FirestoreManager {
12+
/**
13+
Fetch and listen to a collection from Firebase.
14+
15+
- Parameter reference: The collection name
16+
- Parameter filters: Dictionary of the filter key and the value
17+
- Parameter orderBy: Key to order objects by
18+
- Parameter descending: Whether orderBy key should descend
19+
- Parameter limit: Limit number of fetched items
20+
*/
21+
public static func fetchCollection<T>(_ reference: ReferenceProtocol,
22+
filters: [String: Any]? = nil,
23+
orderBy: [String]? = nil,
24+
descending: Bool = false,
25+
limit: Int? = nil,
26+
completion: @escaping (Result<[T], FirestoreError>) -> Void) where T: Decodable {
27+
28+
29+
var query: Query = reference.reference()
30+
31+
filters?.forEach { filter, filterValue in
32+
query = query.whereField(filter, isEqualTo: filterValue)
33+
}
34+
35+
orderBy?.forEach { orderValue in
36+
query = query.order(by: orderValue, descending: descending)
37+
}
38+
39+
if let limit = limit {
40+
query = query.limit(to: limit)
41+
}
42+
43+
query.addSnapshotListener { querySnapshot, error in
44+
guard let documents = querySnapshot?.documents else {
45+
completion(.failure(.documentNotFound(error: error)))
46+
return
47+
}
48+
do {
49+
let objects = try documents.map { queryDocumentSnapshot -> T in
50+
try queryDocumentSnapshot.data(as: T.self)
51+
}
52+
53+
completion(.success(objects))
54+
} catch {
55+
completion(.failure(.decoding(error: error)))
56+
}
57+
}
58+
}
59+
60+
61+
/**
62+
Fetch and listen to a single document in Firebase.
63+
64+
- Parameter reference: The parent's collection name
65+
- Parameter id: ID of the document
66+
*/
67+
public static func fetchDocument<T>(_ reference: ReferenceProtocol,
68+
id: String,
69+
completion: @escaping (Result<T, FirestoreError>) -> Void) where T: Decodable {
70+
71+
let reference = reference.reference().document(id)
72+
73+
let snapshotBlock = { (document: DocumentSnapshot?, error: Error?) in
74+
guard let document = document, document.exists else {
75+
completion(.failure(.documentNotFound(error: error)))
76+
return
77+
}
78+
do {
79+
let decodedObject = try document.data(as: T.self)
80+
completion(.success(decodedObject))
81+
} catch {
82+
completion(.failure(.decoding(error: error)))
83+
}
84+
}
85+
86+
reference.addSnapshotListener(snapshotBlock)
87+
}
88+
}

0 commit comments

Comments
 (0)