diff --git a/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 3e56ff26..40994f54 100644
--- a/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -1,5 +1,5 @@
{
- "originHash" : "8b698458b719345f562ad056ad435aa3db5d6e852f96e6ca49566c5d31ffb528",
+ "originHash" : "c133bf7d10c8ce1e5d6506c3d2f080eac8b4c8c2827044d53a9b925e903564fd",
"pins" : [
{
"identity" : "combine-schedulers",
@@ -73,24 +73,6 @@
"version" : "1.9.4"
}
},
- {
- "identity" : "swift-docc-plugin",
- "kind" : "remoteSourceControl",
- "location" : "https://github.com/apple/swift-docc-plugin",
- "state" : {
- "revision" : "3e4f133a77e644a5812911a0513aeb7288b07d06",
- "version" : "1.4.5"
- }
- },
- {
- "identity" : "swift-docc-symbolkit",
- "kind" : "remoteSourceControl",
- "location" : "https://github.com/swiftlang/swift-docc-symbolkit",
- "state" : {
- "revision" : "b45d1f2ed151d057b54504d653e0da5552844e34",
- "version" : "1.0.0"
- }
- },
{
"identity" : "swift-identified-collections",
"kind" : "remoteSourceControl",
@@ -123,8 +105,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-sharing",
"state" : {
- "revision" : "aaf605733bd93126d1a3658b4021146d95c94cb6",
- "version" : "2.7.3"
+ "revision" : "3bfc408cc2d0bee2287c174da6b1c76768377818",
+ "version" : "2.7.4"
}
},
{
@@ -154,6 +136,15 @@
"version" : "601.0.1"
}
},
+ {
+ "identity" : "swift-tagged",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/pointfreeco/swift-tagged",
+ "state" : {
+ "revision" : "3907a9438f5b57d317001dc99f3f11b46882272b",
+ "version" : "0.10.0"
+ }
+ },
{
"identity" : "xctest-dynamic-overlay",
"kind" : "remoteSourceControl",
diff --git a/Examples/Reminders/TagsForm.swift b/Examples/Reminders/TagsForm.swift
index 1a60166e..c40b777a 100644
--- a/Examples/Reminders/TagsForm.swift
+++ b/Examples/Reminders/TagsForm.swift
@@ -151,7 +151,7 @@ private struct TagView: View {
} label: {
HStack {
if isSelected {
- Image.init(systemName: "checkmark")
+ Image(systemName: "checkmark")
}
Text(tag.title)
}
diff --git a/Package.swift b/Package.swift
index c1d9d21d..73e0aeeb 100644
--- a/Package.swift
+++ b/Package.swift
@@ -24,7 +24,7 @@ let package = Package(
.trait(
name: "SQLiteDataTagged",
description: "Introduce SQLiteData conformances to the swift-tagged package."
- ),
+ )
],
dependencies: [
.package(url: "https://github.com/apple/swift-collections", from: "1.0.0"),
diff --git a/README.md b/README.md
index 29898d0e..f7a9e89e 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# SQLiteData
-A [fast](#Performance), lightweight replacement for SwiftData, powered by SQL and supporting
+A [fast](#Performance), lightweight replacement for SwiftData, powered by SQL and supporting
CloudKit synchronization.
[](https://github.com/pointfreeco/sqlite-data/actions/workflows/ci.yml)
@@ -353,8 +353,8 @@ SQLiteData. Check out [this](./Examples) directory to see them all, including:
* [**CloudKitDemo**](./Examples/CloudKitDemo)
A simplified demo that shows how to synchronize a SQLite database to CloudKit and how to
share records with other iCloud users. See our dedicated articles on [CloudKit Synchronization]
- and [CloudKit Sharing] for more information.
-
+ and [CloudKit Sharing] for more information.
+
[CloudKit Synchronization]: https://swiftpackageindex.com/pointfreeco/sqlite-data/main/documentation/sqlitedata/cloudkit
[CloudKit Sharing]: https://swiftpackageindex.com/pointfreeco/sqlite-data/main/documentation/sqlitedata/cloudkitsharing
diff --git a/Sources/SQLiteData/CloudKit/CloudKitSharing.swift b/Sources/SQLiteData/CloudKit/CloudKitSharing.swift
index eac7c4a3..1e2d25ec 100644
--- a/Sources/SQLiteData/CloudKit/CloudKitSharing.swift
+++ b/Sources/SQLiteData/CloudKit/CloudKitSharing.swift
@@ -126,7 +126,7 @@
}
let rootRecord =
- lastKnownServerRecord
+ lastKnownServerRecord
?? CKRecord(
recordType: recordType,
recordID: CKRecord.ID(recordName: recordName, zoneID: defaultZone.zoneID)
@@ -292,7 +292,7 @@
public func cloudSharingControllerDidStopSharing(_ csc: UICloudSharingController) {
Task {
await withErrorReporting(.sqliteDataCloudKitFailure) {
- try await syncEngine.deleteShare(recordID: share.recordID)
+ try await syncEngine.deleteShare(shareRecordID: share.recordID)
}
}
didStopSharing()
diff --git a/Sources/SQLiteData/CloudKit/Internal/Metadatabase.swift b/Sources/SQLiteData/CloudKit/Internal/Metadatabase.swift
index 36ed7aa1..d7198cb2 100644
--- a/Sources/SQLiteData/CloudKit/Internal/Metadatabase.swift
+++ b/Sources/SQLiteData/CloudKit/Internal/Metadatabase.swift
@@ -56,6 +56,8 @@
"recordPrimaryKey" TEXT NOT NULL,
"recordType" TEXT NOT NULL,
"recordName" TEXT NOT NULL AS ("recordPrimaryKey" || ':' || "recordType"),
+ "zoneName" TEXT NOT NULL,
+ "ownerName" TEXT NOT NULL,
"parentRecordPrimaryKey" TEXT,
"parentRecordType" TEXT,
"parentRecordName" TEXT AS ("parentRecordPrimaryKey" || ':' || "parentRecordType"),
@@ -139,7 +141,7 @@
assert(
!hasSchemaChanges,
"""
- A previously run migration has been removed or edited.
+ A previously run migration has been removed or edited. \
Metadatabase migrations must not be modified after release.
"""
)
diff --git a/Sources/SQLiteData/CloudKit/Internal/MockCloudContainer.swift b/Sources/SQLiteData/CloudKit/Internal/MockCloudContainer.swift
index 4b75e98c..faea3f1b 100644
--- a/Sources/SQLiteData/CloudKit/Internal/MockCloudContainer.swift
+++ b/Sources/SQLiteData/CloudKit/Internal/MockCloudContainer.swift
@@ -105,7 +105,7 @@ package final class MockCloudContainer: CloudContainer, CustomDumpReflectable {
}
package var customDumpMirror: Mirror {
- Mirror.init(
+ Mirror(
self,
children: [
("privateCloudDatabase", privateCloudDatabase),
diff --git a/Sources/SQLiteData/CloudKit/Internal/MockSyncEngine.swift b/Sources/SQLiteData/CloudKit/Internal/MockSyncEngine.swift
index 4b7fad3a..1eca4a4d 100644
--- a/Sources/SQLiteData/CloudKit/Internal/MockSyncEngine.swift
+++ b/Sources/SQLiteData/CloudKit/Internal/MockSyncEngine.swift
@@ -58,7 +58,8 @@ package final class MockSyncEngine: SyncEngineProtocol {
package func sendChanges(_ options: CKSyncEngine.SendChangesOptions) async throws {
guard
- !parentSyncEngine.syncEngine(for: database.databaseScope).state.pendingRecordZoneChanges.isEmpty
+ !parentSyncEngine.syncEngine(for: database.databaseScope).state.pendingRecordZoneChanges
+ .isEmpty
else { return }
try await parentSyncEngine.processPendingRecordZoneChanges(scope: database.databaseScope)
}
diff --git a/Sources/SQLiteData/CloudKit/Internal/Triggers.swift b/Sources/SQLiteData/CloudKit/Internal/Triggers.swift
index 86037162..16077e14 100644
--- a/Sources/SQLiteData/CloudKit/Internal/Triggers.swift
+++ b/Sources/SQLiteData/CloudKit/Internal/Triggers.swift
@@ -4,24 +4,32 @@
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
extension PrimaryKeyedTable {
- static func metadataTriggers(parentForeignKey: ForeignKey?) -> [TemporaryTrigger] {
+ static func metadataTriggers(
+ parentForeignKey: ForeignKey?,
+ defaultZone: CKRecordZone
+ ) -> [TemporaryTrigger] {
[
- afterInsert(parentForeignKey: parentForeignKey),
- afterUpdate(parentForeignKey: parentForeignKey),
- afterDeleteFromUser(parentForeignKey: parentForeignKey),
+ afterInsert(parentForeignKey: parentForeignKey, defaultZone: defaultZone),
+ afterUpdate(parentForeignKey: parentForeignKey, defaultZone: defaultZone),
+ afterDeleteFromUser(parentForeignKey: parentForeignKey, defaultZone: defaultZone),
afterDeleteFromSyncEngine,
- afterPrimaryKeyChange(parentForeignKey: parentForeignKey),
+ afterPrimaryKeyChange(parentForeignKey: parentForeignKey, defaultZone: defaultZone),
]
}
- fileprivate static func afterPrimaryKeyChange(parentForeignKey: ForeignKey?)
- -> TemporaryTrigger
- {
+ fileprivate static func afterPrimaryKeyChange(
+ parentForeignKey: ForeignKey?,
+ defaultZone: CKRecordZone
+ ) -> TemporaryTrigger {
createTemporaryTrigger(
"\(String.sqliteDataCloudKitSchemaName)_after_primary_key_change_on_\(tableName)",
ifNotExists: true,
after: .update(of: \.primaryKey) { old, new in
- checkWritePermissions(alias: new, parentForeignKey: parentForeignKey)
+ checkWritePermissions(
+ alias: new,
+ parentForeignKey: parentForeignKey,
+ defaultZone: defaultZone
+ )
SyncMetadata
.where {
$0.recordPrimaryKey.eq(#sql("\(old.primaryKey)"))
@@ -34,36 +42,70 @@
)
}
- fileprivate static func afterInsert(parentForeignKey: ForeignKey?) -> TemporaryTrigger {
+ fileprivate static func afterInsert(
+ parentForeignKey: ForeignKey?,
+ defaultZone: CKRecordZone
+ ) -> TemporaryTrigger {
createTemporaryTrigger(
"\(String.sqliteDataCloudKitSchemaName)_after_insert_on_\(tableName)",
ifNotExists: true,
after: .insert { new in
- checkWritePermissions(alias: new, parentForeignKey: parentForeignKey)
- SyncMetadata.upsert(new: new, parentForeignKey: parentForeignKey)
+ checkWritePermissions(
+ alias: new,
+ parentForeignKey: parentForeignKey,
+ defaultZone: defaultZone
+ )
+ SyncMetadata.insert(
+ new: new,
+ parentForeignKey: parentForeignKey,
+ defaultZone: defaultZone
+ )
}
)
}
- fileprivate static func afterUpdate(parentForeignKey: ForeignKey?) -> TemporaryTrigger {
+ fileprivate static func afterUpdate(
+ parentForeignKey: ForeignKey?,
+ defaultZone: CKRecordZone
+ ) -> TemporaryTrigger {
createTemporaryTrigger(
"\(String.sqliteDataCloudKitSchemaName)_after_update_on_\(tableName)",
ifNotExists: true,
after: .update { _, new in
- checkWritePermissions(alias: new, parentForeignKey: parentForeignKey)
- SyncMetadata.upsert(new: new, parentForeignKey: parentForeignKey)
+ checkWritePermissions(
+ alias: new,
+ parentForeignKey: parentForeignKey,
+ defaultZone: defaultZone
+ )
+ SyncMetadata.insert(
+ new: new,
+ parentForeignKey: parentForeignKey,
+ defaultZone: defaultZone
+ )
+ SyncMetadata.update(
+ new: new,
+ parentForeignKey: parentForeignKey,
+ defaultZone: defaultZone
+ )
}
)
}
- fileprivate static func afterDeleteFromUser(parentForeignKey: ForeignKey?) -> TemporaryTrigger<
+ fileprivate static func afterDeleteFromUser(
+ parentForeignKey: ForeignKey?,
+ defaultZone: CKRecordZone
+ ) -> TemporaryTrigger<
Self
> {
createTemporaryTrigger(
"\(String.sqliteDataCloudKitSchemaName)_after_delete_on_\(tableName)_from_user",
ifNotExists: true,
after: .delete { old in
- checkWritePermissions(alias: old, parentForeignKey: parentForeignKey)
+ checkWritePermissions(
+ alias: old,
+ parentForeignKey: parentForeignKey,
+ defaultZone: defaultZone
+ )
SyncMetadata
.where {
$0.recordPrimaryKey.eq(#sql("\(old.primaryKey)"))
@@ -96,29 +138,66 @@
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
extension SyncMetadata {
- fileprivate static func upsert(
+ fileprivate static func insert(
new: StructuredQueriesCore.TableAlias.TableColumns,
parentForeignKey: ForeignKey?,
+ defaultZone: CKRecordZone
) -> some StructuredQueriesCore.Statement {
- let (parentRecordPrimaryKey, parentRecordType) = parentFields(
+ let (parentRecordPrimaryKey, parentRecordType, zoneName, ownerName) = parentFields(
alias: new,
- parentForeignKey: parentForeignKey
+ parentForeignKey: parentForeignKey,
+ defaultZone: defaultZone
+ )
+ let defaultZoneName = #sql(
+ "\(quote: defaultZone.zoneID.zoneName, delimiter: .text)",
+ as: String.self
+ )
+ let defaultOwnerName = #sql(
+ "\(quote: defaultZone.zoneID.ownerName, delimiter: .text)",
+ as: String.self
)
return insert {
- ($0.recordPrimaryKey, $0.recordType, $0.parentRecordPrimaryKey, $0.parentRecordType)
+ (
+ $0.recordPrimaryKey,
+ $0.recordType,
+ $0.zoneName,
+ $0.ownerName,
+ $0.parentRecordPrimaryKey,
+ $0.parentRecordType
+ )
} select: {
Values(
#sql("\(new.primaryKey)"),
T.tableName,
- #sql(parentRecordPrimaryKey),
- #sql(parentRecordType)
+ zoneName ?? defaultZoneName,
+ ownerName ?? defaultOwnerName,
+ parentRecordPrimaryKey,
+ parentRecordType
)
- } onConflict: {
- ($0.recordPrimaryKey, $0.recordType)
- } doUpdate: {
- $0.parentRecordPrimaryKey = $1.parentRecordPrimaryKey
- $0.parentRecordType = $1.parentRecordType
- $0.userModificationTime = $1.userModificationTime
+ } onConflictDoUpdate: { _ in
+ }
+ }
+
+ fileprivate static func update(
+ new: StructuredQueriesCore.TableAlias.TableColumns,
+ parentForeignKey: ForeignKey?,
+ defaultZone: CKRecordZone
+ ) -> some StructuredQueriesCore.Statement {
+ let (parentRecordPrimaryKey, parentRecordType, zoneName, ownerName) = parentFields(
+ alias: new,
+ parentForeignKey: parentForeignKey,
+ defaultZone: defaultZone
+ )
+ return Self.where {
+ $0.recordPrimaryKey.eq(#sql("\(new.primaryKey)"))
+ && $0.recordType.eq(T.tableName)
+ }
+ .update {
+ $0.zoneName = zoneName ?? $0.zoneName
+ $0.ownerName = ownerName ?? $0.ownerName
+ $0.parentRecordPrimaryKey = parentRecordPrimaryKey
+ $0.parentRecordType = parentRecordType
+ $0.userModificationTime = $currentTime()
}
}
}
@@ -128,31 +207,27 @@
static func callbackTriggers(for syncEngine: SyncEngine) -> [TemporaryTrigger] {
[
afterInsertTrigger(for: syncEngine),
+ afterZoneUpdateTrigger(),
afterUpdateTrigger(for: syncEngine),
afterSoftDeleteTrigger(for: syncEngine),
]
}
- private enum ParentSyncMetadata: AliasName {}
-
fileprivate static func afterInsertTrigger(for syncEngine: SyncEngine) -> TemporaryTrigger
{
createTemporaryTrigger(
- "after_insert_on_sqlitedata_icloud_metadata",
+ "\(String.sqliteDataCloudKitSchemaName)_after_insert_on_sqlitedata_icloud_metadata",
ifNotExists: true,
after: .insert { new in
validate(recordName: new.recordName)
Values(
syncEngine.$didUpdate(
recordName: new.recordName,
- lastKnownServerRecord: new.lastKnownServerRecord
- ?? rootServerRecord(recordName: new.recordName),
- newParentLastKnownServerRecord: parentLastKnownServerRecordIfShared(
- parentRecordPrimaryKey: new.parentRecordPrimaryKey,
- parentRecordType: new.parentRecordType
- ),
- parentRecordPrimaryKey: new.parentRecordPrimaryKey,
- parentRecordType: new.parentRecordType
+ zoneName: new.zoneName,
+ ownerName: new.ownerName,
+ oldZoneName: new.zoneName,
+ oldOwnerName: new.ownerName,
+ descendantRecordNames: #bind(nil)
)
)
} when: { _ in
@@ -161,24 +236,58 @@
)
}
+ fileprivate static func afterZoneUpdateTrigger() -> TemporaryTrigger {
+ createTemporaryTrigger(
+ "\(String.sqliteDataCloudKitSchemaName)_after_zone_update_on_sqlitedata_icloud_metadata",
+ ifNotExists: true,
+ after: .update {
+ ($0.zoneName, $0.ownerName)
+ } forEachRow: { old, new in
+ let selfAndDescendantRecordNames = descendantRecordNames(
+ recordName: new.recordName,
+ includeSelf: true
+ ) {
+ $0.select(\.recordName)
+ }
+ SyncMetadata
+ .where {
+ $0.recordName.in(selfAndDescendantRecordNames)
+ }
+ .update {
+ $0.zoneName = new.zoneName
+ $0.ownerName = new.ownerName
+ $0.lastKnownServerRecord = nil
+ $0._lastKnownServerRecordAllFields = nil
+ }
+ } when: { old, new in
+ new.zoneName.neq(old.zoneName) || new.ownerName.neq(old.ownerName)
+ }
+ )
+ }
+
fileprivate static func afterUpdateTrigger(for syncEngine: SyncEngine) -> TemporaryTrigger
{
createTemporaryTrigger(
- "after_update_on_sqlitedata_icloud_metadata",
+ "\(String.sqliteDataCloudKitSchemaName)_after_update_on_sqlitedata_icloud_metadata",
ifNotExists: true,
- after: .update { _, new in
+ after: .update { old, new in
+ let zoneChanged = new.zoneName.neq(old.zoneName) || new.ownerName.neq(old.ownerName)
+ let descendantRecordNamesJSON = descendantRecordNames(
+ recordName: new.recordName,
+ includeSelf: false
+ ) {
+ $0.select { $0.recordName.jsonGroupArray() }
+ }
+
validate(recordName: new.recordName)
Values(
syncEngine.$didUpdate(
recordName: new.recordName,
- lastKnownServerRecord: new.lastKnownServerRecord
- ?? rootServerRecord(recordName: new.recordName),
- newParentLastKnownServerRecord: parentLastKnownServerRecordIfShared(
- parentRecordPrimaryKey: new.parentRecordPrimaryKey,
- parentRecordType: new.parentRecordType
- ),
- parentRecordPrimaryKey: new.parentRecordPrimaryKey,
- parentRecordType: new.parentRecordType
+ zoneName: new.zoneName,
+ ownerName: new.ownerName,
+ oldZoneName: old.zoneName,
+ oldOwnerName: old.ownerName,
+ descendantRecordNames: Case().when(zoneChanged, then: descendantRecordNamesJSON)
)
)
} when: { old, new in
@@ -187,11 +296,11 @@
)
}
- fileprivate static func afterSoftDeleteTrigger(for syncEngine: SyncEngine) -> TemporaryTrigger<
- Self
- > {
+ fileprivate static func afterSoftDeleteTrigger(
+ for syncEngine: SyncEngine
+ ) -> TemporaryTrigger {
createTemporaryTrigger(
- "after_delete_on_sqlitedata_icloud_metadata",
+ "\(String.sqliteDataCloudKitSchemaName)_after_delete_on_sqlitedata_icloud_metadata",
ifNotExists: true,
after: .update(of: \._isDeleted) { _, new in
Values(
@@ -209,13 +318,42 @@
}
}
+ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
private func parentFields(
alias: StructuredQueriesCore.TableAlias.TableColumns,
- parentForeignKey: ForeignKey?
- ) -> (parentRecordPrimaryKey: QueryFragment, parentRecordType: QueryFragment) {
- parentForeignKey
- .map { (#"\#(type(of: alias).QueryValue.self).\#(quote: $0.from)"#, "\(bind: $0.table)") }
- ?? ("NULL", "NULL")
+ parentForeignKey: ForeignKey?,
+ defaultZone: CKRecordZone
+ ) -> (
+ parentRecordPrimaryKey: SQLQueryExpression?,
+ parentRecordType: SQLQueryExpression?,
+ zoneName: SQLQueryExpression,
+ ownerName: SQLQueryExpression
+ ) {
+ return
+ parentForeignKey
+ .map { foreignKey in
+ let parentRecordPrimaryKey = #sql(
+ #"\#(type(of: alias).QueryValue.self).\#(quote: foreignKey.from)"#,
+ as: String.self
+ )
+ let parentRecordType = #sql("\(bind: foreignKey.table)", as: String.self)
+ let parentMetadata = SyncMetadata.where {
+ $0.recordPrimaryKey.eq(parentRecordPrimaryKey)
+ && $0.recordType.eq(parentRecordType)
+ }
+ return (
+ parentRecordPrimaryKey,
+ parentRecordType,
+ #sql("coalesce(\($currentZoneName()), (\(parentMetadata.select(\.zoneName))))"),
+ #sql("coalesce(\($currentOwnerName()), (\(parentMetadata.select(\.ownerName))))")
+ )
+ }
+ ?? (
+ nil,
+ nil,
+ SQLQueryExpression($currentZoneName()),
+ SQLQueryExpression($currentOwnerName())
+ )
}
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
@@ -234,18 +372,20 @@
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
private func checkWritePermissions(
alias: StructuredQueriesCore.TableAlias.TableColumns,
- parentForeignKey: ForeignKey?
+ parentForeignKey: ForeignKey?,
+ defaultZone: CKRecordZone
) -> some StructuredQueriesCore.Statement {
- let (parentRecordPrimaryKey, parentRecordType) = parentFields(
+ let (parentRecordPrimaryKey, parentRecordType, _, _) = parentFields(
alias: alias,
- parentForeignKey: parentForeignKey
+ parentForeignKey: parentForeignKey,
+ defaultZone: defaultZone
)
return With {
SyncMetadata
.where {
- $0.recordPrimaryKey.is(#sql(parentRecordPrimaryKey))
- && $0.recordType.is(#sql(parentRecordType))
+ $0.recordPrimaryKey.is(parentRecordPrimaryKey)
+ && $0.recordType.is(parentRecordType)
}
.select { RootShare.Columns(parentRecordName: $0.parentRecordName, share: $0.share) }
.union(
@@ -272,6 +412,40 @@
}
}
+ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
+ private func descendantRecordNames(
+ recordName: some QueryExpression,
+ includeSelf: Bool,
+ select: (Where) -> Select
+ ) -> some Statement {
+ With {
+ SyncMetadata
+ .where { $0.recordName.eq(recordName) }
+ .select {
+ DescendantMetadata.Columns(recordName: $0.recordName, parentRecordName: #bind(nil))
+ }
+ .union(
+ all: true,
+ SyncMetadata
+ .select {
+ DescendantMetadata.Columns(
+ recordName: $0.recordName,
+ parentRecordName: $0.parentRecordName
+ )
+ }
+ .join(DescendantMetadata.all) { $0.parentRecordName.eq($1.recordName) }
+ )
+ } query: {
+ select(
+ DescendantMetadata.where {
+ if !includeSelf {
+ $0.recordName.neq(recordName)
+ }
+ }
+ )
+ }
+ }
+
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
private func rootServerRecord(
recordName: some QueryExpression
@@ -294,7 +468,7 @@
}
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
- private func parentLastKnownServerRecordIfShared(
+ private func parentLastKnownServerRecord(
parentRecordPrimaryKey: some QueryExpression,
parentRecordType: some QueryExpression
) -> some QueryExpression {
@@ -322,4 +496,39 @@
substr(1, 1).neq("_") && octetLength().lte(255) && octetLength().eq(length())
}
}
+
+ @Table @Selection
+ private struct DescendantMetadata {
+ let recordName: String
+ let parentRecordName: String?
+ }
+
+ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
+ @Table @Selection
+ private struct AncestorMetadata {
+ let recordName: String
+ let parentRecordName: String?
+ @Column(as: CKRecord?.SystemFieldsRepresentation.self)
+ let lastKnownServerRecord: CKRecord?
+ }
+
+ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
+ @Table @Selection
+ struct RecordWithRoot {
+ let parentRecordName: String?
+ let recordName: String
+ @Column(as: CKRecord?.SystemFieldsRepresentation.self)
+ let lastKnownServerRecord: CKRecord?
+ let rootRecordName: String
+ @Column(as: CKRecord?.SystemFieldsRepresentation.self)
+ let rootLastKnownServerRecord: CKRecord?
+ }
+
+ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
+ @Table @Selection
+ private struct RootShare {
+ let parentRecordName: String?
+ @Column(as: CKShare?.SystemFieldsRepresentation.self)
+ let share: CKShare?
+ }
#endif
diff --git a/Sources/SQLiteData/CloudKit/SyncEngine.swift b/Sources/SQLiteData/CloudKit/SyncEngine.swift
index 48cdf3f7..cc101c2a 100644
--- a/Sources/SQLiteData/CloudKit/SyncEngine.swift
+++ b/Sources/SQLiteData/CloudKit/SyncEngine.swift
@@ -75,7 +75,10 @@
/// explicit call to ``stop()``. By default this argument is `true`.
/// - logger: The logger used to log events in the sync engine. By default a `.disabled`
/// logger is used, which means logs are not printed.
- public convenience init(
+ public convenience init<
+ each T1: PrimaryKeyedTable & _SendableMetatype,
+ each T2: PrimaryKeyedTable & _SendableMetatype
+ >(
for database: any DatabaseWriter,
tables: repeat (each T1).Type,
privateTables: repeat (each T2).Type,
@@ -327,6 +330,8 @@
db.add(function: $didUpdate)
db.add(function: $didDelete)
db.add(function: $hasPermission)
+ db.add(function: $currentZoneName)
+ db.add(function: $currentOwnerName)
for trigger in SyncMetadata.callbackTriggers(for: self) {
try trigger.execute(db)
@@ -336,6 +341,7 @@
try table.createTriggers(
foreignKeysByTableName: foreignKeysByTableName,
tablesByName: tablesByName,
+ defaultZone: defaultZone,
db: db
)
}
@@ -562,16 +568,11 @@
package func tearDownSyncEngine() throws {
try userDatabase.write { db in
for table in tables.reversed() {
- try table.dropTriggers(db: db)
+ try table.dropTriggers(defaultZone: defaultZone, db: db)
}
for trigger in SyncMetadata.callbackTriggers(for: self).reversed() {
try trigger.drop().execute(db)
}
- db.remove(function: $hasPermission)
- db.remove(function: $didDelete)
- db.remove(function: $didUpdate)
- db.remove(function: $syncEngineIsSynchronizingChanges)
- db.remove(function: $currentTime)
}
try metadatabase.erase()
try migrate(metadatabase: metadatabase)
@@ -598,60 +599,73 @@
@DatabaseFunction(
"sqlitedata_icloud_didUpdate",
- as: (
- (String, CKRecord?.SystemFieldsRepresentation, CKRecord?.SystemFieldsRepresentation, String?, String?) -> Void
- ).self
+ as: ((
+ String,
+ String,
+ String,
+ String,
+ String,
+ [String]?.JSONRepresentation
+ ) -> Void).self
)
func didUpdate(
recordName: String,
- lastKnownServerRecord: CKRecord?,
- newParentLastKnownServerRecord: CKRecord?,
- parentRecordPrimaryKey: String? = nil,
- parentRecordType: String? = nil
- ) throws {
- let zoneID = lastKnownServerRecord?.recordID.zoneID ?? defaultZone.zoneID
- let newZoneID = newParentLastKnownServerRecord?.recordID.zoneID
- if let newZoneID, zoneID != newZoneID {
- struct ZoneChangingError: Error, LocalizedError {
- let recordName: String
- let zoneID: CKRecordZone.ID
- let newZoneID: CKRecordZone.ID
- var errorDescription: String? {
- """
- The record '\(recordName)' was moved from zone \
- '\(zoneID.zoneName)/\(zoneID.ownerName)' to \
- '\(newZoneID.zoneName)/\(newZoneID.ownerName)'. This is currently not supported in \
- SQLiteData. To work around, delete the record and then create a new record with its \
- new parent association.
- """
- }
+ zoneName: String,
+ ownerName: String,
+ oldZoneName: String,
+ oldOwnerName: String,
+ descendantRecordNames: [String]?
+ ) {
+ var oldChanges: [CKSyncEngine.PendingRecordZoneChange] = []
+ var newChanges: [CKSyncEngine.PendingRecordZoneChange] = []
+
+ let oldZoneID = CKRecordZone.ID(zoneName: oldZoneName, ownerName: oldOwnerName)
+ let zoneID = CKRecordZone.ID(zoneName: zoneName, ownerName: ownerName)
+
+ if oldZoneID != zoneID {
+ oldChanges.append(.deleteRecord(CKRecord.ID(recordName: recordName, zoneID: oldZoneID)))
+ for descendantRecordName in descendantRecordNames ?? [] {
+ oldChanges.append(
+ .deleteRecord(CKRecord.ID(recordName: descendantRecordName, zoneID: oldZoneID))
+ )
}
- throw ZoneChangingError(recordName: recordName, zoneID: zoneID, newZoneID: newZoneID)
+ newChanges.append(.saveRecord(CKRecord.ID(recordName: recordName, zoneID: zoneID)))
+ for descendantRecordName in descendantRecordNames ?? [] {
+ newChanges.append(
+ .saveRecord(CKRecord.ID(recordName: descendantRecordName, zoneID: zoneID))
+ )
+ }
+ } else {
+ newChanges.append(
+ .saveRecord(CKRecord.ID(recordName: recordName, zoneID: zoneID))
+ )
}
- let change = CKSyncEngine.PendingRecordZoneChange.saveRecord(
- CKRecord.ID(
- recordName: recordName,
- zoneID: zoneID
- )
- )
guard isRunning else {
- Task {
+ // TODO: Perform this work in a trigger instead of a task.
+ Task { [changes = oldChanges + newChanges] in
await withErrorReporting(.sqliteDataCloudKitFailure) {
try await userDatabase.write { db in
try PendingRecordZoneChange
- .insert { PendingRecordZoneChange(change) }
+ .insert {
+ for change in changes {
+ PendingRecordZoneChange(change)
+ }
+ }
.execute(db)
}
}
}
return
}
-
+ let oldSyncEngine = self.syncEngines.withValue {
+ oldZoneID.ownerName == CKCurrentUserDefaultName ? $0.private : $0.shared
+ }
let syncEngine = self.syncEngines.withValue {
zoneID.ownerName == CKCurrentUserDefaultName ? $0.private : $0.shared
}
- syncEngine?.state.add(pendingRecordZoneChanges: [change])
+ oldSyncEngine?.state.add(pendingRecordZoneChanges: oldChanges)
+ syncEngine?.state.add(pendingRecordZoneChanges: newChanges)
}
@DatabaseFunction(
@@ -721,6 +735,7 @@
fileprivate static func createTriggers(
foreignKeysByTableName: [String: [ForeignKey]],
tablesByName: [String: any PrimaryKeyedTable.Type],
+ defaultZone: CKRecordZone,
db: Database
) throws {
let parentForeignKey =
@@ -728,14 +743,15 @@
? foreignKeysByTableName[tableName]?.first
: nil
- for trigger in metadataTriggers(parentForeignKey: parentForeignKey) {
+ for trigger in metadataTriggers(parentForeignKey: parentForeignKey, defaultZone: defaultZone)
+ {
try trigger.execute(db)
}
}
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
- fileprivate static func dropTriggers(db: Database) throws {
- for trigger in metadataTriggers(parentForeignKey: nil).reversed() {
+ fileprivate static func dropTriggers(defaultZone: CKRecordZone, db: Database) throws {
+ for trigger in metadataTriggers(parentForeignKey: nil, defaultZone: defaultZone).reversed() {
try trigger.drop().execute(db)
}
}
@@ -900,7 +916,7 @@
catching: {
try await metadatabase.read { db in
try SyncMetadata
- .where { $0.recordName.eq(recordID.recordName) }
+ .find(recordID)
.select { ($0, $0._lastKnownServerRecordAllFields) }
.fetchOne(db)
}
@@ -949,7 +965,7 @@
record.parent = CKRecord.Reference(
recordID: CKRecord.ID(
recordName: parentRecordName,
- zoneID: record.recordID.zoneID
+ zoneID: recordID.zoneID
),
action: .none
)
@@ -988,22 +1004,26 @@
return nil
}
}
- let deletedRecordNames = deletedRecordIDs.map(\.recordName)
let (sharesToDelete, recordsWithRoot):
([CKShare?], [(lastKnownServerRecord: CKRecord?, rootLastKnownServerRecord: CKRecord?)]) =
await withErrorReporting(.sqliteDataCloudKitFailure) {
- try await metadatabase.read { db in
+ guard !deletedRecordIDs.isEmpty
+ else { return ([], []) }
+
+ return try await metadatabase.read { db in
let sharesToDelete =
try SyncMetadata
- .where { $0.isShared && $0.recordName.in(deletedRecordNames) }
+ .findAll(deletedRecordIDs)
+ .where(\.isShared)
.select(\.share)
.fetchAll(db)
let recordsWithRoot =
try With {
SyncMetadata
- .where { $0.parentRecordName.is(nil) && $0.recordName.in(deletedRecordNames) }
+ .findAll(deletedRecordIDs)
+ .where { $0.parentRecordName.is(nil) }
.select {
RecordWithRoot.Columns(
parentRecordName: $0.parentRecordName,
@@ -1029,7 +1049,6 @@
)
} query: {
RecordWithRoot
- .where { $0.recordName.in(deletedRecordNames) }
.select { ($0.lastKnownServerRecord, $0.rootLastKnownServerRecord) }
}
.fetchAll(db)
@@ -1057,9 +1076,11 @@
}
await withErrorReporting(.sqliteDataCloudKitFailure) {
+ guard !deletedRecordIDs.isEmpty
+ else { return }
try await userDatabase.write { db in
try SyncMetadata
- .where { $0.recordName.in(deletedRecordNames) }
+ .findAll(deletedRecordIDs)
.delete()
.execute(db)
}
@@ -1201,15 +1222,15 @@
)
.mapValues { $0.map(\.recordID) }
for (recordType, recordIDs) in deletedRecordIDsByRecordType {
- let recordPrimaryKeys = recordIDs.compactMap(\.recordPrimaryKey)
if let table = tablesByName[recordType] {
func open(_: T.Type) async {
await withErrorReporting(.sqliteDataCloudKitFailure) {
try await userDatabase.write { db in
try T
.where {
- $0.primaryKey.in(
- recordPrimaryKeys.map { #sql("\(bind: $0)") }
+ #sql("\($0.primaryKey)").in(
+ SyncMetadata.findAll(recordIDs)
+ .select(\.recordPrimaryKey)
)
}
.delete()
@@ -1224,9 +1245,9 @@
}
await open(table)
} else if recordType == CKRecord.SystemType.share {
- for recordID in recordIDs {
+ for shareRecordID in recordIDs {
await withErrorReporting(.sqliteDataCloudKitFailure) {
- try await deleteShare(recordID: recordID)
+ try await deleteShare(shareRecordID: shareRecordID)
}
}
} else {
@@ -1349,7 +1370,7 @@
await withErrorReporting(.sqliteDataCloudKitFailure) {
try await userDatabase.write { db in
try SyncMetadata
- .where { $0.recordName.eq(failedRecord.recordID.recordName) }
+ .find(failedRecord.recordID)
.update { $0.setLastKnownServerRecord(nil) }
.execute(db)
}
@@ -1503,24 +1524,29 @@
else { return }
try await userDatabase.write { db in
try SyncMetadata
- .where { $0.recordName.eq(rootRecordID.recordName) }
+ .find(rootRecordID)
.update { $0.share = share }
.execute(db)
}
}
- func deleteShare(recordID: CKRecord.ID) async throws {
+ func deleteShare(shareRecordID: CKRecord.ID) async throws {
try await userDatabase.write { db in
- let shareAndRecordName =
+ let shareAndRecordNameAndZone =
try SyncMetadata
.where(\.isShared)
- .select { ($0.share, $0.recordName) }
+ .select { ($0.share, $0.recordName, $0.zoneName, $0.ownerName) }
.fetchAll(db)
- .first(where: { share, _ in share?.recordID == recordID }) ?? nil
- guard let (_, recordName) = shareAndRecordName
+ .first(where: { share, _, _, _ in share?.recordID == shareRecordID }) ?? nil
+ guard let (_, recordName, zoneName, ownerName) = shareAndRecordNameAndZone
else { return }
try SyncMetadata
- .where { $0.recordName.eq(recordName) }
+ .find(
+ CKRecord.ID(
+ recordName: recordName,
+ zoneID: CKRecordZone.ID(zoneName: zoneName, ownerName: ownerName)
+ )
+ )
.update { $0.share = nil }
.execute(db)
}
@@ -1543,68 +1569,66 @@
db: Database
) {
withErrorReporting(.sqliteDataCloudKitFailure) {
- guard let table = tablesByName[serverRecord.recordType]
- else {
- guard let recordPrimaryKey = serverRecord.recordID.recordPrimaryKey
- else { return }
- try SyncMetadata.insert {
- SyncMetadata(
- recordPrimaryKey: recordPrimaryKey,
- recordType: serverRecord.recordType,
- parentRecordPrimaryKey: serverRecord.parent?.recordID.recordPrimaryKey,
- parentRecordType: serverRecord.parent?.recordID.tableName,
- lastKnownServerRecord: serverRecord,
- _lastKnownServerRecordAllFields: serverRecord,
- share: nil,
- userModificationTime: serverRecord.userModificationTime
- )
- } onConflict: {
- ($0.recordPrimaryKey, $0.recordType)
- } doUpdate: {
+ guard let recordPrimaryKey = serverRecord.recordID.recordPrimaryKey
+ else { return }
+
+ try SyncMetadata.insert {
+ SyncMetadata(
+ recordPrimaryKey: recordPrimaryKey,
+ recordType: serverRecord.recordType,
+ zoneName: serverRecord.recordID.zoneID.zoneName,
+ ownerName: serverRecord.recordID.zoneID.ownerName,
+ parentRecordPrimaryKey: serverRecord.parent?.recordID.recordPrimaryKey,
+ parentRecordType: serverRecord.parent?.recordID.tableName,
+ lastKnownServerRecord: serverRecord,
+ _lastKnownServerRecordAllFields: serverRecord,
+ share: nil,
+ userModificationTime: serverRecord.userModificationTime
+ )
+ } onConflict: {
+ ($0.recordPrimaryKey, $0.recordType)
+ } doUpdate: {
+ if tablesByName[serverRecord.recordType] == nil {
$0.setLastKnownServerRecord(serverRecord)
+ } else {
+ $0.zoneName = serverRecord.recordID.zoneID.zoneName
+ $0.ownerName = serverRecord.recordID.zoneID.ownerName
}
- .execute(db)
+ }
+ .execute(db)
+
+ guard
+ let metadata = try SyncMetadata.find(serverRecord.recordID).fetchOne(db),
+ let table = tablesByName[serverRecord.recordType]
+ else {
return
}
- let metadata =
- try SyncMetadata
- .where { $0.recordName.eq(serverRecord.recordID.recordName) }
- .fetchOne(db)
- serverRecord.userModificationTime =
- metadata?.userModificationTime ?? serverRecord.userModificationTime
+ serverRecord.userModificationTime = metadata.userModificationTime
func open(_: T.Type) throws {
- let columnNames: [String]
- if !force, let metadata, let allFields = metadata._lastKnownServerRecordAllFields {
- var _columnNames = T.TableColumns.writableColumns.map(\.name)
+ var columnNames: [String] = T.TableColumns.writableColumns.map(\.name)
+ if !force,
+ let allFields = metadata._lastKnownServerRecordAllFields,
let row = try T.find(#sql("\(bind: metadata.recordPrimaryKey)")).fetchOne(db)
- if let row {
- serverRecord.update(
- with: allFields,
- row: T(queryOutput: row),
- columnNames: &_columnNames,
- parentForeignKey: foreignKeysByTableName[T.tableName]?.count == 1
- ? foreignKeysByTableName[T.tableName]?.first
- : nil
- )
- } else {
- reportIssue(
- """
- Local database record could not be found for '\(serverRecord.recordID.recordName)'.
- """
- )
- }
- columnNames = _columnNames
- } else {
- columnNames = T.TableColumns.writableColumns.map(\.name)
+ {
+ serverRecord.update(
+ with: allFields,
+ row: T(queryOutput: row),
+ columnNames: &columnNames,
+ parentForeignKey: foreignKeysByTableName[T.tableName]?.count == 1
+ ? foreignKeysByTableName[T.tableName]?.first
+ : nil
+ )
}
do {
- try #sql(upsert(T.self, record: serverRecord, columnNames: columnNames)).execute(db)
+ try $_currentZoneID.withValue(serverRecord.recordID.zoneID) {
+ try #sql(upsert(T.self, record: serverRecord, columnNames: columnNames)).execute(db)
+ }
try UnsyncedRecordID.find(serverRecord.recordID).delete().execute(db)
try SyncMetadata
- .where { $0.recordName.eq(serverRecord.recordID.recordName) }
+ .find(serverRecord.recordID)
.update { $0.setLastKnownServerRecord(serverRecord) }
.execute(db)
} catch {
@@ -1626,35 +1650,25 @@
}
private func refreshLastKnownServerRecord(_ record: CKRecord) async {
- let metadata = await metadataFor(recordName: record.recordID.recordName)
-
- func updateLastKnownServerRecord() async {
- await withErrorReporting(.sqliteDataCloudKitFailure) {
- try await userDatabase.write { db in
+ await withErrorReporting(.sqliteDataCloudKitFailure) {
+ try await metadatabase.write { db in
+ let metadata = try SyncMetadata.find(record.recordID).fetchOne(db)
+ func updateLastKnownServerRecord() throws {
try SyncMetadata
- .where { $0.recordName.eq(record.recordID.recordName) }
+ .find(record.recordID)
.update { $0.setLastKnownServerRecord(record) }
.execute(db)
}
- }
- }
- if let lastKnownDate = metadata?.lastKnownServerRecord?.modificationDate {
- if let recordDate = record.modificationDate, lastKnownDate < recordDate {
- await updateLastKnownServerRecord()
- }
- } else {
- await updateLastKnownServerRecord()
- }
- }
-
- private func metadataFor(recordName: String) async -> SyncMetadata? {
- await withErrorReporting(.sqliteDataCloudKitFailure) {
- try await metadatabase.read { db in
- try SyncMetadata.where { $0.recordName.eq(recordName) }.fetchOne(db)
+ if let lastKnownDate = metadata?.lastKnownServerRecord?.modificationDate {
+ if let recordDate = record.modificationDate, lastKnownDate < recordDate {
+ try updateLastKnownServerRecord()
+ }
+ } else {
+ try updateLastKnownServerRecord()
+ }
}
}
- ?? nil
}
private func updateQuery(
@@ -1735,7 +1749,7 @@
extension CKRecord.ID {
var tableName: String? {
guard
- let i = recordName.utf8.lastIndex(of: .init(ascii: ":")),
+ let i = recordName.utf8.lastIndex(of: UTF8.CodeUnit(ascii: ":")),
let j = recordName.utf8.index(i, offsetBy: 1, limitedBy: recordName.utf8.endIndex)
else { return nil }
let recordTypeBytes = recordName.utf8[j...]
@@ -1745,7 +1759,7 @@
var recordPrimaryKey: String? {
guard
- let i = recordName.utf8.lastIndex(of: .init(ascii: ":"))
+ let i = recordName.utf8.lastIndex(of: UTF8.CodeUnit(ascii: ":"))
else { return nil }
let recordPrimaryKeyBytes = recordName.utf8[.. [String: Int] {
let tableDependencies = try userDatabase.read { db in
- var dependencies: [HashablePrimaryKeyedTableType: [any (PrimaryKeyedTable & _SendableMetatype).Type]] = [:]
+ var dependencies:
+ [HashablePrimaryKeyedTableType: [any (PrimaryKeyedTable & _SendableMetatype).Type]] = [:]
for table in tables {
func open(_: T.Type) throws -> [String] {
try PragmaForeignKeyList.select(\.table)
@@ -2047,6 +2062,8 @@
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
extension Updates {
mutating func setLastKnownServerRecord(_ lastKnownServerRecord: CKRecord?) {
+ self.zoneName = lastKnownServerRecord?.recordID.zoneID.zoneName ?? self.zoneName
+ self.ownerName = lastKnownServerRecord?.recordID.zoneID.ownerName ?? self.ownerName
self.lastKnownServerRecord = lastKnownServerRecord
self._lastKnownServerRecordAllFields = lastKnownServerRecord
if let lastKnownServerRecord {
@@ -2099,4 +2116,16 @@
}
@TaskLocal package var _isSynchronizingChanges = false
+ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
+ @TaskLocal package var _currentZoneID: CKRecordZone.ID?
+ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
+ @DatabaseFunction("sqlitedata_icloud_currentZoneName")
+ func currentZoneName() -> String? {
+ _currentZoneID?.zoneName
+ }
+ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
+ @DatabaseFunction("sqlitedata_icloud_currentOwnerName")
+ func currentOwnerName() -> String? {
+ _currentZoneID?.ownerName
+ }
#endif
diff --git a/Sources/SQLiteData/CloudKit/SyncMetadata.swift b/Sources/SQLiteData/CloudKit/SyncMetadata.swift
index cf20bbbe..44672565 100644
--- a/Sources/SQLiteData/CloudKit/SyncMetadata.swift
+++ b/Sources/SQLiteData/CloudKit/SyncMetadata.swift
@@ -18,6 +18,12 @@
/// The type of the record synchronized, _i.e._ its table name.
public var recordType: String
+ /// The record zone name.
+ public var zoneName: String
+
+ /// The record owner name.
+ public var ownerName: String
+
/// The name of the record synchronized.
///
/// This field encodes both the table name and primary key of the record synchronized in
@@ -79,40 +85,13 @@
public var userModificationTime: Int64
}
- @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
- @Table @Selection
- struct AncestorMetadata {
- let recordName: String
- let parentRecordName: String?
- @Column(as: CKRecord?.SystemFieldsRepresentation.self)
- let lastKnownServerRecord: CKRecord?
- }
-
- @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
- @Table @Selection
- struct RecordWithRoot {
- let parentRecordName: String?
- let recordName: String
- @Column(as: CKRecord?.SystemFieldsRepresentation.self)
- let lastKnownServerRecord: CKRecord?
- let rootRecordName: String
- @Column(as: CKRecord?.SystemFieldsRepresentation.self)
- let rootLastKnownServerRecord: CKRecord?
- }
-
- @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
- @Table @Selection
- struct RootShare {
- let parentRecordName: String?
- @Column(as: CKShare?.SystemFieldsRepresentation.self)
- let share: CKShare?
- }
-
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
extension SyncMetadata {
package init(
recordPrimaryKey: String,
recordType: String,
+ zoneName: String,
+ ownerName: String,
parentRecordPrimaryKey: String? = nil,
parentRecordType: String? = nil,
lastKnownServerRecord: CKRecord? = nil,
@@ -123,6 +102,8 @@
self.recordPrimaryKey = recordPrimaryKey
self.recordType = recordType
self.recordName = "\(recordPrimaryKey):\(recordType)"
+ self.zoneName = zoneName
+ self.ownerName = ownerName
self.parentRecordPrimaryKey = parentRecordPrimaryKey
self.parentRecordType = parentRecordType
if let parentRecordPrimaryKey, let parentRecordType {
@@ -137,6 +118,24 @@
self.isShared = share != nil
self.userModificationTime = userModificationTime
}
+
+ package static func find(_ recordID: CKRecord.ID) -> Where {
+ Self.where {
+ $0.recordName.eq(recordID.recordName)
+ && $0.zoneName.eq(recordID.zoneID.zoneName)
+ && $0.ownerName.eq(recordID.zoneID.ownerName)
+ }
+ }
+
+ package static func findAll(_ recordIDs: some Collection) -> Where {
+ let condition: QueryFragment = recordIDs.map {
+ "(\(bind: $0.recordName), \(bind: $0.zoneID.zoneName), \(bind: $0.zoneID.ownerName))"
+ }
+ .joined(separator: ", ")
+ return Self.where {
+ #sql("(\($0.recordName), \($0.zoneName), \($0.ownerName)) IN (\(condition))")
+ }
+ }
}
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
diff --git a/Sources/SQLiteData/Documentation.docc/Articles/CloudKit.md b/Sources/SQLiteData/Documentation.docc/Articles/CloudKit.md
index e9f1ead0..6e2c2350 100644
--- a/Sources/SQLiteData/Documentation.docc/Articles/CloudKit.md
+++ b/Sources/SQLiteData/Documentation.docc/Articles/CloudKit.md
@@ -287,7 +287,7 @@ has been added to the schema, it will populate the table with the cached records
#### Adding columns
> TL;DR: When adding columns to a table that has already been deployed to users' devices, you will
-either need to make the column nullable, or a default value must be provided with an
+either need to make the column nullable, or a default value must be provided with an
`ON CONFLICT REPLACE` clause.
As an example, suppose the 1.0 of your app shipped a table for a reminders list:
diff --git a/Sources/SQLiteData/Documentation.docc/Articles/Observing.md b/Sources/SQLiteData/Documentation.docc/Articles/Observing.md
index f57feb5f..f1ce70e5 100644
--- a/Sources/SQLiteData/Documentation.docc/Articles/Observing.md
+++ b/Sources/SQLiteData/Documentation.docc/Articles/Observing.md
@@ -1,7 +1,7 @@
# Observing changes to model data
-Learn how to observe changes to your database in SwiftUI views, UIKit view controllers, and
-more.
+Learn how to observe changes to your database in SwiftUI views, UIKit view controllers, and
+more.
## Overview
diff --git a/Sources/SQLiteData/Documentation.docc/Articles/PreparingDatabase.md b/Sources/SQLiteData/Documentation.docc/Articles/PreparingDatabase.md
index f1a21b36..eadbdac1 100644
--- a/Sources/SQLiteData/Documentation.docc/Articles/PreparingDatabase.md
+++ b/Sources/SQLiteData/Documentation.docc/Articles/PreparingDatabase.md
@@ -1,6 +1,6 @@
# Preparing a SQLite database
-Learn how to create, configure and migrate the SQLite database that holds your application’s
+Learn how to create, configure and migrate the SQLite database that holds your application’s
data.
## Overview
@@ -46,10 +46,10 @@ optional step:
}
```
-One configuration you may want to enable is query tracing in order to log queries that are executed
-in your application. This can be handy for tracking down long-running queries, or when more queries
-execute than you expect. We also recommend only doing this in debug builds to avoid leaking
-sensitive information when the app is running on a user's device, and we further recommend using
+One configuration you may want to enable is query tracing in order to log queries that are executed
+in your application. This can be handy for tracking down long-running queries, or when more queries
+execute than you expect. We also recommend only doing this in debug builds to avoid leaking
+sensitive information when the app is running on a user's device, and we further recommend using
OSLog when running your app in the simulator/device and using `Swift.print` in previews:
```diff
@@ -85,7 +85,7 @@ OSLog when running your app in the simulator/device and using `Swift.print` in p
[swift-dependencies-gh]: https://github.com/pointfreeco/swift-dependencies
-For more information on configuring the database connection, see [GRDB's documentation][config-docs]
+For more information on configuring the database connection, see [GRDB's documentation][config-docs]
on the matter.
[config-docs]: https://swiftpackageindex.com/groue/grdb.swift/master/documentation/grdb/configuration
diff --git a/Sources/SQLiteData/Documentation.docc/SQLiteData.md b/Sources/SQLiteData/Documentation.docc/SQLiteData.md
index 2112fd3d..c9a3bc32 100644
--- a/Sources/SQLiteData/Documentation.docc/SQLiteData.md
+++ b/Sources/SQLiteData/Documentation.docc/SQLiteData.md
@@ -1,6 +1,6 @@
# ``SQLiteData``
-A fast, lightweight replacement for SwiftData, powered by SQL and supporting CloudKit
+A fast, lightweight replacement for SwiftData, powered by SQL and supporting CloudKit
synchronization.
## Overview
diff --git a/Tests/SQLiteDataTests/AssertQueryTests.swift b/Tests/SQLiteDataTests/AssertQueryTests.swift
index 4878a923..4dfb959a 100644
--- a/Tests/SQLiteDataTests/AssertQueryTests.swift
+++ b/Tests/SQLiteDataTests/AssertQueryTests.swift
@@ -7,7 +7,7 @@ import Testing
@Suite(
.dependency(\.defaultDatabase, try .database()),
- .snapshots(record: .failed),
+ .snapshots(record: .missing),
)
struct AssertQueryTests {
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
diff --git a/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift b/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift
index e9586ca9..e5865a70 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/AccountLifecycleTests.swift
@@ -149,6 +149,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "remindersLists", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:remindersLists", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -177,6 +179,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "reminders", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:reminders", │
│ parentRecordPrimaryKey: "1", │
│ parentRecordType: "remindersLists", │
@@ -226,6 +230,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "remindersLists", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:remindersLists", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -254,6 +260,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "reminders", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:reminders", │
│ parentRecordPrimaryKey: "1", │
│ parentRecordType: "remindersLists", │
@@ -349,7 +357,8 @@
_ = try syncEngine.modifyRecords(scope: .shared, saving: [share, remindersListRecord])
let freshShare = try syncEngine.shared.database.record(for: share.recordID) as! CKShare
- let freshRemindersListRecord = try syncEngine.shared.database.record(for: remindersListRecord.recordID)
+ let freshRemindersListRecord = try syncEngine.shared.database.record(
+ for: remindersListRecord.recordID)
try await syncEngine
.acceptShare(
@@ -375,6 +384,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "remindersLists", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
│ recordName: "1:remindersLists", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -408,6 +419,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "reminders", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
│ recordName: "1:reminders", │
│ parentRecordPrimaryKey: "1", │
│ parentRecordType: "remindersLists", │
@@ -463,6 +476,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "remindersLists", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
│ recordName: "1:remindersLists", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -496,6 +511,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "reminders", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
│ recordName: "1:reminders", │
│ parentRecordPrimaryKey: "1", │
│ parentRecordType: "remindersLists", │
diff --git a/Tests/SQLiteDataTests/CloudKitTests/AppLifecycleTests.swift b/Tests/SQLiteDataTests/CloudKitTests/AppLifecycleTests.swift
index 59033c08..e6af0fd2 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/AppLifecycleTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/AppLifecycleTests.swift
@@ -23,7 +23,8 @@
RemindersList(id: 1, title: "Personal")
}
}
- defaultNotificationCenter.post(name: UIApplication.willResignActiveNotification, object: nil)
+ defaultNotificationCenter.post(
+ name: UIApplication.willResignActiveNotification, object: nil)
try await Task.sleep(for: .seconds(1))
assertInlineSnapshot(of: container, as: .customDump) {
"""
@@ -90,7 +91,8 @@
}
}
- defaultNotificationCenter.post(name: UIApplication.willResignActiveNotification, object: nil)
+ defaultNotificationCenter.post(
+ name: UIApplication.willResignActiveNotification, object: nil)
try await Task.sleep(for: .seconds(1))
assertInlineSnapshot(of: container, as: .customDump) {
"""
diff --git a/Tests/SQLiteDataTests/CloudKitTests/CloudKitTests.swift b/Tests/SQLiteDataTests/CloudKitTests/CloudKitTests.swift
index 57eb9b3c..460c27da 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/CloudKitTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/CloudKitTests.swift
@@ -447,11 +447,13 @@
) {
"""
[
- [0]: "sqlitedata_icloud_currenttime",
- [1]: "sqlitedata_icloud_diddelete",
- [2]: "sqlitedata_icloud_didupdate",
- [3]: "sqlitedata_icloud_haspermission",
- [4]: "sqlitedata_icloud_syncengineissynchronizingchanges"
+ [0]: "sqlitedata_icloud_currentownername",
+ [1]: "sqlitedata_icloud_currenttime",
+ [2]: "sqlitedata_icloud_currentzonename",
+ [3]: "sqlitedata_icloud_diddelete",
+ [4]: "sqlitedata_icloud_didupdate",
+ [5]: "sqlitedata_icloud_haspermission",
+ [6]: "sqlitedata_icloud_syncengineissynchronizingchanges"
]
"""
}
diff --git a/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift b/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift
index 51e73353..6e6007af 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/FetchRecordZoneChangesTests.swift
@@ -524,6 +524,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "tag", │
│ recordType: "tags", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "tag:tags", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -604,6 +606,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "tag", │
│ recordType: "tags", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "tag:tags", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -671,6 +675,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "weekend", │
│ recordType: "tags", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "weekend:tags", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
diff --git a/Tests/SQLiteDataTests/CloudKitTests/ForeignKeyConstraintTests.swift b/Tests/SQLiteDataTests/CloudKitTests/ForeignKeyConstraintTests.swift
index 7f0e0b57..40688a42 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/ForeignKeyConstraintTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/ForeignKeyConstraintTests.swift
@@ -832,6 +832,33 @@
"""
}
}
+
+ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
+ @Test func insertForeignKeyConstraintFailure() async throws {
+ await #expect(throws: (any Error).self) {
+ try await userDatabase.userWrite { db in
+ try db.seed {
+ Reminder(id: 1, title: "Get milk", remindersListID: 1)
+ }
+ }
+ }
+ try await syncEngine.processPendingRecordZoneChanges(scope: .private)
+ assertQuery(SyncMetadata.all, database: syncEngine.metadatabase)
+ assertInlineSnapshot(of: container, as: .customDump) {
+ """
+ MockCloudContainer(
+ privateCloudDatabase: MockCloudDatabase(
+ databaseScope: .private,
+ storage: []
+ ),
+ sharedCloudDatabase: MockCloudDatabase(
+ databaseScope: .shared,
+ storage: []
+ )
+ )
+ """
+ }
+ }
}
}
#endif
diff --git a/Tests/SQLiteDataTests/CloudKitTests/MergeConflictTests.swift b/Tests/SQLiteDataTests/CloudKitTests/MergeConflictTests.swift
index 645540a0..e3a5964a 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/MergeConflictTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/MergeConflictTests.swift
@@ -629,27 +629,26 @@
let reminderRecord = try syncEngine.private.database.record(
for: Reminder.recordID(for: 1)
)
- reminderRecord.setValue(Date(
- timeIntervalSince1970: Double(now + 30)),
+ reminderRecord.setValue(
+ Date(timeIntervalSince1970: Double(now + 30)),
forKey: "dueDate",
- at: now + 1
+ at: now
)
let modificationsFinished = try syncEngine.modifyRecords(
scope: .private,
saving: [reminderRecord]
)
- try withDependencies {
- $0.currentTime.now += 2
+ try await withDependencies {
+ $0.currentTime.now += 1
} operation: {
- try userDatabase.userWrite { db in
+ try await userDatabase.userWrite { db in
try Reminder.find(1).update { $0.priority = 3 }.execute(db)
}
+ await modificationsFinished.notify()
+ try await syncEngine.processPendingRecordZoneChanges(scope: .private)
}
- await modificationsFinished.notify()
- try await syncEngine.processPendingRecordZoneChanges(scope: .private)
-
assertInlineSnapshot(of: container, as: .customDump) {
"""
MockCloudContainer(
@@ -662,18 +661,18 @@
parent: CKReference(recordID: CKRecord.ID(1:remindersLists/zone/__defaultOwner__)),
share: nil,
dueDate: Date(1970-01-01T00:00:30.000Z),
- dueDate🗓️: 1,
+ dueDate🗓️: 0,
id: 1,
id🗓️: 0,
isCompleted: 0,
isCompleted🗓️: 0,
priority: 3,
- priority🗓️: 2,
+ priority🗓️: 1,
remindersListID: 1,
remindersListID🗓️: 0,
title: "",
title🗓️: 0,
- 🗓️: 2
+ 🗓️: 1
),
[1]: CKRecord(
recordID: CKRecord.ID(1:remindersLists/zone/__defaultOwner__),
diff --git a/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift b/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift
index 7fb8a705..e8e40745 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/MetadataTests.swift
@@ -211,6 +211,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "reminderTags", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:reminderTags", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -240,6 +242,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "reminders", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:reminders", │
│ parentRecordPrimaryKey: "1", │
│ parentRecordType: "remindersLists", │
@@ -270,6 +274,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "remindersLists", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:remindersLists", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -298,6 +304,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "2", │
│ recordType: "reminderTags", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "2:reminderTags", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -327,6 +335,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "2", │
│ recordType: "reminders", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "2:reminders", │
│ parentRecordPrimaryKey: "1", │
│ parentRecordType: "remindersLists", │
@@ -357,6 +367,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "2", │
│ recordType: "remindersLists", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "2:remindersLists", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -385,6 +397,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "3", │
│ recordType: "reminderTags", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "3:reminderTags", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -414,6 +428,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "3", │
│ recordType: "reminders", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "3:reminders", │
│ parentRecordPrimaryKey: "2", │
│ parentRecordType: "remindersLists", │
@@ -444,6 +460,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "optional", │
│ recordType: "tags", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "optional:tags", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -471,6 +489,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "weekend", │
│ recordType: "tags", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "weekend:tags", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -520,7 +540,9 @@
│ RemindersList( │ SyncMetadata( │
│ id: 1, │ recordPrimaryKey: "1", │
│ title: "Personal" │ recordType: "remindersLists", │
- │ ) │ recordName: "1:remindersLists", │
+ │ ) │ zoneName: "zone", │
+ │ │ ownerName: "__defaultOwner__", │
+ │ │ recordName: "1:remindersLists", │
│ │ parentRecordPrimaryKey: nil, │
│ │ parentRecordType: nil, │
│ │ parentRecordName: nil, │
@@ -548,7 +570,9 @@
│ RemindersList( │ SyncMetadata( │
│ id: 2, │ recordPrimaryKey: "2", │
│ title: "Work" │ recordType: "remindersLists", │
- │ ) │ recordName: "2:remindersLists", │
+ │ ) │ zoneName: "zone", │
+ │ │ ownerName: "__defaultOwner__", │
+ │ │ recordName: "2:remindersLists", │
│ │ parentRecordPrimaryKey: nil, │
│ │ parentRecordType: nil, │
│ │ parentRecordName: nil, │
diff --git a/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift b/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift
index 3df8dfc9..963599f7 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift
@@ -392,7 +392,8 @@
try withKnownIssue {
_ = try syncEngine.modifyRecords(scope: .private, saving: [share])
} matching: { issue in
- issue.description.hasSuffix("""
+ issue.description.hasSuffix(
+ """
An added share is being saved without its rootRecord being saved in the \
same operation.
""")
diff --git a/Tests/SQLiteDataTests/CloudKitTests/NextRecordZoneChangeBatchTests.swift b/Tests/SQLiteDataTests/CloudKitTests/NextRecordZoneChangeBatchTests.swift
index f887d120..839f2df7 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/NextRecordZoneChangeBatchTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/NextRecordZoneChangeBatchTests.swift
@@ -40,13 +40,15 @@
SyncMetadata(
recordPrimaryKey: "1",
recordType: UnrecognizedTable.tableName,
+ zoneName: "zone-name",
+ ownerName: "owner-name",
userModificationTime: 0
)
}
.execute(db)
}
- try await syncEngine.processPendingRecordZoneChanges(scope: .private)
+ try await syncEngine.processPendingRecordZoneChanges(scope: .shared)
assertInlineSnapshot(of: container, as: .customDump) {
"""
MockCloudContainer(
@@ -70,6 +72,8 @@
SyncMetadata(
recordPrimaryKey: "1",
recordType: RemindersList.tableName,
+ zoneName: syncEngine.defaultZone.zoneID.zoneName,
+ ownerName: syncEngine.defaultZone.zoneID.ownerName,
userModificationTime: 0
)
}
diff --git a/Tests/SQLiteDataTests/CloudKitTests/RecordTypeTests.swift b/Tests/SQLiteDataTests/CloudKitTests/RecordTypeTests.swift
index fd1a0a10..20bf20a3 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/RecordTypeTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/RecordTypeTests.swift
@@ -394,7 +394,7 @@
try #expect(RecordType.all.fetchCount(db) > 0)
try #expect(StateSerialization.all.fetchCount(db) == 0)
}
-
+
try syncEngine.tearDownSyncEngine()
try await syncEngine.metadatabase.read { db in
try #expect(SyncMetadata.all.fetchCount(db) == 0)
diff --git a/Tests/SQLiteDataTests/CloudKitTests/ReferenceViolationTests.swift b/Tests/SQLiteDataTests/CloudKitTests/ReferenceViolationTests.swift
index 33b8bd8e..4c02cf1e 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/ReferenceViolationTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/ReferenceViolationTests.swift
@@ -4,6 +4,7 @@
import CustomDump
import InlineSnapshotTesting
import SQLiteData
+ import SQLiteDataTestSupport
import SnapshotTestingCustomDump
import Testing
@@ -304,17 +305,22 @@
)
"""
}
- try await userDatabase.read { db in
- try #expect(
- ChildWithOnDeleteSetNull.all.fetchAll(db) == [
- ChildWithOnDeleteSetNull(id: 1, parentID: nil)
- ]
- )
- try #expect(
- Parent.all.fetchAll(db) == [
- Parent(id: 1)
- ]
- )
+ assertQuery(ChildWithOnDeleteSetNull.all, database: userDatabase.database) {
+ """
+ ┌───────────────────────────┐
+ │ ChildWithOnDeleteSetNull( │
+ │ id: 1, │
+ │ parentID: nil │
+ │ ) │
+ └───────────────────────────┘
+ """
+ }
+ assertQuery(Parent.all, database: userDatabase.database) {
+ """
+ ┌───────────────┐
+ │ Parent(id: 1) │
+ └───────────────┘
+ """
}
}
}
diff --git a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift
index ca4e414a..9b4c2f54 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift
@@ -218,7 +218,7 @@
}
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
- @Test func shareDelieveredBeforeRecord() async throws {
+ @Test func shareDeliveredBeforeRecord() async throws {
let externalZone = CKRecordZone(
zoneID: CKRecordZone.ID(
zoneName: "external.zone",
@@ -290,6 +290,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "remindersLists", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
│ recordName: "1:remindersLists", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -361,6 +363,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "modelAs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
│ recordName: "1:modelAs", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -389,6 +393,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "modelBs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
│ recordName: "1:modelBs", │
│ parentRecordPrimaryKey: "1", │
│ parentRecordType: "modelAs", │
@@ -418,6 +424,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "modelCs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
│ recordName: "1:modelCs", │
│ parentRecordPrimaryKey: "1", │
│ parentRecordType: "modelBs", │
@@ -827,18 +835,78 @@
try await syncEngine.processPendingRecordZoneChanges(scope: .shared)
- assertQuery(
- SyncMetadata.select { ($0.recordName, $0.parentRecordName) },
- database: syncEngine.metadatabase
- ) {
+ assertQuery(SyncMetadata.all, database: syncEngine.metadatabase) {
"""
- ┌────────────────────┬────────────────────┐
- │ "1:remindersLists" │ nil │
- │ "1:reminders" │ "1:remindersLists" │
- └────────────────────┴────────────────────┘
+ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "remindersLists", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "1:remindersLists", │
+ │ parentRecordPrimaryKey: nil, │
+ │ parentRecordType: nil, │
+ │ parentRecordName: nil, │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner), │
+ │ recordType: "remindersLists", │
+ │ parent: nil, │
+ │ share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/external.zone/external.owner)) │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner), │
+ │ recordType: "remindersLists", │
+ │ parent: nil, │
+ │ share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/external.zone/external.owner)), │
+ │ id: 1, │
+ │ title: "Personal" │
+ │ ), │
+ │ share: CKRecord( │
+ │ recordID: CKRecord.ID(share-1:remindersLists/external.zone/external.owner), │
+ │ recordType: "cloudkit.share", │
+ │ parent: nil, │
+ │ share: nil │
+ │ ), │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: true, │
+ │ userModificationTime: 0 │
+ │ ) │
+ ├─────────────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "reminders", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "1:reminders", │
+ │ parentRecordPrimaryKey: "1", │
+ │ parentRecordType: "remindersLists", │
+ │ parentRecordName: "1:remindersLists", │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:reminders/external.zone/external.owner), │
+ │ recordType: "reminders", │
+ │ parent: CKReference(recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner)), │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:reminders/external.zone/external.owner), │
+ │ recordType: "reminders", │
+ │ parent: CKReference(recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner)), │
+ │ share: nil, │
+ │ id: 1, │
+ │ isCompleted: 0, │
+ │ remindersListID: 1, │
+ │ title: "Get milk" │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 0 │
+ │ ) │
+ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘
"""
}
-
assertInlineSnapshot(of: container, as: .customDump) {
"""
MockCloudContainer(
@@ -956,6 +1024,7 @@
try await userDatabase.userWrite { db in
try db.seed {
Reminder(id: 1, title: "Get milk", remindersListID: 1)
+ Reminder(id: 2, title: "Take a walk", remindersListID: 1)
}
}
@@ -967,13 +1036,9 @@
try await syncEngine.processPendingRecordZoneChanges(scope: .shared)
- assertQuery(
- SyncMetadata.select { ($0.recordName, $0.share) },
- database: syncEngine.metadatabase
- ) {
- """
- """
- }
+ assertQuery(Reminder.all, database: userDatabase.database)
+ assertQuery(RemindersList.all, database: userDatabase.database)
+ assertQuery(SyncMetadata.all, database: syncEngine.metadatabase)
assertInlineSnapshot(of: container, as: .customDump) {
"""
@@ -996,6 +1061,16 @@
title: "Get milk"
),
[1]: CKRecord(
+ recordID: CKRecord.ID(2:reminders/external.zone/external.owner),
+ recordType: "reminders",
+ parent: CKReference(recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner)),
+ share: nil,
+ id: 2,
+ isCompleted: 0,
+ remindersListID: 1,
+ title: "Take a walk"
+ ),
+ [2]: CKRecord(
recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner),
recordType: "remindersLists",
parent: nil,
@@ -1010,12 +1085,69 @@
}
}
+ // NB: Come back to this when we have time to investigate.
+ // /// Deleting a root shared record that is not owned by current user should only delete
+ // /// the CKShare, not delete the actual CloudKit records, but delete all the local records.
+ // @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
+ // @Test func deleteRootSharedRecord_OnDeleteSetNull() async throws {
+ // let externalZone = CKRecordZone(
+ // zoneID: CKRecordZone.ID(
+ // zoneName: "external.zone",
+ // ownerName: "external.owner"
+ // )
+ // )
+ // try await syncEngine.modifyRecordZones(scope: .shared, saving: [externalZone]).notify()
+ //
+ // let parentRecord = CKRecord(
+ // recordType: Parent.tableName,
+ // recordID: Parent.recordID(for: 1, zoneID: externalZone.zoneID)
+ // )
+ // parentRecord.setValue(1, forKey: "id", at: now)
+ // let share = CKShare(
+ // rootRecord: parentRecord,
+ // shareID: CKRecord.ID(
+ // recordName: "share-\(parentRecord.recordID.recordName)",
+ // zoneID: parentRecord.recordID.zoneID
+ // )
+ // )
+ //
+ // try await syncEngine
+ // .acceptShare(
+ // metadata: ShareMetadata(
+ // containerIdentifier: container.containerIdentifier!,
+ // hierarchicalRootRecordID: parentRecord.recordID,
+ // rootRecord: parentRecord,
+ // share: share
+ // )
+ // )
+ //
+ // try await userDatabase.userWrite { db in
+ // try db.seed {
+ // ChildWithOnDeleteSetNull(id: 1, parentID: 1)
+ // }
+ // }
+ //
+ // try await syncEngine.processPendingRecordZoneChanges(scope: .shared)
+ //
+ // try await userDatabase.userWrite { db in
+ // try Parent.find(1).delete().execute(db)
+ // }
+ //
+ // try await syncEngine.processPendingRecordZoneChanges(scope: .shared)
+ //
+ // assertQuery(Parent.all, database: userDatabase.database)
+ // assertQuery(ChildWithOnDeleteSetNull.all, database: userDatabase.database)
+ // assertQuery(SyncMetadata.all, database: syncEngine.metadatabase)
+ // assertInlineSnapshot(of: container, as: .customDump)
+ // }
+
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
@Test func movesChildRecordFromPrivateParentToSharedParent() async throws {
try await userDatabase.userWrite { db in
try db.seed {
ModelA.Draft(id: 1, count: 42)
ModelB.Draft(id: 1, isOn: true, modelAID: 1)
+ ModelC.Draft(id: 1, title: "Blob", modelBID: 1)
}
}
try await syncEngine.processPendingRecordZoneChanges(scope: .private)
@@ -1055,16 +1187,16 @@
)
)
- let error = await #expect(throws: DatabaseError.self) {
+ try await withDependencies {
+ $0.currentTime.now += 1
+ } operation: {
try await self.userDatabase.userWrite { db in
try ModelB.find(1).update { $0.modelAID = 2 }.execute(db)
}
+
+ try await syncEngine.processPendingRecordZoneChanges(scope: .private)
+ try await syncEngine.processPendingRecordZoneChanges(scope: .shared)
}
- #expect(error?.message == """
- The record '1:modelBs' was moved from zone 'zone/__defaultOwner__' to \
- 'external.zone/external.owner'. This is currently not supported in SQLiteData. To work \
- around, delete the record and then create a new record with its new parent association.
- """)
assertQuery(ModelB.all, database: userDatabase.database) {
"""
@@ -1072,17 +1204,33 @@
│ ModelB( │
│ id: 1, │
│ isOn: true, │
- │ modelAID: 1 │
+ │ modelAID: 2 │
│ ) │
└───────────────┘
"""
}
- assertQuery(SyncMetadata.all, database: syncEngine.metadatabase) {
+ assertQuery(ModelC.all, database: userDatabase.database) {
+ """
+ ┌──────────────────┐
+ │ ModelC( │
+ │ id: 1, │
+ │ title: "Blob", │
+ │ modelBID: 1 │
+ │ ) │
+ └──────────────────┘
+ """
+ }
+ assertQuery(
+ SyncMetadata.order { ($0.recordType, $0.recordName) },
+ database: syncEngine.metadatabase
+ ) {
"""
┌──────────────────────────────────────────────────────────────────────────────────────────────┐
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "modelAs", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:modelAs", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -1109,37 +1257,10 @@
│ ) │
├──────────────────────────────────────────────────────────────────────────────────────────────┤
│ SyncMetadata( │
- │ recordPrimaryKey: "1", │
- │ recordType: "modelBs", │
- │ recordName: "1:modelBs", │
- │ parentRecordPrimaryKey: "1", │
- │ parentRecordType: "modelAs", │
- │ parentRecordName: "1:modelAs", │
- │ lastKnownServerRecord: CKRecord( │
- │ recordID: CKRecord.ID(1:modelBs/zone/__defaultOwner__), │
- │ recordType: "modelBs", │
- │ parent: CKReference(recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__)), │
- │ share: nil │
- │ ), │
- │ _lastKnownServerRecordAllFields: CKRecord( │
- │ recordID: CKRecord.ID(1:modelBs/zone/__defaultOwner__), │
- │ recordType: "modelBs", │
- │ parent: CKReference(recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__)), │
- │ share: nil, │
- │ id: 1, │
- │ isOn: 1, │
- │ modelAID: 1 │
- │ ), │
- │ share: nil, │
- │ _isDeleted: false, │
- │ hasLastKnownServerRecord: true, │
- │ isShared: false, │
- │ userModificationTime: 0 │
- │ ) │
- ├──────────────────────────────────────────────────────────────────────────────────────────────┤
- │ SyncMetadata( │
│ recordPrimaryKey: "2", │
│ recordType: "modelAs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
│ recordName: "2:modelAs", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -1169,6 +1290,68 @@
│ isShared: true, │
│ userModificationTime: 0 │
│ ) │
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "modelBs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "1:modelBs", │
+ │ parentRecordPrimaryKey: "2", │
+ │ parentRecordType: "modelAs", │
+ │ parentRecordName: "2:modelAs", │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelBs/external.zone/external.owner), │
+ │ recordType: "modelBs", │
+ │ parent: CKReference(recordID: CKRecord.ID(2:modelAs/external.zone/external.owner)), │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelBs/external.zone/external.owner), │
+ │ recordType: "modelBs", │
+ │ parent: CKReference(recordID: CKRecord.ID(2:modelAs/external.zone/external.owner)), │
+ │ share: nil, │
+ │ id: 1, │
+ │ isOn: 1, │
+ │ modelAID: 2 │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 1 │
+ │ ) │
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "modelCs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "1:modelCs", │
+ │ parentRecordPrimaryKey: "1", │
+ │ parentRecordType: "modelBs", │
+ │ parentRecordName: "1:modelBs", │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelCs/external.zone/external.owner), │
+ │ recordType: "modelCs", │
+ │ parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)), │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelCs/external.zone/external.owner), │
+ │ recordType: "modelCs", │
+ │ parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)), │
+ │ share: nil, │
+ │ id: 1, │
+ │ modelBID: 1, │
+ │ title: "Blob" │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 0 │
+ │ ) │
└──────────────────────────────────────────────────────────────────────────────────────────────┘
"""
}
@@ -1185,15 +1368,6 @@
share: nil,
count: 42,
id: 1
- ),
- [1]: CKRecord(
- recordID: CKRecord.ID(1:modelBs/zone/__defaultOwner__),
- recordType: "modelBs",
- parent: CKReference(recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__)),
- share: nil,
- id: 1,
- isOn: 1,
- modelAID: 1
)
]
),
@@ -1213,6 +1387,1121 @@
share: CKReference(recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner)),
count: 1729,
id: 2
+ ),
+ [2]: CKRecord(
+ recordID: CKRecord.ID(1:modelBs/external.zone/external.owner),
+ recordType: "modelBs",
+ parent: CKReference(recordID: CKRecord.ID(2:modelAs/external.zone/external.owner)),
+ share: nil,
+ id: 1,
+ isOn: 1,
+ modelAID: 2
+ ),
+ [3]: CKRecord(
+ recordID: CKRecord.ID(1:modelCs/external.zone/external.owner),
+ recordType: "modelCs",
+ parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)),
+ share: nil,
+ id: 1,
+ modelBID: 1,
+ title: "Blob"
+ )
+ ]
+ )
+ )
+ """
+ }
+ }
+
+ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
+ @Test func movesChildRecordFromPrivateParentToSharedParent_ReceiveDeleteBeforeSave()
+ async throws
+ {
+ try await userDatabase.userWrite { db in
+ try db.seed {
+ ModelA.Draft(id: 1, count: 42)
+ ModelB.Draft(id: 1, isOn: true, modelAID: 1)
+ ModelC.Draft(id: 1, title: "Blob", modelBID: 1)
+ }
+ }
+ try await syncEngine.processPendingRecordZoneChanges(scope: .private)
+
+ let externalZone = CKRecordZone(
+ zoneID: CKRecordZone.ID(
+ zoneName: "external.zone",
+ ownerName: "external.owner"
+ )
+ )
+ try await syncEngine.modifyRecordZones(scope: .shared, saving: [externalZone]).notify()
+
+ let modelARecord = CKRecord(
+ recordType: ModelA.tableName,
+ recordID: ModelA.recordID(for: 2, zoneID: externalZone.zoneID)
+ )
+ modelARecord.setValue(2, forKey: "id", at: now)
+ modelARecord.setValue(1729, forKey: "count", at: now)
+ let share = CKShare(
+ rootRecord: modelARecord,
+ shareID: CKRecord.ID(
+ recordName: "share-\(modelARecord.recordID.recordName)",
+ zoneID: modelARecord.recordID.zoneID
+ )
+ )
+ _ = try syncEngine.modifyRecords(scope: .shared, saving: [share, modelARecord])
+ let freshShare = try syncEngine.shared.database.record(for: share.recordID) as! CKShare
+ let freshModelARecord = try syncEngine.shared.database.record(for: modelARecord.recordID)
+
+ try await syncEngine
+ .acceptShare(
+ metadata: ShareMetadata(
+ containerIdentifier: container.containerIdentifier!,
+ hierarchicalRootRecordID: freshModelARecord.recordID,
+ rootRecord: freshModelARecord,
+ share: freshShare
+ )
+ )
+
+ let movedModelBRecord = CKRecord(
+ recordType: ModelB.tableName,
+ recordID: ModelB.recordID(for: 1, zoneID: externalZone.zoneID)
+ )
+ movedModelBRecord.setValue(1, forKey: "id", at: now)
+ movedModelBRecord.setValue(true, forKey: "isOn", at: now)
+ movedModelBRecord.setValue(2, forKey: "modelAID", at: now)
+ movedModelBRecord.parent = CKRecord.Reference(
+ recordID: ModelA.recordID(for: 2, zoneID: externalZone.zoneID),
+ action: .none
+ )
+ let movedModelCRecord = CKRecord(
+ recordType: ModelC.tableName,
+ recordID: ModelC.recordID(for: 1, zoneID: externalZone.zoneID)
+ )
+ movedModelCRecord.setValue(1, forKey: "id", at: now)
+ movedModelCRecord.setValue("Blob", forKey: "title", at: now)
+ movedModelCRecord.setValue(1, forKey: "modelBID", at: now)
+ movedModelCRecord.parent = CKRecord.Reference(
+ recordID: ModelB.recordID(for: 1, zoneID: externalZone.zoneID),
+ action: .none
+ )
+
+ try await syncEngine.modifyRecords(
+ scope: .private,
+ deleting: [ModelB.recordID(for: 1), ModelC.recordID(for: 1)]
+ ).notify()
+ try await syncEngine.modifyRecords(
+ scope: .shared,
+ saving: [movedModelBRecord, movedModelCRecord]
+ ).notify()
+
+ assertQuery(ModelB.all, database: userDatabase.database) {
+ """
+ ┌───────────────┐
+ │ ModelB( │
+ │ id: 1, │
+ │ isOn: true, │
+ │ modelAID: 2 │
+ │ ) │
+ └───────────────┘
+ """
+ }
+ assertQuery(ModelC.all, database: userDatabase.database) {
+ """
+ ┌──────────────────┐
+ │ ModelC( │
+ │ id: 1, │
+ │ title: "Blob", │
+ │ modelBID: 1 │
+ │ ) │
+ └──────────────────┘
+ """
+ }
+ assertQuery(
+ SyncMetadata.order { ($0.recordType, $0.recordName) },
+ database: syncEngine.metadatabase
+ ) {
+ """
+ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "modelAs", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
+ │ recordName: "1:modelAs", │
+ │ parentRecordPrimaryKey: nil, │
+ │ parentRecordType: nil, │
+ │ parentRecordName: nil, │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: nil, │
+ │ count: 42, │
+ │ id: 1 │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 0 │
+ │ ) │
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "2", │
+ │ recordType: "modelAs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "2:modelAs", │
+ │ parentRecordPrimaryKey: nil, │
+ │ parentRecordType: nil, │
+ │ parentRecordName: nil, │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(2:modelAs/external.zone/external.owner), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: CKReference(recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner)) │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(2:modelAs/external.zone/external.owner), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: CKReference(recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner)), │
+ │ count: 1729, │
+ │ id: 2 │
+ │ ), │
+ │ share: CKRecord( │
+ │ recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner), │
+ │ recordType: "cloudkit.share", │
+ │ parent: nil, │
+ │ share: nil │
+ │ ), │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: true, │
+ │ userModificationTime: 0 │
+ │ ) │
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "modelBs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "1:modelBs", │
+ │ parentRecordPrimaryKey: "2", │
+ │ parentRecordType: "modelAs", │
+ │ parentRecordName: "2:modelAs", │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelBs/external.zone/external.owner), │
+ │ recordType: "modelBs", │
+ │ parent: CKReference(recordID: CKRecord.ID(2:modelAs/external.zone/external.owner)), │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelBs/external.zone/external.owner), │
+ │ recordType: "modelBs", │
+ │ parent: CKReference(recordID: CKRecord.ID(2:modelAs/external.zone/external.owner)), │
+ │ share: nil, │
+ │ id: 1, │
+ │ isOn: 1, │
+ │ modelAID: 2 │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 0 │
+ │ ) │
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "modelCs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "1:modelCs", │
+ │ parentRecordPrimaryKey: "1", │
+ │ parentRecordType: "modelBs", │
+ │ parentRecordName: "1:modelBs", │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelCs/external.zone/external.owner), │
+ │ recordType: "modelCs", │
+ │ parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)), │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelCs/external.zone/external.owner), │
+ │ recordType: "modelCs", │
+ │ parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)), │
+ │ share: nil, │
+ │ id: 1, │
+ │ modelBID: 1, │
+ │ title: "Blob" │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 0 │
+ │ ) │
+ └──────────────────────────────────────────────────────────────────────────────────────────────┘
+ """
+ }
+ assertInlineSnapshot(of: container, as: .customDump) {
+ """
+ MockCloudContainer(
+ privateCloudDatabase: MockCloudDatabase(
+ databaseScope: .private,
+ storage: [
+ [0]: CKRecord(
+ recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__),
+ recordType: "modelAs",
+ parent: nil,
+ share: nil,
+ count: 42,
+ id: 1
+ )
+ ]
+ ),
+ sharedCloudDatabase: MockCloudDatabase(
+ databaseScope: .shared,
+ storage: [
+ [0]: CKRecord(
+ recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner),
+ recordType: "cloudkit.share",
+ parent: nil,
+ share: nil
+ ),
+ [1]: CKRecord(
+ recordID: CKRecord.ID(2:modelAs/external.zone/external.owner),
+ recordType: "modelAs",
+ parent: nil,
+ share: CKReference(recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner)),
+ count: 1729,
+ id: 2
+ ),
+ [2]: CKRecord(
+ recordID: CKRecord.ID(1:modelBs/external.zone/external.owner),
+ recordType: "modelBs",
+ parent: CKReference(recordID: CKRecord.ID(2:modelAs/external.zone/external.owner)),
+ share: nil,
+ id: 1,
+ isOn: 1,
+ modelAID: 2
+ ),
+ [3]: CKRecord(
+ recordID: CKRecord.ID(1:modelCs/external.zone/external.owner),
+ recordType: "modelCs",
+ parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)),
+ share: nil,
+ id: 1,
+ modelBID: 1,
+ title: "Blob"
+ )
+ ]
+ )
+ )
+ """
+ }
+ }
+
+ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
+ @Test func movesChildRecordFromPrivateParentToSharedParent_ReceiveSaveBeforeDelete()
+ async throws
+ {
+ try await userDatabase.userWrite { db in
+ try db.seed {
+ ModelA.Draft(id: 1, count: 42)
+ ModelB.Draft(id: 1, isOn: true, modelAID: 1)
+ ModelC.Draft(id: 1, title: "Blob", modelBID: 1)
+ }
+ }
+ try await syncEngine.processPendingRecordZoneChanges(scope: .private)
+
+ let externalZone = CKRecordZone(
+ zoneID: CKRecordZone.ID(
+ zoneName: "external.zone",
+ ownerName: "external.owner"
+ )
+ )
+ try await syncEngine.modifyRecordZones(scope: .shared, saving: [externalZone]).notify()
+
+ let modelARecord = CKRecord(
+ recordType: ModelA.tableName,
+ recordID: ModelA.recordID(for: 2, zoneID: externalZone.zoneID)
+ )
+ modelARecord.setValue(2, forKey: "id", at: now)
+ modelARecord.setValue(1729, forKey: "count", at: now)
+ let share = CKShare(
+ rootRecord: modelARecord,
+ shareID: CKRecord.ID(
+ recordName: "share-\(modelARecord.recordID.recordName)",
+ zoneID: modelARecord.recordID.zoneID
+ )
+ )
+ _ = try syncEngine.modifyRecords(scope: .shared, saving: [share, modelARecord])
+ let freshShare = try syncEngine.shared.database.record(for: share.recordID) as! CKShare
+ let freshModelARecord = try syncEngine.shared.database.record(for: modelARecord.recordID)
+
+ try await syncEngine
+ .acceptShare(
+ metadata: ShareMetadata(
+ containerIdentifier: container.containerIdentifier!,
+ hierarchicalRootRecordID: freshModelARecord.recordID,
+ rootRecord: freshModelARecord,
+ share: freshShare
+ )
+ )
+
+ let movedModelBRecord = CKRecord(
+ recordType: ModelB.tableName,
+ recordID: ModelB.recordID(for: 1, zoneID: externalZone.zoneID)
+ )
+ movedModelBRecord.setValue(1, forKey: "id", at: now)
+ movedModelBRecord.setValue(true, forKey: "isOn", at: now)
+ movedModelBRecord.setValue(2, forKey: "modelAID", at: now)
+ movedModelBRecord.parent = CKRecord.Reference(
+ recordID: ModelA.recordID(for: 2, zoneID: externalZone.zoneID),
+ action: .none
+ )
+ let movedModelCRecord = CKRecord(
+ recordType: ModelC.tableName,
+ recordID: ModelC.recordID(for: 1, zoneID: externalZone.zoneID)
+ )
+ movedModelCRecord.setValue(1, forKey: "id", at: now)
+ movedModelCRecord.setValue("Blob", forKey: "title", at: now)
+ movedModelCRecord.setValue(1, forKey: "modelBID", at: now)
+ movedModelCRecord.parent = CKRecord.Reference(
+ recordID: ModelB.recordID(for: 1, zoneID: externalZone.zoneID),
+ action: .none
+ )
+
+ try await syncEngine.modifyRecords(
+ scope: .shared,
+ saving: [movedModelBRecord, movedModelCRecord]
+ ).notify()
+ try await syncEngine.modifyRecords(
+ scope: .private,
+ deleting: [ModelB.recordID(for: 1), ModelC.recordID(for: 1)]
+ ).notify()
+
+ assertQuery(ModelB.all, database: userDatabase.database) {
+ """
+ ┌───────────────┐
+ │ ModelB( │
+ │ id: 1, │
+ │ isOn: true, │
+ │ modelAID: 2 │
+ │ ) │
+ └───────────────┘
+ """
+ }
+ assertQuery(ModelC.all, database: userDatabase.database) {
+ """
+ ┌──────────────────┐
+ │ ModelC( │
+ │ id: 1, │
+ │ title: "Blob", │
+ │ modelBID: 1 │
+ │ ) │
+ └──────────────────┘
+ """
+ }
+ assertQuery(
+ SyncMetadata.order { ($0.recordType, $0.recordName) },
+ database: syncEngine.metadatabase
+ ) {
+ """
+ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "modelAs", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
+ │ recordName: "1:modelAs", │
+ │ parentRecordPrimaryKey: nil, │
+ │ parentRecordType: nil, │
+ │ parentRecordName: nil, │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: nil, │
+ │ count: 42, │
+ │ id: 1 │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 0 │
+ │ ) │
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "2", │
+ │ recordType: "modelAs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "2:modelAs", │
+ │ parentRecordPrimaryKey: nil, │
+ │ parentRecordType: nil, │
+ │ parentRecordName: nil, │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(2:modelAs/external.zone/external.owner), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: CKReference(recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner)) │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(2:modelAs/external.zone/external.owner), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: CKReference(recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner)), │
+ │ count: 1729, │
+ │ id: 2 │
+ │ ), │
+ │ share: CKRecord( │
+ │ recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner), │
+ │ recordType: "cloudkit.share", │
+ │ parent: nil, │
+ │ share: nil │
+ │ ), │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: true, │
+ │ userModificationTime: 0 │
+ │ ) │
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "modelBs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "1:modelBs", │
+ │ parentRecordPrimaryKey: "2", │
+ │ parentRecordType: "modelAs", │
+ │ parentRecordName: "2:modelAs", │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelBs/external.zone/external.owner), │
+ │ recordType: "modelBs", │
+ │ parent: CKReference(recordID: CKRecord.ID(2:modelAs/external.zone/external.owner)), │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelBs/external.zone/external.owner), │
+ │ recordType: "modelBs", │
+ │ parent: CKReference(recordID: CKRecord.ID(2:modelAs/external.zone/external.owner)), │
+ │ share: nil, │
+ │ id: 1, │
+ │ isOn: 1, │
+ │ modelAID: 2 │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 0 │
+ │ ) │
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "modelCs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "1:modelCs", │
+ │ parentRecordPrimaryKey: "1", │
+ │ parentRecordType: "modelBs", │
+ │ parentRecordName: "1:modelBs", │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelCs/external.zone/external.owner), │
+ │ recordType: "modelCs", │
+ │ parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)), │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelCs/external.zone/external.owner), │
+ │ recordType: "modelCs", │
+ │ parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)), │
+ │ share: nil, │
+ │ id: 1, │
+ │ modelBID: 1, │
+ │ title: "Blob" │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 0 │
+ │ ) │
+ └──────────────────────────────────────────────────────────────────────────────────────────────┘
+ """
+ }
+ assertInlineSnapshot(of: container, as: .customDump) {
+ """
+ MockCloudContainer(
+ privateCloudDatabase: MockCloudDatabase(
+ databaseScope: .private,
+ storage: [
+ [0]: CKRecord(
+ recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__),
+ recordType: "modelAs",
+ parent: nil,
+ share: nil,
+ count: 42,
+ id: 1
+ )
+ ]
+ ),
+ sharedCloudDatabase: MockCloudDatabase(
+ databaseScope: .shared,
+ storage: [
+ [0]: CKRecord(
+ recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner),
+ recordType: "cloudkit.share",
+ parent: nil,
+ share: nil
+ ),
+ [1]: CKRecord(
+ recordID: CKRecord.ID(2:modelAs/external.zone/external.owner),
+ recordType: "modelAs",
+ parent: nil,
+ share: CKReference(recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner)),
+ count: 1729,
+ id: 2
+ ),
+ [2]: CKRecord(
+ recordID: CKRecord.ID(1:modelBs/external.zone/external.owner),
+ recordType: "modelBs",
+ parent: CKReference(recordID: CKRecord.ID(2:modelAs/external.zone/external.owner)),
+ share: nil,
+ id: 1,
+ isOn: 1,
+ modelAID: 2
+ ),
+ [3]: CKRecord(
+ recordID: CKRecord.ID(1:modelCs/external.zone/external.owner),
+ recordType: "modelCs",
+ parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)),
+ share: nil,
+ id: 1,
+ modelBID: 1,
+ title: "Blob"
+ )
+ ]
+ )
+ )
+ """
+ }
+ }
+
+ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
+ @Test func movesChildRecordFromSharedParentToPrivateParent() async throws {
+ try await userDatabase.userWrite { db in
+ try db.seed {
+ ModelA.Draft(id: 1, count: 42)
+ }
+ }
+ try await syncEngine.processPendingRecordZoneChanges(scope: .private)
+
+ let externalZone = CKRecordZone(
+ zoneID: CKRecordZone.ID(
+ zoneName: "external.zone",
+ ownerName: "external.owner"
+ )
+ )
+ try await syncEngine.modifyRecordZones(scope: .shared, saving: [externalZone]).notify()
+
+ let modelARecord = CKRecord(
+ recordType: ModelA.tableName,
+ recordID: ModelA.recordID(for: 2, zoneID: externalZone.zoneID)
+ )
+ modelARecord.setValue(2, forKey: "id", at: now)
+ modelARecord.setValue(1729, forKey: "count", at: now)
+ let share = CKShare(
+ rootRecord: modelARecord,
+ shareID: CKRecord.ID(
+ recordName: "share-\(modelARecord.recordID.recordName)",
+ zoneID: modelARecord.recordID.zoneID
+ )
+ )
+ let modelBRecord = CKRecord(
+ recordType: ModelB.tableName,
+ recordID: ModelB.recordID(for: 1, zoneID: externalZone.zoneID)
+ )
+ modelBRecord.setValue(1, forKey: "id", at: now)
+ modelBRecord.setValue(true, forKey: "isOne", at: now)
+ modelBRecord.setValue(1, forKey: "modelAID", at: now)
+ modelBRecord.parent = CKRecord.Reference(record: modelARecord, action: .none)
+
+ _ =
+ try syncEngine
+ .modifyRecords(scope: .shared, saving: [share, modelARecord, modelBRecord])
+ let freshShare = try syncEngine.shared.database.record(for: share.recordID) as! CKShare
+ let freshModelARecord = try syncEngine.shared.database.record(for: modelARecord.recordID)
+
+ try await syncEngine
+ .acceptShare(
+ metadata: ShareMetadata(
+ containerIdentifier: container.containerIdentifier!,
+ hierarchicalRootRecordID: freshModelARecord.recordID,
+ rootRecord: freshModelARecord,
+ share: freshShare
+ )
+ )
+
+ try await withDependencies {
+ $0.currentTime.now += 1
+ } operation: {
+ try await self.userDatabase.userWrite { db in
+ try ModelB.find(1).update { $0.modelAID = 1 }.execute(db)
+ }
+
+ try await syncEngine.processPendingRecordZoneChanges(scope: .private)
+ try await syncEngine.processPendingRecordZoneChanges(scope: .shared)
+ }
+
+ assertQuery(ModelB.all, database: userDatabase.database) {
+ """
+ ┌────────────────┐
+ │ ModelB( │
+ │ id: 1, │
+ │ isOn: false, │
+ │ modelAID: 1 │
+ │ ) │
+ └────────────────┘
+ """
+ }
+ assertQuery(ModelC.all, database: userDatabase.database)
+ assertQuery(
+ SyncMetadata.order { ($0.recordType, $0.recordName) },
+ database: syncEngine.metadatabase
+ ) {
+ """
+ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "modelAs", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
+ │ recordName: "1:modelAs", │
+ │ parentRecordPrimaryKey: nil, │
+ │ parentRecordType: nil, │
+ │ parentRecordName: nil, │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: nil, │
+ │ count: 42, │
+ │ id: 1 │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 0 │
+ │ ) │
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "2", │
+ │ recordType: "modelAs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "2:modelAs", │
+ │ parentRecordPrimaryKey: nil, │
+ │ parentRecordType: nil, │
+ │ parentRecordName: nil, │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(2:modelAs/external.zone/external.owner), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: CKReference(recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner)) │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(2:modelAs/external.zone/external.owner), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: CKReference(recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner)), │
+ │ count: 1729, │
+ │ id: 2 │
+ │ ), │
+ │ share: CKRecord( │
+ │ recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner), │
+ │ recordType: "cloudkit.share", │
+ │ parent: nil, │
+ │ share: nil │
+ │ ), │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: true, │
+ │ userModificationTime: 0 │
+ │ ) │
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "modelBs", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
+ │ recordName: "1:modelBs", │
+ │ parentRecordPrimaryKey: "1", │
+ │ parentRecordType: "modelAs", │
+ │ parentRecordName: "1:modelAs", │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelBs/zone/__defaultOwner__), │
+ │ recordType: "modelBs", │
+ │ parent: CKReference(recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__)), │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelBs/zone/__defaultOwner__), │
+ │ recordType: "modelBs", │
+ │ parent: CKReference(recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__)), │
+ │ share: nil, │
+ │ id: 1, │
+ │ isOn: 0, │
+ │ modelAID: 1 │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 1 │
+ │ ) │
+ └──────────────────────────────────────────────────────────────────────────────────────────────┘
+ """
+ }
+ assertInlineSnapshot(of: container, as: .customDump) {
+ """
+ MockCloudContainer(
+ privateCloudDatabase: MockCloudDatabase(
+ databaseScope: .private,
+ storage: [
+ [0]: CKRecord(
+ recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__),
+ recordType: "modelAs",
+ parent: nil,
+ share: nil,
+ count: 42,
+ id: 1
+ ),
+ [1]: CKRecord(
+ recordID: CKRecord.ID(1:modelBs/zone/__defaultOwner__),
+ recordType: "modelBs",
+ parent: CKReference(recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__)),
+ share: nil,
+ id: 1,
+ isOn: 0,
+ modelAID: 1
+ )
+ ]
+ ),
+ sharedCloudDatabase: MockCloudDatabase(
+ databaseScope: .shared,
+ storage: [
+ [0]: CKRecord(
+ recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner),
+ recordType: "cloudkit.share",
+ parent: nil,
+ share: nil
+ ),
+ [1]: CKRecord(
+ recordID: CKRecord.ID(2:modelAs/external.zone/external.owner),
+ recordType: "modelAs",
+ parent: nil,
+ share: CKReference(recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner)),
+ count: 1729,
+ id: 2
+ )
+ ]
+ )
+ )
+ """
+ }
+ }
+
+ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
+ @Test
+ func movesChildRecordFromPrivateParentToSharedParentWhileSyncEngineStopped() async throws {
+ try await userDatabase.userWrite { db in
+ try db.seed {
+ ModelA.Draft(id: 1, count: 42)
+ ModelB.Draft(id: 1, isOn: true, modelAID: 1)
+ ModelC.Draft(id: 1, title: "Blob", modelBID: 1)
+ }
+ }
+ try await syncEngine.processPendingRecordZoneChanges(scope: .private)
+
+ let externalZone = CKRecordZone(
+ zoneID: CKRecordZone.ID(
+ zoneName: "external.zone",
+ ownerName: "external.owner"
+ )
+ )
+ try await syncEngine.modifyRecordZones(scope: .shared, saving: [externalZone]).notify()
+
+ let modelARecord = CKRecord(
+ recordType: ModelA.tableName,
+ recordID: ModelA.recordID(for: 2, zoneID: externalZone.zoneID)
+ )
+ modelARecord.setValue(2, forKey: "id", at: now)
+ modelARecord.setValue(1729, forKey: "count", at: now)
+ let share = CKShare(
+ rootRecord: modelARecord,
+ shareID: CKRecord.ID(
+ recordName: "share-\(modelARecord.recordID.recordName)",
+ zoneID: modelARecord.recordID.zoneID
+ )
+ )
+ _ = try syncEngine.modifyRecords(scope: .shared, saving: [share, modelARecord])
+ let freshShare = try syncEngine.shared.database.record(for: share.recordID) as! CKShare
+ let freshModelARecord = try syncEngine.shared.database.record(for: modelARecord.recordID)
+
+ try await syncEngine
+ .acceptShare(
+ metadata: ShareMetadata(
+ containerIdentifier: container.containerIdentifier!,
+ hierarchicalRootRecordID: freshModelARecord.recordID,
+ rootRecord: freshModelARecord,
+ share: freshShare
+ )
+ )
+
+ syncEngine.stop()
+
+ try await withDependencies {
+ $0.currentTime.now += 1
+ } operation: {
+ try await self.userDatabase.userWrite { db in
+ try ModelB.find(1).update { $0.modelAID = 2 }.execute(db)
+ }
+ }
+
+ try await syncEngine.start()
+ try await syncEngine.processPendingRecordZoneChanges(scope: .private)
+ try await syncEngine.processPendingRecordZoneChanges(scope: .shared)
+
+ assertQuery(ModelB.all, database: userDatabase.database) {
+ """
+ ┌───────────────┐
+ │ ModelB( │
+ │ id: 1, │
+ │ isOn: true, │
+ │ modelAID: 2 │
+ │ ) │
+ └───────────────┘
+ """
+ }
+ assertQuery(ModelC.all, database: userDatabase.database) {
+ """
+ ┌──────────────────┐
+ │ ModelC( │
+ │ id: 1, │
+ │ title: "Blob", │
+ │ modelBID: 1 │
+ │ ) │
+ └──────────────────┘
+ """
+ }
+ assertQuery(
+ SyncMetadata.order { ($0.recordType, $0.recordName) },
+ database: syncEngine.metadatabase
+ ) {
+ """
+ ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "modelAs", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
+ │ recordName: "1:modelAs", │
+ │ parentRecordPrimaryKey: nil, │
+ │ parentRecordType: nil, │
+ │ parentRecordName: nil, │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: nil, │
+ │ count: 42, │
+ │ id: 1 │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 0 │
+ │ ) │
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "2", │
+ │ recordType: "modelAs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "2:modelAs", │
+ │ parentRecordPrimaryKey: nil, │
+ │ parentRecordType: nil, │
+ │ parentRecordName: nil, │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(2:modelAs/external.zone/external.owner), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: CKReference(recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner)) │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(2:modelAs/external.zone/external.owner), │
+ │ recordType: "modelAs", │
+ │ parent: nil, │
+ │ share: CKReference(recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner)), │
+ │ count: 1729, │
+ │ id: 2 │
+ │ ), │
+ │ share: CKRecord( │
+ │ recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner), │
+ │ recordType: "cloudkit.share", │
+ │ parent: nil, │
+ │ share: nil │
+ │ ), │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: true, │
+ │ userModificationTime: 0 │
+ │ ) │
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "modelBs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "1:modelBs", │
+ │ parentRecordPrimaryKey: "2", │
+ │ parentRecordType: "modelAs", │
+ │ parentRecordName: "2:modelAs", │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelBs/external.zone/external.owner), │
+ │ recordType: "modelBs", │
+ │ parent: CKReference(recordID: CKRecord.ID(2:modelAs/external.zone/external.owner)), │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelBs/external.zone/external.owner), │
+ │ recordType: "modelBs", │
+ │ parent: CKReference(recordID: CKRecord.ID(2:modelAs/external.zone/external.owner)), │
+ │ share: nil, │
+ │ id: 1, │
+ │ isOn: 1, │
+ │ modelAID: 2 │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 1 │
+ │ ) │
+ ├──────────────────────────────────────────────────────────────────────────────────────────────┤
+ │ SyncMetadata( │
+ │ recordPrimaryKey: "1", │
+ │ recordType: "modelCs", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
+ │ recordName: "1:modelCs", │
+ │ parentRecordPrimaryKey: "1", │
+ │ parentRecordType: "modelBs", │
+ │ parentRecordName: "1:modelBs", │
+ │ lastKnownServerRecord: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelCs/external.zone/external.owner), │
+ │ recordType: "modelCs", │
+ │ parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)), │
+ │ share: nil │
+ │ ), │
+ │ _lastKnownServerRecordAllFields: CKRecord( │
+ │ recordID: CKRecord.ID(1:modelCs/external.zone/external.owner), │
+ │ recordType: "modelCs", │
+ │ parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)), │
+ │ share: nil, │
+ │ id: 1, │
+ │ modelBID: 1, │
+ │ title: "Blob" │
+ │ ), │
+ │ share: nil, │
+ │ _isDeleted: false, │
+ │ hasLastKnownServerRecord: true, │
+ │ isShared: false, │
+ │ userModificationTime: 0 │
+ │ ) │
+ └──────────────────────────────────────────────────────────────────────────────────────────────┘
+ """
+ }
+ assertInlineSnapshot(of: container, as: .customDump) {
+ """
+ MockCloudContainer(
+ privateCloudDatabase: MockCloudDatabase(
+ databaseScope: .private,
+ storage: [
+ [0]: CKRecord(
+ recordID: CKRecord.ID(1:modelAs/zone/__defaultOwner__),
+ recordType: "modelAs",
+ parent: nil,
+ share: nil,
+ count: 42,
+ id: 1
+ )
+ ]
+ ),
+ sharedCloudDatabase: MockCloudDatabase(
+ databaseScope: .shared,
+ storage: [
+ [0]: CKRecord(
+ recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner),
+ recordType: "cloudkit.share",
+ parent: nil,
+ share: nil
+ ),
+ [1]: CKRecord(
+ recordID: CKRecord.ID(2:modelAs/external.zone/external.owner),
+ recordType: "modelAs",
+ parent: nil,
+ share: CKReference(recordID: CKRecord.ID(share-2:modelAs/external.zone/external.owner)),
+ count: 1729,
+ id: 2
+ ),
+ [2]: CKRecord(
+ recordID: CKRecord.ID(1:modelBs/external.zone/external.owner),
+ recordType: "modelBs",
+ parent: CKReference(recordID: CKRecord.ID(2:modelAs/external.zone/external.owner)),
+ share: nil,
+ id: 1,
+ isOn: 1,
+ modelAID: 2
+ ),
+ [3]: CKRecord(
+ recordID: CKRecord.ID(1:modelCs/external.zone/external.owner),
+ recordType: "modelCs",
+ parent: CKReference(recordID: CKRecord.ID(1:modelBs/external.zone/external.owner)),
+ share: nil,
+ id: 1,
+ modelBID: 1,
+ title: "Blob"
)
]
)
diff --git a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift
index 76784d08..3da22697 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift
@@ -37,6 +37,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "remindersLists", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:remindersLists", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -53,6 +55,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "reminders", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:reminders", │
│ parentRecordPrimaryKey: "1", │
│ parentRecordType: "remindersLists", │
@@ -273,6 +277,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "remindersLists", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
│ recordName: "1:remindersLists", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -302,6 +308,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "reminders", │
+ │ zoneName: "external.zone", │
+ │ ownerName: "external.owner", │
│ recordName: "1:reminders", │
│ parentRecordPrimaryKey: "1", │
│ parentRecordType: "remindersLists", │
@@ -490,6 +498,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "remindersLists", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:remindersLists", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -506,6 +516,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "reminders", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:reminders", │
│ parentRecordPrimaryKey: "1", │
│ parentRecordType: "remindersLists", │
@@ -547,6 +559,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "remindersLists", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:remindersLists", │
│ parentRecordPrimaryKey: nil, │
│ parentRecordType: nil, │
@@ -575,6 +589,8 @@
│ SyncMetadata( │
│ recordPrimaryKey: "1", │
│ recordType: "reminders", │
+ │ zoneName: "zone", │
+ │ ownerName: "__defaultOwner__", │
│ recordName: "1:reminders", │
│ parentRecordPrimaryKey: "1", │
│ parentRecordType: "remindersLists", │
diff --git a/Tests/SQLiteDataTests/CloudKitTests/TriggerTests.swift b/Tests/SQLiteDataTests/CloudKitTests/TriggerTests.swift
index d1d4a52d..d7ef5e19 100644
--- a/Tests/SQLiteDataTests/CloudKitTests/TriggerTests.swift
+++ b/Tests/SQLiteDataTests/CloudKitTests/TriggerTests.swift
@@ -19,78 +19,6 @@
#"""
[
[0]: """
- CREATE TRIGGER "after_delete_on_sqlitedata_icloud_metadata"
- AFTER UPDATE OF "_isDeleted" ON "sqlitedata_icloud_metadata"
- FOR EACH ROW WHEN ((NOT ("old"."_isDeleted") AND "new"."_isDeleted") AND NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"())) BEGIN
- SELECT "sqlitedata_icloud_didDelete"("new"."recordName", coalesce("new"."lastKnownServerRecord", (
- WITH "ancestorMetadatas" AS (
- SELECT "sqlitedata_icloud_metadata"."recordName" AS "recordName", "sqlitedata_icloud_metadata"."parentRecordName" AS "parentRecordName", "sqlitedata_icloud_metadata"."lastKnownServerRecord" AS "lastKnownServerRecord"
- FROM "sqlitedata_icloud_metadata"
- WHERE ("sqlitedata_icloud_metadata"."recordName" = "new"."recordName")
- UNION ALL
- SELECT "sqlitedata_icloud_metadata"."recordName" AS "recordName", "sqlitedata_icloud_metadata"."parentRecordName" AS "parentRecordName", "sqlitedata_icloud_metadata"."lastKnownServerRecord" AS "lastKnownServerRecord"
- FROM "sqlitedata_icloud_metadata"
- JOIN "ancestorMetadatas" ON ("sqlitedata_icloud_metadata"."recordName" IS "ancestorMetadatas"."parentRecordName")
- )
- SELECT "ancestorMetadatas"."lastKnownServerRecord"
- FROM "ancestorMetadatas"
- WHERE ("ancestorMetadatas"."parentRecordName" IS NULL)
- )), "new"."share");
- END
- """,
- [1]: """
- CREATE TRIGGER "after_insert_on_sqlitedata_icloud_metadata"
- AFTER INSERT ON "sqlitedata_icloud_metadata"
- FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
- SELECT RAISE(ABORT, 'co.pointfree.SQLiteData.CloudKit.invalid-record-name-error')
- WHERE NOT (((substr("new"."recordName", 1, 1) <> '_') AND (octet_length("new"."recordName") <= 255)) AND (octet_length("new"."recordName") = length("new"."recordName")));
- SELECT "sqlitedata_icloud_didUpdate"("new"."recordName", coalesce("new"."lastKnownServerRecord", (
- WITH "ancestorMetadatas" AS (
- SELECT "sqlitedata_icloud_metadata"."recordName" AS "recordName", "sqlitedata_icloud_metadata"."parentRecordName" AS "parentRecordName", "sqlitedata_icloud_metadata"."lastKnownServerRecord" AS "lastKnownServerRecord"
- FROM "sqlitedata_icloud_metadata"
- WHERE ("sqlitedata_icloud_metadata"."recordName" = "new"."recordName")
- UNION ALL
- SELECT "sqlitedata_icloud_metadata"."recordName" AS "recordName", "sqlitedata_icloud_metadata"."parentRecordName" AS "parentRecordName", "sqlitedata_icloud_metadata"."lastKnownServerRecord" AS "lastKnownServerRecord"
- FROM "sqlitedata_icloud_metadata"
- JOIN "ancestorMetadatas" ON ("sqlitedata_icloud_metadata"."recordName" IS "ancestorMetadatas"."parentRecordName")
- )
- SELECT "ancestorMetadatas"."lastKnownServerRecord"
- FROM "ancestorMetadatas"
- WHERE ("ancestorMetadatas"."parentRecordName" IS NULL)
- )), (
- SELECT "sqlitedata_icloud_metadata"."lastKnownServerRecord"
- FROM "sqlitedata_icloud_metadata"
- WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" IS "new"."parentRecordPrimaryKey") AND ("sqlitedata_icloud_metadata"."recordType" IS "new"."parentRecordType"))
- ), "new"."parentRecordPrimaryKey", "new"."parentRecordType");
- END
- """,
- [2]: """
- CREATE TRIGGER "after_update_on_sqlitedata_icloud_metadata"
- AFTER UPDATE ON "sqlitedata_icloud_metadata"
- FOR EACH ROW WHEN (("old"."_isDeleted" = "new"."_isDeleted") AND NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"())) BEGIN
- SELECT RAISE(ABORT, 'co.pointfree.SQLiteData.CloudKit.invalid-record-name-error')
- WHERE NOT (((substr("new"."recordName", 1, 1) <> '_') AND (octet_length("new"."recordName") <= 255)) AND (octet_length("new"."recordName") = length("new"."recordName")));
- SELECT "sqlitedata_icloud_didUpdate"("new"."recordName", coalesce("new"."lastKnownServerRecord", (
- WITH "ancestorMetadatas" AS (
- SELECT "sqlitedata_icloud_metadata"."recordName" AS "recordName", "sqlitedata_icloud_metadata"."parentRecordName" AS "parentRecordName", "sqlitedata_icloud_metadata"."lastKnownServerRecord" AS "lastKnownServerRecord"
- FROM "sqlitedata_icloud_metadata"
- WHERE ("sqlitedata_icloud_metadata"."recordName" = "new"."recordName")
- UNION ALL
- SELECT "sqlitedata_icloud_metadata"."recordName" AS "recordName", "sqlitedata_icloud_metadata"."parentRecordName" AS "parentRecordName", "sqlitedata_icloud_metadata"."lastKnownServerRecord" AS "lastKnownServerRecord"
- FROM "sqlitedata_icloud_metadata"
- JOIN "ancestorMetadatas" ON ("sqlitedata_icloud_metadata"."recordName" IS "ancestorMetadatas"."parentRecordName")
- )
- SELECT "ancestorMetadatas"."lastKnownServerRecord"
- FROM "ancestorMetadatas"
- WHERE ("ancestorMetadatas"."parentRecordName" IS NULL)
- )), (
- SELECT "sqlitedata_icloud_metadata"."lastKnownServerRecord"
- FROM "sqlitedata_icloud_metadata"
- WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" IS "new"."parentRecordPrimaryKey") AND ("sqlitedata_icloud_metadata"."recordType" IS "new"."parentRecordType"))
- ), "new"."parentRecordPrimaryKey", "new"."parentRecordType");
- END
- """,
- [3]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_childWithOnDeleteSetDefaults_from_sync_engine"
AFTER DELETE ON "childWithOnDeleteSetDefaults"
FOR EACH ROW WHEN "sqlitedata_icloud_syncEngineIsSynchronizingChanges"() BEGIN
@@ -98,7 +26,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'childWithOnDeleteSetDefaults'));
END
""",
- [4]: """
+ [1]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_childWithOnDeleteSetDefaults_from_user"
AFTER DELETE ON "childWithOnDeleteSetDefaults"
FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
@@ -119,7 +47,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'childWithOnDeleteSetDefaults'));
END
""",
- [5]: """
+ [2]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_childWithOnDeleteSetNulls_from_sync_engine"
AFTER DELETE ON "childWithOnDeleteSetNulls"
FOR EACH ROW WHEN "sqlitedata_icloud_syncEngineIsSynchronizingChanges"() BEGIN
@@ -127,7 +55,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'childWithOnDeleteSetNulls'));
END
""",
- [6]: """
+ [3]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_childWithOnDeleteSetNulls_from_user"
AFTER DELETE ON "childWithOnDeleteSetNulls"
FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
@@ -148,7 +76,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'childWithOnDeleteSetNulls'));
END
""",
- [7]: """
+ [4]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_modelAs_from_sync_engine"
AFTER DELETE ON "modelAs"
FOR EACH ROW WHEN "sqlitedata_icloud_syncEngineIsSynchronizingChanges"() BEGIN
@@ -156,7 +84,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelAs'));
END
""",
- [8]: """
+ [5]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_modelAs_from_user"
AFTER DELETE ON "modelAs"
FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
@@ -177,7 +105,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelAs'));
END
""",
- [9]: """
+ [6]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_modelBs_from_sync_engine"
AFTER DELETE ON "modelBs"
FOR EACH ROW WHEN "sqlitedata_icloud_syncEngineIsSynchronizingChanges"() BEGIN
@@ -185,7 +113,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelBs'));
END
""",
- [10]: """
+ [7]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_modelBs_from_user"
AFTER DELETE ON "modelBs"
FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
@@ -206,7 +134,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelBs'));
END
""",
- [11]: """
+ [8]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_modelCs_from_sync_engine"
AFTER DELETE ON "modelCs"
FOR EACH ROW WHEN "sqlitedata_icloud_syncEngineIsSynchronizingChanges"() BEGIN
@@ -214,7 +142,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelCs'));
END
""",
- [12]: """
+ [9]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_modelCs_from_user"
AFTER DELETE ON "modelCs"
FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
@@ -235,7 +163,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelCs'));
END
""",
- [13]: """
+ [10]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_parents_from_sync_engine"
AFTER DELETE ON "parents"
FOR EACH ROW WHEN "sqlitedata_icloud_syncEngineIsSynchronizingChanges"() BEGIN
@@ -243,7 +171,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents'));
END
""",
- [14]: """
+ [11]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_parents_from_user"
AFTER DELETE ON "parents"
FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
@@ -264,7 +192,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents'));
END
""",
- [15]: """
+ [12]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_reminderTags_from_sync_engine"
AFTER DELETE ON "reminderTags"
FOR EACH ROW WHEN "sqlitedata_icloud_syncEngineIsSynchronizingChanges"() BEGIN
@@ -272,7 +200,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'reminderTags'));
END
""",
- [16]: """
+ [13]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_reminderTags_from_user"
AFTER DELETE ON "reminderTags"
FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
@@ -293,7 +221,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'reminderTags'));
END
""",
- [17]: """
+ [14]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_remindersListAssets_from_sync_engine"
AFTER DELETE ON "remindersListAssets"
FOR EACH ROW WHEN "sqlitedata_icloud_syncEngineIsSynchronizingChanges"() BEGIN
@@ -301,7 +229,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersListAssets'));
END
""",
- [18]: """
+ [15]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_remindersListAssets_from_user"
AFTER DELETE ON "remindersListAssets"
FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
@@ -322,7 +250,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersListAssets'));
END
""",
- [19]: """
+ [16]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_remindersListPrivates_from_sync_engine"
AFTER DELETE ON "remindersListPrivates"
FOR EACH ROW WHEN "sqlitedata_icloud_syncEngineIsSynchronizingChanges"() BEGIN
@@ -330,7 +258,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersListPrivates'));
END
""",
- [20]: """
+ [17]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_remindersListPrivates_from_user"
AFTER DELETE ON "remindersListPrivates"
FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
@@ -351,7 +279,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersListPrivates'));
END
""",
- [21]: """
+ [18]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_remindersLists_from_sync_engine"
AFTER DELETE ON "remindersLists"
FOR EACH ROW WHEN "sqlitedata_icloud_syncEngineIsSynchronizingChanges"() BEGIN
@@ -359,7 +287,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists'));
END
""",
- [22]: """
+ [19]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_remindersLists_from_user"
AFTER DELETE ON "remindersLists"
FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
@@ -380,7 +308,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists'));
END
""",
- [23]: """
+ [20]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_reminders_from_sync_engine"
AFTER DELETE ON "reminders"
FOR EACH ROW WHEN "sqlitedata_icloud_syncEngineIsSynchronizingChanges"() BEGIN
@@ -388,7 +316,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'reminders'));
END
""",
- [24]: """
+ [21]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_reminders_from_user"
AFTER DELETE ON "reminders"
FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
@@ -409,7 +337,27 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'reminders'));
END
""",
- [25]: """
+ [22]: """
+ CREATE TRIGGER "sqlitedata_icloud_after_delete_on_sqlitedata_icloud_metadata"
+ AFTER UPDATE OF "_isDeleted" ON "sqlitedata_icloud_metadata"
+ FOR EACH ROW WHEN ((NOT ("old"."_isDeleted") AND "new"."_isDeleted") AND NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"())) BEGIN
+ SELECT "sqlitedata_icloud_didDelete"("new"."recordName", coalesce("new"."lastKnownServerRecord", (
+ WITH "ancestorMetadatas" AS (
+ SELECT "sqlitedata_icloud_metadata"."recordName" AS "recordName", "sqlitedata_icloud_metadata"."parentRecordName" AS "parentRecordName", "sqlitedata_icloud_metadata"."lastKnownServerRecord" AS "lastKnownServerRecord"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE ("sqlitedata_icloud_metadata"."recordName" = "new"."recordName")
+ UNION ALL
+ SELECT "sqlitedata_icloud_metadata"."recordName" AS "recordName", "sqlitedata_icloud_metadata"."parentRecordName" AS "parentRecordName", "sqlitedata_icloud_metadata"."lastKnownServerRecord" AS "lastKnownServerRecord"
+ FROM "sqlitedata_icloud_metadata"
+ JOIN "ancestorMetadatas" ON ("sqlitedata_icloud_metadata"."recordName" IS "ancestorMetadatas"."parentRecordName")
+ )
+ SELECT "ancestorMetadatas"."lastKnownServerRecord"
+ FROM "ancestorMetadatas"
+ WHERE ("ancestorMetadatas"."parentRecordName" IS NULL)
+ )), "new"."share");
+ END
+ """,
+ [23]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_tags_from_sync_engine"
AFTER DELETE ON "tags"
FOR EACH ROW WHEN "sqlitedata_icloud_syncEngineIsSynchronizingChanges"() BEGIN
@@ -417,7 +365,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."title") AND ("sqlitedata_icloud_metadata"."recordType" = 'tags'));
END
""",
- [26]: """
+ [24]: """
CREATE TRIGGER "sqlitedata_icloud_after_delete_on_tags_from_user"
AFTER DELETE ON "tags"
FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
@@ -438,7 +386,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."title") AND ("sqlitedata_icloud_metadata"."recordType" = 'tags'));
END
""",
- [27]: """
+ [25]: """
CREATE TRIGGER "sqlitedata_icloud_after_insert_on_childWithOnDeleteSetDefaults"
AFTER INSERT ON "childWithOnDeleteSetDefaults"
FOR EACH ROW BEGIN
@@ -455,13 +403,16 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'childWithOnDeleteSetDefaults', "new"."parentID", 'parents'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'childWithOnDeleteSetDefaults', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."parentID") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."parentID") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents')))), '__defaultOwner__'), "new"."parentID", 'parents'
+ ON CONFLICT DO NOTHING;
END
""",
- [28]: """
+ [26]: """
CREATE TRIGGER "sqlitedata_icloud_after_insert_on_childWithOnDeleteSetNulls"
AFTER INSERT ON "childWithOnDeleteSetNulls"
FOR EACH ROW BEGIN
@@ -478,13 +429,16 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'childWithOnDeleteSetNulls', "new"."parentID", 'parents'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'childWithOnDeleteSetNulls', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."parentID") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."parentID") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents')))), '__defaultOwner__'), "new"."parentID", 'parents'
+ ON CONFLICT DO NOTHING;
END
""",
- [29]: """
+ [27]: """
CREATE TRIGGER "sqlitedata_icloud_after_insert_on_modelAs"
AFTER INSERT ON "modelAs"
FOR EACH ROW BEGIN
@@ -501,13 +455,12 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'modelAs', NULL, NULL
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'modelAs', coalesce("sqlitedata_icloud_currentZoneName"(), 'zone'), coalesce("sqlitedata_icloud_currentOwnerName"(), '__defaultOwner__'), NULL, NULL
+ ON CONFLICT DO NOTHING;
END
""",
- [30]: """
+ [28]: """
CREATE TRIGGER "sqlitedata_icloud_after_insert_on_modelBs"
AFTER INSERT ON "modelBs"
FOR EACH ROW BEGIN
@@ -524,13 +477,16 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'modelBs', "new"."modelAID", 'modelAs'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'modelBs', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."modelAID") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelAs')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."modelAID") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelAs')))), '__defaultOwner__'), "new"."modelAID", 'modelAs'
+ ON CONFLICT DO NOTHING;
END
""",
- [31]: """
+ [29]: """
CREATE TRIGGER "sqlitedata_icloud_after_insert_on_modelCs"
AFTER INSERT ON "modelCs"
FOR EACH ROW BEGIN
@@ -547,13 +503,16 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'modelCs', "new"."modelBID", 'modelBs'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'modelCs', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."modelBID") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelBs')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."modelBID") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelBs')))), '__defaultOwner__'), "new"."modelBID", 'modelBs'
+ ON CONFLICT DO NOTHING;
END
""",
- [32]: """
+ [30]: """
CREATE TRIGGER "sqlitedata_icloud_after_insert_on_parents"
AFTER INSERT ON "parents"
FOR EACH ROW BEGIN
@@ -570,13 +529,12 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'parents', NULL, NULL
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'parents', coalesce("sqlitedata_icloud_currentZoneName"(), 'zone'), coalesce("sqlitedata_icloud_currentOwnerName"(), '__defaultOwner__'), NULL, NULL
+ ON CONFLICT DO NOTHING;
END
""",
- [33]: """
+ [31]: """
CREATE TRIGGER "sqlitedata_icloud_after_insert_on_reminderTags"
AFTER INSERT ON "reminderTags"
FOR EACH ROW BEGIN
@@ -593,13 +551,12 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'reminderTags', NULL, NULL
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'reminderTags', coalesce("sqlitedata_icloud_currentZoneName"(), 'zone'), coalesce("sqlitedata_icloud_currentOwnerName"(), '__defaultOwner__'), NULL, NULL
+ ON CONFLICT DO NOTHING;
END
""",
- [34]: """
+ [32]: """
CREATE TRIGGER "sqlitedata_icloud_after_insert_on_reminders"
AFTER INSERT ON "reminders"
FOR EACH ROW BEGIN
@@ -616,13 +573,16 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'reminders', "new"."remindersListID", 'remindersLists'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'reminders', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), '__defaultOwner__'), "new"."remindersListID", 'remindersLists'
+ ON CONFLICT DO NOTHING;
END
""",
- [35]: """
+ [33]: """
CREATE TRIGGER "sqlitedata_icloud_after_insert_on_remindersListAssets"
AFTER INSERT ON "remindersListAssets"
FOR EACH ROW BEGIN
@@ -639,13 +599,16 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'remindersListAssets', "new"."remindersListID", 'remindersLists'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'remindersListAssets', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), '__defaultOwner__'), "new"."remindersListID", 'remindersLists'
+ ON CONFLICT DO NOTHING;
END
""",
- [36]: """
+ [34]: """
CREATE TRIGGER "sqlitedata_icloud_after_insert_on_remindersListPrivates"
AFTER INSERT ON "remindersListPrivates"
FOR EACH ROW BEGIN
@@ -662,13 +625,16 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'remindersListPrivates', "new"."remindersListID", 'remindersLists'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'remindersListPrivates', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), '__defaultOwner__'), "new"."remindersListID", 'remindersLists'
+ ON CONFLICT DO NOTHING;
END
""",
- [37]: """
+ [35]: """
CREATE TRIGGER "sqlitedata_icloud_after_insert_on_remindersLists"
AFTER INSERT ON "remindersLists"
FOR EACH ROW BEGIN
@@ -685,13 +651,21 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'remindersLists', NULL, NULL
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'remindersLists', coalesce("sqlitedata_icloud_currentZoneName"(), 'zone'), coalesce("sqlitedata_icloud_currentOwnerName"(), '__defaultOwner__'), NULL, NULL
+ ON CONFLICT DO NOTHING;
END
""",
- [38]: """
+ [36]: """
+ CREATE TRIGGER "sqlitedata_icloud_after_insert_on_sqlitedata_icloud_metadata"
+ AFTER INSERT ON "sqlitedata_icloud_metadata"
+ FOR EACH ROW WHEN NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) BEGIN
+ SELECT RAISE(ABORT, 'co.pointfree.SQLiteData.CloudKit.invalid-record-name-error')
+ WHERE NOT (((substr("new"."recordName", 1, 1) <> '_') AND (octet_length("new"."recordName") <= 255)) AND (octet_length("new"."recordName") = length("new"."recordName")));
+ SELECT "sqlitedata_icloud_didUpdate"("new"."recordName", "new"."zoneName", "new"."ownerName", "new"."zoneName", "new"."ownerName", NULL);
+ END
+ """,
+ [37]: """
CREATE TRIGGER "sqlitedata_icloud_after_insert_on_tags"
AFTER INSERT ON "tags"
FOR EACH ROW BEGIN
@@ -708,13 +682,12 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."title", 'tags', NULL, NULL
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."title", 'tags', coalesce("sqlitedata_icloud_currentZoneName"(), 'zone'), coalesce("sqlitedata_icloud_currentOwnerName"(), '__defaultOwner__'), NULL, NULL
+ ON CONFLICT DO NOTHING;
END
""",
- [39]: """
+ [38]: """
CREATE TRIGGER "sqlitedata_icloud_after_primary_key_change_on_childWithOnDeleteSetDefaults"
AFTER UPDATE OF "id" ON "childWithOnDeleteSetDefaults"
FOR EACH ROW WHEN ("old"."id" <> "new"."id") BEGIN
@@ -735,7 +708,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'childWithOnDeleteSetDefaults'));
END
""",
- [40]: """
+ [39]: """
CREATE TRIGGER "sqlitedata_icloud_after_primary_key_change_on_childWithOnDeleteSetNulls"
AFTER UPDATE OF "id" ON "childWithOnDeleteSetNulls"
FOR EACH ROW WHEN ("old"."id" <> "new"."id") BEGIN
@@ -756,7 +729,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'childWithOnDeleteSetNulls'));
END
""",
- [41]: """
+ [40]: """
CREATE TRIGGER "sqlitedata_icloud_after_primary_key_change_on_modelAs"
AFTER UPDATE OF "id" ON "modelAs"
FOR EACH ROW WHEN ("old"."id" <> "new"."id") BEGIN
@@ -777,7 +750,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelAs'));
END
""",
- [42]: """
+ [41]: """
CREATE TRIGGER "sqlitedata_icloud_after_primary_key_change_on_modelBs"
AFTER UPDATE OF "id" ON "modelBs"
FOR EACH ROW WHEN ("old"."id" <> "new"."id") BEGIN
@@ -798,7 +771,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelBs'));
END
""",
- [43]: """
+ [42]: """
CREATE TRIGGER "sqlitedata_icloud_after_primary_key_change_on_modelCs"
AFTER UPDATE OF "id" ON "modelCs"
FOR EACH ROW WHEN ("old"."id" <> "new"."id") BEGIN
@@ -819,7 +792,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelCs'));
END
""",
- [44]: """
+ [43]: """
CREATE TRIGGER "sqlitedata_icloud_after_primary_key_change_on_parents"
AFTER UPDATE OF "id" ON "parents"
FOR EACH ROW WHEN ("old"."id" <> "new"."id") BEGIN
@@ -840,7 +813,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents'));
END
""",
- [45]: """
+ [44]: """
CREATE TRIGGER "sqlitedata_icloud_after_primary_key_change_on_reminderTags"
AFTER UPDATE OF "id" ON "reminderTags"
FOR EACH ROW WHEN ("old"."id" <> "new"."id") BEGIN
@@ -861,7 +834,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'reminderTags'));
END
""",
- [46]: """
+ [45]: """
CREATE TRIGGER "sqlitedata_icloud_after_primary_key_change_on_reminders"
AFTER UPDATE OF "id" ON "reminders"
FOR EACH ROW WHEN ("old"."id" <> "new"."id") BEGIN
@@ -882,7 +855,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'reminders'));
END
""",
- [47]: """
+ [46]: """
CREATE TRIGGER "sqlitedata_icloud_after_primary_key_change_on_remindersListAssets"
AFTER UPDATE OF "id" ON "remindersListAssets"
FOR EACH ROW WHEN ("old"."id" <> "new"."id") BEGIN
@@ -903,7 +876,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersListAssets'));
END
""",
- [48]: """
+ [47]: """
CREATE TRIGGER "sqlitedata_icloud_after_primary_key_change_on_remindersListPrivates"
AFTER UPDATE OF "id" ON "remindersListPrivates"
FOR EACH ROW WHEN ("old"."id" <> "new"."id") BEGIN
@@ -924,7 +897,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersListPrivates'));
END
""",
- [49]: """
+ [48]: """
CREATE TRIGGER "sqlitedata_icloud_after_primary_key_change_on_remindersLists"
AFTER UPDATE OF "id" ON "remindersLists"
FOR EACH ROW WHEN ("old"."id" <> "new"."id") BEGIN
@@ -945,7 +918,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists'));
END
""",
- [50]: """
+ [49]: """
CREATE TRIGGER "sqlitedata_icloud_after_primary_key_change_on_tags"
AFTER UPDATE OF "title" ON "tags"
FOR EACH ROW WHEN ("old"."title" <> "new"."title") BEGIN
@@ -966,7 +939,7 @@
WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "old"."title") AND ("sqlitedata_icloud_metadata"."recordType" = 'tags'));
END
""",
- [51]: """
+ [50]: """
CREATE TRIGGER "sqlitedata_icloud_after_update_on_childWithOnDeleteSetDefaults"
AFTER UPDATE ON "childWithOnDeleteSetDefaults"
FOR EACH ROW BEGIN
@@ -983,13 +956,23 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'childWithOnDeleteSetDefaults', "new"."parentID", 'parents'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'childWithOnDeleteSetDefaults', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."parentID") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."parentID") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents')))), '__defaultOwner__'), "new"."parentID", 'parents'
+ ON CONFLICT DO NOTHING;
+ UPDATE "sqlitedata_icloud_metadata"
+ SET "zoneName" = coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."parentID") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents')))), "sqlitedata_icloud_metadata"."zoneName"), "ownerName" = coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."parentID") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents')))), "sqlitedata_icloud_metadata"."ownerName"), "parentRecordPrimaryKey" = "new"."parentID", "parentRecordType" = 'parents', "userModificationTime" = "sqlitedata_icloud_currentTime"()
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'childWithOnDeleteSetDefaults'));
END
""",
- [52]: """
+ [51]: """
CREATE TRIGGER "sqlitedata_icloud_after_update_on_childWithOnDeleteSetNulls"
AFTER UPDATE ON "childWithOnDeleteSetNulls"
FOR EACH ROW BEGIN
@@ -1006,13 +989,23 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'childWithOnDeleteSetNulls', "new"."parentID", 'parents'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'childWithOnDeleteSetNulls', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."parentID") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."parentID") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents')))), '__defaultOwner__'), "new"."parentID", 'parents'
+ ON CONFLICT DO NOTHING;
+ UPDATE "sqlitedata_icloud_metadata"
+ SET "zoneName" = coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."parentID") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents')))), "sqlitedata_icloud_metadata"."zoneName"), "ownerName" = coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."parentID") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents')))), "sqlitedata_icloud_metadata"."ownerName"), "parentRecordPrimaryKey" = "new"."parentID", "parentRecordType" = 'parents', "userModificationTime" = "sqlitedata_icloud_currentTime"()
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'childWithOnDeleteSetNulls'));
END
""",
- [53]: """
+ [52]: """
CREATE TRIGGER "sqlitedata_icloud_after_update_on_modelAs"
AFTER UPDATE ON "modelAs"
FOR EACH ROW BEGIN
@@ -1029,13 +1022,15 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'modelAs', NULL, NULL
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'modelAs', coalesce("sqlitedata_icloud_currentZoneName"(), 'zone'), coalesce("sqlitedata_icloud_currentOwnerName"(), '__defaultOwner__'), NULL, NULL
+ ON CONFLICT DO NOTHING;
+ UPDATE "sqlitedata_icloud_metadata"
+ SET "zoneName" = coalesce("sqlitedata_icloud_currentZoneName"(), "sqlitedata_icloud_metadata"."zoneName"), "ownerName" = coalesce("sqlitedata_icloud_currentOwnerName"(), "sqlitedata_icloud_metadata"."ownerName"), "parentRecordPrimaryKey" = NULL, "parentRecordType" = NULL, "userModificationTime" = "sqlitedata_icloud_currentTime"()
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelAs'));
END
""",
- [54]: """
+ [53]: """
CREATE TRIGGER "sqlitedata_icloud_after_update_on_modelBs"
AFTER UPDATE ON "modelBs"
FOR EACH ROW BEGIN
@@ -1052,13 +1047,23 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'modelBs', "new"."modelAID", 'modelAs'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'modelBs', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."modelAID") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelAs')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."modelAID") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelAs')))), '__defaultOwner__'), "new"."modelAID", 'modelAs'
+ ON CONFLICT DO NOTHING;
+ UPDATE "sqlitedata_icloud_metadata"
+ SET "zoneName" = coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."modelAID") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelAs')))), "sqlitedata_icloud_metadata"."zoneName"), "ownerName" = coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."modelAID") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelAs')))), "sqlitedata_icloud_metadata"."ownerName"), "parentRecordPrimaryKey" = "new"."modelAID", "parentRecordType" = 'modelAs', "userModificationTime" = "sqlitedata_icloud_currentTime"()
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelBs'));
END
""",
- [55]: """
+ [54]: """
CREATE TRIGGER "sqlitedata_icloud_after_update_on_modelCs"
AFTER UPDATE ON "modelCs"
FOR EACH ROW BEGIN
@@ -1075,13 +1080,23 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'modelCs', "new"."modelBID", 'modelBs'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'modelCs', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."modelBID") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelBs')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."modelBID") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelBs')))), '__defaultOwner__'), "new"."modelBID", 'modelBs'
+ ON CONFLICT DO NOTHING;
+ UPDATE "sqlitedata_icloud_metadata"
+ SET "zoneName" = coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."modelBID") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelBs')))), "sqlitedata_icloud_metadata"."zoneName"), "ownerName" = coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."modelBID") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelBs')))), "sqlitedata_icloud_metadata"."ownerName"), "parentRecordPrimaryKey" = "new"."modelBID", "parentRecordType" = 'modelBs', "userModificationTime" = "sqlitedata_icloud_currentTime"()
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'modelCs'));
END
""",
- [56]: """
+ [55]: """
CREATE TRIGGER "sqlitedata_icloud_after_update_on_parents"
AFTER UPDATE ON "parents"
FOR EACH ROW BEGIN
@@ -1098,13 +1113,15 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'parents', NULL, NULL
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'parents', coalesce("sqlitedata_icloud_currentZoneName"(), 'zone'), coalesce("sqlitedata_icloud_currentOwnerName"(), '__defaultOwner__'), NULL, NULL
+ ON CONFLICT DO NOTHING;
+ UPDATE "sqlitedata_icloud_metadata"
+ SET "zoneName" = coalesce("sqlitedata_icloud_currentZoneName"(), "sqlitedata_icloud_metadata"."zoneName"), "ownerName" = coalesce("sqlitedata_icloud_currentOwnerName"(), "sqlitedata_icloud_metadata"."ownerName"), "parentRecordPrimaryKey" = NULL, "parentRecordType" = NULL, "userModificationTime" = "sqlitedata_icloud_currentTime"()
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'parents'));
END
""",
- [57]: """
+ [56]: """
CREATE TRIGGER "sqlitedata_icloud_after_update_on_reminderTags"
AFTER UPDATE ON "reminderTags"
FOR EACH ROW BEGIN
@@ -1121,13 +1138,15 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'reminderTags', NULL, NULL
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'reminderTags', coalesce("sqlitedata_icloud_currentZoneName"(), 'zone'), coalesce("sqlitedata_icloud_currentOwnerName"(), '__defaultOwner__'), NULL, NULL
+ ON CONFLICT DO NOTHING;
+ UPDATE "sqlitedata_icloud_metadata"
+ SET "zoneName" = coalesce("sqlitedata_icloud_currentZoneName"(), "sqlitedata_icloud_metadata"."zoneName"), "ownerName" = coalesce("sqlitedata_icloud_currentOwnerName"(), "sqlitedata_icloud_metadata"."ownerName"), "parentRecordPrimaryKey" = NULL, "parentRecordType" = NULL, "userModificationTime" = "sqlitedata_icloud_currentTime"()
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'reminderTags'));
END
""",
- [58]: """
+ [57]: """
CREATE TRIGGER "sqlitedata_icloud_after_update_on_reminders"
AFTER UPDATE ON "reminders"
FOR EACH ROW BEGIN
@@ -1144,13 +1163,23 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'reminders', "new"."remindersListID", 'remindersLists'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'reminders', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), '__defaultOwner__'), "new"."remindersListID", 'remindersLists'
+ ON CONFLICT DO NOTHING;
+ UPDATE "sqlitedata_icloud_metadata"
+ SET "zoneName" = coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), "sqlitedata_icloud_metadata"."zoneName"), "ownerName" = coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), "sqlitedata_icloud_metadata"."ownerName"), "parentRecordPrimaryKey" = "new"."remindersListID", "parentRecordType" = 'remindersLists', "userModificationTime" = "sqlitedata_icloud_currentTime"()
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'reminders'));
END
""",
- [59]: """
+ [58]: """
CREATE TRIGGER "sqlitedata_icloud_after_update_on_remindersListAssets"
AFTER UPDATE ON "remindersListAssets"
FOR EACH ROW BEGIN
@@ -1167,13 +1196,23 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'remindersListAssets', "new"."remindersListID", 'remindersLists'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'remindersListAssets', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), '__defaultOwner__'), "new"."remindersListID", 'remindersLists'
+ ON CONFLICT DO NOTHING;
+ UPDATE "sqlitedata_icloud_metadata"
+ SET "zoneName" = coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), "sqlitedata_icloud_metadata"."zoneName"), "ownerName" = coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), "sqlitedata_icloud_metadata"."ownerName"), "parentRecordPrimaryKey" = "new"."remindersListID", "parentRecordType" = 'remindersLists', "userModificationTime" = "sqlitedata_icloud_currentTime"()
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersListAssets'));
END
""",
- [60]: """
+ [59]: """
CREATE TRIGGER "sqlitedata_icloud_after_update_on_remindersListPrivates"
AFTER UPDATE ON "remindersListPrivates"
FOR EACH ROW BEGIN
@@ -1190,13 +1229,23 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'remindersListPrivates', "new"."remindersListID", 'remindersLists'
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'remindersListPrivates', coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), 'zone'), coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), '__defaultOwner__'), "new"."remindersListID", 'remindersLists'
+ ON CONFLICT DO NOTHING;
+ UPDATE "sqlitedata_icloud_metadata"
+ SET "zoneName" = coalesce(coalesce("sqlitedata_icloud_currentZoneName"(), (SELECT "sqlitedata_icloud_metadata"."zoneName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), "sqlitedata_icloud_metadata"."zoneName"), "ownerName" = coalesce(coalesce("sqlitedata_icloud_currentOwnerName"(), (SELECT "sqlitedata_icloud_metadata"."ownerName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."remindersListID") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists')))), "sqlitedata_icloud_metadata"."ownerName"), "parentRecordPrimaryKey" = "new"."remindersListID", "parentRecordType" = 'remindersLists', "userModificationTime" = "sqlitedata_icloud_currentTime"()
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersListPrivates'));
END
""",
- [61]: """
+ [60]: """
CREATE TRIGGER "sqlitedata_icloud_after_update_on_remindersLists"
AFTER UPDATE ON "remindersLists"
FOR EACH ROW BEGIN
@@ -1213,10 +1262,34 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."id", 'remindersLists', NULL, NULL
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."id", 'remindersLists', coalesce("sqlitedata_icloud_currentZoneName"(), 'zone'), coalesce("sqlitedata_icloud_currentOwnerName"(), '__defaultOwner__'), NULL, NULL
+ ON CONFLICT DO NOTHING;
+ UPDATE "sqlitedata_icloud_metadata"
+ SET "zoneName" = coalesce("sqlitedata_icloud_currentZoneName"(), "sqlitedata_icloud_metadata"."zoneName"), "ownerName" = coalesce("sqlitedata_icloud_currentOwnerName"(), "sqlitedata_icloud_metadata"."ownerName"), "parentRecordPrimaryKey" = NULL, "parentRecordType" = NULL, "userModificationTime" = "sqlitedata_icloud_currentTime"()
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."id") AND ("sqlitedata_icloud_metadata"."recordType" = 'remindersLists'));
+ END
+ """,
+ [61]: """
+ CREATE TRIGGER "sqlitedata_icloud_after_update_on_sqlitedata_icloud_metadata"
+ AFTER UPDATE ON "sqlitedata_icloud_metadata"
+ FOR EACH ROW WHEN (("old"."_isDeleted" = "new"."_isDeleted") AND NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"())) BEGIN
+ SELECT RAISE(ABORT, 'co.pointfree.SQLiteData.CloudKit.invalid-record-name-error')
+ WHERE NOT (((substr("new"."recordName", 1, 1) <> '_') AND (octet_length("new"."recordName") <= 255)) AND (octet_length("new"."recordName") = length("new"."recordName")));
+ SELECT "sqlitedata_icloud_didUpdate"("new"."recordName", "new"."zoneName", "new"."ownerName", "old"."zoneName", "old"."ownerName", CASE WHEN (("new"."zoneName" <> "old"."zoneName") OR ("new"."ownerName" <> "old"."ownerName")) THEN (
+ WITH "descendantMetadatas" AS (
+ SELECT "sqlitedata_icloud_metadata"."recordName" AS "recordName", NULL AS "parentRecordName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE ("sqlitedata_icloud_metadata"."recordName" = "new"."recordName")
+ UNION ALL
+ SELECT "sqlitedata_icloud_metadata"."recordName" AS "recordName", "sqlitedata_icloud_metadata"."parentRecordName" AS "parentRecordName"
+ FROM "sqlitedata_icloud_metadata"
+ JOIN "descendantMetadatas" ON ("sqlitedata_icloud_metadata"."parentRecordName" = "descendantMetadatas"."recordName")
+ )
+ SELECT json_group_array("descendantMetadatas"."recordName")
+ FROM "descendantMetadatas"
+ WHERE ("descendantMetadatas"."recordName" <> "new"."recordName")
+ ) END);
END
""",
[62]: """
@@ -1236,10 +1309,31 @@
FROM "rootShares"
WHERE ((NOT ("sqlitedata_icloud_syncEngineIsSynchronizingChanges"()) AND ("rootShares"."parentRecordName" IS NULL)) AND NOT ("sqlitedata_icloud_hasPermission"("rootShares"."share")));
INSERT INTO "sqlitedata_icloud_metadata"
- ("recordPrimaryKey", "recordType", "parentRecordPrimaryKey", "parentRecordType")
- SELECT "new"."title", 'tags', NULL, NULL
- ON CONFLICT ("recordPrimaryKey", "recordType")
- DO UPDATE SET "parentRecordPrimaryKey" = "excluded"."parentRecordPrimaryKey", "parentRecordType" = "excluded"."parentRecordType", "userModificationTime" = "excluded"."userModificationTime";
+ ("recordPrimaryKey", "recordType", "zoneName", "ownerName", "parentRecordPrimaryKey", "parentRecordType")
+ SELECT "new"."title", 'tags', coalesce("sqlitedata_icloud_currentZoneName"(), 'zone'), coalesce("sqlitedata_icloud_currentOwnerName"(), '__defaultOwner__'), NULL, NULL
+ ON CONFLICT DO NOTHING;
+ UPDATE "sqlitedata_icloud_metadata"
+ SET "zoneName" = coalesce("sqlitedata_icloud_currentZoneName"(), "sqlitedata_icloud_metadata"."zoneName"), "ownerName" = coalesce("sqlitedata_icloud_currentOwnerName"(), "sqlitedata_icloud_metadata"."ownerName"), "parentRecordPrimaryKey" = NULL, "parentRecordType" = NULL, "userModificationTime" = "sqlitedata_icloud_currentTime"()
+ WHERE (("sqlitedata_icloud_metadata"."recordPrimaryKey" = "new"."title") AND ("sqlitedata_icloud_metadata"."recordType" = 'tags'));
+ END
+ """,
+ [63]: """
+ CREATE TRIGGER "sqlitedata_icloud_after_zone_update_on_sqlitedata_icloud_metadata"
+ AFTER UPDATE OF "zoneName", "ownerName" ON "sqlitedata_icloud_metadata"
+ FOR EACH ROW WHEN (("new"."zoneName" <> "old"."zoneName") OR ("new"."ownerName" <> "old"."ownerName")) BEGIN
+ UPDATE "sqlitedata_icloud_metadata"
+ SET "zoneName" = "new"."zoneName", "ownerName" = "new"."ownerName", "lastKnownServerRecord" = NULL, "_lastKnownServerRecordAllFields" = NULL
+ WHERE ("sqlitedata_icloud_metadata"."recordName" IN (WITH "descendantMetadatas" AS (
+ SELECT "sqlitedata_icloud_metadata"."recordName" AS "recordName", NULL AS "parentRecordName"
+ FROM "sqlitedata_icloud_metadata"
+ WHERE ("sqlitedata_icloud_metadata"."recordName" = "new"."recordName")
+ UNION ALL
+ SELECT "sqlitedata_icloud_metadata"."recordName" AS "recordName", "sqlitedata_icloud_metadata"."parentRecordName" AS "parentRecordName"
+ FROM "sqlitedata_icloud_metadata"
+ JOIN "descendantMetadatas" ON ("sqlitedata_icloud_metadata"."parentRecordName" = "descendantMetadatas"."recordName")
+ )
+ SELECT "descendantMetadatas"."recordName"
+ FROM "descendantMetadatas"));
END
"""
]
diff --git a/Tests/SQLiteDataTests/Internal/BaseCloudKitTests.swift b/Tests/SQLiteDataTests/Internal/BaseCloudKitTests.swift
index 5e34de4e..ba37e57b 100644
--- a/Tests/SQLiteDataTests/Internal/BaseCloudKitTests.swift
+++ b/Tests/SQLiteDataTests/Internal/BaseCloudKitTests.swift
@@ -7,7 +7,7 @@ import Testing
import os
@Suite(
- .snapshots(record: .missing),
+ .snapshots(record: .failed),
.dependencies {
$0.currentTime.now = 0
$0.dataManager = InMemoryDataManager()
diff --git a/Tests/SQLiteDataTests/Internal/PrintTimestampsScope.swift b/Tests/SQLiteDataTests/Internal/PrintTimestampsScope.swift
index f300124c..067815c6 100644
--- a/Tests/SQLiteDataTests/Internal/PrintTimestampsScope.swift
+++ b/Tests/SQLiteDataTests/Internal/PrintTimestampsScope.swift
@@ -20,9 +20,9 @@
}
extension Trait where Self == _PrintTimestampsScope {
- static var printTimestamps: Self { .init() }
+ static var printTimestamps: Self { Self() }
static func printTimestamps(_ printTimestamps: Bool) -> Self {
- .init(printTimestamps)
+ Self(printTimestamps)
}
}
#endif
diff --git a/Tests/SQLiteDataTests/Internal/Schema.swift b/Tests/SQLiteDataTests/Internal/Schema.swift
index 92614e21..3d11f0a7 100644
--- a/Tests/SQLiteDataTests/Internal/Schema.swift
+++ b/Tests/SQLiteDataTests/Internal/Schema.swift
@@ -82,6 +82,9 @@ func database(
if attachMetadatabase {
try db.attachMetadatabase(containerIdentifier: containerIdentifier)
}
+ // db.trace {
+ // print($0.expandedDescription)
+ // }
}
let url = URL.temporaryDirectory.appending(path: "\(UUID().uuidString).sqlite")
let database = try DatabasePool(path: url.path(), configuration: configuration)
diff --git a/Tests/SQLiteDataTests/Internal/TestScopes.swift b/Tests/SQLiteDataTests/Internal/TestScopes.swift
index 42ab482d..3608458b 100644
--- a/Tests/SQLiteDataTests/Internal/TestScopes.swift
+++ b/Tests/SQLiteDataTests/Internal/TestScopes.swift
@@ -25,7 +25,7 @@
static func prepareDatabase(
_ prepareDatabase: @escaping @Sendable (UserDatabase) async throws -> Void
) -> Self {
- .init(prepareDatabase: prepareDatabase)
+ Self(prepareDatabase: prepareDatabase)
}
}
@@ -48,7 +48,7 @@
extension Trait where Self == _StartImmediatelyTrait {
static func startImmediately(_ startImmediately: Bool) -> Self {
- .init(startImmediately: startImmediately)
+ Self(startImmediately: startImmediately)
}
}
@@ -70,9 +70,9 @@
}
extension Trait where Self == _AttachMetadatabaseTrait {
- static var attachMetadatabase: Self { .init(attachMetadatabase: true) }
+ static var attachMetadatabase: Self { Self(attachMetadatabase: true) }
static func attachMetadatabase(_ attachMetadatabase: Bool) -> Self {
- .init(attachMetadatabase: attachMetadatabase)
+ Self(attachMetadatabase: attachMetadatabase)
}
}
@@ -96,9 +96,9 @@
}
extension Trait where Self == _AccountStatusScope {
- static var accountStatus: Self { .init() }
+ static var accountStatus: Self { Self() }
static func accountStatus(_ accountStatus: CKAccountStatus) -> Self {
- .init(accountStatus)
+ Self(accountStatus)
}
}
#endif