diff --git a/Sources/Weather/Models/Forecast.swift b/Sources/Weather/Models/Forecast.swift index 4e0ed29..a1a1f8e 100644 --- a/Sources/Weather/Models/Forecast.swift +++ b/Sources/Weather/Models/Forecast.swift @@ -25,20 +25,27 @@ import struct Foundation.Date -/// A `Forecast` is a collection of `Value`s for a set of `Parameter`s +/// A `Forecast` is a collection of `Parameter`s public struct Forecast: Decodable { /// A timestamp for when the `Forecast` is valid - internal let validTime: Date + public let validTime: Date /// An array of `Value` instances internal let parameters: [Parameter] - /// Get `Value` for a `Parameter` + /// Get a `Parameter` by name. /// /// - Parameter parameter: The `Parameter` to get `Value` for - internal func get(_ name: Parameter.Name) -> Parameter? { + public func get(_ name: Parameter.Name) -> Parameter { return self.parameters.first { (value) -> Bool in value.name == name - } + }.unsafelyUnwrapped + } + + /// Get `Value` for a `Parameter` + /// + /// - Parameter parameter: The `Parameter` to get `Value` for + public func get(_ name: Parameter.Name, _ keyPath: KeyPath) -> T { + return self.get(name)[keyPath: keyPath] } } diff --git a/Sources/Weather/Models/Parameter.swift b/Sources/Weather/Models/Parameter.swift index 4f14f70..22b4f3b 100644 --- a/Sources/Weather/Models/Parameter.swift +++ b/Sources/Weather/Models/Parameter.swift @@ -41,3 +41,9 @@ public struct Parameter: Decodable { /// An array of raw parameter values public let values: [Double] } + +extension Parameter { + public var value: Double { + return values.first ?? 0 + } +} diff --git a/Sources/Weather/Models/Weather.swift b/Sources/Weather/Models/Weather.swift index 5646108..87e387f 100644 --- a/Sources/Weather/Models/Weather.swift +++ b/Sources/Weather/Models/Weather.swift @@ -42,76 +42,28 @@ public struct Weather: Decodable { /// An extension to house convenience attributes extension Weather { - /// - Returns: Whether or not the forecast is valid for the current date + /// - Returns: Whether or not any relevant forecasts are available public var isRelevant: Bool { let now = Date() - return self.timeSeries.contains { forecast -> Bool in + return timeSeries.contains { forecast -> Bool in forecast.validTime > now } } - /// - Returns: The current `Forecast` - public func get(by date: Date = .init()) -> Forecast? { - return self.timeSeries.sorted(by: { $0.validTime < $1.validTime }) - .first { forecast -> Bool in - forecast.validTime >= date - } - } -} - -// MARK: Convenience - -extension Array { - func first(where keyPath: KeyPath, _ value: Value) -> Element? where Value: Equatable { - self.first { element in - element[keyPath: keyPath] == value - } - } -} - -extension Parameter { - fileprivate var value: Double { - return values.first ?? 0 - } -} - -extension Forecast { - fileprivate func parameter(byName name: Parameter.Name, transform: (Parameter) -> T) -> T { - return transform(parameters.first(where: \.name, name).unsafelyUnwrapped) - } -} - -extension Weather { - fileprivate var forecast: Forecast { - return self.get() ?? Forecast(validTime: .distantPast, parameters: []) - } - - fileprivate var forecasts: [Forecast] { - return self.timeSeries.sorted(by: { $0.validTime < $1.validTime }) - } - - public func get(_ keyPath: KeyPath, for name: Parameter.Name) -> T { - return forecast.parameter(byName: name) { - $0[keyPath: keyPath] - } + public var forecast: Forecast? { + return get() } - public func get(_ name: Parameter.Name) -> Parameter { - return forecast.parameter(byName: name) { $0 } + public var unsafeForecast: Forecast { + return forecast.unsafelyUnwrapped } - public func getAll(_ keyPath: KeyPath, for name: Parameter.Name) -> [T] { - return forecasts.map { - $0.parameter(byName: name) { - $0[keyPath: keyPath] + /// - Returns: The most relevant `Forecast` + public func get(by date: Date = .init()) -> Forecast? { + return timeSeries.sorted(by: { $0.validTime < $1.validTime }) + .first { forecast -> Bool in + forecast.validTime >= date } - } - } - - public func getAll(_ name: Parameter.Name) -> [(validTime: Date, parameter: Parameter)] { - return forecasts.map { - ($0.validTime, $0.parameter(byName: name) { $0 }) - } } }