-
Notifications
You must be signed in to change notification settings - Fork 452
fix: Query HealthKit samples over specified date interval #723
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix: Query HealthKit samples over specified date interval #723
Conversation
// Search over the interval provided by OCKOutcomeQuery if present | ||
// or else constrain sample query over the current day. | ||
let dateInterval = outcomeQuery.dateInterval ?? | ||
Calendar.current.dateInterval(of: .day, for: Date())! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to
CareKit/CareKitStore/CareKitStore/Protocols/Events/OCKReadOnlyEventStore+VersioningUtilities.swift
Lines 225 to 232 in b16d15c
// We need to explicitly set the date interval in case it's nil | |
// to ensure that we fetch the most recent version of a task in a | |
// given date interval, and not all versions of the task | |
let dateInterval = latestTaskVersionsQuery.dateInterval ?? | |
Calendar.current.dateInterval(of: .day, for: Date())! | |
latestTaskVersionsQuery.dateInterval = dateInterval |
* feat: All OCKOutcomeQuery sorting * effectiveDate ascending should be false for all single queries * add unit tests
@@ -144,6 +144,7 @@ extension OCKStore { | |||
switch order { | |||
case .effectiveDate(let ascending): return NSSortDescriptor(keyPath: \OCKCDCarePlan.effectiveDate, ascending: ascending) | |||
case .title(let ascending): return NSSortDescriptor(keyPath: \OCKCDCarePlan.title, ascending: ascending) | |||
case .groupIdentifier(let ascending): return NSSortDescriptor(keyPath: \OCKCDCarePlan.groupIdentifier, ascending: ascending) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added groupIdentifier sort to all that was missing
|
||
var taskQuery = OCKTaskQuery(dateInterval: dateInterval) | ||
taskQuery.ids = outcomeQuery.taskIDs | ||
taskQuery.remoteIDs = outcomeQuery.taskRemoteIDs | ||
taskQuery.uuids = outcomeQuery.taskUUIDs | ||
taskQuery.sortDescriptors = outcomeQuery.sortDescriptors.map { descriptor in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass relevant sort criteria to the task query.
@@ -138,7 +138,7 @@ public extension OCKAnyReadOnlyCarePlanStore { | |||
completion: @escaping OCKResultClosure<OCKAnyCarePlan>) { | |||
var query = OCKCarePlanQuery(for: Date()) | |||
query.limit = 1 | |||
query.sortDescriptors = [.effectiveDate(ascending: true)] | |||
query.sortDescriptors = [.effectiveDate(ascending: false)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of these should be false to always get the newest version related to today, similar to how the fetching task was set up.
@@ -44,14 +44,13 @@ extension OCKStoreCoordinator { | |||
$0.anyOutcomes(matching: query) | |||
} | |||
|
|||
let sortDescriptor = NSSortDescriptor( | |||
keyPath: \OCKCDOutcome.id, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming this is leftover from when the OCKCDOutcome.id had the the task occurrence appended to it:
public var id: String { taskUUID.uuidString + "_\(taskOccurrenceIndex)" } |
@@ -33,6 +33,22 @@ import Foundation | |||
/// A query that limits which outcomes will be returned when fetching. | |||
public struct OCKOutcomeQuery: Equatable, OCKQueryProtocol { | |||
|
|||
/// Specifies the order in which query results will be sorted. | |||
public enum SortDescriptor: Equatable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a sort descriptor for OCKOutcomeQuery
@@ -133,7 +133,7 @@ public protocol OCKAnyTaskStore: OCKAnyReadOnlyTaskStore { | |||
|
|||
public extension OCKAnyReadOnlyTaskStore { | |||
func fetchAnyTask(withID id: String, callbackQueue: DispatchQueue = .main, completion: @escaping OCKResultClosure<OCKAnyTask>) { | |||
var query = OCKTaskQuery(id: id) | |||
var query = OCKTaskQuery(for: Date()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switched this so it's aligned with the other Entity fetches. It was setting the id
twice instead of querying the current version for today. Without the change, it's possible for this fetch to return a future version of the task since it would have a future effectiveDate
.
@@ -356,13 +356,34 @@ class TestStoreTasks: XCTestCase { | |||
|
|||
var taskV2 = taskV1 | |||
taskV2.title = "V2" | |||
taskV2.effectiveDate = Calendar.current.date(byAdding: .year, value: 1, to: Date())! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adjusted this test based on #723 (comment). This effectiveDate
essentially could have been next year and it would have returned next years task today, which would be unexpected
98bc61c
to
e9be043
Compare
This fixes a problem where all HealthKit queries using CareKit don't take advantage of the
DateInterval
specified inOCKOutcomeQuery
and instead default to theDateInterval
of the current day, resulting in all HealthKit samples being queried for the whole day. This can become expensive when a developer only needs samples for a small interval. In addition, it doesn't allow querying over days different from the current day. This is because the taskdateInterval
is propagated to generateHKQueryDescriptor
's here:CareKit/CareKitStore/CareKitStore/HealthKit/OCKHealthKitPassthroughStore+EventUtilities.swift
Lines 577 to 590 in b16d15c
OCKOutcomeQuery
if provided or else default to current dayfetchAnyTask(withID...)
to always return the current version based on thetaskID
effectiveDate
andgroupIdentifier
to OCKOutcomeQueryeffectiveDate
assending asfalse
for all single entity fetches