mirror of
https://github.com/CharlesWiltgen/Axiom.git
synced 2026-09-20 19:58:20 +08:00
fix(axiom-data): stop to-one cascades from deleting parents and siblings
Track.album carried deleteRule: .cascade while Album.tracks cascades too, so deleting one track deleted its album and, through it, every sibling track. The NoteTag junction example in swiftdata-migration.md cascaded both of its to-one sides the same way, and never compiled: Note and Tag had no initializer. Drop the cascade from the to-one sides (the default .nullify applies), declare the junction's inverses, and add the missing initializers. Verified: deleting one of two tracks now leaves 1 album and 1 track (was 0 and 0); removing one tag from a note keeps every note and tag (was all deleted). The edited blocks compile against the iOS 27.1 SDK.
This commit is contained in:
@@ -420,10 +420,12 @@ final class NoteTag {
|
||||
@Attribute(.unique) var id: String
|
||||
var addedAt: Date // Metadata on relationship
|
||||
|
||||
@Relationship(deleteRule: .cascade)
|
||||
// No cascade on the junction's own sides: removing one tag from one note
|
||||
// would delete that note and that tag, and their cascades would take the rest
|
||||
@Relationship(inverse: \Note.noteTags)
|
||||
var note: Note?
|
||||
|
||||
@Relationship(deleteRule: .cascade)
|
||||
@Relationship(inverse: \Tag.noteTags)
|
||||
var tag: Tag?
|
||||
|
||||
init(id: String, note: Note, tag: Tag, addedAt: Date) {
|
||||
@@ -445,6 +447,11 @@ final class Note {
|
||||
var tags: [Tag] {
|
||||
noteTags.compactMap { $0.tag }
|
||||
}
|
||||
|
||||
init(id: String, title: String) {
|
||||
self.id = id
|
||||
self.title = title
|
||||
}
|
||||
}
|
||||
|
||||
@Model
|
||||
@@ -458,6 +465,11 @@ final class Tag {
|
||||
var notes: [Note] {
|
||||
noteTags.compactMap { $0.note }
|
||||
}
|
||||
|
||||
init(id: String, name: String) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -121,7 +121,9 @@ final class Track {
|
||||
@Attribute(.unique) var id: String
|
||||
var title: String
|
||||
|
||||
@Relationship(deleteRule: .cascade, inverse: \Album.tracks)
|
||||
// No cascade on this side: deleting one track would delete its album,
|
||||
// and Album.tracks' cascade would then delete every sibling track
|
||||
@Relationship(inverse: \Album.tracks)
|
||||
var album: Album?
|
||||
|
||||
init(id: String, title: String, album: Album? = nil) {
|
||||
@@ -805,7 +807,7 @@ Run the sweep on a background context (not the main one), keyed by the natural I
|
||||
```swift
|
||||
@Model
|
||||
final class Track {
|
||||
@Relationship(deleteRule: .cascade, inverse: \Album.tracks)
|
||||
@Relationship(inverse: \Album.tracks)
|
||||
var album: Album? // ✅ Must be optional for CloudKit
|
||||
|
||||
init(album: Album? = nil) {
|
||||
@@ -887,7 +889,6 @@ let container = try ModelContainer(for: schema, configurations: testConfig)
|
||||
@Model
|
||||
final class Track {
|
||||
@Relationship(
|
||||
deleteRule: .cascade,
|
||||
minimumModelCount: 0,
|
||||
maximumModelCount: 1, // Track belongs to at most one album
|
||||
inverse: \Album.tracks
|
||||
|
||||
Reference in New Issue
Block a user