diff --git a/Package.swift b/Package.swift index f4fb341..8a730fb 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.5 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/README.md b/README.md index b32ab7b..6b2b1ab 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ func consumerPrices(startDate: Date, endDate: Date, geo: GEO, completion: @escap func consumerPrices(date: Date, geo: GEO, completion: @escaping (Result<[Value], Error>) -> Void) func consumerPrices(startDate: Date, endDate: Date, geo: GEO) -> AnyPublisher<[Value], Error> func consumerPrices(date: Date, geo: GEO) -> AnyPublisher<[Value], Error> +func consumerPrices(startDate: Date, endDate: Date, geo: GEO) async throws -> [Value] +func consumerPrices(date: Date, geo: GEO) async throws -> [Value] ``` ### Obtener precios mercado spot @@ -42,6 +44,8 @@ func spotPrices(startDate: Date, endDate: Date, geo: GEO, completion: @escaping func spotPrices(date: Date, geo: GEO, completion: @escaping (Result<[Value], Error>) -> Void) func spotPrices(startDate: Date, endDate: Date, geo: GEO) -> AnyPublisher<[Value], Error> func spotPrices(date: Date, geo: GEO) -> AnyPublisher<[Value], Error> +func spotPrices(startDate: Date, endDate: Date) async throws -> [Value] +func spotPrices(date: Date) async throws -> [Value] ``` ## Licencia de uso y contribuciĆ³n con el proyecto diff --git a/Sources/REESwift/Extensions/URLSession.swift b/Sources/REESwift/Extensions/URLSession.swift new file mode 100644 index 0000000..3bf48f6 --- /dev/null +++ b/Sources/REESwift/Extensions/URLSession.swift @@ -0,0 +1,17 @@ +import Foundation + +@available(iOS, deprecated: 15.0) +extension URLSession { + func data(from url: URL) async throws -> (Data, URLResponse) { + try await withCheckedThrowingContinuation { continuation in + let task = self.dataTask(with: url) { data, response, error in + guard let data = data, let response = response else { + let error = error ?? URLError(.badServerResponse) + return continuation.resume(throwing: error) + } + continuation.resume(returning: (data, response)) + } + task.resume() + } + } +} diff --git a/Sources/REESwift/Network.swift b/Sources/REESwift/Network.swift index 31c5305..934d07d 100644 --- a/Sources/REESwift/Network.swift +++ b/Sources/REESwift/Network.swift @@ -17,6 +17,13 @@ class Network { } } + func request(_ endpoint: Endpoint) async throws -> T { + let (data, response) = try await URLSession.shared.data(from: endpoint.url) + guard (response as? HTTPURLResponse)?.statusCode == 200 else { throw URLError(.badServerResponse) } + let decodedData = try decoder.decode(T.self, from: data) + return decodedData + } + func request(_ endpoint: Endpoint) -> AnyPublisher { URLSession.shared .dataTaskPublisher(for: endpoint.url) diff --git a/Sources/REESwift/REESwift.swift b/Sources/REESwift/REESwift.swift index 443c7a0..22d934f 100644 --- a/Sources/REESwift/REESwift.swift +++ b/Sources/REESwift/REESwift.swift @@ -17,14 +17,6 @@ public extension REESwift { prices(id: "1001", startDate: date.start, endDate: date.end, geo: geo, completion: completion) } - func consumerPrices(startDate: Date, endDate: Date, geo: GEO) -> AnyPublisher<[Value], Error> { - return prices(id: "1001", startDate: startDate, endDate: endDate, geo: geo) - } - - func consumerPrices(date: Date, geo: GEO) -> AnyPublisher<[Value], Error> { - return prices(id: "1001", startDate: date.start, endDate: date.end, geo: geo) - } - func spotPrices(startDate: Date, endDate: Date, completion: @escaping (Result<[Value], Error>) -> Void) { prices(id: "600", startDate: startDate, endDate: endDate, geo: nil, completion: completion) } @@ -33,14 +25,6 @@ public extension REESwift { prices(id: "600", startDate: date.start, endDate: date.end, geo: nil, completion: completion) } - func spotPrices(startDate: Date, endDate: Date) -> AnyPublisher<[Value], Error> { - return prices(id: "600", startDate: startDate, endDate: endDate, geo: nil) - } - - func spotPrices(date: Date) -> AnyPublisher<[Value], Error> { - return prices(id: "600", startDate: date.start, endDate: date.end, geo: nil) - } - private func prices(id: String, startDate: Date, endDate: Date, geo: GEO?, completion: @escaping (Result<[Value], Error>) -> Void) { let endpoint = Endpoint.prices(startDate: startDate, endDate: endDate, geo: geo) Network.shared.request(endpoint) { (result: Result) in @@ -55,6 +39,26 @@ public extension REESwift { } } +} + +public extension REESwift { + + func consumerPrices(startDate: Date, endDate: Date, geo: GEO) -> AnyPublisher<[Value], Error> { + return prices(id: "1001", startDate: startDate, endDate: endDate, geo: geo) + } + + func consumerPrices(date: Date, geo: GEO) -> AnyPublisher<[Value], Error> { + return prices(id: "1001", startDate: date.start, endDate: date.end, geo: geo) + } + + func spotPrices(startDate: Date, endDate: Date) -> AnyPublisher<[Value], Error> { + return prices(id: "600", startDate: startDate, endDate: endDate, geo: nil) + } + + func spotPrices(date: Date) -> AnyPublisher<[Value], Error> { + return prices(id: "600", startDate: date.start, endDate: date.end, geo: nil) + } + private func prices(id: String, startDate: Date, endDate: Date, geo: GEO?) -> AnyPublisher<[Value], Error> { let endpoint = Endpoint.prices(startDate: startDate, endDate: endDate, geo: geo) return Network.shared.request(endpoint) @@ -67,3 +71,31 @@ public extension REESwift { } } + +public extension REESwift { + + func consumerPrices(startDate: Date, endDate: Date, geo: GEO) async throws -> [Value] { + return try await prices(id: "1001", startDate: startDate, endDate: endDate, geo: geo) + } + + func consumerPrices(date: Date, geo: GEO) async throws -> [Value] { + return try await prices(id: "1001", startDate: date.start, endDate: date.end, geo: geo) + } + + func spotPrices(startDate: Date, endDate: Date) async throws -> [Value] { + return try await prices(id: "600", startDate: startDate, endDate: endDate, geo: nil) + } + + func spotPrices(date: Date) async throws -> [Value] { + return try await prices(id: "600", startDate: date.start, endDate: date.end, geo: nil) + } + + private func prices(id: String, startDate: Date, endDate: Date, geo: GEO?) async throws -> [Value] { + let endpoint = Endpoint.prices(startDate: startDate, endDate: endDate, geo: geo) + let apiResponse: APIResponse = try await Network.shared.request(endpoint) + let prices = apiResponse.included.first { $0.id == id } + guard let values = prices?.attributes?.values, !values.isEmpty else { throw URLError(.badServerResponse) } + return values + } + +} diff --git a/Tests/REESwiftTests/REESwiftTests.swift b/Tests/REESwiftTests/REESwiftTests.swift index 6517906..6066809 100644 --- a/Tests/REESwiftTests/REESwiftTests.swift +++ b/Tests/REESwiftTests/REESwiftTests.swift @@ -8,6 +8,45 @@ final class REESwiftTests: XCTestCase { // MARK: - Test consumer prices + func testConsumerPricesAsync() async { + + let now = Date() + + let todayPrices = try? await ree.consumerPrices(date: now, geo: .peninsula) + XCTAssertNotNil(todayPrices) + XCTAssert(todayPrices?.count == 24) + + let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: now)! + let otherPrices = try? await ree.consumerPrices(startDate: yesterday.start, endDate: now.end, geo: .peninsula) + XCTAssertNotNil(otherPrices) + XCTAssert(otherPrices?.count == 48) + + let futureDate = Calendar.current.date(byAdding: .month, value: 1, to: now)! + let futurePrices = try? await ree.consumerPrices(date: futureDate, geo: .peninsula) + XCTAssertNil(futurePrices) + + } + + func testConsumerPricesAsyncOtherGEOs() async { + + let now = Date() + + let peninsulaPrices = try? await ree.consumerPrices(date: now, geo: .peninsula) + let ceutaPrices = try? await ree.consumerPrices(date: now, geo: .ceuta) + XCTAssertNotNil(peninsulaPrices) + XCTAssertNotNil(ceutaPrices) + XCTAssert(peninsulaPrices?.count == ceutaPrices?.count) + var priceEquals = true + for i in 0..