Skip to content

Commit 0175b86

Browse files
Swift extension for RTDB (#6568)
* Added pristine version of JSONEncoder.swift to the project * Renamed JSONEncoder and JSONDecoder and namespaced them under Database. Skip JSONSerialization steps of encoding and decoding * Added convenience decoding to DataSnapshot and encoding to DatabaseReference * Convert to 2 space indentation * Added ServerTimestamp - modelled on Firestore ditto * Added a ServerIncrement enum/property wrapper. Not too happy about the property wrapper API though * Fix ServerTimestamp Date decoding and encoding * Fix ServerTimestamp Date decoding and encoding * Added API for setting default decoder and encoder * Fix typo and linter error * Changed requirement for ServerIncrement generic parameter to be AdditiveArithmetic instead of Numeric. Added tests for server value coding. * Add test for alternative ServerIncrement API and demonstrate that this version of the API also models actual optionality * Test the default encoder and decoder * Added more tests derived from corresponding Firestore coding tests * Ran linter * Delete EncoderTests.swift Ooops, I added this file prematurely. * Added modified version of tests from apple/swift * Rename all but a few occurrences of 'json' and add a reference to the original file from apple/swift * Made it possible to decode Optional types * Updated copyright messages * Removed CodableErrors and force cast ServerValue.timestamp() based on feedback on PR * Changed completion handler to take a Result<Void, Error> * Add escaping to closure parameter * Fixed format * Change completion handler type to accept and Optional Error rather than a Result<Void, Error> * Remove ServerIncrement for now * Fix function signature error * Remove Swift 4 support. Remove default encoder/decoder configuration. Add FirebaseDatabaseSwift.podspec - I don't know if it's good though, as I don't use CocoaPods myself. * Update podspec with fixes from review * Run scripts/style.sh * Add -Beta to FirebaseDatabaseSwift library
1 parent 7048626 commit 0175b86

File tree

11 files changed

+5485
-1
lines changed

11 files changed

+5485
-1
lines changed

FirebaseDatabaseSwift.podspec

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#
2+
# Be sure to run `pod lib lint FirebaseDatabaseSwift.podspec' to ensure this is a
3+
# valid spec before submitting.
4+
#
5+
6+
Pod::Spec.new do |s|
7+
s.name = 'FirebaseDatabaseSwift'
8+
s.version = '7.9.0-beta'
9+
s.summary = 'Swift Extensions for Firebase Realtime Database'
10+
11+
s.description = <<-DESC
12+
Simplify your iOS development, grow your user base, and monetize more effectively with Firebase.
13+
DESC
14+
15+
s.homepage = 'https://developers.google.com/'
16+
s.license = { :type => 'Apache', :file => 'LICENSE' }
17+
s.authors = 'Google, Inc.'
18+
19+
s.source = {
20+
:git => 'https://github.com/Firebase/firebase-ios-sdk.git',
21+
:tag => 'CocoaPods-' + s.version.to_s
22+
}
23+
24+
s.swift_version = '5.1'
25+
s.ios.deployment_target = '10.0'
26+
s.osx.deployment_target = '10.12'
27+
s.tvos.deployment_target = '10.0'
28+
29+
s.cocoapods_version = '>= 1.4.0'
30+
s.prefix_header_file = false
31+
32+
s.source_files = [
33+
'FirebaseDatabaseSwift/Sources/**/*.swift',
34+
]
35+
36+
s.dependency 'FirebaseDatabase', '~> 7.8'
37+
end
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2020 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 Foundation
18+
import FirebaseDatabase
19+
20+
extension DataSnapshot {
21+
/// Retrieves the value of a snapshot and converts it to an instance of
22+
/// caller-specified type.
23+
/// Throws `DecodingError.valueNotFound`
24+
/// if the document does not exist and `T` is not an `Optional`.
25+
///
26+
/// See `Database.Decoder` for more details about the decoding process.
27+
///
28+
/// - Parameters
29+
/// - type: The type to convert the document fields to.
30+
/// - decoder: The decoder to use to convert the document. Defaults to use
31+
/// default decoder.
32+
public func data<T: Decodable>(as type: T.Type,
33+
decoder: Database.Decoder =
34+
Database.Decoder()) throws -> T {
35+
try decoder.decode(T.self, from: value ?? NSNull())
36+
}
37+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2020 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 Foundation
18+
import FirebaseDatabase
19+
20+
extension DatabaseReference {
21+
/// Encodes an instance of `Encodable` and overwrites the encoded data
22+
/// to the path referred by this `DatabaseReference`. If no value exists,
23+
/// it is created. If a value already exists, it is overwritten.
24+
///
25+
/// See `Database.Encoder` for more details about the encoding process.
26+
///
27+
/// - Parameters:
28+
/// - value: An instance of `Encodable` to be encoded to a document.
29+
/// - encoder: An encoder instance to use to run the encoding.
30+
/// - completion: A block to execute once the value has been successfully
31+
/// written to the server. This block will not be called while
32+
/// the client is offline, though local changes will be visible
33+
/// immediately.
34+
public func setValue<T: Encodable>(from value: T,
35+
encoder: Database.Encoder = Database.Encoder(),
36+
completion: ((Error?) -> Void)? =
37+
nil) throws {
38+
let encoded = try encoder.encode(value)
39+
if let completion = completion {
40+
setValue(encoded, withCompletionBlock: { error, _ in completion(error) })
41+
} else {
42+
setValue(encoded)
43+
}
44+
}
45+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2020 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 FirebaseDatabase
18+
19+
/// A property wrapper that marks an `Optional<Date>` field to be
20+
/// populated with a server timestamp. If a `Codable` object being written
21+
/// contains a `nil` for an `@ServerTimestamp`-annotated field, it will be
22+
/// replaced with `ServerValue.timestamp()` as it is sent.
23+
///
24+
/// Example:
25+
/// ```
26+
/// struct CustomModel {
27+
/// @ServerTimestamp var ts: Date?
28+
/// }
29+
/// ```
30+
///
31+
/// Then writing `CustomModel(ts: nil)` will tell server to fill `ts` with
32+
/// current timestamp.
33+
@propertyWrapper
34+
public struct ServerTimestamp: Codable, Equatable, Hashable {
35+
var value: Date?
36+
37+
public init(wrappedValue value: Date?) {
38+
self.value = value
39+
}
40+
41+
public var wrappedValue: Date? {
42+
get { value }
43+
set { value = newValue }
44+
}
45+
46+
// MARK: Codable
47+
48+
public init(from decoder: Decoder) throws {
49+
let container = try decoder.singleValueContainer()
50+
if container.decodeNil() {
51+
value = nil
52+
} else {
53+
let msecs = try container.decode(Int.self)
54+
value = Date(timeIntervalSince1970: TimeInterval(msecs) / 1000)
55+
}
56+
}
57+
58+
public func encode(to encoder: Encoder) throws {
59+
var container = encoder.singleValueContainer()
60+
if let value = value {
61+
let interval = value.timeIntervalSince1970
62+
try container.encode(Int(interval * 1000))
63+
} else {
64+
let dictionary = ServerValue.timestamp() as! [String: String]
65+
try container.encode(dictionary)
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)