Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the ISO8601 date transcoder configurable #94

Merged
Merged
Show file tree
Hide file tree
Changes from 2 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
34 changes: 31 additions & 3 deletions Sources/OpenAPIRuntime/Conversion/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,37 @@ public protocol DateTranscoder: Sendable {
}

/// A transcoder for dates encoded as an ISO-8601 string (in RFC 3339 format).
public struct ISO8601DateTranscoder: DateTranscoder {
public struct ISO8601DateTranscoder: DateTranscoder, @unchecked Sendable {

/// The lock protecting the formatter.
private let lock: NSLock

/// The underlying date formatter.
private let locked_formatter: ISO8601DateFormatter
czechboy0 marked this conversation as resolved.
Show resolved Hide resolved

/// Creates a new transcoder with the provided options.
/// - Parameter optionsOverride: Options to override the default ones. If you provide
/// nil here, the default options are used.
public init(options: ISO8601DateFormatter.Options? = nil) {
let formatter = ISO8601DateFormatter()
if let options { formatter.formatOptions = options }
lock = NSLock()
lock.name = "com.apple.swift-openapi-generator.runtime.ISO8601DateTranscoder"
locked_formatter = formatter
}

/// Creates and returns an ISO 8601 formatted string representation of the specified date.
public func encode(_ date: Date) throws -> String { ISO8601DateFormatter().string(from: date) }
public func encode(_ date: Date) throws -> String {
lock.lock()
defer { lock.unlock() }
czechboy0 marked this conversation as resolved.
Show resolved Hide resolved
return locked_formatter.string(from: date)
}

/// Creates and returns a date object from the specified ISO 8601 formatted string representation.
public func decode(_ dateString: String) throws -> Date {
guard let date = ISO8601DateFormatter().date(from: dateString) else {
lock.lock()
defer { lock.unlock() }
guard let date = locked_formatter.date(from: dateString) else {
throw DecodingError.dataCorrupted(
.init(codingPath: [], debugDescription: "Expected date string to be ISO8601-formatted.")
)
Expand All @@ -44,6 +67,11 @@ public struct ISO8601DateTranscoder: DateTranscoder {
extension DateTranscoder where Self == ISO8601DateTranscoder {
/// A transcoder that transcodes dates as ISO-8601–formatted string (in RFC 3339 format).
public static var iso8601: Self { ISO8601DateTranscoder() }

/// A transcoder that transcodes dates as ISO-8601–formatted string (in RFC 3339 format) with fractional seconds.
public static var iso8601WithFractionalSeconds: Self {
czechboy0 marked this conversation as resolved.
Show resolved Hide resolved
ISO8601DateTranscoder(options: [.withInternetDateTime, .withFractionalSeconds])
}
}

extension JSONEncoder.DateEncodingStrategy {
Expand Down
30 changes: 30 additions & 0 deletions Tests/OpenAPIRuntimeTests/Conversion/Test_Configuration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftOpenAPIGenerator open source project
//
// Copyright (c) 2023 Apple Inc. and the SwiftOpenAPIGenerator project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftOpenAPIGenerator project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import XCTest
@_spi(Generated) import OpenAPIRuntime

final class Test_Configuration: Test_Runtime {

func testDateTranscoder_iso8601() throws {
let transcoder: any DateTranscoder = .iso8601
XCTAssertEqual(try transcoder.encode(testDate), testDateString)
XCTAssertEqual(testDate, try transcoder.decode(testDateString))
}

func testDateTranscoder_iso8601WithFractionalSeconds() throws {
let transcoder: any DateTranscoder = .iso8601WithFractionalSeconds
XCTAssertEqual(try transcoder.encode(testDateWithFractionalSeconds), testDateWithFractionalSecondsString)
XCTAssertEqual(testDateWithFractionalSeconds, try transcoder.decode(testDateWithFractionalSecondsString))
}
}
4 changes: 4 additions & 0 deletions Tests/OpenAPIRuntimeTests/Test_Runtime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ class Test_Runtime: XCTestCase {

var testDateString: String { "2023-01-18T10:04:11Z" }

var testDateWithFractionalSeconds: Date { Date(timeIntervalSince1970: 1_674_036_251.123) }

var testDateWithFractionalSecondsString: String { "2023-01-18T10:04:11.123Z" }

var testDateEscapedString: String { "2023-01-18T10%3A04%3A11Z" }

var testDateStringData: Data { Data(testDateString.utf8) }
Expand Down