Skip to content

Commit 4f0d99b

Browse files
authored
Merge pull request #47 from roanutil/runtime-crash-on-failure-to-build-count-fetch-request
2 parents 861f267 + b4052a0 commit 4f0d99b

20 files changed

Lines changed: 683 additions & 397 deletions

‎Sources/CoreDataRepository/CoreDataRepository+Aggregate.swift‎

Lines changed: 312 additions & 178 deletions
Large diffs are not rendered by default.

‎Sources/CoreDataRepository/Internal/AggregateSubscription.swift‎

Lines changed: 24 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -48,48 +48,25 @@ final class AggregateSubscription<Value: Numeric & Sendable>: Subscription<Value
4848
attributeDesc: NSAttributeDescription,
4949
groupBy: NSAttributeDescription? = nil,
5050
continuation: AsyncStream<Result<Value, CoreDataError>>.Continuation
51-
) {
52-
let request: NSFetchRequest<NSDictionary>
53-
do {
54-
request = try NSFetchRequest.request(
55-
function: function,
56-
predicate: predicate,
57-
entityDesc: entityDesc,
58-
attributeDesc: attributeDesc,
59-
groupBy: groupBy
60-
)
61-
} catch {
62-
self.init(
63-
fetchRequest: NSFetchRequest(),
64-
fetchResultControllerRequest: NSFetchRequest(),
65-
context: context,
66-
continuation: continuation
67-
)
68-
fail(error)
69-
return
70-
}
51+
) throws(CoreDataError) {
52+
let request: NSFetchRequest<NSDictionary> = try NSFetchRequest.request(
53+
function: function,
54+
predicate: predicate,
55+
entityDesc: entityDesc,
56+
attributeDesc: attributeDesc,
57+
groupBy: groupBy
58+
)
7159
guard entityDesc == attributeDesc.entity else {
72-
self.init(
73-
fetchRequest: NSFetchRequest(),
74-
fetchResultControllerRequest: NSFetchRequest(),
75-
context: context,
76-
continuation: continuation
77-
)
7860
guard let entityName = entityDesc.name ?? entityDesc.managedObjectClassName else {
79-
fail(.propertyDoesNotMatchEntity(description: nil))
80-
return
61+
throw CoreDataError.propertyDoesNotMatchEntity(description: nil)
8162
}
8263
guard let attributeEntityName = attributeDesc.entity.name ?? attributeDesc.entity.managedObjectClassName
8364
else {
84-
fail(.propertyDoesNotMatchEntity(description: entityName))
85-
return
65+
throw CoreDataError.propertyDoesNotMatchEntity(description: entityName)
8666
}
87-
fail(
88-
.propertyDoesNotMatchEntity(
89-
description: "\(entityName) != \(attributeDesc.name).\(attributeEntityName)"
90-
)
67+
throw CoreDataError.propertyDoesNotMatchEntity(
68+
description: "\(entityName) != \(attributeDesc.name).\(attributeEntityName)"
9169
)
92-
return
9370
}
9471
self.init(request: request, context: context, continuation: continuation)
9572
}
@@ -104,48 +81,25 @@ final class AggregateSubscription<Value: Numeric & Sendable>: Subscription<Value
10481
attributeDesc: NSAttributeDescription,
10582
groupBy: NSAttributeDescription? = nil,
10683
continuation: AsyncStream<Result<Value, CoreDataError>>.Continuation
107-
) {
108-
let request: NSFetchRequest<NSDictionary>
109-
do {
110-
request = try NSFetchRequest.request(
111-
function: function,
112-
predicate: predicate,
113-
entityDesc: entityDesc,
114-
attributeDesc: attributeDesc,
115-
groupBy: groupBy
116-
)
117-
} catch {
118-
self.init(
119-
fetchRequest: NSFetchRequest(),
120-
fetchResultControllerRequest: NSFetchRequest(),
121-
context: context,
122-
continuation: continuation
123-
)
124-
fail(error)
125-
return
126-
}
84+
) throws(CoreDataError) {
85+
let request: NSFetchRequest<NSDictionary> = try NSFetchRequest.request(
86+
function: function,
87+
predicate: predicate,
88+
entityDesc: entityDesc,
89+
attributeDesc: attributeDesc,
90+
groupBy: groupBy
91+
)
12792
guard entityDesc == attributeDesc.entity else {
128-
self.init(
129-
fetchRequest: NSFetchRequest(),
130-
fetchResultControllerRequest: NSFetchRequest(),
131-
context: context,
132-
continuation: continuation
133-
)
13493
guard let entityName = entityDesc.name ?? entityDesc.managedObjectClassName else {
135-
fail(.propertyDoesNotMatchEntity(description: nil))
136-
return
94+
throw CoreDataError.propertyDoesNotMatchEntity(description: nil)
13795
}
13896
guard let attributeEntityName = attributeDesc.entity.name ?? attributeDesc.entity.managedObjectClassName
13997
else {
140-
fail(.propertyDoesNotMatchEntity(description: entityName))
141-
return
98+
throw CoreDataError.propertyDoesNotMatchEntity(description: entityName)
14299
}
143-
fail(
144-
.propertyDoesNotMatchEntity(
145-
description: "\(entityName) != \(attributeDesc.name).\(attributeEntityName)"
146-
)
100+
throw CoreDataError.propertyDoesNotMatchEntity(
101+
description: "\(entityName) != \(attributeDesc.name).\(attributeEntityName)"
147102
)
148-
return
149103
}
150104
self.init(
151105
fetchRequest: request,

‎Sources/CoreDataRepository/Internal/AggregateThrowingSubscription.swift‎

Lines changed: 24 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -52,48 +52,25 @@ final class AggregateThrowingSubscription<Value: Numeric & Sendable>: ThrowingSu
5252
attributeDesc: NSAttributeDescription,
5353
groupBy: NSAttributeDescription? = nil,
5454
continuation: AsyncThrowingStream<Value, any Error>.Continuation
55-
) {
56-
let request: NSFetchRequest<NSDictionary>
57-
do {
58-
request = try NSFetchRequest.request(
59-
function: function,
60-
predicate: predicate,
61-
entityDesc: entityDesc,
62-
attributeDesc: attributeDesc,
63-
groupBy: groupBy
64-
)
65-
} catch {
66-
self.init(
67-
fetchRequest: NSFetchRequest(),
68-
fetchResultControllerRequest: NSFetchRequest(),
69-
context: context,
70-
continuation: continuation
71-
)
72-
fail(error)
73-
return
74-
}
55+
) throws(CoreDataError) {
56+
let request: NSFetchRequest<NSDictionary> = try NSFetchRequest.request(
57+
function: function,
58+
predicate: predicate,
59+
entityDesc: entityDesc,
60+
attributeDesc: attributeDesc,
61+
groupBy: groupBy
62+
)
7563
guard entityDesc == attributeDesc.entity else {
76-
self.init(
77-
fetchRequest: NSFetchRequest(),
78-
fetchResultControllerRequest: NSFetchRequest(),
79-
context: context,
80-
continuation: continuation
81-
)
8264
guard let entityName = entityDesc.name ?? entityDesc.managedObjectClassName else {
83-
fail(.propertyDoesNotMatchEntity(description: nil))
84-
return
65+
throw CoreDataError.propertyDoesNotMatchEntity(description: nil)
8566
}
8667
guard let attributeEntityName = attributeDesc.entity.name ?? attributeDesc.entity.managedObjectClassName
8768
else {
88-
fail(.propertyDoesNotMatchEntity(description: entityName))
89-
return
69+
throw CoreDataError.propertyDoesNotMatchEntity(description: entityName)
9070
}
91-
fail(
92-
.propertyDoesNotMatchEntity(
93-
description: "\(entityName) != \(attributeDesc.name).\(attributeEntityName)"
94-
)
71+
throw CoreDataError.propertyDoesNotMatchEntity(
72+
description: "\(entityName) != \(attributeDesc.name).\(attributeEntityName)"
9573
)
96-
return
9774
}
9875
self.init(request: request, context: context, continuation: continuation)
9976
}
@@ -108,48 +85,25 @@ final class AggregateThrowingSubscription<Value: Numeric & Sendable>: ThrowingSu
10885
attributeDesc: NSAttributeDescription,
10986
groupBy: NSAttributeDescription? = nil,
11087
continuation: AsyncThrowingStream<Value, any Error>.Continuation
111-
) {
112-
let request: NSFetchRequest<NSDictionary>
113-
do {
114-
request = try NSFetchRequest.request(
115-
function: function,
116-
predicate: predicate,
117-
entityDesc: entityDesc,
118-
attributeDesc: attributeDesc,
119-
groupBy: groupBy
120-
)
121-
} catch {
122-
self.init(
123-
fetchRequest: NSFetchRequest(),
124-
fetchResultControllerRequest: NSFetchRequest(),
125-
context: context,
126-
continuation: continuation
127-
)
128-
fail(error)
129-
return
130-
}
88+
) throws(CoreDataError) {
89+
let request: NSFetchRequest<NSDictionary> = try NSFetchRequest.request(
90+
function: function,
91+
predicate: predicate,
92+
entityDesc: entityDesc,
93+
attributeDesc: attributeDesc,
94+
groupBy: groupBy
95+
)
13196
guard entityDesc == attributeDesc.entity else {
132-
self.init(
133-
fetchRequest: NSFetchRequest(),
134-
fetchResultControllerRequest: NSFetchRequest(),
135-
context: context,
136-
continuation: continuation
137-
)
13897
guard let entityName = entityDesc.name ?? entityDesc.managedObjectClassName else {
139-
fail(.propertyDoesNotMatchEntity(description: nil))
140-
return
98+
throw CoreDataError.propertyDoesNotMatchEntity(description: nil)
14199
}
142100
guard let attributeEntityName = attributeDesc.entity.name ?? attributeDesc.entity.managedObjectClassName
143101
else {
144-
fail(.propertyDoesNotMatchEntity(description: entityName))
145-
return
102+
throw CoreDataError.propertyDoesNotMatchEntity(description: entityName)
146103
}
147-
fail(
148-
.propertyDoesNotMatchEntity(
149-
description: "\(entityName) != \(attributeDesc.name).\(attributeEntityName)"
150-
)
104+
throw CoreDataError.propertyDoesNotMatchEntity(
105+
description: "\(entityName) != \(attributeDesc.name).\(attributeEntityName)"
151106
)
152-
return
153107
}
154108
self.init(
155109
fetchRequest: request,

‎Sources/CoreDataRepository/Internal/BaseSubscription.swift‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ class BaseSubscription<
2323
fetchResultControllerRequest: NSFetchRequest<ControllerResult>,
2424
context: NSManagedObjectContext
2525
) {
26+
if fetchRequest.sortDescriptors == nil {
27+
// if `sortDescriptors` is `nil`, an exception is raised and causes a runtime crash
28+
fetchRequest.sortDescriptors = []
29+
}
30+
if fetchResultControllerRequest.sortDescriptors == nil {
31+
// if `sortDescriptors` is `nil`, an exception is raised and causes a runtime crash
32+
fetchResultControllerRequest.sortDescriptors = []
33+
}
2634
request = fetchRequest
2735
frc = NSFetchedResultsController(
2836
fetchRequest: fetchResultControllerRequest,

‎Sources/CoreDataRepository/Internal/CountSubscription.swift‎

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,11 @@ final class CountSubscription<Value: Numeric & Sendable>: Subscription<Value, NS
3535
predicate: NSPredicate,
3636
entityDesc: NSEntityDescription,
3737
continuation: AsyncStream<Result<Value, CoreDataError>>.Continuation
38-
) {
39-
let request: NSFetchRequest<NSDictionary>
40-
do {
41-
request = try NSFetchRequest.countRequest(
42-
predicate: predicate,
43-
entityDesc: entityDesc
44-
)
45-
} catch {
46-
self.init(
47-
fetchRequest: NSFetchRequest(),
48-
fetchResultControllerRequest: NSFetchRequest(),
49-
context: context,
50-
continuation: continuation
51-
)
52-
fail(error)
53-
return
54-
}
38+
) throws(CoreDataError) {
39+
let request: NSFetchRequest<NSDictionary> = try NSFetchRequest.countRequest(
40+
predicate: predicate,
41+
entityDesc: entityDesc
42+
)
5543
self.init(request: request, context: context, continuation: continuation)
5644
}
5745

@@ -62,20 +50,11 @@ final class CountSubscription<Value: Numeric & Sendable>: Subscription<Value, NS
6250
changeTrackingRequest: NSFetchRequest<NSManagedObject>,
6351
entityDesc: NSEntityDescription,
6452
continuation: AsyncStream<Result<Value, CoreDataError>>.Continuation
65-
) {
66-
let request: NSFetchRequest<NSDictionary>
67-
do {
68-
request = try NSFetchRequest.countRequest(predicate: predicate, entityDesc: entityDesc)
69-
} catch {
70-
self.init(
71-
fetchRequest: NSFetchRequest(),
72-
fetchResultControllerRequest: NSFetchRequest(),
73-
context: context,
74-
continuation: continuation
75-
)
76-
fail(error)
77-
return
78-
}
53+
) throws(CoreDataError) {
54+
let request: NSFetchRequest<NSDictionary> = try NSFetchRequest.countRequest(
55+
predicate: predicate,
56+
entityDesc: entityDesc
57+
)
7958
self.init(
8059
fetchRequest: request,
8160
fetchResultControllerRequest: changeTrackingRequest,

‎Sources/CoreDataRepository/Internal/CountThrowingSubscription.swift‎

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,11 @@ final class CountThrowingSubscription<Value: Numeric & Sendable>: ThrowingSubscr
3939
predicate: NSPredicate,
4040
entityDesc: NSEntityDescription,
4141
continuation: AsyncThrowingStream<Value, any Error>.Continuation
42-
) {
43-
let request: NSFetchRequest<NSDictionary>
44-
do {
45-
request = try NSFetchRequest.countRequest(
46-
predicate: predicate,
47-
entityDesc: entityDesc
48-
)
49-
} catch {
50-
self.init(
51-
fetchRequest: NSFetchRequest(),
52-
fetchResultControllerRequest: NSFetchRequest(),
53-
context: context,
54-
continuation: continuation
55-
)
56-
fail(error)
57-
return
58-
}
42+
) throws(CoreDataError) {
43+
let request: NSFetchRequest<NSDictionary> = try NSFetchRequest.countRequest(
44+
predicate: predicate,
45+
entityDesc: entityDesc
46+
)
5947
self.init(request: request, context: context, continuation: continuation)
6048
}
6149

@@ -66,23 +54,11 @@ final class CountThrowingSubscription<Value: Numeric & Sendable>: ThrowingSubscr
6654
changeTrackingRequest: NSFetchRequest<NSManagedObject>,
6755
entityDesc: NSEntityDescription,
6856
continuation: AsyncThrowingStream<Value, any Error>.Continuation
69-
) {
70-
let request: NSFetchRequest<NSDictionary>
71-
do {
72-
request = try NSFetchRequest.countRequest(
73-
predicate: predicate,
74-
entityDesc: entityDesc
75-
)
76-
} catch {
77-
self.init(
78-
fetchRequest: NSFetchRequest(),
79-
fetchResultControllerRequest: NSFetchRequest(),
80-
context: context,
81-
continuation: continuation
82-
)
83-
fail(error)
84-
return
85-
}
57+
) throws(CoreDataError) {
58+
let request: NSFetchRequest<NSDictionary> = try NSFetchRequest.countRequest(
59+
predicate: predicate,
60+
entityDesc: entityDesc
61+
)
8662
self.init(
8763
fetchRequest: request,
8864
fetchResultControllerRequest: changeTrackingRequest,

0 commit comments

Comments
 (0)