GlucoseStored+helper.swift 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. static var manualGlucoseNotYetUploadedToTidepool: NSPredicate {
  87. let date = Date.oneDayAgo
  88. return NSPredicate(
  89. format: "date >= %@ AND isUploadedToTidepool == %@ AND isManual == %@",
  90. date as NSDate,
  91. false as NSNumber,
  92. true as NSNumber
  93. )
  94. }
  95. }
  96. extension GlucoseStored: Encodable {
  97. enum CodingKeys: String, CodingKey {
  98. case date
  99. case dateString
  100. case sgv
  101. case glucose
  102. case direction
  103. case id
  104. case type
  105. }
  106. public func encode(to encoder: Encoder) throws {
  107. var container = encoder.container(keyedBy: CodingKeys.self)
  108. let dateFormatter = ISO8601DateFormatter()
  109. dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
  110. try container.encode(dateFormatter.string(from: date ?? Date()), forKey: .dateString)
  111. let dateAsUnixTimestamp = String(format: "%.0f", (date?.timeIntervalSince1970 ?? Date().timeIntervalSince1970) * 1000)
  112. try container.encode(dateAsUnixTimestamp, forKey: .date)
  113. try container.encode(direction, forKey: .direction)
  114. try container.encode(id, forKey: .id)
  115. // TODO: Handle the type of the glucose entry conditionally not hardcoded
  116. try container.encode("sgv", forKey: .type)
  117. if isManual {
  118. try container.encode(glucose, forKey: .glucose)
  119. } else {
  120. try container.encode(glucose, forKey: .sgv)
  121. }
  122. }
  123. }
  124. // In order to show the correct direction in the bobble we convert the direction property of the NSManagedObject GlucoseStored back to the Direction type
  125. extension GlucoseStored {
  126. var directionEnum: BloodGlucose.Direction? {
  127. BloodGlucose.Direction(rawValue: direction ?? "")
  128. }
  129. }