Skip to content
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

feat: All OCKOutcomeQuery sorting #22

Merged
merged 3 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
} + query.defaultSortDescriptors()
}
Expand Down
1 change: 1 addition & 0 deletions CareKitStore/CareKitStore/CoreData/OCKStore+Contacts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ extension OCKStore {
case .effectiveDate(ascending: let ascending): return NSSortDescriptor(keyPath: \OCKCDContact.effectiveDate, ascending: ascending)
case .familyName(ascending: let ascending): return NSSortDescriptor(keyPath: \OCKCDContact.name.familyName, ascending: ascending)
case .givenName(ascending: let ascending): return NSSortDescriptor(keyPath: \OCKCDContact.name.givenName, ascending: ascending)
case .groupIdentifier(let ascending): return NSSortDescriptor(keyPath: \OCKCDContact.groupIdentifier, ascending: ascending)
}
} + query.defaultSortDescriptors()
}
Expand Down
7 changes: 6 additions & 1 deletion CareKitStore/CareKitStore/CoreData/OCKStore+Outcomes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,12 @@ extension OCKStore {
}

private func buildSortDescriptors(for query: OCKOutcomeQuery) -> [NSSortDescriptor] {
query.defaultSortDescriptors()
query.sortDescriptors.map { order -> NSSortDescriptor in
switch order {
case .effectiveDate(let ascending): return NSSortDescriptor(keyPath: \OCKCDOutcome.effectiveDate, ascending: ascending)
case .groupIdentifier(let ascending): return NSSortDescriptor(keyPath: \OCKCDOutcome.groupIdentifier, ascending: ascending)
}
} + query.defaultSortDescriptors()
}

