MigrationScript.swift 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import CoreData
  2. import Foundation
  3. class JSONImporter {
  4. private let context: NSManagedObjectContext
  5. private let fileManager = FileManager.default
  6. init(context: NSManagedObjectContext) {
  7. self.context = context
  8. }
  9. func importPumpHistoryIfNeeded() async {
  10. let userDefaultsKey = "pumpHistoryImported"
  11. let hasImported = UserDefaults.standard.bool(forKey: userDefaultsKey)
  12. guard !hasImported else {
  13. debugPrint("Pump history already imported. Skipping import.")
  14. return
  15. }
  16. do {
  17. // Get filepath
  18. guard let filePath = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
  19. .first?
  20. .appendingPathComponent(OpenAPS.Monitor.pumpHistory),
  21. fileManager.fileExists(atPath: filePath.path)
  22. else {
  23. debugPrint("Pump history file not found at path \(OpenAPS.Monitor.pumpHistory)")
  24. return
  25. }
  26. // Read JSON and decode
  27. let data = try Data(contentsOf: filePath)
  28. let pumpEvents = try JSONDecoder().decode([PumpEventDTO].self, from: data)
  29. // Save to Core Data
  30. await context.perform {
  31. for event in pumpEvents {
  32. self.storePumpEventFromDTO(event)
  33. }
  34. do {
  35. guard self.context.hasChanges else { return }
  36. try self.context.save()
  37. debugPrint("\(DebuggingIdentifiers.succeeded) Pump history successfully imported into Core Data.")
  38. } catch {
  39. debugPrint("\(DebuggingIdentifiers.failed) Failed to save pump history to Core Data: \(error)")
  40. }
  41. }
  42. // Delete JSON
  43. try fileManager.removeItem(at: filePath)
  44. debugPrint("pumphistory.json deleted after successful import.")
  45. // Update UserDefaults flag
  46. UserDefaults.standard.set(true, forKey: userDefaultsKey)
  47. } catch {
  48. debugPrint("Error importing pump history: \(error)")
  49. }
  50. }
  51. private func storePumpEventFromDTO(_ event: PumpEventDTO) {
  52. // Map each type of PumpEventDTO to its corresponding Core Data model.
  53. switch event {
  54. case let .bolus(bolusDTO):
  55. let pumpEvent = PumpEventStored(context: context)
  56. pumpEvent.id = bolusDTO.id
  57. pumpEvent.timestamp = ISO8601DateFormatter().date(from: bolusDTO.timestamp)
  58. pumpEvent.type = bolusDTO._type
  59. let bolus = BolusStored(context: context)
  60. bolus.amount = NSDecimalNumber(value: bolusDTO.amount)
  61. bolus.isExternal = bolusDTO.isExternal
  62. bolus.isSMB = bolusDTO.isSMB ?? false
  63. pumpEvent.bolus = bolus
  64. case let .tempBasal(tempBasalDTO):
  65. let pumpEvent = PumpEventStored(context: context)
  66. pumpEvent.id = tempBasalDTO.id
  67. pumpEvent.timestamp = ISO8601DateFormatter().date(from: tempBasalDTO.timestamp)
  68. pumpEvent.type = tempBasalDTO._type
  69. let tempBasal = TempBasalStored(context: context)
  70. tempBasal.tempType = tempBasalDTO.temp
  71. tempBasal.rate = NSDecimalNumber(value: tempBasalDTO.rate)
  72. pumpEvent.tempBasal = tempBasal
  73. case let .tempBasalDuration(tempBasalDurationDTO):
  74. let pumpEvent = PumpEventStored(context: context)
  75. pumpEvent.id = tempBasalDurationDTO.id
  76. pumpEvent.timestamp = ISO8601DateFormatter().date(from: tempBasalDurationDTO.timestamp)
  77. pumpEvent.type = tempBasalDurationDTO._type
  78. let tempBasal = TempBasalStored(context: context)
  79. tempBasal.duration = Int16(tempBasalDurationDTO.duration)
  80. pumpEvent.tempBasal = tempBasal
  81. case .pumpSuspend:
  82. return
  83. }
  84. }
  85. func importCarbHistoryIfNeeded() async {
  86. let userDefaultsKey = "carbHistoryImported"
  87. let hasImported = UserDefaults.standard.bool(forKey: userDefaultsKey)
  88. guard !hasImported else {
  89. debugPrint("Carb history already imported. Skipping import.")
  90. return
  91. }
  92. do {
  93. // Get filepath
  94. guard let filePath = fileManager.urls(for: .documentDirectory, in: .userDomainMask)
  95. .first?
  96. .appendingPathComponent(OpenAPS.Monitor.carbHistory),
  97. fileManager.fileExists(atPath: filePath.path)
  98. else {
  99. debugPrint("Carb history file not found at path \(OpenAPS.Monitor.carbHistory)")
  100. return
  101. }
  102. // Read JSON and decode
  103. let data = try Data(contentsOf: filePath)
  104. let decoder = JSONDecoder()
  105. decoder.dateDecodingStrategy = .iso8601
  106. // Decode JSON
  107. let carbEntries = try decoder.decode([CarbEntryDTO].self, from: data)
  108. // Save to Core Data
  109. await context.perform {
  110. for entryDTO in carbEntries {
  111. self.storeCarbEntryFromDTO(entryDTO)
  112. }
  113. do {
  114. guard self.context.hasChanges else { return }
  115. try self.context.save()
  116. debugPrint("\(DebuggingIdentifiers.succeeded) Carb history successfully imported into Core Data.")
  117. } catch {
  118. debugPrint("\(DebuggingIdentifiers.failed) Failed to save carb history to Core Data: \(error)")
  119. }
  120. }
  121. // Delete JSON
  122. try fileManager.removeItem(at: filePath)
  123. debugPrint("carbHistory.json deleted after successful import.")
  124. // Update UserDefaults flag
  125. UserDefaults.standard.set(true, forKey: userDefaultsKey)
  126. } catch {
  127. debugPrint("Error importing carb history: \(error)")
  128. }
  129. }
  130. private func storeCarbEntryFromDTO(_ entryDTO: CarbEntryDTO) {
  131. let carbEntry = CarbEntryStored(context: context)
  132. carbEntry.id = entryDTO.id ?? UUID()
  133. carbEntry.carbs = entryDTO.carbs
  134. carbEntry.date = entryDTO.date ?? Date()
  135. carbEntry.fat = entryDTO.fat ?? 0.0
  136. carbEntry.protein = entryDTO.protein ?? 0.0
  137. carbEntry.isFPU = entryDTO.isFPU ?? false
  138. carbEntry.note = entryDTO.note
  139. carbEntry.isUploadedToNS = false
  140. carbEntry.isUploadedToHealth = false
  141. carbEntry.isUploadedToTidepool = false
  142. }
  143. }