GlucoseStored+helper.swift 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import CoreData
  2. import Foundation
  3. extension GlucoseStored {
  4. static func fetch(
  5. _ predicate: NSPredicate = .all,
  6. ascending: Bool,
  7. fetchLimit: Int? = nil,
  8. batchSize: Int? = nil
  9. ) -> NSFetchRequest<GlucoseStored> {
  10. let request = GlucoseStored.fetchRequest()
  11. request.sortDescriptors = [NSSortDescriptor(keyPath: \GlucoseStored.date, ascending: ascending)]
  12. request.predicate = predicate
  13. if let limit = fetchLimit {
  14. request.fetchLimit = limit
  15. }
  16. if let batchSize = batchSize {
  17. request.fetchBatchSize = batchSize
  18. }
  19. return request
  20. }
  21. static func glucoseIsFlat(_ glucose: [GlucoseStored]) -> Bool {
  22. guard glucose.count >= 6 else { return false }
  23. let firstValue = glucose.first?.glucose
  24. return glucose.allSatisfy { $0.glucose == firstValue }
  25. }
  26. }
  27. extension NSPredicate {
  28. static var glucose: NSPredicate {
  29. let date = Date.oneDayAgo
  30. return NSPredicate(format: "date >= %@", date as NSDate)
  31. }
  32. static var manualGlucose: NSPredicate {
  33. let date = Date.oneDayAgo
  34. return NSPredicate(format: "isManual == %@ AND date >= %@", true as NSNumber, date as NSDate)
  35. }
  36. static var glucoseForStatsDay: NSPredicate {
  37. let date = Date.oneDayAgo
  38. return NSPredicate(format: "date >= %@", date as NSDate)
  39. }
  40. static var glucoseForStatsToday: NSPredicate {
  41. let date = Date.startOfToday
  42. return NSPredicate(format: "date >= %@", date as NSDate)
  43. }
  44. static var glucoseForStatsMonth: NSPredicate {
  45. let date = Date.oneMonthAgo
  46. return NSPredicate(format: "date >= %@", date as NSDate)
  47. }
  48. static var glucoseForStatsTotal: NSPredicate {
  49. let date = Date.threeMonthsAgo
  50. return NSPredicate(format: "date >= %@", date as NSDate)
  51. }
  52. static var glucoseForStatsWeek: NSPredicate {
  53. let date = Date.oneWeekAgo
  54. return NSPredicate(format: "date >= %@", date as NSDate)
  55. }
  56. static var glucoseNotYetUploadedToNightscout: NSPredicate {
  57. let date = Date.oneDayAgo
  58. return NSPredicate(format: "date >= %@ AND isUploadedToNS == %@", date as NSDate, false as NSNumber)
  59. }
  60. static var glucoseNotYetUploadedToHealth: NSPredicate {
  61. let date = Date.oneDayAgo
  62. return NSPredicate(format: "date >= %@ AND isUploadedToHealth == %@", date as NSDate, false as NSNumber)
  63. }
  64. static var glucoseNotYetUploadedToTidepool: NSPredicate {
  65. let date = Date.oneDayAgo
  66. return NSPredicate(format: "date >= %@ AND isUploadedToTidepool == %@", date as NSDate, false as NSNumber)
  67. }
  68. static var manualGlucoseNotYetUploadedToNightscout: NSPredicate {
  69. let date = Date.oneDayAgo
  70. return NSPredicate(
  71. format: "date >= %@ AND isUploadedToNS == %@ AND isManual == %@",
  72. date as NSDate,
  73. false as NSNumber,
  74. true as NSNumber
  75. )
  76. }
  77. static var manualGlucoseNotYetUploadedToHealth: NSPredicate {
  78. let date = Date.oneDayAgo
  79. return NSPredicate(
  80. format: "date >= %@ AND isUploadedToHealth == %@ AND isManual == %@",
  81. date as NSDate,
  82. false as NSNumber,
  83. true as NSNumber
  84. )
  85. }
  86. }
  87. extension GlucoseStored: Encodable {
  88. enum CodingKeys: String, CodingKey {
  89. case date
  90. case dateString
  91. case sgv
  92. case glucose
  93. case direction
  94. case id
  95. case type
  96. }
  97. public func encode(to encoder: Encoder) throws {
  98. var container = encoder.container(keyedBy: CodingKeys.self)
  99. let dateFormatter = ISO8601DateFormatter()
  100. dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
  101. try container.encode(dateFormatter.string(from: date ?? Date()), forKey: .dateString)
  102. let dateAsUnixTimestamp = String(format: "%.0f", (date?.timeIntervalSince1970 ?? Date().timeIntervalSince1970) * 1000)
  103. try container.encode(dateAsUnixTimestamp, forKey: .date)
  104. try container.encode(direction, forKey: .direction)
  105. try container.encode(id, forKey: .id)
  106. // TODO: Handle the type of the glucose entry conditionally not hardcoded
  107. try container.encode("sgv", forKey: .type)
  108. if isManual {
  109. try container.encode(glucose, forKey: .glucose)
  110. } else {
  111. try container.encode(glucose, forKey: .sgv)
  112. }
  113. }
  114. }
  115. // In order to show the correct direction in the bobble we convert the direction property of the NSManagedObject GlucoseStored back to the Direction type
  116. extension GlucoseStored {
  117. var directionEnum: BloodGlucose.Direction? {
  118. BloodGlucose.Direction(rawValue: direction ?? "")
  119. }
  120. }