DataManager.swift 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import CoreData
  2. import Foundation
  3. // Fetch Data for Glucose and Determination from Core Data and map them to the Structs in order to pass them thread safe to the glucoseDidUpdate/ pushUpdate function
  4. @available(iOS 16.2, *)
  5. extension LiveActivityManager {
  6. func fetchAndMapGlucose() async throws -> [GlucoseData] {
  7. let results = try await CoreDataStack.shared.fetchEntitiesAsync(
  8. ofType: GlucoseStored.self,
  9. onContext: context,
  10. predicate: NSPredicate.predicateForSixHoursAgo,
  11. key: "date",
  12. ascending: false,
  13. fetchLimit: 72
  14. )
  15. return try await context.perform {
  16. guard let glucoseResults = results as? [GlucoseStored] else {
  17. throw CoreDataError.fetchError(function: #function, file: #file)
  18. }
  19. return glucoseResults.map {
  20. GlucoseData(glucose: Int($0.glucose), date: $0.date ?? Date(), direction: $0.directionEnum)
  21. }
  22. }
  23. }
  24. // TODO: extract logic or at least rename function appropiately
  25. func fetchAndMapDetermination() async throws -> DeterminationData? {
  26. let results = try await CoreDataStack.shared.fetchEntitiesAsync(
  27. ofType: OrefDetermination.self,
  28. onContext: context,
  29. predicate: NSPredicate.predicateFor30MinAgoForDetermination,
  30. key: "deliverAt",
  31. ascending: false,
  32. fetchLimit: 1,
  33. propertiesToFetch: ["cob", "currentTarget", "deliverAt"]
  34. )
  35. let tddResults = try await CoreDataStack.shared.fetchEntitiesAsync(
  36. ofType: TDDStored.self,
  37. onContext: context,
  38. predicate: NSPredicate.predicateFor30MinAgo,
  39. key: "date",
  40. ascending: false,
  41. fetchLimit: 1,
  42. propertiesToFetch: ["total"]
  43. )
  44. return try await context.perform {
  45. guard let determinationResults = results as? [[String: Any]], let tddResults = tddResults as? [[String: Any]] else {
  46. throw CoreDataError.fetchError(function: #function, file: #file)
  47. }
  48. guard let determination = determinationResults.first else {
  49. return nil
  50. }
  51. let tddValue = (tddResults.first?["total"] as? NSDecimalNumber)?.decimalValue ?? 0
  52. return DeterminationData(
  53. cob: (determination["cob"] as? Int) ?? 0,
  54. tdd: tddValue,
  55. target: (determination["currentTarget"] as? NSDecimalNumber)?.decimalValue ?? 0,
  56. date: determination["deliverAt"] as? Date ?? nil
  57. )
  58. }
  59. }
  60. func fetchAndMapTempTarget() async throws -> TempTargetData? {
  61. try await fetchAndMapLatest(
  62. ofType: TempTargetStored.self,
  63. predicate: .predicateForOneDayAgo,
  64. key: "date",
  65. propertiesToFetch: ["enabled", "name", "target", "date", "duration"]
  66. ) { row in
  67. TempTargetData(
  68. isActive: row["enabled"] as? Bool ?? false,
  69. tempTargetName: row["name"] as? String ?? "Temp Target",
  70. date: row["date"] as? Date ?? Date(),
  71. duration: row["duration"] as? Decimal ?? 0,
  72. target: row["target"] as? Decimal ?? 0
  73. )
  74. }
  75. }
  76. func fetchAndMapOverride() async throws -> OverrideData? {
  77. try await fetchAndMapLatest(
  78. ofType: OverrideStored.self,
  79. predicate: .predicateForOneDayAgo,
  80. key: "date",
  81. propertiesToFetch: ["enabled", "name", "target", "date", "duration"]
  82. ) { row in
  83. OverrideData(
  84. isActive: row["enabled"] as? Bool ?? false,
  85. overrideName: row["name"] as? String ?? "Override",
  86. date: row["date"] as? Date ?? Date(),
  87. duration: row["duration"] as? Decimal ?? 0,
  88. target: row["target"] as? Decimal ?? 0
  89. )
  90. }
  91. }
  92. private func fetchAndMapLatest<Entity: NSManagedObject, Output>(
  93. ofType type: Entity.Type,
  94. predicate: NSPredicate,
  95. key: String,
  96. propertiesToFetch: [String],
  97. map: @escaping ([String: Any]) -> Output
  98. ) async throws -> Output? {
  99. let results = try await CoreDataStack.shared.fetchEntitiesAsync(
  100. ofType: type,
  101. onContext: context,
  102. predicate: predicate,
  103. key: key,
  104. ascending: false,
  105. fetchLimit: 1,
  106. propertiesToFetch: propertiesToFetch
  107. )
  108. return try await context.perform {
  109. guard let rows = results as? [[String: Any]] else {
  110. throw CoreDataError.fetchError(function: #function, file: #file)
  111. }
  112. return rows.first.map(map)
  113. }
  114. }
  115. }