Skip to content

Commit 2d85120

Browse files
committed
encode healthKitLinkage as string
1 parent 39c66ac commit 2d85120

File tree

4 files changed

+103
-31
lines changed

4 files changed

+103
-31
lines changed

Sources/ParseCareKit/Models/PCKClock.swift

+11-13
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,20 @@ public struct PCKClock: ParseObject {
2929

3030
public var uuid: UUID?
3131

32-
var vector: String?
32+
var knowledgeVectorString: String?
3333

3434
/// A knowledge vector indicating the last known state of each other device
3535
/// by the device that authored this revision record.
3636
public var knowledgeVector: OCKRevisionRecord.KnowledgeVector? {
3737
get {
38-
try? PCKClock.decodeVector(vector)
38+
try? PCKClock.decodeVector(knowledgeVectorString)
3939
}
4040
set {
4141
guard let newValue = newValue else {
42-
vector = nil
42+
knowledgeVectorString = nil
4343
return
4444
}
45-
vector = PCKClock.encodeVector(newValue)
45+
knowledgeVectorString = PCKClock.encodeVector(newValue)
4646
}
4747
}
4848

@@ -54,15 +54,15 @@ public struct PCKClock: ParseObject {
5454
original: object) {
5555
updated.uuid = object.uuid
5656
}
57-
if updated.shouldRestoreKey(\.vector,
57+
if updated.shouldRestoreKey(\.knowledgeVectorString,
5858
original: object) {
59-
updated.vector = object.vector
59+
updated.knowledgeVectorString = object.knowledgeVectorString
6060
}
6161
return updated
6262
}
6363

6464
static func decodeVector(_ clock: Self) throws -> OCKRevisionRecord.KnowledgeVector {
65-
try decodeVector(clock.vector)
65+
try decodeVector(clock.knowledgeVectorString)
6666
}
6767

6868
static func decodeVector(_ vector: String?) throws -> OCKRevisionRecord.KnowledgeVector {
@@ -73,10 +73,8 @@ public struct PCKClock: ParseObject {
7373
}
7474

7575
do {
76-
// swiftlint:disable:next line_length
77-
let remoteVector: OCKRevisionRecord.KnowledgeVector = try JSONDecoder().decode(OCKRevisionRecord.KnowledgeVector.self,
78-
from: data)
79-
return remoteVector
76+
return try JSONDecoder().decode(OCKRevisionRecord.KnowledgeVector.self,
77+
from: data)
8078
} catch {
8179
Logger.clock.error("Clock.decodeVector(): \(error, privacy: .private). Vector \(data, privacy: .private).")
8280
throw ParseCareKitError.errorString("Clock.decodeVector(): \(error)")
@@ -88,7 +86,7 @@ public struct PCKClock: ParseObject {
8886
return nil
8987
}
9088
var mutableClock = clock
91-
mutableClock.vector = remoteVectorString
89+
mutableClock.knowledgeVectorString = remoteVectorString
9290
return mutableClock
9391
}
9492

@@ -212,7 +210,7 @@ public struct PCKClock: ParseObject {
212210
extension PCKClock {
213211
init(uuid: UUID) {
214212
self.uuid = uuid
215-
vector = "{\"processes\":[{\"id\":\"\(uuid)\",\"clock\":0}]}"
213+
knowledgeVectorString = "{\"processes\":[{\"id\":\"\(uuid)\",\"clock\":0}]}"
216214
ACL = PCKUtility.getDefaultACL()
217215
}
218216
}

Sources/ParseCareKit/Models/PCKHealthKitTask.swift

+75-6
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,28 @@ public struct PCKHealthKitTask: PCKVersionable {
103103

104104
public var originalData: Data?
105105

106+
#if canImport(HealthKit)
106107
/// A structure specifying how this task is linked with HealthKit.
107-
public var healthKitLinkage: OCKHealthKitLinkage?
108+
public var healthKitLinkage: OCKHealthKitLinkage? {
109+
get {
110+
guard let data = healthKitLinkageString?.data(using: .utf8) else {
111+
return nil
112+
}
113+
return try? JSONDecoder().decode(OCKHealthKitLinkage.self,
114+
from: data)
115+
} set {
116+
guard let json = try? JSONEncoder().encode(newValue),
117+
let encodedString = String(data: json, encoding: .utf8) else {
118+
healthKitLinkageString = nil
119+
return
120+
}
121+
healthKitLinkageString = encodedString
122+
}
123+
}
124+
#endif
125+
126+
/// A string specifying how this task is linked with HealthKit.
127+
public var healthKitLinkageString: String?
108128

109129
/// If true, completion of this task will be factored into the patient's overall adherence. True by default.
110130
public var impactsAdherence: Bool?
@@ -135,12 +155,18 @@ public struct PCKHealthKitTask: PCKVersionable {
135155
}
136156

137157
enum CodingKeys: String, CodingKey {
138-
case objectId, createdAt, updatedAt
158+
case objectId, createdAt, updatedAt,
159+
className, ACL, uuid
139160
case entityId, schemaVersion, createdDate, updatedDate,
140161
deletedDate, timezone, userInfo, groupIdentifier,
141162
tags, source, asset, remoteID, notes, logicalClock
142163
case previousVersionUUIDs, nextVersionUUIDs, effectiveDate
143-
case title, carePlan, carePlanUUID, impactsAdherence, instructions, schedule, healthKitLinkage
164+
case title, carePlan, carePlanUUID, impactsAdherence,
165+
instructions, schedule, healthKitLinkageString
166+
case previousVersions, nextVersions
167+
#if canImport(HealthKit)
168+
case healthKitLinkage
169+
#endif
144170
}
145171

146172
public init() {
@@ -215,18 +241,61 @@ public struct PCKHealthKitTask: PCKVersionable {
215241
}
216242
}
217243

218-
extension PCKHealthKitTask {
219-
public func encode(to encoder: Encoder) throws {
244+
public extension PCKHealthKitTask {
245+
init(from decoder: Decoder) throws {
246+
let container = try decoder.container(keyedBy: CodingKeys.self)
247+
self.objectId = try container.decodeIfPresent(String.self, forKey: .objectId)
248+
self.createdAt = try container.decodeIfPresent(Date.self, forKey: .createdAt)
249+
self.updatedAt = try container.decodeIfPresent(Date.self, forKey: .updatedAt)
250+
self.ACL = try container.decodeIfPresent(ParseACL.self, forKey: .ACL)
251+
self.healthKitLinkageString = try container.decodeIfPresent(String.self, forKey: .healthKitLinkageString)
252+
#if canImport(HealthKit)
253+
if healthKitLinkageString == nil {
254+
self.healthKitLinkage = try container.decodeIfPresent(OCKHealthKitLinkage.self, forKey: .healthKitLinkage)
255+
}
256+
#endif
257+
self.carePlan = try container.decodeIfPresent(PCKCarePlan.self, forKey: .carePlan)
258+
self.carePlanUUID = try container.decodeIfPresent(UUID.self, forKey: .carePlanUUID)
259+
self.title = try container.decodeIfPresent(String.self, forKey: .title)
260+
self.logicalClock = try container.decodeIfPresent(Int.self, forKey: .logicalClock)
261+
self.impactsAdherence = try container.decodeIfPresent(Bool.self, forKey: .impactsAdherence)
262+
self.instructions = try container.decodeIfPresent(String.self, forKey: .instructions)
263+
self.schedule = try container.decodeIfPresent(OCKSchedule.self, forKey: .schedule)
264+
self.entityId = try container.decodeIfPresent(String.self, forKey: .entityId)
265+
self.createdDate = try container.decodeIfPresent(Date.self, forKey: .createdDate)
266+
self.updatedDate = try container.decodeIfPresent(Date.self, forKey: .updatedDate)
267+
self.deletedDate = try container.decodeIfPresent(Date.self, forKey: .deletedDate)
268+
self.effectiveDate = try container.decodeIfPresent(Date.self, forKey: .effectiveDate)
269+
self.timezone = try container.decodeIfPresent(TimeZone.self, forKey: .timezone)
270+
self.previousVersions = try container.decodeIfPresent([Pointer<Self>].self, forKey: .previousVersions)
271+
self.nextVersions = try container.decodeIfPresent([Pointer<Self>].self, forKey: .nextVersions)
272+
self.previousVersionUUIDs = try container.decodeIfPresent([UUID].self, forKey: .previousVersionUUIDs)
273+
self.nextVersionUUIDs = try container.decodeIfPresent([UUID].self, forKey: .nextVersionUUIDs)
274+
self.userInfo = try container.decodeIfPresent([String: String].self, forKey: .userInfo)
275+
self.remoteID = try container.decodeIfPresent(String.self, forKey: .remoteID)
276+
self.source = try container.decodeIfPresent(String.self, forKey: .source)
277+
self.asset = try container.decodeIfPresent(String.self, forKey: .asset)
278+
self.schemaVersion = try container.decodeIfPresent(OCKSemanticVersion.self, forKey: .schemaVersion)
279+
self.groupIdentifier = try container.decodeIfPresent(String.self, forKey: .groupIdentifier)
280+
self.tags = try container.decodeIfPresent([String].self, forKey: .tags)
281+
self.notes = try container.decodeIfPresent([OCKNote].self, forKey: .notes)
282+
}
283+
284+
func encode(to encoder: Encoder) throws {
220285
var container = encoder.container(keyedBy: CodingKeys.self)
221286
if encodingForParse {
222287
try container.encodeIfPresent(carePlan?.toPointer(), forKey: .carePlan)
288+
try container.encodeIfPresent(healthKitLinkageString, forKey: .healthKitLinkageString)
289+
} else {
290+
#if canImport(HealthKit)
291+
try container.encodeIfPresent(healthKitLinkage, forKey: .healthKitLinkage)
292+
#endif
223293
}
224294
try container.encodeIfPresent(title, forKey: .title)
225295
try container.encodeIfPresent(carePlanUUID, forKey: .carePlanUUID)
226296
try container.encodeIfPresent(impactsAdherence, forKey: .impactsAdherence)
227297
try container.encodeIfPresent(instructions, forKey: .instructions)
228298
try container.encodeIfPresent(schedule, forKey: .schedule)
229-
try container.encodeIfPresent(healthKitLinkage, forKey: .healthKitLinkage)
230299
try encodeVersionable(to: encoder)
231300
}
232301
}

Sources/ParseCareKit/Models/PCKRevisionRecord.swift

+8-8
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,18 @@ struct PCKRevisionRecord: ParseObject, Equatable, Codable {
4444
/// by the device that authored this revision record.
4545
var knowledgeVector: OCKRevisionRecord.KnowledgeVector? {
4646
get {
47-
try? PCKClock.decodeVector(vector)
47+
try? PCKClock.decodeVector(knowledgeVectorString)
4848
}
4949
set {
5050
guard let newValue = newValue else {
51-
vector = nil
51+
knowledgeVectorString = nil
5252
return
5353
}
54-
vector = PCKClock.encodeVector(newValue)
54+
knowledgeVectorString = PCKClock.encodeVector(newValue)
5555
}
5656
}
5757

58-
var vector: String?
58+
var knowledgeVectorString: String?
5959

6060
var storeClassesToSynchronize: [PCKStoreClass: any PCKVersionable.Type]? = try? PCKStoreClass.getConcrete()
6161

@@ -112,12 +112,12 @@ struct PCKRevisionRecord: ParseObject, Equatable, Codable {
112112

113113
enum CodingKeys: String, CodingKey {
114114
case objectId, createdAt, updatedAt, className,
115-
ACL, vector, entities,
115+
ACL, knowledgeVectorString, entities,
116116
logicalClock, clock, clockUUID
117117
}
118118

119119
static func == (lhs: PCKRevisionRecord, rhs: PCKRevisionRecord) -> Bool {
120-
lhs.vector == rhs.vector &&
120+
lhs.knowledgeVectorString == rhs.knowledgeVectorString &&
121121
lhs.logicalClock == rhs.logicalClock &&
122122
lhs.objectId == rhs.objectId &&
123123
lhs.entities == rhs.entities
@@ -226,7 +226,7 @@ extension PCKRevisionRecord {
226226
self.createdAt = try container.decodeIfPresent(Date.self, forKey: .createdAt)
227227
self.updatedAt = try container.decodeIfPresent(Date.self, forKey: .updatedAt)
228228
self.ACL = try container.decodeIfPresent(ParseACL.self, forKey: .ACL)
229-
self.vector = try container.decodeIfPresent(String.self, forKey: .vector)
229+
self.knowledgeVectorString = try container.decodeIfPresent(String.self, forKey: .knowledgeVectorString)
230230
self.entities = try container.decodeIfPresent([PCKEntity].self, forKey: .entities)
231231
self.clock = try container.decodeIfPresent(PCKClock.self, forKey: .clock)
232232
self.logicalClock = try container.decodeIfPresent(Int.self, forKey: .logicalClock)
@@ -240,7 +240,7 @@ extension PCKRevisionRecord {
240240
try container.encodeIfPresent(createdAt, forKey: .createdAt)
241241
try container.encodeIfPresent(updatedAt, forKey: .updatedAt)
242242
try container.encodeIfPresent(ACL, forKey: .ACL)
243-
try container.encodeIfPresent(vector, forKey: .vector)
243+
try container.encodeIfPresent(knowledgeVectorString, forKey: .knowledgeVectorString)
244244
try container.encodeIfPresent(entities, forKey: .entities)
245245
try container.encodeIfPresent(clock, forKey: .clock)
246246
try container.encodeIfPresent(logicalClock, forKey: .logicalClock)

Tests/ParseCareKitTests/EncodingCareKitTests.swift

+9-4
Original file line numberDiff line numberDiff line change
@@ -693,15 +693,17 @@ class ParseCareKitTests: XCTestCase {
693693
XCTAssertTrue(acl2.getWriteAccess(objectId: objectId))
694694
}
695695

696+
#if canImport(HealthKit)
696697
// swiftlint:disable:next function_body_length
697698
func testHealthKitTask() async throws {
698699
let careKitSchedule = OCKScheduleElement(start: Date(),
699700
end: Date().addingTimeInterval(3000), interval: .init(day: 1))
701+
let linkage = OCKHealthKitLinkage(quantityIdentifier: .bodyTemperature,
702+
quantityType: .discrete,
703+
unit: .degreeCelsius())
700704
var careKit = OCKHealthKitTask(id: "myId", title: "hello", carePlanUUID: UUID(),
701705
schedule: .init(composing: [careKitSchedule]),
702-
healthKitLinkage: .init(quantityIdentifier: .bodyTemperature,
703-
quantityType: .discrete,
704-
unit: .degreeCelsius()))
706+
healthKitLinkage: linkage)
705707
let careKitNote = OCKNote(author: "myId", title: "hello", content: "world")
706708

707709
// Special
@@ -737,7 +739,7 @@ class ParseCareKitTests: XCTestCase {
737739
XCTAssertEqual(parse.title, careKit.title)
738740
XCTAssertEqual(parse.carePlanUUID, careKit.carePlanUUID)
739741
XCTAssertEqual(parse.carePlan?.objectId, careKit.carePlanUUID?.uuidString)
740-
// XCTAssertEqual(parse.allergies, careKit.allergies)
742+
XCTAssertEqual(parse.healthKitLinkage, careKit.healthKitLinkage)
741743

742744
// Objectable
743745
XCTAssertEqual(parse.className, "HealthKitTask")
@@ -769,6 +771,7 @@ class ParseCareKitTests: XCTestCase {
769771

770772
// Special
771773
XCTAssertEqual(parse2.impactsAdherence, careKit.impactsAdherence)
774+
XCTAssertEqual(parse2.healthKitLinkage, careKit.healthKitLinkage)
772775
XCTAssertEqual(parse2.title, careKit.title)
773776
XCTAssertEqual(parse2.carePlanUUID, careKit.carePlanUUID)
774777

@@ -826,6 +829,7 @@ class ParseCareKitTests: XCTestCase {
826829
XCTAssertEqual(parse.impactsAdherence, cloudDecoded.impactsAdherence)
827830
XCTAssertEqual(parse.title, cloudDecoded.title)
828831
XCTAssertEqual(parse.carePlanUUID, cloudDecoded.carePlanUUID)
832+
XCTAssertEqual(parse.healthKitLinkage, cloudDecoded.healthKitLinkage)
829833

830834
// Versionable
831835
XCTAssertNotNil(cloudDecoded.effectiveDate)
@@ -883,6 +887,7 @@ class ParseCareKitTests: XCTestCase {
883887
XCTAssertTrue(acl2.getReadAccess(objectId: objectId))
884888
XCTAssertTrue(acl2.getWriteAccess(objectId: objectId))
885889
}
890+
#endif
886891

887892
// swiftlint:disable:next function_body_length
888893
func testCarePlan() async throws {

0 commit comments

Comments
 (0)