Skip to content

Commit 57274d5

Browse files
authored
Fix for schema migration involving 'NOT NULL' columns. (#365)
* Fix for schema migration involving 'NOT NULL' columns. * wip
1 parent 20f2e41 commit 57274d5

2 files changed

Lines changed: 44 additions & 2 deletions

File tree

Sources/SQLiteData/CloudKit/SyncEngine.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2045,11 +2045,11 @@
20452045
if data == nil {
20462046
reportIssue("Asset data not found on disk")
20472047
}
2048-
return "\(quote: columnName) = \(data?.queryFragment ?? "NULL")"
2048+
return "\(quote: columnName) = \(data?.queryFragment ?? #""excluded".\#(quote: columnName)"#)"
20492049
} else {
20502050
return """
20512051
\(quote: columnName) = \
2052-
\(record.encryptedValues[columnName]?.queryFragment ?? "NULL")
2052+
\(record.encryptedValues[columnName]?.queryFragment ?? #""excluded".\#(quote: columnName)"#)
20532053
"""
20542054
}
20552055
}

Tests/SQLiteDataTests/CloudKitTests/SchemaChangeTests.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,48 @@
196196
}
197197
}
198198

199+
/*
200+
* Old schema creates record and synchronizes to iCloud.
201+
* Schema is migrated to add a "NOT NULL" column.
202+
* New sync engine is launched.
203+
=> Sync starts without emitting an error.
204+
*/
205+
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
206+
@Test func addColumn_OldRecordsSyncToNewSchema() async throws {
207+
let remindersList = RemindersList(id: 1, title: "Personal")
208+
try await userDatabase.userWrite { db in
209+
try db.seed {
210+
remindersList
211+
}
212+
}
213+
try await syncEngine.processPendingRecordZoneChanges(scope: .private)
214+
215+
syncEngine.stop()
216+
217+
try await userDatabase.userWrite { db in
218+
try #sql(
219+
"""
220+
ALTER TABLE "remindersLists"
221+
ADD COLUMN "position" INTEGER NOT NULL ON CONFLICT REPLACE DEFAULT 0
222+
"""
223+
)
224+
.execute(db)
225+
}
226+
227+
// NB: Sync engine should start without emitting issue.
228+
_ = try await SyncEngine(
229+
container: syncEngine.container,
230+
userDatabase: syncEngine.userDatabase,
231+
tables: syncEngine.tables
232+
.filter { $0.base != Reminder.self && $0.base != RemindersList.self }
233+
+ [
234+
SynchronizedTable(for: ReminderWithPosition.self),
235+
SynchronizedTable(for: RemindersListWithPosition.self),
236+
],
237+
privateTables: syncEngine.privateTables
238+
)
239+
}
240+
199241
/*
200242
* Test run from perspective of old device with old schema.
201243
* Old schema saves record in cloud database.

0 commit comments

Comments
 (0)