Skip to content

Commit

Permalink
Merge pull request #3 from rehannali/develop
Browse files Browse the repository at this point in the history
— Added extension to Date with milliseconds.
— remove warning for shadow generics
  • Loading branch information
rehannali committed Nov 3, 2023
2 parents d810255 + 82f6704 commit 0e494e1
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 23 deletions.
30 changes: 30 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE/pull_request_template.md
@@ -0,0 +1,30 @@
## What type of PR is this? (check all applicable)

- [ ] Refactor
- [ ] Feature
- [ ] Bug Fix
- [ ] Optimization
- [ ] Documentation Update

## Description

_Please replace this line with a description of what this PR does, and why._

## Related Issues Tickets

- Related Issue #
- Closes #

## Instructions, Screenshots, Recordings (If Applicable)

_Please replace this line with instructions on how to test your changes, a note
on the devices this has been tested on, as well as any relevant instructions._

## Added/updated tests?
_We encourage you to keep the code coverage percentage at 80% and above._

- [ ] Yes
- [ ] No, They aren't needed.
- [ ] No, I need help with writing tests.

## [optional] Other information:
20 changes: 10 additions & 10 deletions Sources/SGSerializable/Helpers/SGSerializable+FallBack.swift
Expand Up @@ -12,22 +12,22 @@ import UIKit
#endif

