@@ -2093,6 +2093,41 @@ actor SQLiteHealthArchiveStore: HealthArchiveStore {
|
||
| 2093 | 2093 |
db: db, |
| 2094 | 2094 |
statementCache: statementCache |
| 2095 | 2095 |
) |
| 2096 |
+ |
|
| 2097 |
+ if sampleResult.inserted {
|
|
| 2098 |
+ let versionID = try insertSampleVersion( |
|
| 2099 |
+ row, |
|
| 2100 |
+ sampleID: sampleResult.id, |
|
| 2101 |
+ sourceRevisionID: sourceRevisionID, |
|
| 2102 |
+ deviceID: deviceID, |
|
| 2103 |
+ metadataID: metadataID, |
|
| 2104 |
+ observationID: observationID, |
|
| 2105 |
+ db: db, |
|
| 2106 |
+ statementCache: statementCache |
|
| 2107 |
+ ) |
|
| 2108 |
+ try insertObservationEvent( |
|
| 2109 |
+ observationID: observationID, |
|
| 2110 |
+ sampleID: sampleResult.id, |
|
| 2111 |
+ versionID: versionID, |
|
| 2112 |
+ eventKind: "appeared", |
|
| 2113 |
+ evidenceKind: "healthkit_sample", |
|
| 2114 |
+ observedAt: row.observedAt, |
|
| 2115 |
+ db: db, |
|
| 2116 |
+ statementCache: statementCache, |
|
| 2117 |
+ allowConflict: false |
|
| 2118 |
+ ) |
|
| 2119 |
+ try insertOpenVisibilityRange( |
|
| 2120 |
+ sampleID: sampleResult.id, |
|
| 2121 |
+ versionID: versionID, |
|
| 2122 |
+ observationID: observationID, |
|
| 2123 |
+ observedAt: row.observedAt, |
|
| 2124 |
+ db: db, |
|
| 2125 |
+ statementCache: statementCache, |
|
| 2126 |
+ allowConflict: false |
|
| 2127 |
+ ) |
|
| 2128 |
+ return ArchiveV2SampleWriteResult(sampleTypeID: sampleTypeID, kind: .inserted) |
|
| 2129 |
+ } |
|
| 2130 |
+ |
|
| 2096 | 2131 |
let versionResult = try upsertSampleVersion( |
| 2097 | 2132 |
row, |
| 2098 | 2133 |
sampleID: sampleResult.id, |
@@ -2106,10 +2141,7 @@ actor SQLiteHealthArchiveStore: HealthArchiveStore {
|
||
| 2106 | 2141 |
|
| 2107 | 2142 |
let writeKind: ArchiveV2SampleWriteKind |
| 2108 | 2143 |
let eventKind: String |
| 2109 |
- if sampleResult.inserted {
|
|
| 2110 |
- writeKind = .inserted |
|
| 2111 |
- eventKind = "appeared" |
|
| 2112 |
- } else if versionResult.inserted {
|
|
| 2144 |
+ if versionResult.inserted {
|
|
| 2113 | 2145 |
writeKind = .updated |
| 2114 | 2146 |
eventKind = "representationChanged" |
| 2115 | 2147 |
} else {
|
@@ -2127,16 +2159,7 @@ actor SQLiteHealthArchiveStore: HealthArchiveStore {
|
||
| 2127 | 2159 |
db: db, |
| 2128 | 2160 |
statementCache: statementCache |
| 2129 | 2161 |
) |
| 2130 |
- if sampleResult.inserted {
|
|
| 2131 |
- try insertOpenVisibilityRange( |
|
| 2132 |
- sampleID: sampleResult.id, |
|
| 2133 |
- versionID: versionResult.id, |
|
| 2134 |
- observationID: observationID, |
|
| 2135 |
- observedAt: row.observedAt, |
|
| 2136 |
- db: db, |
|
| 2137 |
- statementCache: statementCache |
|
| 2138 |
- ) |
|
| 2139 |
- } else if versionResult.inserted {
|
|
| 2162 |
+ if versionResult.inserted {
|
|
| 2140 | 2163 |
try closeOpenVisibilityRanges( |
| 2141 | 2164 |
sampleID: sampleResult.id, |
| 2142 | 2165 |
excludingVersionID: versionResult.id, |
@@ -2743,6 +2766,48 @@ actor SQLiteHealthArchiveStore: HealthArchiveStore {
|
||
| 2743 | 2766 |
return (id, inserted) |
| 2744 | 2767 |
} |
| 2745 | 2768 |
|
| 2769 |
+ private func insertSampleVersion( |
|
| 2770 |
+ _ row: ArchiveSampleRow, |
|
| 2771 |
+ sampleID: Int64, |
|
| 2772 |
+ sourceRevisionID: Int64?, |
|
| 2773 |
+ deviceID: Int64?, |
|
| 2774 |
+ metadataID: Int64?, |
|
| 2775 |
+ observationID: Int64, |
|
| 2776 |
+ db: OpaquePointer?, |
|
| 2777 |
+ statementCache: SQLiteStatementCache? = nil |
|
| 2778 |
+ ) throws -> Int64 {
|
|
| 2779 |
+ try withStatement( |
|
| 2780 |
+ """ |
|
| 2781 |
+ INSERT INTO sample_versions ( |
|
| 2782 |
+ sample_id, payload_hash, start_date, end_date, value_kind, numeric_value, |
|
| 2783 |
+ unit, category_value, workout_activity_type, duration_seconds, |
|
| 2784 |
+ source_revision_id, hk_device_id, metadata_id, created_observation_id |
|
| 2785 |
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) |
|
| 2786 |
+ """, |
|
| 2787 |
+ db: db, |
|
| 2788 |
+ statementCache: statementCache |
|
| 2789 |
+ ) { statement in
|
|
| 2790 |
+ bindInt64(sampleID, to: 1, in: statement) |
|
| 2791 |
+ bindText(row.payloadHash, to: 2, in: statement) |
|
| 2792 |
+ sqlite3_bind_double(statement, 3, row.startDate.timeIntervalSince1970) |
|
| 2793 |
+ sqlite3_bind_double(statement, 4, row.endDate.timeIntervalSince1970) |
|
| 2794 |
+ bindText(row.valueKind, to: 5, in: statement) |
|
| 2795 |
+ bindDouble(row.value, to: 6, in: statement) |
|
| 2796 |
+ bindText(row.unit, to: 7, in: statement) |
|
| 2797 |
+ bindInt(row.categoryValue, to: 8, in: statement) |
|
| 2798 |
+ bindInt(row.workoutActivityType, to: 9, in: statement) |
|
| 2799 |
+ bindDouble(row.durationSeconds, to: 10, in: statement) |
|
| 2800 |
+ bindInt64(sourceRevisionID, to: 11, in: statement) |
|
| 2801 |
+ bindInt64(deviceID, to: 12, in: statement) |
|
| 2802 |
+ bindInt64(metadataID, to: 13, in: statement) |
|
| 2803 |
+ bindInt64(observationID, to: 14, in: statement) |
|
| 2804 |
+ guard sqlite3_step(statement) == SQLITE_DONE else {
|
|
| 2805 |
+ throw SQLiteHealthArchiveStoreError.stepFailed(lastErrorMessage(db)) |
|
| 2806 |
+ } |
|
| 2807 |
+ } |
|
| 2808 |
+ return sqlite3_last_insert_rowid(db) |
|
| 2809 |
+ } |
|
| 2810 |
+ |
|
| 2746 | 2811 |
private func insertObservationEvent( |
| 2747 | 2812 |
observationID: Int64, |
| 2748 | 2813 |
sampleID: Int64, |
@@ -2751,11 +2816,13 @@ actor SQLiteHealthArchiveStore: HealthArchiveStore {
|
||
| 2751 | 2816 |
evidenceKind: String, |
| 2752 | 2817 |
observedAt: Date, |
| 2753 | 2818 |
db: OpaquePointer?, |
| 2754 |
- statementCache: SQLiteStatementCache? = nil |
|
| 2819 |
+ statementCache: SQLiteStatementCache? = nil, |
|
| 2820 |
+ allowConflict: Bool = true |
|
| 2755 | 2821 |
) throws {
|
| 2822 |
+ let insertMode = allowConflict ? "INSERT OR IGNORE" : "INSERT" |
|
| 2756 | 2823 |
try withStatement( |
| 2757 | 2824 |
""" |
| 2758 |
- INSERT OR IGNORE INTO sample_observation_events ( |
|
| 2825 |
+ \(insertMode) INTO sample_observation_events ( |
|
| 2759 | 2826 |
observation_id, sample_id, version_id, event_kind, observed_at, evidence_kind |
| 2760 | 2827 |
) VALUES (?, ?, ?, ?, ?, ?) |
| 2761 | 2828 |
""", |
@@ -2841,11 +2908,13 @@ actor SQLiteHealthArchiveStore: HealthArchiveStore {
|
||
| 2841 | 2908 |
observationID: Int64, |
| 2842 | 2909 |
observedAt: Date, |
| 2843 | 2910 |
db: OpaquePointer?, |
| 2844 |
- statementCache: SQLiteStatementCache? = nil |
|
| 2911 |
+ statementCache: SQLiteStatementCache? = nil, |
|
| 2912 |
+ allowConflict: Bool = true |
|
| 2845 | 2913 |
) throws {
|
| 2914 |
+ let insertMode = allowConflict ? "INSERT OR IGNORE" : "INSERT" |
|
| 2846 | 2915 |
try withStatement( |
| 2847 | 2916 |
""" |
| 2848 |
- INSERT OR IGNORE INTO sample_visibility_ranges ( |
|
| 2917 |
+ \(insertMode) INTO sample_visibility_ranges ( |
|
| 2849 | 2918 |
sample_id, version_id, first_observation_id, last_observation_id, first_seen_at, last_seen_at |
| 2850 | 2919 |
) VALUES (?, ?, ?, NULL, ?, NULL) |
| 2851 | 2920 |
""", |