-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathAggregateSubscription.swift
More file actions
102 lines (97 loc) · 3.38 KB
/
AggregateSubscription.swift
File metadata and controls
102 lines (97 loc) · 3.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// AggregateSubscription.swift
// CoreDataRepository
//
// This source code is licensed under the MIT License (MIT) found in the
// LICENSE file in the root directory of this source tree.
@preconcurrency import CoreData
import Foundation
/// Subscription provider that sends updates when an aggregate fetch request changes
@usableFromInline
final class AggregateSubscription<Value>: Subscription<Value, NSDictionary, NSManagedObject>,
@unchecked Sendable where Value: Numeric,
Value: Sendable
{
@usableFromInline
override func fetch() {
frc.managedObjectContext.perform { [weak self, frc, request] in
guard frc.fetchedObjects != nil else {
self?.start()
return
}
let result: [NSDictionary]
do {
result = try frc.managedObjectContext.fetch(request)
} catch let error as CocoaError {
self?.fail(.cocoa(error))
return
} catch {
self?.fail(.unknown(error as NSError))
return
}
guard let value: Value = result.asAggregateValue() else {
self?.fail(.fetchedObjectFailedToCastToExpectedType)
return
}
self?.send(value)
}
}
@usableFromInline
convenience init(
function: CoreDataRepository.AggregateFunction,
context: NSManagedObjectContext,
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
continuation: AsyncStream<Result<Value, CoreDataError>>.Continuation
) {
let request: NSFetchRequest<NSDictionary>
do {
request = try NSFetchRequest<NSDictionary>.request(
function: function,
predicate: predicate,
entityDesc: entityDesc,
attributeDesc: attributeDesc,
groupBy: groupBy
)
} catch let error as CoreDataError {
self.init(
fetchRequest: NSFetchRequest(),
fetchResultControllerRequest: NSFetchRequest(),
context: context,
continuation: continuation
)
self.fail(error)
return
} catch let error as CocoaError {
self.init(
fetchRequest: NSFetchRequest(),
fetchResultControllerRequest: NSFetchRequest(),
context: context,
continuation: continuation
)
self.fail(.cocoa(error))
return
} catch {
self.init(
fetchRequest: NSFetchRequest(),
fetchResultControllerRequest: NSFetchRequest(),
context: context,
continuation: continuation
)
fail(.unknown(error as NSError))
return
}
guard entityDesc == attributeDesc.entity else {
self.init(
fetchRequest: NSFetchRequest(),
fetchResultControllerRequest: NSFetchRequest(),
context: context,
continuation: continuation
)
fail(.propertyDoesNotMatchEntity)
return
}
self.init(request: request, context: context, continuation: continuation)
}
}