Commit ea42db8c by Demid Merzlyakov

Storage: CoreData: model conversion code.

parent 34a064cd
...@@ -5,11 +5,15 @@ ...@@ -5,11 +5,15 @@
<attribute name="index" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/> <attribute name="index" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<relationship name="health" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CoreHealth" inverseName="airQuality" inverseEntity="CoreHealth"/> <relationship name="health" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CoreHealth" inverseName="airQuality" inverseEntity="CoreHealth"/>
</entity> </entity>
<entity name="CoreAppData" representedClassName="CoreAppData" syncable="YES">
<attribute name="selectedIndex" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="locations" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="CoreLocation" inverseName="appData" inverseEntity="CoreLocation"/>
</entity>
<entity name="CoreCurrentWeather" representedClassName="CoreCurrentWeather" syncable="YES"> <entity name="CoreCurrentWeather" representedClassName="CoreCurrentWeather" syncable="YES">
<attribute name="apparentTemp" optional="YES" attributeType="Binary"/> <attribute name="apparentTemp" optional="YES" attributeType="Binary"/>
<attribute name="approximateMoonrise" optional="YES" attributeType="Date" usesScalarValueType="NO"/> <attribute name="approximateMoonrise" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="date" attributeType="Date" usesScalarValueType="NO"/> <attribute name="date" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="humidity" optional="YES" attributeType="Integer 16" defaultValueString="0.0" usesScalarValueType="YES"/> <attribute name="humidity" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
<attribute name="isDay" attributeType="Boolean" usesScalarValueType="YES"/> <attribute name="isDay" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="lastTimeUpdated" attributeType="Date" usesScalarValueType="NO"/> <attribute name="lastTimeUpdated" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="maxTemp" optional="YES" attributeType="Binary"/> <attribute name="maxTemp" optional="YES" attributeType="Binary"/>
...@@ -18,7 +22,7 @@ ...@@ -18,7 +22,7 @@
<attribute name="moonrise" optional="YES" attributeType="Date" usesScalarValueType="NO"/> <attribute name="moonrise" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="moonset" optional="YES" attributeType="Date" usesScalarValueType="NO"/> <attribute name="moonset" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="moonState" optional="YES" attributeType="String"/> <attribute name="moonState" optional="YES" attributeType="String"/>
<attribute name="precipitationProbability" optional="YES" attributeType="Integer 16" defaultValueString="0.0" usesScalarValueType="YES"/> <attribute name="precipitationProbability" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
<attribute name="pressure" optional="YES" attributeType="Binary"/> <attribute name="pressure" optional="YES" attributeType="Binary"/>
<attribute name="sunrise" optional="YES" attributeType="Date" usesScalarValueType="NO"/> <attribute name="sunrise" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="sunset" optional="YES" attributeType="Date" usesScalarValueType="NO"/> <attribute name="sunset" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
...@@ -41,7 +45,7 @@ ...@@ -41,7 +45,7 @@
<attribute name="moonrise" optional="YES" attributeType="Date" usesScalarValueType="NO"/> <attribute name="moonrise" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="moonset" optional="YES" attributeType="Date" usesScalarValueType="NO"/> <attribute name="moonset" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="moonState" optional="YES" attributeType="String"/> <attribute name="moonState" optional="YES" attributeType="String"/>
<attribute name="precipitationProbability" optional="YES" attributeType="Integer 16" defaultValueString="0.0" usesScalarValueType="YES"/> <attribute name="precipitationProbability" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
<attribute name="sunrise" optional="YES" attributeType="Date" usesScalarValueType="NO"/> <attribute name="sunrise" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="sunset" optional="YES" attributeType="Date" usesScalarValueType="NO"/> <attribute name="sunset" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="sunState" optional="YES" attributeType="String"/> <attribute name="sunState" optional="YES" attributeType="String"/>
...@@ -52,17 +56,6 @@ ...@@ -52,17 +56,6 @@
<attribute name="windSpeed" optional="YES" attributeType="Binary"/> <attribute name="windSpeed" optional="YES" attributeType="Binary"/>
<relationship name="location" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CoreLocation" inverseName="daily" inverseEntity="CoreLocation"/> <relationship name="location" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CoreLocation" inverseName="daily" inverseEntity="CoreLocation"/>
</entity> </entity>
<entity name="CoreDayTimeWeather" representedClassName="CoreDayTimeWeather" syncable="YES">
<attribute name="date" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="dayTime" attributeType="Integer 16" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="isDay" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="lastTimeUpdated" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="temp" optional="YES" attributeType="Binary"/>
<attribute name="timeZone" attributeType="String"/>
<attribute name="type" attributeType="String"/>
<attribute name="weekDay" attributeType="String"/>
<relationship name="location" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CoreLocation" inverseName="dayTimeForecast" inverseEntity="CoreLocation"/>
</entity>
<entity name="CoreHealth" representedClassName="CoreHealth" syncable="YES"> <entity name="CoreHealth" representedClassName="CoreHealth" syncable="YES">
<attribute name="lastUpdateTime" attributeType="Date" usesScalarValueType="NO"/> <attribute name="lastUpdateTime" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="airQuality" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="CoreAirQuality" inverseName="health" inverseEntity="CoreAirQuality"/> <relationship name="airQuality" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="CoreAirQuality" inverseName="health" inverseEntity="CoreAirQuality"/>
...@@ -72,10 +65,10 @@ ...@@ -72,10 +65,10 @@
<entity name="CoreHourlyWeather" representedClassName="CoreHourlyWeather" syncable="YES"> <entity name="CoreHourlyWeather" representedClassName="CoreHourlyWeather" syncable="YES">
<attribute name="apparentTemp" optional="YES" attributeType="Binary"/> <attribute name="apparentTemp" optional="YES" attributeType="Binary"/>
<attribute name="date" attributeType="Date" usesScalarValueType="NO"/> <attribute name="date" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="humidity" optional="YES" attributeType="Integer 16" defaultValueString="0.0" usesScalarValueType="YES"/> <attribute name="humidity" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
<attribute name="isDay" attributeType="Boolean" usesScalarValueType="YES"/> <attribute name="isDay" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="lastTimeUpdated" attributeType="Date" usesScalarValueType="NO"/> <attribute name="lastTimeUpdated" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="precipitationProbability" optional="YES" attributeType="Integer 16" defaultValueString="0.0" usesScalarValueType="YES"/> <attribute name="precipitationProbability" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
<attribute name="temp" optional="YES" attributeType="Binary"/> <attribute name="temp" optional="YES" attributeType="Binary"/>
<attribute name="timeZone" attributeType="String"/> <attribute name="timeZone" attributeType="String"/>
<attribute name="type" attributeType="String"/> <attribute name="type" attributeType="String"/>
...@@ -90,15 +83,16 @@ ...@@ -90,15 +83,16 @@
<attribute name="countryName" optional="YES" attributeType="String"/> <attribute name="countryName" optional="YES" attributeType="String"/>
<attribute name="deviceLocation" attributeType="Boolean" usesScalarValueType="YES"/> <attribute name="deviceLocation" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="fipsCode" optional="YES" attributeType="String"/> <attribute name="fipsCode" optional="YES" attributeType="String"/>
<attribute name="imageName" optional="YES" attributeType="String"/>
<attribute name="lastWeatherUpdateDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/> <attribute name="lastWeatherUpdateDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="latitude" optional="YES" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/> <attribute name="latitude" optional="YES" attributeType="Decimal"/>
<attribute name="longitude" optional="YES" attributeType="Decimal" defaultValueString="0.0"/> <attribute name="longitude" optional="YES" attributeType="Decimal"/>
<attribute name="nickname" optional="YES" attributeType="String"/> <attribute name="nickname" optional="YES" attributeType="String"/>
<attribute name="region" optional="YES" attributeType="String"/> <attribute name="region" optional="YES" attributeType="String"/>
<attribute name="timeZone" attributeType="String"/> <attribute name="timeZone" attributeType="String"/>
<attribute name="zip" optional="YES" attributeType="String"/> <attribute name="zip" optional="YES" attributeType="String"/>
<relationship name="appData" maxCount="1" deletionRule="Nullify" destinationEntity="CoreAppData" inverseName="locations" inverseEntity="CoreAppData"/>
<relationship name="daily" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="CoreDailyWeather" inverseName="location" inverseEntity="CoreDailyWeather"/> <relationship name="daily" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="CoreDailyWeather" inverseName="location" inverseEntity="CoreDailyWeather"/>
<relationship name="dayTimeForecast" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="CoreDayTimeWeather" inverseName="location" inverseEntity="CoreDayTimeWeather"/>
<relationship name="health" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="CoreHealth" inverseName="location" inverseEntity="CoreHealth"/> <relationship name="health" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="CoreHealth" inverseName="location" inverseEntity="CoreHealth"/>
<relationship name="hourly" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="CoreHourlyWeather" inverseName="location" inverseEntity="CoreHourlyWeather"/> <relationship name="hourly" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="CoreHourlyWeather" inverseName="location" inverseEntity="CoreHourlyWeather"/>
<relationship name="today" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="CoreCurrentWeather" inverseName="location" inverseEntity="CoreCurrentWeather"/> <relationship name="today" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="CoreCurrentWeather" inverseName="location" inverseEntity="CoreCurrentWeather"/>
...@@ -109,13 +103,13 @@ ...@@ -109,13 +103,13 @@
<relationship name="health" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CoreHealth" inverseName="pollutants" inverseEntity="CoreHealth"/> <relationship name="health" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CoreHealth" inverseName="pollutants" inverseEntity="CoreHealth"/>
</entity> </entity>
<elements> <elements>
<element name="CoreAppData" positionX="114.79296875" positionY="-494.5078125" width="128" height="73"/>
<element name="CoreAirQuality" positionX="438.48828125" positionY="-201.96875" width="128" height="88"/> <element name="CoreAirQuality" positionX="438.48828125" positionY="-201.96875" width="128" height="88"/>
<element name="CoreCurrentWeather" positionX="-105.953125" positionY="-203.82421875" width="128" height="418"/> <element name="CoreCurrentWeather" positionX="-105.953125" positionY="-203.82421875" width="128" height="418"/>
<element name="CoreDailyWeather" positionX="270.5546875" positionY="-505.83203125" width="128" height="313"/> <element name="CoreDailyWeather" positionX="270.5546875" positionY="-505.83203125" width="128" height="313"/>
<element name="CoreDayTimeWeather" positionX="-103.97265625" positionY="-396.28515625" width="128" height="178"/>
<element name="CoreHealth" positionX="277.1640625" positionY="-156.77734375" width="128" height="103"/> <element name="CoreHealth" positionX="277.1640625" positionY="-156.77734375" width="128" height="103"/>
<element name="CoreHourlyWeather" positionX="279.15234375" positionY="-29.234375" width="128" height="238"/> <element name="CoreHourlyWeather" positionX="279.15234375" positionY="-29.234375" width="128" height="238"/>
<element name="CoreLocation" positionX="113.6640625" positionY="-337.08984375" width="128" height="298"/> <element name="CoreLocation" positionX="113.6640625" positionY="-337.08984375" width="128" height="313"/>
<element name="CorePollutant" positionX="438.171875" positionY="-103.41015625" width="128" height="88"/> <element name="CorePollutant" positionX="438.171875" positionY="-103.41015625" width="128" height="88"/>
</elements> </elements>
</model> </model>
\ No newline at end of file
//
// CoreDataAppModelConvertable.swift
// 1Weather
//
// Created by Demid Merzlyakov on 05.04.2021.
//
import Foundation
import CoreData
protocol CoreDataAppModelConvertable {
associatedtype AppModel
func toAppModel() throws -> AppModel
init?(context: NSManagedObjectContext, appModel: AppModel?) throws
}
//
// CoreDataError.swift
// 1Weather
//
// Created by Demid Merzlyakov on 05.04.2021.
//
import Foundation
struct CoreDataError {
struct SaveAttributeError<T>: Error {
let entityName: String?
let attributeName: String
let attributeValue: T
let nestedError: Error?
init(entity: Any?, attributeName: String, value: T, nestedError: Error? = nil) {
if let entity = entity {
self.entityName = String(describing: type(of: entity))
}
else {
self.entityName = nil
}
self.attributeName = attributeName
self.attributeValue = value
self.nestedError = nestedError
}
}
struct LoadAttributeError<T>: Error {
let entityName: String?
let attributeName: String
let attributeValue: T
let nestedError: Error?
init(entity: Any?, attributeName: String, value: T, nestedError: Error? = nil) {
if let entity = entity {
self.entityName = String(describing: type(of: entity))
}
else {
self.entityName = nil
}
self.attributeName = attributeName
self.attributeValue = value
self.nestedError = nestedError
}
}
}
...@@ -6,13 +6,57 @@ ...@@ -6,13 +6,57 @@
// //
import Foundation import Foundation
import CoreData
public class CoreDataStorage: Storage { public class CoreDataStorage: Storage {
private let log = Logger(componentName: "CoreDataStorage")
private lazy var managedContext: NSManagedObjectContext? = {
persistentContainer.newBackgroundContext()
}()
private lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "1WModel")
container.loadPersistentStores { [weak self] (description, error) in
if let error = error {
self?.log.error("Error loading persistent stores: \(error)")
}
}
return container
}()
public func save(locations: [Location], selectedIndex: Int) { public func save(locations: [Location], selectedIndex: Int) {
managedContext?.perform { [weak self] in
guard let self = self else { return }
guard let context = self.managedContext else {
return
}
self.deleteAll(in: context)
} }
}
public func load(completion: StorageCompletion) { public func load(completion: StorageCompletion) {
managedContext?.perform {
} }
}
private func deleteAll(in context: NSManagedObjectContext) {
#warning("Not implemented!")
//TODO: implement
}
private func saveContext() {
guard let context = managedContext else {
log.warning("saveContext: no context.")
return
}
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
log.error("Error saving: \(nserror), \(nserror.userInfo)")
}
}
}
} }
//
// CoreDataUtils.swift
// 1Weather
//
// Created by Demid Merzlyakov on 05.04.2021.
//
import Foundation
import CoreData
struct CoreDataUtils {
public static func foreach<T>(in set: NSOrderedSet, of entity: Any, attributeName: String, do action: (T) throws -> ()) throws {
for elem in set {
guard let converted = elem as? T else {
throw CoreDataError.LoadAttributeError(entity: entity, attributeName: attributeName, value: set)
}
try action(converted)
}
}
public static func measurementToData<T>(_ measurement: Measurement<T>?, in entity: Any, attributeName: String) throws -> Data? {
guard let measurement = measurement else {
return nil
}
let encoder = JSONEncoder()
do {
let result = try encoder.encode(measurement)
return result
}
catch {
throw CoreDataError.SaveAttributeError(entity: entity, attributeName: attributeName, value: measurement, nestedError: error)
}
}
public static func measurement<T>(from data: Data?, in entity: Any, attributeName: String) throws -> Measurement<T>? {
guard let data = data else {
return nil
}
let decoder = JSONDecoder()
do {
let result = try decoder.decode(Measurement<T>.self, from: data)
return result
}
catch {
let valueStr = String(data: data, encoding: .utf8) ?? "<couldn't-turn-into-string>"
throw CoreDataError.LoadAttributeError(entity: entity, attributeName: attributeName, value: valueStr, nestedError: error)
}
}
public static func timeZone(from timeZoneString: String, in entity: Any, attributeName: String) throws -> TimeZone {
guard let timeZone = TimeZone(abbreviation: timeZoneString) else {
throw CoreDataError.LoadAttributeError(entity: entity, attributeName: attributeName, value: timeZoneString)
}
return timeZone
}
public static func timeZoneToString(_ timeZone: TimeZone, in entity: Any, attributeName: String) throws -> String {
guard let result = timeZone.abbreviation() else {
throw CoreDataError.SaveAttributeError(entity: entity, attributeName: attributeName, value: timeZone)
}
return result
}
public static func appValue<T>(name: String, value: T.RawValue, in entity: Any) throws -> T where T: RawRepresentable {
guard let result = T(rawValue: value) else {
throw CoreDataError.LoadAttributeError(entity: entity, attributeName: name, value: value)
}
return result
}
public static func appValue<T>(name: String, value: T.RawValue?, in entity: Any) throws -> T? where T: RawRepresentable {
guard let value = value else {
return nil
}
return try appValue(name: name, value: value, in: entity)
}
}
import Foundation import Foundation
import CoreData
@objc(CoreAirQuality) @objc(CoreAirQuality)
open class CoreAirQuality: _CoreAirQuality { open class CoreAirQuality: _CoreAirQuality, CoreDataAppModelConvertable {
// Custom logic goes here. func toAppModel() throws -> AirQuality {
let result = AirQuality(index: self.index, advice: self.advice)
return result
}
/// This is here just so that we could inherit the generated init(managedObjectContext) convenience initializer.
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
required public init?(context: NSManagedObjectContext, appModel: AirQuality?) throws {
guard let appModel = appModel else {
return nil
}
self.init(managedObjectContext: context)
self.index = appModel.index
self.advice = appModel.advice
}
typealias AppModel = AirQuality
} }
import Foundation
@objc(CoreAppData)
open class CoreAppData: _CoreAppData {
}
import Foundation import Foundation
import CoreData
@objc(CoreCurrentWeather) @objc(CoreCurrentWeather)
open class CoreCurrentWeather: _CoreCurrentWeather { open class CoreCurrentWeather: _CoreCurrentWeather, CoreDataAppModelConvertable {
// Custom logic goes here. typealias AppModel = CurrentWeather
func toAppModel() throws -> CurrentWeather {
let timeZone = try CoreDataUtils.timeZone(from: self.timeZone, in: self, attributeName: "timeZone")
let weekDay: WeekDay = try CoreDataUtils.appValue(name: "weekDay", value: self.weekDay, in: self)
var result = CurrentWeather(lastTimeUpdated: self.lastTimeUpdated, date: self.date, timeZone: timeZone, weekDay: weekDay, isDay: self.isDay)
result.type = try CoreDataUtils.appValue(name: "type", value: self.type, in: self)
result.minTemp = try CoreDataUtils.measurement(from: self.minTemp, in: self, attributeName: "minTemp")
result.maxTemp = try CoreDataUtils.measurement(from: self.maxTemp, in: self, attributeName: "maxTemp")
result.windSpeed = try CoreDataUtils.measurement(from: self.windSpeed, in: self, attributeName: "windSpeed")
result.windDirection = try CoreDataUtils.appValue(name: "windDirection", value: self.windDirection, in: self)
if let precipProb = self.precipitationProbability {
result.precipitationProbability = Percent(precipProb.uintValue)
}
result.temp = try CoreDataUtils.measurement(from: self.temp, in: self, attributeName: "temp")
result.apparentTemp = try CoreDataUtils.measurement(from: self.apparentTemp, in: self, attributeName: "apparentTemp")
if let humidity = self.humidity {
result.humidity = Percent(humidity.uintValue)
}
result.visibility = try CoreDataUtils.measurement(from: self.visibility, in: self, attributeName: "visibility")
result.pressure = try CoreDataUtils.measurement(from: self.pressure, in: self, attributeName: "pressure")
result.sunrise = self.sunrise
result.sunset = self.sunset
result.sunState = try CoreDataUtils.appValue(name: "sunState", value: self.sunState, in: self)
result.moonrise = self.moonrise
result.moonset = self.moonset
result.approximateMoonrise = self.approximateMoonrise
result.moonState = try CoreDataUtils.appValue(name: "moonState", value: self.moonState, in: self)
result.moonPhase = try CoreDataUtils.appValue(name: "moonPhase", value: self.moonPhase, in: self)
return result
}
/// This is here just so that we could inherit the generated init(managedObjectContext) convenience initializer.
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
required public init?(context: NSManagedObjectContext, appModel: CurrentWeather?) throws {
guard let appModel = appModel else {
return nil
}
self.init(managedObjectContext: context)
self.lastTimeUpdated = appModel.lastTimeUpdated
self.date = appModel.date
self.timeZone = try CoreDataUtils.timeZoneToString(appModel.timeZone, in: self, attributeName: "timeZone")
self.weekDay = appModel.weekDay.rawValue
self.type = appModel.type.rawValue
self.isDay = appModel.isDay
self.minTemp = try CoreDataUtils.measurementToData(appModel.minTemp, in: self, attributeName: "minTemp")
self.maxTemp = try CoreDataUtils.measurementToData(appModel.maxTemp, in: self, attributeName: "maxTemp")
self.windSpeed = try CoreDataUtils.measurementToData(appModel.windSpeed, in: self, attributeName: "windSpeed")
self.windDirection = appModel.windDirection?.rawValue
if let precipProb = appModel.precipitationProbability {
self.precipitationProbability = NSDecimalNumber(value: precipProb)
}
self.temp = try CoreDataUtils.measurementToData(appModel.temp, in: self, attributeName: "temp")
self.apparentTemp = try CoreDataUtils.measurementToData(appModel.apparentTemp, in: self, attributeName: "apparentTemp")
if let humidity = appModel.humidity {
self.humidity = NSDecimalNumber(value: humidity)
}
self.visibility = try CoreDataUtils.measurementToData(appModel.visibility, in: self, attributeName: "visibility")
self.pressure = try CoreDataUtils.measurementToData(appModel.pressure, in: self, attributeName: "pressure")
self.sunrise = appModel.sunrise
self.sunset = appModel.sunset
self.sunState = appModel.sunState?.rawValue
self.moonrise = appModel.moonrise
self.moonset = appModel.moonset
self.approximateMoonrise = appModel.approximateMoonrise
self.moonState = appModel.moonState?.rawValue
self.moonPhase = appModel.moonPhase?.rawValue
}
} }
import Foundation import Foundation
import CoreData
@objc(CoreDailyWeather) @objc(CoreDailyWeather)
open class CoreDailyWeather: _CoreDailyWeather { open class CoreDailyWeather: _CoreDailyWeather, CoreDataAppModelConvertable {
// Custom logic goes here. typealias AppModel = DailyWeather
func toAppModel() throws -> DailyWeather {
let timeZone = try CoreDataUtils.timeZone(from: self.timeZone, in: self, attributeName: "timeZone")
let weekDay: WeekDay = try CoreDataUtils.appValue(name: "weekDay", value: self.weekDay, in: self)
var result = DailyWeather(lastTimeUpdated: lastTimeUpdated, date: date, timeZone: timeZone, weekDay: weekDay)
result.type = try CoreDataUtils.appValue(name: "type", value: self.type, in: self)
result.minTemp = try CoreDataUtils.measurement(from: self.minTemp, in: self, attributeName: "minTemp")
result.maxTemp = try CoreDataUtils.measurement(from: self.maxTemp, in: self, attributeName: "maxTemp")
result.windSpeed = try CoreDataUtils.measurement(from: self.windSpeed, in: self, attributeName: "windSpeed")
result.windDirection = try CoreDataUtils.appValue(name: "windDirection", value: self.windDirection, in: self)
if let precipProb = self.precipitationProbability {
result.precipitationProbability = Percent(precipProb.uintValue)
}
result.sunrise = self.sunrise
result.sunset = self.sunset
result.sunState = try CoreDataUtils.appValue(name: "sunState", value: self.sunState, in: self)
result.moonrise = self.moonrise
result.moonset = self.moonset
result.moonState = try CoreDataUtils.appValue(name: "moonState", value: self.moonState, in: self)
result.moonPhase = try CoreDataUtils.appValue(name: "moonPhase", value: self.moonPhase, in: self)
return result
}
/// This is here just so that we could inherit the generated init(managedObjectContext) convenience initializer.
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
required public init?(context: NSManagedObjectContext, appModel: DailyWeather?) throws {
guard let appModel = appModel else {
return nil
}
self.init(managedObjectContext: context)
self.date = appModel.date
self.lastTimeUpdated = appModel.lastTimeUpdated
self.minTemp = try CoreDataUtils.measurementToData(appModel.minTemp, in: self, attributeName: "minTemp")
self.maxTemp = try CoreDataUtils.measurementToData(appModel.maxTemp, in: self, attributeName: "maxTemp")
self.moonPhase = appModel.moonPhase?.rawValue
self.moonrise = appModel.moonrise
self.moonset = appModel.moonset
self.moonState = appModel.moonState?.rawValue
if let precipProb = appModel.precipitationProbability {
self.precipitationProbability = NSDecimalNumber(value: precipProb)
}
self.sunrise = appModel.sunrise
self.sunset = appModel.sunset
self.sunState = appModel.sunState?.rawValue
self.timeZone = try CoreDataUtils.timeZoneToString(appModel.timeZone, in: self, attributeName: "timeZone")
self.type = appModel.type.rawValue
self.weekDay = appModel.weekDay.rawValue
self.windDirection = appModel.windDirection?.rawValue
self.windSpeed = try CoreDataUtils.measurementToData(appModel.windSpeed, in: self, attributeName: "windSpeed")
}
} }
import Foundation
@objc(CoreDayTimeWeather)
open class CoreDayTimeWeather: _CoreDayTimeWeather {
// Custom logic goes here.
}
import Foundation import Foundation
import CoreData
@objc(CoreHealth) @objc(CoreHealth)
open class CoreHealth: _CoreHealth { open class CoreHealth: _CoreHealth, CoreDataAppModelConvertable {
// Custom logic goes here. func toAppModel() throws -> Health {
let airQuality = try self.airQuality?.toAppModel()
var pollutants = [String: Pollutant]()
try CoreDataUtils.foreach(in: self.pollutants, of: self, attributeName: "pollutants") { (corePollutant: CorePollutant) in
let pollutant = try corePollutant.toAppModel()
pollutants[pollutant.name] = pollutant
}
let result = Health(lastUpdateTime: self.lastUpdateTime, airQuality: airQuality, pollutants: pollutants)
return result
}
/// This is here just so that we could inherit the generated init(managedObjectContext) convenience initializer.
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
required public init?(context: NSManagedObjectContext, appModel: Health?) throws {
guard let appModel = appModel else {
return nil
}
self.init(managedObjectContext: context)
self.lastUpdateTime = appModel.lastUpdateTime
self.airQuality = try CoreAirQuality(context: context, appModel: appModel.airQuality)
self.pollutants = NSOrderedSet(array: try appModel.pollutants.compactMap { try CorePollutant(context: context, appModel: $0.value) })
}
typealias AppModel = Health
} }
import Foundation import Foundation
import CoreData
@objc(CoreHourlyWeather) @objc(CoreHourlyWeather)
open class CoreHourlyWeather: _CoreHourlyWeather { open class CoreHourlyWeather: _CoreHourlyWeather, CoreDataAppModelConvertable {
// Custom logic goes here. func toAppModel() throws -> HourlyWeather {
let timeZone = try CoreDataUtils.timeZone(from: self.timeZone, in: self, attributeName: "timeZone")
let weekDay: WeekDay = try CoreDataUtils.appValue(name: "weekDay", value: self.weekDay, in: self)
var result = HourlyWeather(lastTimeUpdated: self.lastTimeUpdated, date: self.date, timeZone: timeZone, weekDay: weekDay, isDay: self.isDay)
result.type = try CoreDataUtils.appValue(name: "type", value: self.type, in: self)
result.isDay = self.isDay
result.temp = try CoreDataUtils.measurement(from: self.temp, in: self, attributeName: "temp")
result.apparentTemp = try CoreDataUtils.measurement(from: self.apparentTemp, in: self, attributeName: "apparentTemp")
result.windSpeed = try CoreDataUtils.measurement(from: self.windSpeed, in: self, attributeName: "windSpeed")
result.windDirection = try CoreDataUtils.appValue(name: "windDirection", value: self.windDirection, in: self)
if let precipProb = self.precipitationProbability {
result.precipitationProbability = Percent(precipProb.uintValue)
}
if let humidity = self.humidity {
result.humidity = Percent(humidity.uintValue)
}
return result
}
/// This is here just so that we could inherit the generated init(managedObjectContext) convenience initializer.
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
required public init?(context: NSManagedObjectContext, appModel: HourlyWeather?) throws {
guard let appModel = appModel else {
return nil
}
self.init(managedObjectContext: context)
self.lastTimeUpdated = appModel.lastTimeUpdated
self.date = appModel.date
self.timeZone = try CoreDataUtils.timeZoneToString(appModel.timeZone, in: self, attributeName: "timeZone")
self.weekDay = appModel.weekDay.rawValue
self.type = appModel.type.rawValue
self.isDay = appModel.isDay
self.temp = try CoreDataUtils.measurementToData(appModel.temp, in: self, attributeName: "temp")
self.apparentTemp = try CoreDataUtils.measurementToData(appModel.apparentTemp, in: self, attributeName: "apparentTemp")
self.windSpeed = try CoreDataUtils.measurementToData(appModel.windSpeed, in: self, attributeName: "windSpeed")
self.windDirection = appModel.windDirection?.rawValue
if let precipProb = appModel.precipitationProbability {
self.precipitationProbability = NSDecimalNumber(value: precipProb)
}
if let humidity = appModel.humidity {
self.humidity = NSDecimalNumber(value: humidity)
}
}
typealias AppModel = HourlyWeather
} }
import Foundation import Foundation
import CoreData
@objc(CoreLocation) @objc(CoreLocation)
open class CoreLocation: _CoreLocation { open class CoreLocation: _CoreLocation, CoreDataAppModelConvertable {
// Custom logic goes here. typealias AppModel = Location
func toAppModel() throws -> Location {
let timeZone = try CoreDataUtils.timeZone(from: self.timeZone, in: self, attributeName: "timeZone")
var location = Location(deviceLocation: self.deviceLocation, timeZone: timeZone)
location.lastWeatherUpdateDate = self.lastWeatherUpdateDate
if let lat = self.latitude?.doubleValue, let lon = self.longitude?.doubleValue {
location.coordinates = CLLocationCoordinate2D(latitude: lat, longitude: lon)
}
location.imageName = self.imageName
location.countryCode = self.countryCode
location.countryName = self.countryName
location.region = self.region
location.cityName = self.cityName
location.nickname = self.nickname
location.zip = self.zip
location.fipsCode = self.fipsCode
location.today = try (self.today?.toAppModel())
try CoreDataUtils.foreach(in: self.daily, of: self, attributeName: "daily") { (coreDaily: CoreDailyWeather) in
location.daily.append(try coreDaily.toAppModel())
}
try CoreDataUtils.foreach(in: self.hourly, of: self, attributeName: "hourly") { (coreHourly: CoreHourlyWeather) in
location.hourly.append(try coreHourly.toAppModel())
}
location.health = try self.health?.toAppModel()
return location
}
/// This is here just so that we could inherit the generated init(managedObjectContext) convenience initializer.
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
required public init?(context: NSManagedObjectContext, appModel: Location?) throws {
guard let appModel = appModel else {
return nil
}
self.init(managedObjectContext: context)
self.lastWeatherUpdateDate = appModel.lastWeatherUpdateDate
if let coordinates = appModel.coordinates {
self.latitude = NSDecimalNumber(value: coordinates.latitude)
self.longitude = NSDecimalNumber(value: coordinates.longitude)
}
self.imageName = appModel.imageName
self.countryCode = appModel.countryCode
self.countryName = appModel.countryName
self.region = appModel.region
self.cityName = appModel.cityName
self.nickname = appModel.nickname
self.zip = appModel.zip
self.fipsCode = appModel.fipsCode
self.today = skipIfError(attribute: "today", action: {try CoreCurrentWeather(context: context, appModel: appModel.today)})
self.daily = NSOrderedSet(array: appModel.daily.compactMap {elem in
skipIfError(attribute: "daily") {
try CoreDailyWeather(context: context, appModel: elem)
}
})
self.hourly = NSOrderedSet(array: appModel.hourly.compactMap {elem in
skipIfError(attribute: "hourly") {
try CoreHourlyWeather(context: context, appModel: elem)
}
})
self.health = skipIfError(attribute: "health", action: { try CoreHealth(context: context, appModel: appModel.health) })
}
private func skipIfError<T>(attribute: String, action: () throws -> T?) -> T? {
do {
let result = try action()
return result
}
catch {
Logger(componentName: "CoreLocation").error("Couldn't parse \(attribute) in CoreLocation due to error: \(error)")
return nil
}
}
} }
import Foundation import Foundation
import CoreData
@objc(CorePollutant) @objc(CorePollutant)
open class CorePollutant: _CorePollutant { open class CorePollutant: _CorePollutant, CoreDataAppModelConvertable {
// Custom logic goes here. func toAppModel() throws -> Pollutant {
let result = Pollutant(name: self.name, value: self.value)
return result
}
/// This is here just so that we could inherit the generated init(managedObjectContext) convenience initializer.
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
required public init?(context: NSManagedObjectContext, appModel: Pollutant?) throws {
guard let appModel = appModel else {
return nil
}
self.init(managedObjectContext: context)
self.name = appModel.name
self.value = appModel.value
}
typealias AppModel = Pollutant
} }
// DO NOT EDIT. This file is machine-generated and constantly overwritten.
// Make changes to CoreAppData.swift instead.
import Foundation
import CoreData
public enum CoreAppDataAttributes: String {
case selectedIndex = "selectedIndex"
}
public enum CoreAppDataRelationships: String {
case locations = "locations"
}
open class _CoreAppData: NSManagedObject {
// MARK: - Class methods
open class func entityName () -> String {
return "CoreAppData"
}
open class func entity(managedObjectContext: NSManagedObjectContext) -> NSEntityDescription? {
return NSEntityDescription.entity(forEntityName: self.entityName(), in: managedObjectContext)
}
@nonobjc
open class func fetchRequest() -> NSFetchRequest<CoreAppData> {
return NSFetchRequest(entityName: self.entityName())
}
// MARK: - Life cycle methods
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
public convenience init?(managedObjectContext: NSManagedObjectContext) {
guard let entity = _CoreAppData.entity(managedObjectContext: managedObjectContext) else { return nil }
self.init(entity: entity, insertInto: managedObjectContext)
}
// MARK: - Properties
@NSManaged open
var selectedIndex: Int16 // Optional scalars not supported
// MARK: - Relationships
@NSManaged open
var locations: NSOrderedSet
open func locationsSet() -> NSMutableOrderedSet {
return self.locations.mutableCopy() as! NSMutableOrderedSet
}
}
extension _CoreAppData {
open func addLocations(_ objects: NSOrderedSet) {
let mutable = self.locations.mutableCopy() as! NSMutableOrderedSet
mutable.union(objects)
self.locations = mutable.copy() as! NSOrderedSet
}
open func removeLocations(_ objects: NSOrderedSet) {
let mutable = self.locations.mutableCopy() as! NSMutableOrderedSet
mutable.minus(objects)
self.locations = mutable.copy() as! NSOrderedSet
}
open func addLocationsObject(_ value: CoreLocation) {
let mutable = self.locations.mutableCopy() as! NSMutableOrderedSet
mutable.add(value)
self.locations = mutable.copy() as! NSOrderedSet
}
open func removeLocationsObject(_ value: CoreLocation) {
let mutable = self.locations.mutableCopy() as! NSMutableOrderedSet
mutable.remove(value)
self.locations = mutable.copy() as! NSOrderedSet
}
}
...@@ -75,7 +75,7 @@ open class _CoreCurrentWeather: NSManagedObject { ...@@ -75,7 +75,7 @@ open class _CoreCurrentWeather: NSManagedObject {
var date: Date! var date: Date!
@NSManaged open @NSManaged open
var humidity: Int16 // Optional scalars not supported var humidity: NSDecimalNumber?
@NSManaged open @NSManaged open
var isDay: Bool var isDay: Bool
...@@ -102,7 +102,7 @@ open class _CoreCurrentWeather: NSManagedObject { ...@@ -102,7 +102,7 @@ open class _CoreCurrentWeather: NSManagedObject {
var moonset: Date? var moonset: Date?
@NSManaged open @NSManaged open
var precipitationProbability: Int16 // Optional scalars not supported var precipitationProbability: NSDecimalNumber?
@NSManaged open @NSManaged open
var pressure: Data? var pressure: Data?
......
...@@ -83,7 +83,7 @@ open class _CoreDailyWeather: NSManagedObject { ...@@ -83,7 +83,7 @@ open class _CoreDailyWeather: NSManagedObject {
var moonset: Date? var moonset: Date?
@NSManaged open @NSManaged open
var precipitationProbability: Int16 // Optional scalars not supported var precipitationProbability: NSDecimalNumber?
@NSManaged open @NSManaged open
var sunState: String? var sunState: String?
......
// DO NOT EDIT. This file is machine-generated and constantly overwritten.
// Make changes to CoreDayTimeWeather.swift instead.
import Foundation
import CoreData
public enum CoreDayTimeWeatherAttributes: String {
case date = "date"
case dayTime = "dayTime"
case isDay = "isDay"
case lastTimeUpdated = "lastTimeUpdated"
case temp = "temp"
case timeZone = "timeZone"
case type = "type"
case weekDay = "weekDay"
}
public enum CoreDayTimeWeatherRelationships: String {
case location = "location"
}
open class _CoreDayTimeWeather: NSManagedObject {
// MARK: - Class methods
open class func entityName () -> String {
return "CoreDayTimeWeather"
}
open class func entity(managedObjectContext: NSManagedObjectContext) -> NSEntityDescription? {
return NSEntityDescription.entity(forEntityName: self.entityName(), in: managedObjectContext)
}
@nonobjc
open class func fetchRequest() -> NSFetchRequest<CoreDayTimeWeather> {
return NSFetchRequest(entityName: self.entityName())
}
// MARK: - Life cycle methods
public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
public convenience init?(managedObjectContext: NSManagedObjectContext) {
guard let entity = _CoreDayTimeWeather.entity(managedObjectContext: managedObjectContext) else { return nil }
self.init(entity: entity, insertInto: managedObjectContext)
}
// MARK: - Properties
@NSManaged open
var date: Date!
@NSManaged open
var dayTime: Int16
@NSManaged open
var isDay: Bool
@NSManaged open
var lastTimeUpdated: Date!
@NSManaged open
var temp: Data?
@NSManaged open
var timeZone: String!
@NSManaged open
var type: String!
@NSManaged open
var weekDay: String!
// MARK: - Relationships
@NSManaged open
var location: CoreLocation?
}
...@@ -60,7 +60,7 @@ open class _CoreHourlyWeather: NSManagedObject { ...@@ -60,7 +60,7 @@ open class _CoreHourlyWeather: NSManagedObject {
var date: Date! var date: Date!
@NSManaged open @NSManaged open
var humidity: Int16 // Optional scalars not supported var humidity: NSDecimalNumber?
@NSManaged open @NSManaged open
var isDay: Bool var isDay: Bool
...@@ -69,7 +69,7 @@ open class _CoreHourlyWeather: NSManagedObject { ...@@ -69,7 +69,7 @@ open class _CoreHourlyWeather: NSManagedObject {
var lastTimeUpdated: Date! var lastTimeUpdated: Date!
@NSManaged open @NSManaged open
var precipitationProbability: Int16 // Optional scalars not supported var precipitationProbability: NSDecimalNumber?
@NSManaged open @NSManaged open
var temp: Data? var temp: Data?
......
...@@ -10,6 +10,7 @@ public enum CoreLocationAttributes: String { ...@@ -10,6 +10,7 @@ public enum CoreLocationAttributes: String {
case countryName = "countryName" case countryName = "countryName"
case deviceLocation = "deviceLocation" case deviceLocation = "deviceLocation"
case fipsCode = "fipsCode" case fipsCode = "fipsCode"
case imageName = "imageName"
case lastWeatherUpdateDate = "lastWeatherUpdateDate" case lastWeatherUpdateDate = "lastWeatherUpdateDate"
case latitude = "latitude" case latitude = "latitude"
case longitude = "longitude" case longitude = "longitude"
...@@ -20,8 +21,8 @@ public enum CoreLocationAttributes: String { ...@@ -20,8 +21,8 @@ public enum CoreLocationAttributes: String {
} }
public enum CoreLocationRelationships: String { public enum CoreLocationRelationships: String {
case appData = "appData"
case daily = "daily" case daily = "daily"
case dayTimeForecast = "dayTimeForecast"
case health = "health" case health = "health"
case hourly = "hourly" case hourly = "hourly"
case today = "today" case today = "today"
...@@ -73,10 +74,13 @@ open class _CoreLocation: NSManagedObject { ...@@ -73,10 +74,13 @@ open class _CoreLocation: NSManagedObject {
var fipsCode: String? var fipsCode: String?
@NSManaged open @NSManaged open
var imageName: String?
@NSManaged open
var lastWeatherUpdateDate: Date? var lastWeatherUpdateDate: Date?
@NSManaged open @NSManaged open
var latitude: Double // Optional scalars not supported var latitude: NSDecimalNumber?
@NSManaged open @NSManaged open
var longitude: NSDecimalNumber? var longitude: NSDecimalNumber?
...@@ -96,6 +100,9 @@ open class _CoreLocation: NSManagedObject { ...@@ -96,6 +100,9 @@ open class _CoreLocation: NSManagedObject {
// MARK: - Relationships // MARK: - Relationships
@NSManaged open @NSManaged open
var appData: CoreAppData
@NSManaged open
var daily: NSOrderedSet var daily: NSOrderedSet
open func dailySet() -> NSMutableOrderedSet { open func dailySet() -> NSMutableOrderedSet {
...@@ -103,13 +110,6 @@ open class _CoreLocation: NSManagedObject { ...@@ -103,13 +110,6 @@ open class _CoreLocation: NSManagedObject {
} }
@NSManaged open @NSManaged open
var dayTimeForecast: NSOrderedSet
open func dayTimeForecastSet() -> NSMutableOrderedSet {
return self.dayTimeForecast.mutableCopy() as! NSMutableOrderedSet
}
@NSManaged open
var health: CoreHealth? var health: CoreHealth?
@NSManaged open @NSManaged open
...@@ -154,34 +154,6 @@ extension _CoreLocation { ...@@ -154,34 +154,6 @@ extension _CoreLocation {
extension _CoreLocation { extension _CoreLocation {
open func addDayTimeForecast(_ objects: NSOrderedSet) {
let mutable = self.dayTimeForecast.mutableCopy() as! NSMutableOrderedSet
mutable.union(objects)
self.dayTimeForecast = mutable.copy() as! NSOrderedSet
}
open func removeDayTimeForecast(_ objects: NSOrderedSet) {
let mutable = self.dayTimeForecast.mutableCopy() as! NSMutableOrderedSet
mutable.minus(objects)
self.dayTimeForecast = mutable.copy() as! NSOrderedSet
}
open func addDayTimeForecastObject(_ value: CoreDayTimeWeather) {
let mutable = self.dayTimeForecast.mutableCopy() as! NSMutableOrderedSet
mutable.add(value)
self.dayTimeForecast = mutable.copy() as! NSOrderedSet
}
open func removeDayTimeForecastObject(_ value: CoreDayTimeWeather) {
let mutable = self.dayTimeForecast.mutableCopy() as! NSMutableOrderedSet
mutable.remove(value)
self.dayTimeForecast = mutable.copy() as! NSOrderedSet
}
}
extension _CoreLocation {
open func addHourly(_ objects: NSOrderedSet) { open func addHourly(_ objects: NSOrderedSet) {
let mutable = self.hourly.mutableCopy() as! NSMutableOrderedSet let mutable = self.hourly.mutableCopy() as! NSMutableOrderedSet
mutable.union(objects) mutable.union(objects)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment