Skip to content

Instantly share code, notes, and snippets.

@krodak
Last active April 27, 2023 19:16
Show Gist options
  • Save krodak/b47ea81b3ae25ca2f10c27476bed450c to your computer and use it in GitHub Desktop.
Save krodak/b47ea81b3ae25ca2f10c27476bed450c to your computer and use it in GitHub Desktop.
Cascade deletion for RealmSwift
import RealmSwift
import Realm
protocol CascadeDeleting: class {
func delete<Entity>(_ list: List<Entity>, cascading: Bool)
func delete<Entity>(_ results: Results<Entity>, cascading: Bool)
func delete<Entity: Object>(_ entity: Entity, cascading: Bool)
}
extension Realm: CascadeDeleting {
func delete<Entity>(_ list: List<Entity>, cascading: Bool) {
list.forEach {
delete($0, cascading: cascading)
}
}
func delete<Entity>(_ results: Results<Entity>, cascading: Bool) {
results.forEach {
delete($0, cascading: cascading)
}
}
func delete<Entity: Object>(_ entity: Entity, cascading: Bool) {
if cascading {
cascadeDelete(entity)
} else {
delete(entity)
}
}
}
private extension Realm {
private func cascadeDelete(_ entity: RLMObjectBase) {
guard let entity = entity as? Object else { return }
var toBeDeleted = Set<RLMObjectBase>()
toBeDeleted.insert(entity)
while !toBeDeleted.isEmpty {
guard let element = toBeDeleted.removeFirst() as? Object,
!element.isInvalidated else { continue }
resolve(element: element, toBeDeleted: &toBeDeleted)
}
}
private func resolve(element: Object, toBeDeleted: inout Set<RLMObjectBase>) {
element.objectSchema.properties.forEach {
guard let value = element.value(forKey: $0.name) else { return }
if let entity = value as? RLMObjectBase {
toBeDeleted.insert(entity)
} else if let list = value as? RealmSwift.ListBase {
for index in 0..<list._rlmArray.count {
toBeDeleted.insert(list._rlmArray.object(at: index))
}
}
}
delete(element)
}
}
@cpd
Copy link

cpd commented Aug 5, 2021

Updated code to use RLMSwiftCollectionBase instead of RealmSwift.ListBase which looks fine at first glance but using this hack with latest release seems pretty dangerous, since Realm 10.0 theres a built in cascade delete https://www.mongodb.com/developer/article/realm-database-cascading-deletes/#cascading-deletes probably better to stick with it although I didn't tried that yet.

extension Realm {
    func delete<S: Sequence>(_ objects: S, cascading: Bool) where S.Iterator.Element: Object {
        for obj in objects {
            delete(obj, cascading: cascading)
        }
    }
    
    func delete<Entity: Object>(_ entity: Entity, cascading: Bool) {
        if cascading {
            cascadeDelete(entity)
        } else {
            delete(entity)
        }
    }
}

private extension Realm {
    private func cascadeDelete(_ entity: RLMObjectBase) {
        guard let entity = entity as? Object else { return }
        
        var toBeDeleted = Set<RLMObjectBase>()
        
        toBeDeleted.insert(entity)
        
        while !toBeDeleted.isEmpty {
            guard let element = toBeDeleted.removeFirst() as? Object, !element.isInvalidated else { continue }
            
            resolve(element: element, toBeDeleted: &toBeDeleted)
        }
    }
    
    private func resolve(element: Object, toBeDeleted: inout Set<RLMObjectBase>) {
        element.objectSchema.properties.forEach {
            guard let value = element.value(forKey: $0.name) else { return }
            
            if let entity = value as? RLMObjectBase {
                toBeDeleted.insert(entity)
            } else if let list = value as? RLMSwiftCollectionBase {
                for index in 0..<list._rlmCollection.count {
                    if let object = list._rlmCollection.object(at: index) as? RLMObjectBase {
                        toBeDeleted.insert(object)
                    }
                }
            }
        }
        
        delete(element)
    }
}

@iSevenDays
Copy link

@cpd, thanks for letting us know! I didn't know the cascading delete was implemented. Thanks!

@lif-wtag
Copy link

@cpd, Thanks a lot mate!
I was having trouble with Resolve function as RealmSwift.ListBase is no longer supported in RealmSwift v10.17.0.
Your code with RLMSwiftCollectionBase helped me, Thanks again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment