Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions Sources/Auth/Defaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@
// Created by Guilherme Souza on 14/12/23.
//

import ConcurrencyExtras
import Foundation
import Helpers

extension AuthClient.Configuration {
private static let supportedDateFormatters: [UncheckedSendable<ISO8601DateFormatter>] = [
ISO8601DateFormatter.iso8601WithFractionalSeconds,
ISO8601DateFormatter.iso8601,
]

/// The default JSONEncoder instance used by the ``AuthClient``.
public static let jsonEncoder: JSONEncoder = {
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
encoder.dateEncodingStrategy = .custom { date, encoder in
let string = ISO8601DateFormatter.iso8601WithFractionalSeconds.value.string(from: date)
var container = encoder.singleValueContainer()
let string = DateFormatter.iso8601.string(from: date)
try container.encode(string)
}
return encoder
Expand All @@ -29,10 +35,8 @@ extension AuthClient.Configuration {
let container = try decoder.singleValueContainer()
let string = try container.decode(String.self)

let supportedFormatters: [DateFormatter] = [.iso8601, .iso8601_noMilliseconds]

for formatter in supportedFormatters {
if let date = formatter.date(from: string) {
for formatter in supportedDateFormatters {
if let date = formatter.value.date(from: string) {
return date
}
}
Expand Down
17 changes: 8 additions & 9 deletions Sources/Helpers/AnyJSON/AnyJSON+Codable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,11 @@ extension AnyJSON {
let container = try decoder.singleValueContainer()
let dateString = try container.decode(String.self)

let date = DateFormatter.iso8601.date(from: dateString) ?? DateFormatter
.iso8601_noMilliseconds.date(from: dateString)
let date = ISO8601DateFormatter.iso8601WithFractionalSeconds.value.date(from: dateString) ?? ISO8601DateFormatter.iso8601.value.date(from: dateString)

guard let decodedDate = date else {
throw DecodingError.typeMismatch(
Date.self,
DecodingError.Context(
codingPath: container.codingPath,
debugDescription: "String is not a valid Date"
)
throw DecodingError.dataCorruptedError(
in: container, debugDescription: "Invalid date format: \(dateString)"
)
}

Expand All @@ -38,7 +33,11 @@ extension AnyJSON {
public static let encoder: JSONEncoder = {
let encoder = JSONEncoder()
encoder.dataEncodingStrategy = .base64
encoder.dateEncodingStrategy = .formatted(DateFormatter.iso8601)
encoder.dateEncodingStrategy = .custom { date, encoder in
let string = ISO8601DateFormatter.iso8601WithFractionalSeconds.value.string(from: date)
var container = encoder.singleValueContainer()
try container.encode(string)
}
return encoder
}()
}
Expand Down
27 changes: 10 additions & 17 deletions Sources/Helpers/DateFormatter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,19 @@
// Created by Guilherme Souza on 28/12/23.
//

import ConcurrencyExtras
import Foundation

extension DateFormatter {
/// DateFormatter class that generates and parses string representations of dates following the
/// ISO 8601 standard
package static let iso8601: DateFormatter = {
let iso8601DateFormatter = DateFormatter()

iso8601DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
iso8601DateFormatter.locale = Locale(identifier: "en_US_POSIX")
iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
return iso8601DateFormatter
extension ISO8601DateFormatter {
package static let iso8601: UncheckedSendable<ISO8601DateFormatter> = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime]
return UncheckedSendable(formatter)
}()

package static let iso8601_noMilliseconds: DateFormatter = {
let iso8601DateFormatter = DateFormatter()

iso8601DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
iso8601DateFormatter.locale = Locale(identifier: "en_US_POSIX")
iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
return iso8601DateFormatter
package static let iso8601WithFractionalSeconds: UncheckedSendable<ISO8601DateFormatter> = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
return UncheckedSendable(formatter)
}()
}
2 changes: 1 addition & 1 deletion Sources/Helpers/SupabaseLogger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public struct SupabaseLogMessage: Codable, CustomStringConvertible, Sendable {
}

public var description: String {
let date = DateFormatter.iso8601_noMilliseconds.string(from: Date(timeIntervalSince1970: timestamp))
let date = ISO8601DateFormatter.iso8601.value.string(from: Date(timeIntervalSince1970: timestamp))
let file = fileID.split(separator: ".", maxSplits: 1).first.map(String.init) ?? fileID
var description = "\(date) [\(level)] [\(system)] [\(file).\(function):\(line)] \(message)"
if !additionalContext.isEmpty {
Expand Down
9 changes: 5 additions & 4 deletions Sources/PostgREST/Defaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
// Created by Guilherme Souza on 14/12/23.
//

import ConcurrencyExtras
import Foundation
import Helpers

let version = Helpers.version

extension PostgrestClient.Configuration {
private static let supportedDateFormatters: [DateFormatter] = [
.iso8601,
.iso8601_noMilliseconds,
private static let supportedDateFormatters: [UncheckedSendable<ISO8601DateFormatter>] = [
ISO8601DateFormatter.iso8601WithFractionalSeconds,
ISO8601DateFormatter.iso8601,
]

/// The default `JSONDecoder` instance for ``PostgrestClient`` responses.
Expand All @@ -24,7 +25,7 @@ extension PostgrestClient.Configuration {
let string = try container.decode(String.self)

for formatter in supportedDateFormatters {
if let date = formatter.date(from: string) {
if let date = formatter.value.date(from: string) {
return date
}
}
Expand Down
28 changes: 28 additions & 0 deletions Tests/PostgRESTTests/JSONTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// JSONTests.swift
//
//
// Created by Guilherme Souza on 01/07/24.
//

@testable import PostgREST
import XCTest

final class JSONTests: XCTestCase {
func testDecodeJSON() throws {
let json = """
{
"created_at": "2024-06-15T18:12:04+00:00"
}
""".data(using: .utf8)!

struct Value: Decodable {
var createdAt: Date

enum CodingKeys: String, CodingKey {
case createdAt = "created_at"
}
}
_ = try PostgrestClient.Configuration.jsonDecoder.decode(Value.self, from: json)
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.