extension SGSerializable {
func getFallBack<Value>(_ type: Value.Type) -> Value {
func getFallBack<V>(_ type: V.Type) -> V {
switch self.type {
case .int: return 0 as! Value
case .double: return 0 as! Value
case .bool: return false as! Value
case .float: return 0 as! Value
case .string: return "" as! Value
case .auto: return processAuto(Value.self)
case .none: fatalError("\(Value.self) has been used before initialization.")
case .int: return 0 as! V
case .double: return 0 as! V
case .bool: return false as! V
case .float: return 0 as! V
case .string: return "" as! V
case .auto: return processAuto(V.self)
case .none: fatalError("\(V.self) has been used before initialization.")
}
}
}

extension SGTransformSerializable {
func getFallBack<Value>(_ type: Value.Type) -> Value {
return processAuto(Value.self)
func getFallBack<W>(_ type: W.Type) -> W {
return processAuto(W.self)
}
}

Expand Down
7 changes: 3 additions & 4 deletions Sources/SGSerializable/Transformable/SGTransformDecoder.swift
Expand Up @@ -8,10 +8,9 @@

import Foundation

extension SGTransformSerializable: SGDecoder where Value.FromType: Decodable {
extension SGTransformSerializable: SGDecoder where Transform.FromType: Decodable {
func decodeValue(from container: DecodeContainer, with key: String) throws {
if let value = try? container.decodeIfPresent(Value.FromType.self, forKey: getKey(with: key)) {
wrappedValue = Value.transform(from: value)
}
let value = try container.decodeIfPresent(Transform.FromType.self, forKey: getKey(with: key))
wrappedValue = Transform.transform(from: value)
}
}
4 changes: 2 additions & 2 deletions Sources/SGSerializable/Transformable/SGTransformEncoder.swift
Expand Up @@ -8,8 +8,8 @@

import Foundation

extension SGTransformSerializable: SGEncoder where Value.FromType: Encodable {
extension SGTransformSerializable: SGEncoder where Transform.FromType: Encodable {
func encodeValue(from container: inout EncodeContainer, with key: String) throws {
try container.encodeIfPresent(Value.transform(from: wrappedValue), forKey: getKey(with: key))
try container.encodeIfPresent(Transform.transform(from: wrappedValue), forKey: getKey(with: key))
}
}
Expand Up @@ -12,29 +12,29 @@ import Foundation
///
/// You must provide custom implementation of `SGTranformable` which is needed for transformation.
@propertyWrapper
public final class SGTransformSerializable<Value: SGTranformable> {
public var wrappedValue: Value.ToType?
public final class SGTransformSerializable<Transform: SGTranformable> {
public var wrappedValue: Transform.ToType?
public var name: String?

public var projectedValue: Value.ToType {
public var projectedValue: Transform.ToType {
set { wrappedValue = newValue }
get {
guard let wrappedValue = wrappedValue else {
return getFallBack(Value.ToType.self)
return getFallBack(Transform.ToType.self)
}
return wrappedValue
}
}

public init(default value: Value.ToType? = nil, key: String? = nil) {
public init(default value: Transform.ToType? = nil, key: String? = nil) {
self.wrappedValue = value
self.name = key
}
}

extension SGTransformSerializable {
internal func getKey(with key: String) -> SGCodingKey {
let cKey: SGCodingKey!
let cKey: SGCodingKey
if let name = name, !name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
cKey = SGCodingKey(name: name)
}else {
Expand Down
@@ -0,0 +1,24 @@
//
// MilliSecondsToDate.swift
// SGSerializable
//
// Created by Rehan Ali on 02/11/2023 at 12:49 AM.
// Copyright © 2022 Rehan Ali. All rights reserved.
//

import Foundation

public struct MilliSecondsToDate: SGTranformable {
public typealias FromType = TimeInterval
public typealias ToType = Date

public static func transform(from value: TimeInterval?) -> Date? {
guard let value = value else { return nil }
return Date(timeIntervalSince1970: value / 1000)
}

public static func transform(from value: Date?) -> TimeInterval? {
guard let value = value else { return nil }
return value.timeIntervalSince1970 * 1000
}
}
Expand Up @@ -270,6 +270,61 @@ class SGAdvancedTransformSerializable: QuickSpec, EncodableTestSpec, DecodableTe
expect(dict?["time"] as? TimeInterval).to(equal(1263008235))
}
}

context("Milliseconds Date") {
var object: MilliSecondDate?
it("should access default value before [En/De]Coding") {
object = MilliSecondDate()
expect(object).toNot(beNil())
expect(object?.date).to(beNil())
expect(object?.$date).to(equal(Date(timeIntervalSince1970: 0)))
}

it("should decode properly using Default") {
object = try? self.jsonDecoder.decode(MilliSecondDate.self, from: jsonData)

let calendar = Calendar.current
let actualDate = calendar.date(from: .init(timeZone: .init(secondsFromGMT: 0), year: 2010, month: 1, day: 9, hour: 3, minute: 37, second: 15))

expect(object).toNot(beNil())
expect(object?.date).to(equal(actualDate))
expect(object?.$date).to(equal(actualDate!))
}

it("should decode properly using custom") {
object = try? MilliSecondDate.initialize(with: jsonData)

let calendar = Calendar.current
let actualDate = calendar.date(from: .init(timeZone: .init(secondsFromGMT: 0), year: 2010, month: 1, day: 9, hour: 3, minute: 37, second: 15))

expect(object).toNot(beNil())
expect(object?.date).to(equal(actualDate))
expect(object?.$date).to(equal(actualDate!))
}

it("should encode propery using default") {
object = try? MilliSecondDate.initialize(with: jsonData)
let data = try? self.jsonEncoder.encode(object)

guard let data = data , let string = String(data: data, encoding: .utf8) else {
fail("Unable to get valid string")
return
}

let nsDict = try? JSONSerializer.toDictionary(string)
let dict = nsDict?.swiftDictionary
expect(dict).toNot(beNil())
expect(dict?["timeMilli"] as? TimeInterval).to(equal(1263008235000))
}

it("should encode propery using custom") {
object = try? MilliSecondDate.initialize(with: jsonData)

let dict = object?.dictionary
expect(dict).toNot(beNil())
expect(dict?["timeMilli"] as? TimeInterval).to(equal(1263008235000))
}
}
}
}
}
Expand All @@ -279,7 +334,8 @@ fileprivate let jsonData = """
"base64Encoded": "SGkhIHRoZXJlLiBJJ20gaGFwcHkgdG8gc2VlIHlvdS4=",
"url": "https://www.apple.com",
"datetime": "2021-09-12T23:43:33Z",
"time": 1263008235
"time": 1263008235,
"timeMilli": 1263008235000
}
""".data(using: .utf8)!

Expand All @@ -303,6 +359,11 @@ fileprivate struct TimeIntervalDate: SGCodable {
var date: Date?
}

fileprivate struct MilliSecondDate: SGCodable {
@SGTransformSerializable<MilliSecondsToDate>(key: "timeMilli")
var date: Date?
}

fileprivate struct StringURL: SGCodable {
@SGTransformSerializable<StringToURL>
var url: URL?
Expand Down

0 comments on commit 0e494e1

Please sign in to comment.