Przeglądaj źródła

Add logic to only import most recent 24 hours of glucose readings

Sam King 1 rok temu
rodzic
commit
c1110eafac

+ 4 - 0
Model/Helper/NSPredicates.swift

@@ -120,4 +120,8 @@ extension NSPredicate {
         let date = Date.threeMonthsAgo
         return NSPredicate(format: "date >= %@", date as NSDate)
     }
+
+    static func predicateForDateBetween(start: Date, end: Date) -> NSPredicate {
+        NSPredicate(format: "date >= %@ AND date <= %@", start as NSDate, end as NSDate)
+    }
 }

+ 12 - 8
Model/JSONImporter.swift

@@ -40,13 +40,14 @@ class JSONImporter {
 
     /// Retrieves the set of dates for all glucose values currently stored in CoreData.
     ///
+    /// - Parameters: the start and end dates to fetch glucose values, inclusive
     /// - Returns: A set of dates corresponding to existing glucose readings.
     /// - Throws: An error if the fetch operation fails.
-    private func fetchGlucoseDates() async throws -> Set<Date> {
+    private func fetchGlucoseDates(start: Date, end: Date) async throws -> Set<Date> {
         let allReadings = try await coreDataStack.fetchEntitiesAsync(
             ofType: GlucoseStored.self,
             onContext: context,
-            predicate: NSPredicate(format: "TRUEPREDICATE"),
+            predicate: .predicateForDateBetween(start: start, end: end),
             key: "date",
             ascending: false
         ) as? [GlucoseStored] ?? []
@@ -65,13 +66,16 @@ class JSONImporter {
     ///   - JSONImporterError.missingGlucoseValueInGlucoseEntry if a glucose entry is missing a value.
     ///   - An error if the file cannot be read or decoded.
     ///   - An error if the CoreData operation fails.
-    func importGlucoseHistory(url: URL) async throws {
-        let glucoseHistory: [BloodGlucose] = try readJsonFile(url: url)
-        let existingDates = try await fetchGlucoseDates()
+    func importGlucoseHistory(url: URL, now: Date) async throws {
+        let twentyFourHoursAgo = now - 24.hours.timeInterval
+        let glucoseHistoryFull: [BloodGlucose] = try readJsonFile(url: url)
+        let existingDates = try await fetchGlucoseDates(start: twentyFourHoursAgo, end: now)
+
+        // only import glucose values from the last 24 hours that don't exist
+        let glucoseHistory = glucoseHistoryFull
+            .filter { $0.dateString >= twentyFourHoursAgo && $0.dateString <= now && !existingDates.contains($0.dateString) }
         for glucoseEntry in glucoseHistory {
-            if !existingDates.contains(glucoseEntry.dateString) {
-                try glucoseEntry.store(in: context)
-            }
+            try glucoseEntry.store(in: context)
         }
     }
 }

+ 23 - 2
TrioTests/JSONImporterTests.swift

@@ -30,9 +30,10 @@ class BundleReference {}
         let path = testBundle.path(forResource: "glucose", ofType: "json")!
         let url = URL(filePath: path)
 
-        try await importer.importGlucoseHistory(url: url)
+        let now = Date("2025-04-28T19:32:52.000Z")!
+        try await importer.importGlucoseHistory(url: url, now: now)
         // run the import againt to check our deduplication logic
-        try await importer.importGlucoseHistory(url: url)
+        try await importer.importGlucoseHistory(url: url, now: now)
 
         let allReadings = try await coreDataStack.fetchEntitiesAsync(
             ofType: GlucoseStored.self,
@@ -51,4 +52,24 @@ class BundleReference {}
         let manualCount = allReadings.filter({ $0.isManual }).count
         #expect(manualCount == 1)
     }
+
+    @Test("Skip importing old glucose values") func testSkipImportOldGlucoseValues() async throws {
+        let testBundle = Bundle(for: BundleReference.self)
+        let path = testBundle.path(forResource: "glucose", ofType: "json")!
+        let url = URL(filePath: path)
+
+        // more than 24 hours past the most recent entry
+        let now = Date("2025-04-29T19:32:52.000Z")!
+        try await importer.importGlucoseHistory(url: url, now: now)
+
+        let allReadings = try await coreDataStack.fetchEntitiesAsync(
+            ofType: GlucoseStored.self,
+            onContext: context,
+            predicate: NSPredicate(format: "TRUEPREDICATE"),
+            key: "date",
+            ascending: false
+        ) as? [GlucoseStored] ?? []
+
+        #expect(allReadings.isEmpty)
+    }
 }