I'm facing a strange behaviour with NSBatchInsertRequest and I don't seems to understand what is causing my problem.
I have some piece of code that updates local data depending on some remote data changes.
The model that is being updated contains a boolean shared indicating if the item is shared or not. Updating this model seems to work correctly when the boolean goes from false to true but when trying to update the data with the reverse action the new local data doesn't seem to be persisted and I end up having the shared variable always returning true even is the content of the NSBatchInsertRequest has it set as false.
Following are the different parts of my logic and my managed object description.
Helper functions
func newTaskContext(type: TaskContextType,
transactionAuthor: String = #function) -> NSManagedObjectContext {
let taskContext = container.newBackgroundContext()
taskContext.name = type.rawValue
taskContext.transactionAuthor = transactionAuthor
taskContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
taskContext.undoManager = nil
return taskContext
}
func newBatchInsertRequest<T>(entity: NSEntityDescription,
sourceItems: [T],
hydrateBlock: @escaping (NSManagedObject, T) -> Void)
-> NSBatchInsertRequest {
var index = 0
let request = NSBatchInsertRequest(entity: entity,
managedObjectHandler: { object in
guard index < sourceItems.count else { return true }
let item = sourceItems[index]
hydrateBlock(object, item)
index += 1
return false
})
return request
}
extension ShareEntity {
func hydrate(from symmetricallyEncryptedShare: SymmetricallyEncryptedShare, userId: String) {
let share = symmetricallyEncryptedShare.share
content = share.content
contentFormatVersion = share.contentFormatVersion ?? -1
contentKeyRotation = share.contentKeyRotation ?? -1
createTime = share.createTime
expireTime = share.expireTime ?? -1
owner = share.owner
permission = share.permission
primary = share.primary
shareID = share.shareID
symmetricallyEncryptedContent = symmetricallyEncryptedShare.encryptedContent
targetID = share.targetID
targetType = share.targetType
vaultID = share.vaultID
addressID = share.addressID
userID = userId
shareRoleID = share.shareRoleID
targetMembers = share.targetMembers
shared = share.shared
}
}
func execute(batchInsertRequest request: NSBatchInsertRequest,
context: NSManagedObjectContext) async throws {
try await context.perform {
guard context.hasPersistentStore else { return }
let fetchResult = try context.execute(request)
if let result = fetchResult as? NSBatchInsertResult,
let success = result.result as? Bool, success {
return
} else {
throw error
}
}
}
Main local data updating entry point
func upsertShares(_ shares: [SymmetricallyEncryptedShare], userId: String) async throws {
let taskContext = newTaskContext(type: .insert)
let batchInsertRequest =
newBatchInsertRequest(entity: ShareEntity.entity(context: taskContext),
sourceItems: shares) { managedObject, share in
(managedObject as? ShareEntity)?.hydrate(from: share, userId: userId)
}
try await execute(batchInsertRequest: batchInsertRequest, context: taskContext)
}
I don't understand why the update of ShareEntity work one way but cannot be updated back to containing the variable shared as false.
Any tips or advice would be welcome on this issue.
