You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This library offers a DSL (Domain Specific Language) to safely build predicates and requests to fetch a CoreData store. Also a wrapper around `NSFetchedResultsController` is offered to publish arrays of `NSManagedObject` to be used with a `NSDiffableDataSource`.
3
+
This library offers a DSL (Domain Specific Language) to safely build predicates and requests to fetch a CoreData store.
4
4
5
5
The documentation is built with docC. You can [read it online](https://abridoux.github.io/SafeFetching/documentation/safefetching/) or locally by running *Product* → *Build Documentation* or hitting **⇧⌃⌘D**.
6
6
7
-
## Convenient and safe fetching
7
+
## Convenient and Safe Fetching
8
8
9
-
For any CoreData entity generated by Xcode, the only required step is to make it implement `Fetchable`.
9
+
The library requires to manually define the entity class. Then the macro `FetchableManagedObject` can be used.
10
10
11
11
```swift
12
-
finalclassRandomEntity: NSManagedObject {
12
+
@FetchableManagedObject
13
+
finalclassUser: NSManagedObject {
13
14
14
15
@NSManagedvar score =0.0
15
16
@NSManagedvar name: String?=""
16
17
}
17
18
```
19
+
This makes `User` conform to `Fetchable` and ready to be used with the SafeFetching API.
18
20
19
-
```swift
20
-
extensionRandomEntity: Fetchable {}
21
-
```
22
-
23
-
Then it's possible to use the DSL to build a request. The last step can either get the built request as `NSFetchRequest<RandomEntity>` or execute the request in the provided context.
21
+
Then it's possible to use the DSL to build a request. The last step can either get the built request as `NSFetchRequest<User>` or execute the request in the provided context.
Copy file name to clipboardExpand all lines: Sources/SafeFetching/SafeFetching.docc/Articles/build-predicates.md
+48-7Lines changed: 48 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,14 +5,14 @@ Learn how to specify safe predicates safely when building a request.
5
5
Examples in the article refer to this entity.
6
6
7
7
```swift
8
+
@FetchableManagedObject
8
9
finalclassStubEntity: NSManagedObject {
9
-
10
10
@NSManagedvar score =0.0
11
-
@NSManagedvar name: String?=""
11
+
@NSManagedvar name: String?=""
12
12
}
13
13
```
14
14
15
-
When building a request, the ``Builders/Request/where(_:)-((Entity.FetchableMembers)->Builders.Predicate<Entity>)`` operation allows to specify a predicate. For a demonstration purpose in this article, predicates are specified after their implicit declaration.
15
+
When building a request, the ``Builders/Request/where(_:)-5uzqj`` operation allows to specify a predicate. For a demonstration purpose in this article, predicates are specified after their implicit declaration.
16
16
17
17
```swift
18
18
let predicate: Builders.Predicate<StubEntity>
@@ -55,18 +55,20 @@ $0.score <= 20
55
55
56
56
##### Boolean
57
57
58
+
```swift
59
+
$0.isAdmin
60
+
```
61
+
58
62
```swift
59
63
$0.isAdmin==true
60
64
```
61
65
66
+
Inversion is supported.
67
+
62
68
```swift
63
69
!$0.isAdmin
64
70
```
65
71
66
-
> Tip: The `where(_:)` function has convenient variations to take a single boolean like ``Builders/Request/where(_:)-3pukm``:
67
-
>
68
-
> `.where(\.isAdmin)`.
69
-
70
72
71
73
## Advanced Operations
72
74
It's possible to use the advanced operators offered by `NSPredicate` safely by specifying calling the dedicated function from the ``FetchableMember``.
@@ -234,3 +236,42 @@ is only the same as
234
236
$0.color== .blue
235
237
```
236
238
*when the stored `color` is a single option*.
239
+
240
+
## Relationships
241
+
Predicates in SafeFetching support relationships. Given the two entities:
242
+
243
+
```swift
244
+
@FetchableManagedObject
245
+
finalclassStubEntity: NSManagedObject {
246
+
@NSManagedvar score =0.0
247
+
@NSManagedvar pet: Pet?
248
+
}
249
+
250
+
@FetchableManagedObject
251
+
finalclassPet: NSManagedObject {
252
+
@NSManagedvar name: String
253
+
}
254
+
```
255
+
The following predicate can be expressed for the `User` entity.
256
+
257
+
```swift
258
+
$0.pet.name=="Minouche"
259
+
```
260
+
> Note: Even if `pet` is an optional `Pet` relationship, SafeFetching has no concerns about it when specifying comparison. Optionals are not relevant when writing a `NSPredicate` string format to fetch a CoreData store (unless of course when checking nullity).
261
+
262
+
## Standalone predicate
263
+
Using a `where(_:)` function is not the only way to make predicate.
264
+
265
+
### NSPredicate convenience
266
+
If needed, a predicate can be specified to make a `NSPredicate`.
267
+
268
+
```swift
269
+
let predicate: NSPredicate = .safe(on: User.self) { $0.score>10 }
270
+
```
271
+
272
+
### Static
273
+
Also, a predicate can be provided with ``Builders/Predicate/predicate(_:)``.
274
+
275
+
```swift
276
+
let predicate: Builders.Predicate<User> = .predicate { $0.score>10 }
Copy file name to clipboardExpand all lines: Sources/SafeFetching/SafeFetching.docc/Articles/build-requests.md
+56-38Lines changed: 56 additions & 38 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,25 +2,20 @@
2
2
3
3
Learn how to build requests with the SafeFetching DSL.
4
4
5
-
Examples in the article refer to this entity.
5
+
Examples in the article refer to this `User`class.
6
6
7
7
```swift
8
-
finalclassStubEntity: NSManagedObject {
9
-
8
+
@FetchableManagedObject
9
+
finalclassUser: NSManagedObject {
10
10
@NSManagedvar score =0.0
11
-
@NSManagedvar name: String?=""
11
+
@NSManagedvar name: String?=""
12
+
@NSManagedvar isAdmin: Bool
12
13
}
13
14
```
14
15
15
16
## Setup
16
17
17
-
To be able to use the DSL for an entity, the only required step is to make it conform to `Fetchable`.
18
-
19
-
```swift
20
-
extensionStubEntity: Fetchable {}
21
-
```
22
-
23
-
Then the request creation starts with `StubEntity.request()`.
18
+
To be able to use the DSL for an entity it is needed to make it conform to `Fetchable` which is done here using the ``FetchableManagedObject()`` macro. Then the request creation starts with `User.request()`.
24
19
25
20
## Steps
26
21
There are four steps (some are optional) to build a request:
@@ -29,100 +24,123 @@ There are four steps (some are optional) to build a request:
29
24
- specify sorts (optional)
30
25
- get either the build request `NSFetchRequest` with ``Builders/Request/nsValue`` or execute it directly with ``Builders/Request/fetch(in:)``
31
26
32
-
Additionally, the "setting" can be performed.
27
+
Additionally, the "setting" step can be performed to set a property of `NSFetchRequest` before using it for fetching the store.
33
28
34
29
### Target
35
30
36
31
##### All
37
32
To target all entities (which is the default behavior of CoreData's fetch requests), use the ``Builders/PreRequest/all(after:)`` function.
38
33
39
34
```swift
40
-
StubEntity.request()
35
+
User.request()
41
36
.all()
42
37
```
43
38
44
-
To ignore the first nth results:
39
+
To ignore the first nth results.
45
40
46
41
```swift
47
-
StubEntity.request()
42
+
User.request()
48
43
.all(after: 10)
49
44
```
50
45
51
46
##### First
52
-
To target the first entity meeting the criteria, use ``Builders/PreRequest/first()`` and ``Builders/PreRequest/first(nth:after:)``
47
+
To target the first User meeting the criteria, use ``Builders/PreRequest/first()`` and ``Builders/PreRequest/first(nth:after:)``
53
48
54
49
```swift
55
-
StubEntity.request()
50
+
User.request()
56
51
.first()
57
52
```
58
53
59
-
Ignore the first nth results
54
+
Ignore the first nth results.
60
55
61
56
```swift
62
-
StubEntity.request()
57
+
User.request()
63
58
.first(after: 10)
64
59
```
65
60
66
-
Limit the results
61
+
Limit the results.
67
62
68
63
```swift
69
-
StubEntity.request()
64
+
User.request()
70
65
.first(20)
71
66
```
72
67
73
-
Limit the results and ignore the nth first
68
+
Limit the results and ignore the nth first.
74
69
75
70
```swift
76
-
StubEntity.request()
71
+
User.request()
77
72
.first(20, after: 10)
78
73
```
79
74
80
75
### Predicate
81
76
82
-
Specify a predicate with the ``Builders/Request/where(_:)-5ar9o`` function after the target.
77
+
Specify a predicate with one of the `where(_:)` functions after the target.
83
78
84
79
```swift
85
-
StubEntity.request()
80
+
User.request()
86
81
.all()
87
-
.where(\.score>20)
82
+
.where { $0.score>20 }
88
83
```
89
84
85
+
Compound predicates are also supported.
86
+
87
+
```swift
88
+
User.request()
89
+
.all()
90
+
.where { $0.score>20&&$0.name.contains("dore") }
91
+
```
92
+
93
+
Single boolean values can be used.
94
+
95
+
```swift
96
+
User.request()
97
+
.all()
98
+
.where { $0.isAdmin }
99
+
```
100
+
101
+
> Tip: The `where(_:)` function has convenient variations to take a single boolean like ``Builders/Request/where(_:)-3pukm``:
102
+
>
103
+
> `.where(\.isAdmin)`.
104
+
105
+
Naming the parameter can sometimes be preferable for longer predicates.
106
+
90
107
```swift
91
-
StubEntity.request()
108
+
User.request()
92
109
.all()
93
-
.where(\.score>20
94
-
&& \.name* .contains("dore")
95
-
)
110
+
.where { members in
111
+
members.score>20&& members.name.contains("dore")
112
+
||!members.isAdmin
113
+
}
96
114
```
97
115
98
116
To learn more about building predicates, you can read <doc:build-predicates>.
99
117
100
118
### Sort
101
-
After the target has been specified, one sort or more can be set to the request with ``Builders/Request/sorted(by:_:)``
119
+
After the target has been specified, one sort or more can be set to the request with ``Builders/Request/sorted(by:_:)``.
If needed, it's possible to assign a value to the request being built with ``Builders/Request/setting(_:to:)`` which allows to keep the functional appearance.
134
+
If needed, it's possible to assign a value to a property of the request being built with ``Builders/Request/setting(_:to:)``.
117
135
118
136
```swift
119
-
StubEntity.request()
137
+
User.request()
120
138
.all()
121
139
.setting(\.returnsDistinctResults, to: true)
122
140
```
123
141
124
142
## Steps order
125
-
Whereas some steps cannot be performed in a random order, others like the "setting" can be used any time after the target is specified. That said, it's advised to keep the order used to expose the steps:
143
+
Whereas some steps cannot be performed in a random order, others like the "setting" can be used any time after the target is specified. That said, it's advised to keep the following order:
126
144
127
145
- target
128
146
- predicate
@@ -132,9 +150,9 @@ Whereas some steps cannot be performed in a random order, others like the "setti
132
150
For instance, here is a request with all the possible/required steps.
0 commit comments