private func doesEventForOutcomeOccur(in interval: DateInterval) -> NSPredicate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,14 @@ extension OCKHealthKitPassthroughStore {
taskQuery.ids = outcomeQuery.taskIDs
taskQuery.remoteIDs = outcomeQuery.taskRemoteIDs
taskQuery.uuids = outcomeQuery.taskUUIDs
taskQuery.sortDescriptors = outcomeQuery.sortDescriptors.map { descriptor in
switch descriptor {
case .effectiveDate(ascending: let ascending):
return OCKTaskQuery.SortDescriptor.effectiveDate(ascending: ascending)
case .groupIdentifier(ascending: let ascending):
return OCKTaskQuery.SortDescriptor.groupIdentifier(ascending: ascending)
}
}

return taskQuery
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
query.ids = [id]

fetchAnyCarePlans(query: query, callbackQueue: callbackQueue, completion:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public extension OCKReadableCarePlanStore {
func fetchCarePlan(withID id: String, callbackQueue: DispatchQueue = .main, completion: @escaping OCKResultClosure<Plan>) {
var query = OCKCarePlanQuery(for: Date())
query.limit = 1
query.sortDescriptors = [.effectiveDate(ascending: true)]
query.sortDescriptors = [.effectiveDate(ascending: false)]
query.ids = [id]

fetchCarePlans(query: query, callbackQueue: callbackQueue, completion:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public extension OCKAnyReadOnlyContactStore {
completion: @escaping OCKResultClosure<OCKAnyContact>) {
var query = OCKContactQuery(for: Date())
query.limit = 1
query.sortDescriptors = [.effectiveDate(ascending: true)]
query.sortDescriptors = [.effectiveDate(ascending: false)]
query.ids = [id]

fetchAnyContacts(query: query, callbackQueue: callbackQueue, completion:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public extension OCKReadableContactStore {
var query = OCKContactQuery(for: Date())
query.limit = 1
query.ids = [id]
query.sortDescriptors = [.effectiveDate(ascending: true)]
query.sortDescriptors = [.effectiveDate(ascending: false)]

fetchContacts(query: query, callbackQueue: callbackQueue, completion:
chooseFirst(then: completion, replacementError: .fetchFailed(reason: "No contact with matching ID")))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public extension OCKAnyReadOnlyPatientStore {
completion: @escaping OCKResultClosure<OCKAnyPatient>) {
var query = OCKPatientQuery(for: Date())
query.limit = 1
query.sortDescriptors = [.effectiveDate(ascending: true)]
query.sortDescriptors = [.effectiveDate(ascending: false)]
query.ids = [id]

fetchAnyPatients(query: query, callbackQueue: callbackQueue, completion:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public extension OCKReadablePatientStore {
var query = OCKPatientQuery(for: Date())
query.limit = 1
query.ids = [id]
query.sortDescriptors = [.effectiveDate(ascending: true)]
query.sortDescriptors = [.effectiveDate(ascending: false)]

fetchPatients(query: query, callbackQueue: callbackQueue, completion:
chooseFirst(then: completion, replacementError: .fetchFailed(reason: "No patient with matching ID")))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public protocol OCKTaskStore: OCKReadableTaskStore, OCKAnyTaskStore {
public extension OCKReadableTaskStore {
func fetchTask(withID id: String, callbackQueue: DispatchQueue = .main, completion: @escaping OCKResultClosure<Task>) {
var query = OCKTaskQuery(for: Date())
query.sortDescriptors = [.effectiveDate(ascending: true)]
query.sortDescriptors = [.effectiveDate(ascending: false)]
query.ids = [id]
query.limit = 1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,13 @@ extension OCKStoreCoordinator {
$0.anyOutcomes(matching: query)
}

let sortDescriptor = NSSortDescriptor(
keyPath: \OCKCDOutcome.id,
ascending: true
)
let sortDescriptors = query
.sortDescriptors
.map(\.nsSortDescriptor)

let outcomes = combineMany(
sequences: outcomesStreams,
sortingElementsUsing: [sortDescriptor]
sortingElementsUsing: sortDescriptors
)

return outcomes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ public struct OCKCarePlanQuery: Equatable, OCKQueryProtocol {

case title(ascending: Bool)
case effectiveDate(ascending: Bool)
case groupIdentifier(ascending: Bool)

var nsSortDescriptor: NSSortDescriptor {
switch self {
case let .effectiveDate(ascending):
return NSSortDescriptor(keyPath: \OCKCDCarePlan.effectiveDate, ascending: ascending)
case let .title(ascending):
return NSSortDescriptor(keyPath: \OCKCDCarePlan.title, ascending: ascending)
case let .groupIdentifier(ascending):
return NSSortDescriptor(keyPath: \OCKCDCarePlan.groupIdentifier, ascending: ascending)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,18 @@ public struct OCKContactQuery: Equatable, OCKQueryProtocol {
case givenName(ascending: Bool)
case familyName(ascending: Bool)
case effectiveDate(ascending: Bool)
case groupIdentifier(ascending: Bool)

var nsSortDescriptor: NSSortDescriptor {
switch self {
case let .effectiveDate(ascending):
return NSSortDescriptor(keyPath: \OCKCDContact.effectiveDate, ascending: ascending)
case let .givenName(ascending):
return NSSortDescriptor(keyPath: \OCKCDContact.name.givenName, ascending: ascending)
case let .familyName(ascending):
return NSSortDescriptor(keyPath: \OCKCDContact.name.familyName, ascending: ascending)
case let .effectiveDate(ascending):
return NSSortDescriptor(keyPath: \OCKCDContact.effectiveDate, ascending: ascending)
case let .groupIdentifier(ascending):
return NSSortDescriptor(keyPath: \OCKCDContact.groupIdentifier, ascending: ascending)
}
}
}
Expand Down
19 changes: 19 additions & 0 deletions CareKitStore/CareKitStore/Structs/Queries/OCKOutcomeQuery.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

case effectiveDate(ascending: Bool)
case groupIdentifier(ascending: Bool)

var nsSortDescriptor: NSSortDescriptor {
switch self {
case let .effectiveDate(ascending):
return NSSortDescriptor(keyPath: \OCKCDOutcome.effectiveDate, ascending: ascending)
case let .groupIdentifier(ascending):
return NSSortDescriptor(keyPath: \OCKCDOutcome.groupIdentifier, ascending: ascending)
}
}
}

/// An array of task identifiers to match against.
public var taskIDs: [String] = []

Expand All @@ -42,6 +58,9 @@ public struct OCKOutcomeQuery: Equatable, OCKQueryProtocol {
/// An array of remote IDs of tasks for which outcomes should be returned.
public var taskRemoteIDs: [String] = []

/// The order in which the results will be sorted when returned from the query.
public var sortDescriptors: [SortDescriptor] = []

// MARK: OCKQuery
public var ids: [String] = []
public var uuids: [UUID] = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ class TestHealthKitPassthroughStoreOutcomes: XCTestCase {
XCTAssertEqual(taskQuery.ids, outcomeTaskQuery.taskIDs)
XCTAssertEqual(taskQuery.remoteIDs, outcomeTaskQuery.taskRemoteIDs)
XCTAssertEqual(taskQuery.uuids, outcomeTaskQuery.taskUUIDs)
XCTAssertTrue(taskQuery.sortDescriptors.isEmpty)
}

func testTaskQueryPropertiesAdoptsOutcomeQueryProperties() async throws {
Expand All @@ -177,12 +178,21 @@ class TestHealthKitPassthroughStoreOutcomes: XCTestCase {
outcomeTaskQuery.taskIDs = ["id"]
outcomeTaskQuery.taskRemoteIDs = ["remoteID"]
outcomeTaskQuery.taskUUIDs = [UUID()]
outcomeTaskQuery.sortDescriptors = [
.effectiveDate(ascending: true),
.groupIdentifier(ascending: true)
]
let taskQuery = passthroughStore.makeTaskQuery(from: outcomeTaskQuery)
let expectedTaskSortDescriptors: [OCKTaskQuery.SortDescriptor] = [
.effectiveDate(ascending: true),
.groupIdentifier(ascending: true)
]

XCTAssertEqual(taskQuery.dateInterval, outcomeTaskQuery.dateInterval)
XCTAssertEqual(taskQuery.ids, outcomeTaskQuery.taskIDs)
XCTAssertEqual(taskQuery.remoteIDs, outcomeTaskQuery.taskRemoteIDs)
XCTAssertEqual(taskQuery.uuids, outcomeTaskQuery.taskUUIDs)
XCTAssertEqual(taskQuery.sortDescriptors, expectedTaskSortDescriptors)
}

// MARK: - Utilities
Expand Down
Loading