Determination+helper.swift 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import CoreData
  2. import Foundation
  3. extension OrefDetermination {
  4. static func fetch(_ predicate: NSPredicate = .predicateForOneDayAgo) -> NSFetchRequest<OrefDetermination> {
  5. let request = OrefDetermination.fetchRequest()
  6. request.sortDescriptors = [NSSortDescriptor(keyPath: \OrefDetermination.deliverAt, ascending: false)]
  7. request.predicate = predicate
  8. request.fetchLimit = 1
  9. return request
  10. }
  11. }
  12. extension OrefDetermination {
  13. var reasonParts: [String] {
  14. reason?.components(separatedBy: "; ").first?.components(separatedBy: ", ") ?? []
  15. }
  16. var reasonConclusion: String {
  17. reason?.components(separatedBy: "; ").last ?? ""
  18. }
  19. }
  20. extension NSPredicate {
  21. static var enactedDetermination: NSPredicate {
  22. let date = Date.halfHourAgo
  23. return NSPredicate(format: "enacted == %@ AND timestamp >= %@", true as NSNumber, date as NSDate)
  24. }
  25. static var determinationsForCobIobCharts: NSPredicate {
  26. let date = Date.oneDayAgo
  27. return NSPredicate(format: "deliverAt >= %@", date as NSDate)
  28. }
  29. static var enactedDeterminationsNotYetUploadedToNightscout: NSPredicate {
  30. NSPredicate(
  31. format: "deliverAt >= %@ AND isUploadedToNS == %@ AND enacted == %@",
  32. Date.sixHoursAgo as NSDate,
  33. false as NSNumber,
  34. true as NSNumber
  35. )
  36. }
  37. static var suggestedDeterminationsNotYetUploadedToNightscout: NSPredicate {
  38. NSPredicate(
  39. format: "deliverAt >= %@ AND isUploadedToNS == %@ AND (enacted == %@ OR enacted == nil OR enacted != %@)",
  40. Date.sixHoursAgo as NSDate,
  41. false as NSNumber,
  42. true as NSNumber,
  43. true as NSNumber
  44. )
  45. }
  46. }
  47. // MARK: - DeterminationDTO and Conformance to ImportableDTO
  48. /// Data Transfer Object for the enacted.json.
  49. struct DeterminationDTO: Decodable, ImportableDTO {
  50. let tdd: Decimal?
  51. let threshold: Decimal?
  52. let timestamp: String?
  53. let insulinForManualBolus: Decimal?
  54. let sensitivityRatio: Decimal?
  55. let predictions: Predictions?
  56. let received: Bool?
  57. let currentTarget: Decimal?
  58. let expectedDelta: Decimal?
  59. let cob: Int?
  60. let minDelta: Decimal?
  61. let bg: Decimal?
  62. let manualBolusErrorString: Decimal?
  63. let eventualBG: Decimal?
  64. let isf: Decimal?
  65. let rate: Decimal?
  66. let duration: Decimal?
  67. let temp: String?
  68. let insulinReq: Decimal?
  69. let insulin: Insulin?
  70. let deliverAt: String?
  71. let reason: String?
  72. let iob: Decimal?
  73. let reservoir: Decimal?
  74. enum CodingKeys: String, CodingKey {
  75. case tdd = "TDD"
  76. case threshold
  77. case timestamp
  78. case insulinForManualBolus
  79. case sensitivityRatio
  80. case predictions = "predBGs"
  81. case received = "recieved"
  82. case currentTarget = "current_target"
  83. case expectedDelta
  84. case cob = "COB"
  85. case minDelta
  86. case bg
  87. case manualBolusErrorString
  88. case eventualBG
  89. case isf = "ISF"
  90. case rate
  91. case duration
  92. case temp
  93. case insulinReq
  94. case insulin
  95. case deliverAt
  96. case reason
  97. case iob = "IOB"
  98. case reservoir
  99. }
  100. // Conformance to ImportableDTO
  101. typealias ManagedObject = OrefDetermination
  102. /// Stores the DTO in Core Data by mapping it to the corresponding managed object.
  103. func store(in context: NSManagedObjectContext) -> OrefDetermination {
  104. let determinationEntity = OrefDetermination(context: context)
  105. let dateFormatter = ISO8601DateFormatter()
  106. determinationEntity.timestamp = timestamp.flatMap { dateFormatter.date(from: $0) }
  107. determinationEntity.deliverAt = deliverAt.flatMap { dateFormatter.date(from: $0) }
  108. determinationEntity.cob = cob.map { Int16($0) } ?? 0
  109. determinationEntity.temp = temp
  110. determinationEntity.iob = iob.map { NSDecimalNumber(decimal: $0) }
  111. determinationEntity.minDelta = minDelta.map { NSDecimalNumber(decimal: $0) }
  112. determinationEntity.expectedDelta = expectedDelta.map { NSDecimalNumber(decimal: $0) }
  113. determinationEntity.rate = rate.map { NSDecimalNumber(decimal: $0) }
  114. determinationEntity.reason = reason
  115. determinationEntity.totalDailyDose = tdd.map { NSDecimalNumber(decimal: $0) }
  116. determinationEntity.reservoir = reservoir.map { NSDecimalNumber(decimal: $0) }
  117. determinationEntity.duration = duration.map { NSDecimalNumber(decimal: $0) }
  118. determinationEntity.currentTarget = currentTarget.map { NSDecimalNumber(decimal: $0) }
  119. determinationEntity.insulinForManualBolus = insulinForManualBolus.map { NSDecimalNumber(decimal: $0) }
  120. determinationEntity.sensitivityRatio = sensitivityRatio.map { NSDecimalNumber(decimal: $0) }
  121. determinationEntity.threshold = threshold.map { NSDecimalNumber(decimal: $0) }
  122. determinationEntity.eventualBG = eventualBG.map { NSDecimalNumber(decimal: $0) }
  123. determinationEntity.received = received ?? false
  124. determinationEntity.insulinReq = insulinReq.map { NSDecimalNumber(decimal: $0) }
  125. determinationEntity.insulinSensitivity = isf.map { NSDecimalNumber(decimal: $0) }
  126. determinationEntity.manualBolusErrorString = manualBolusErrorString.map { NSDecimalNumber(decimal: $0) }
  127. determinationEntity.glucose = bg.map { NSDecimalNumber(decimal: $0) }
  128. if let predictionData = predictions {
  129. var forecasts = Set<Forecast>()
  130. if let iobPredictions = predictionData.iob {
  131. forecasts.insert(createForecast(context: context, type: "IOB", values: iobPredictions))
  132. }
  133. if let ztPredictions = predictionData.zt {
  134. forecasts.insert(createForecast(context: context, type: "ZT", values: ztPredictions))
  135. }
  136. if let uamPredictions = predictionData.uam {
  137. forecasts.insert(createForecast(context: context, type: "UAM", values: uamPredictions))
  138. }
  139. determinationEntity.forecasts = forecasts
  140. }
  141. return determinationEntity
  142. }
  143. private func createForecast(context: NSManagedObjectContext, type: String, values: [Int]) -> Forecast {
  144. let forecast = Forecast(context: context)
  145. forecast.type = type
  146. forecast.date = Date()
  147. forecast.forecastValues = Set(values.enumerated().map { index, value in
  148. let forecastValue = ForecastValue(context: context)
  149. forecastValue.index = Int32(index)
  150. forecastValue.value = Int32(value)
  151. return forecastValue
  152. })
  153. return forecast
  154. }
  155. }