-
-
Save krodak/b47ea81b3ae25ca2f10c27476bed450c to your computer and use it in GitHub Desktop.
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) | |
} | |
} |
In new Realm version just remove : class
after protocol declaration (Realm object is struct now).
LinkingObjectsBase
not found in Realm 4.x.x
Fixed for Realm 4 and removed the need to specify types for the properties as long as all objects have a primaryKey()
.
https://gist.github.com/samrayner/44d34fdc77e7d8d766fd467d557753a9
Hello,
Since Realm 10.8.0, RealmSwift.ListBase or RLMListBase are not reachable anymore. Does anyone have an idea how to replace them ?
Thank you very much for your help.
I think the following code should be used, but I am yet to see it in production
internal protocol CascadingDeletable: RealmSwift.Object {
static var propertiesToCascadeDelete: [String] { get }
}
extension Realm {
internal func cascadingDelete(_ object: RealmSwift.Object) {
var toBeDeleted: Set<RLMObjectBase> = [object]
while let element = toBeDeleted.popFirst() as? RealmSwift.Object {
guard !element.isInvalidated else { continue }
if let cascadingDeletable = element as? CascadingDeletable {
cascade(into: cascadingDeletable, toBeDeleted: &toBeDeleted)
}
delete(element)
}
}
private func cascade(into object: CascadingDeletable, toBeDeleted: inout Set<RLMObjectBase>) {
let objectType = type(of: object)
guard let schema = objectType.sharedSchema() else { return }
let primaryKey = objectType.primaryKey()
let primaryKeyValue = primaryKey.flatMap(object.value(forKey:))
let properties = (schema.properties + schema.computedProperties)
.filter { objectType.propertiesToCascadeDelete.contains($0.name) }
for property in properties {
switch object.value(forKey: property.name) {
case let realmObject as RLMObjectBase:
toBeDeleted.insert(realmObject)
case let list as RLMSwiftCollectionBase:
for index in 0 ..< list._rlmCollection.count {
guard let realmObject = list._rlmCollection.object(at: index) as? RLMObjectBase else { continue }
toBeDeleted.insert(realmObject)
}
default: // LinkingObjects
if let linkOriginPropertyName = property.linkOriginPropertyName,
let linkOriginTypeName = property.objectClassName,
let primaryKey = primaryKey,
let primaryKeyValue = primaryKeyValue {
dynamicObjects(linkOriginTypeName)
.filter("%K == %@", "\(linkOriginPropertyName).\(primaryKey)", primaryKeyValue)
.forEach { toBeDeleted.insert($0) }
}
}
}
}
}
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)
}
}
@cpd, thanks for letting us know! I didn't know the cascading delete was implemented. Thanks!
@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.
Can you give an example on how to use this in objective c?