Skip to content

Commit e8861de

Browse files
committed
Add atomic batch operations
3.0-preview
1 parent 597f68a commit e8861de

1 file changed

Lines changed: 87 additions & 0 deletions

File tree

Sources/CoreDataRepository/CoreDataRepository+Batch.swift

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,28 @@ extension CoreDataRepository {
6767
return (success: successes, failed: failures)
6868
}
6969

70+
/// Create a batch of unmanaged models.
71+
public func createAtomiclly<Model: UnmanagedModel>(
72+
_ items: [Model],
73+
transactionAuthor: String? = nil
74+
) async -> Result<[Model], CoreDataError> {
75+
await context.performInScratchPad(schedule: .enqueued) { [context] scratchPad in
76+
let objects = try items.map { item in
77+
let object = Model.ManagedModel(context: scratchPad)
78+
try item.updating(managed: object)
79+
return object
80+
}
81+
try scratchPad.save()
82+
try context.performAndWait {
83+
context.transactionAuthor = transactionAuthor
84+
try context.save()
85+
context.transactionAuthor = nil
86+
}
87+
try scratchPad.obtainPermanentIDs(for: objects)
88+
return try objects.map(Model.init(managed:))
89+
}
90+
}
91+
7092
/// Read a batch of unmanaged models.
7193
///
7294
/// This operation is non-atomic. Each instance may succeed or fail individually.
@@ -107,6 +129,21 @@ extension CoreDataRepository {
107129
return (success: successes, failed: failures)
108130
}
109131

132+
/// Read a batch of unmanaged models.
133+
public func readAtomically<Model: UnmanagedModel>(
134+
_ urls: [URL],
135+
of _: Model.Type
136+
) async -> Result<[Model], CoreDataError> {
137+
await context.performInChild(schedule: .enqueued) { readContext in
138+
try urls.map { url in
139+
let id = try readContext.objectId(from: url).get()
140+
let object = try readContext.notDeletedObject(for: id)
141+
let managed: Model.ManagedModel = try object.asManagedModel()
142+
return try Model(managed: managed)
143+
}
144+
}
145+
}
146+
110147
/// Execute a NSBatchUpdateRequest against the store.
111148
public func update(
112149
_ request: NSBatchUpdateRequest,
@@ -123,6 +160,33 @@ extension CoreDataRepository {
123160
}
124161
}
125162

163+
/// Update the store with a batch of unmanaged models.
164+
public func updateAtomically<Model: UnmanagedModel>(
165+
_ items: [Model],
166+
transactionAuthor: String? = nil
167+
) async -> Result<[Model], CoreDataError> {
168+
await context.performInScratchPad(schedule: .enqueued) { [context] scratchPad in
169+
scratchPad.transactionAuthor = transactionAuthor
170+
let objects = try items.map { item in
171+
guard let url = item.managedIdUrl else {
172+
throw CoreDataError.noUrlOnItemToMapToObjectId
173+
}
174+
let id = try scratchPad.objectId(from: url).get()
175+
let object = try scratchPad.notDeletedObject(for: id)
176+
let managed: Model.ManagedModel = try object.asManagedModel()
177+
try item.updating(managed: managed)
178+
return managed
179+
}
180+
try scratchPad.save()
181+
try context.performAndWait {
182+
context.transactionAuthor = transactionAuthor
183+
try context.save()
184+
context.transactionAuthor = nil
185+
}
186+
return try objects.map(Model.init(managed:))
187+
}
188+
}
189+
126190
/// Update the store with a batch of unmanaged models.
127191
///
128192
/// This operation is non-atomic. Each instance may succeed or fail individually.
@@ -223,4 +287,27 @@ extension CoreDataRepository {
223287
})
224288
return (success: successes, failed: failures)
225289
}
290+
291+
/// Delete from the store with a batch of unmanaged models.
292+
public func deleteAtomically(
293+
_ urls: [URL],
294+
transactionAuthor: String? = nil
295+
) async -> Result<Void, CoreDataError> {
296+
await context.performInScratchPad(schedule: .enqueued) { [context] scratchPad in
297+
scratchPad.transactionAuthor = transactionAuthor
298+
for url in urls {
299+
let id = try scratchPad.objectId(from: url).get()
300+
let object = try scratchPad.notDeletedObject(for: id)
301+
object.prepareForDeletion()
302+
scratchPad.delete(object)
303+
}
304+
try scratchPad.save()
305+
try context.performAndWait {
306+
context.transactionAuthor = transactionAuthor
307+
try context.save()
308+
context.transactionAuthor = nil
309+
}
310+
return ()
311+
}
312+
}
226313
}

0 commit comments

Comments
 (0)