mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-18 23:17:02 +01:00
Updated Fetching and querying (markdown)
@@ -4,10 +4,11 @@ Before we dive in, be aware that CoreStore distinguishes between *fetching* and
|
||||
- unsaved objects should be included in the search (though fetches can be configured to exclude unsaved ones)
|
||||
- A *query* pulls data straight from the persistent store. This means faster searches when computing aggregates such as *count*, *min*, *max*, etc. Use queries when:
|
||||
- you need to compute aggregate functions (see below for a list of supported functions)
|
||||
- results can be raw values like `NSString`'s, `NSNumber`'s, `Int`'s, `NSDate`'s, an `NSDictionary` of key-values, etc.
|
||||
- only specific attribute keys need to be included in the results
|
||||
- results can be raw values like `NSString`s, `NSNumber`s, `Int`s, `NSDate`s, an `NSDictionary` of key-values, etc.
|
||||
- only values for specified attribute keys need to be included in the results
|
||||
- unsaved objects should be ignored
|
||||
|
||||
#### `From` clause
|
||||
The search conditions for fetches and queries are specified using *clauses*. All fetches and queries require a `From` clause that indicates the target entity type:
|
||||
```swift
|
||||
let people = CoreStore.fetchAll(From(MyPersonEntity))
|
||||
@@ -15,7 +16,7 @@ let people = CoreStore.fetchAll(From(MyPersonEntity))
|
||||
```
|
||||
`people` in the example above will be of type `[MyPersonEntity]`. The `From(MyPersonEntity)` clause indicates a fetch to all persistent stores that `MyPersonEntity` belong to.
|
||||
|
||||
If the entity exists in multiple configurations and you need to only search from a particular configuration, provide the `From` clause the configuration name for the destination persistent store:
|
||||
If the entity exists in multiple configurations and you need to only search from a particular configuration, indicate in the `From` clause the configuration name for the destination persistent store:
|
||||
```swift
|
||||
let people = CoreStore.fetchAll(From<MyPersonEntity>("Config1")) // ignore objects in persistent stores other than the "Config1" configuration
|
||||
```
|
||||
@@ -25,19 +26,19 @@ let person = CoreStore.fetchAll(From<MyPersonEntity>(nil))
|
||||
```
|
||||
Now we know how to use a `From` clause, let's move on to fetching and querying.
|
||||
|
||||
#### Fetching
|
||||
### Fetching
|
||||
|
||||
There are currently 5 fetch methods you can call from `CoreStore`, from a `DataStack` instance, or from a `BaseDataTransaction` instance. All of the methods below accept the same parameters: a required `From` clause, and an optional series of `Where`, `OrderBy`, and/or `Tweak` clauses.
|
||||
|
||||
- `fetchAll(_:_:)` - returns an array of all objects that match the criteria.
|
||||
- `fetchOne(_:_:)` - returns the first object that match the criteria.
|
||||
- `fetchCount(_:_:)` - returns the number of objects that match the criteria.
|
||||
- `fetchObjectIDs(_:_:)`` - returns an array of `NSManagedObjectID`'s for all objects that match the criteria.
|
||||
- `fetchObjectID(_:_:)` - returns the `NSManagedObjectID`'s for the first objects that match the criteria.
|
||||
- `fetchAll(...)` - returns an array of all objects that match the criteria.
|
||||
- `fetchOne(...)` - returns the first object that match the criteria.
|
||||
- `fetchCount(...)` - returns the number of objects that match the criteria.
|
||||
- `fetchObjectIDs(...)` - returns an array of `NSManagedObjectID`s for all objects that match the criteria.
|
||||
- `fetchObjectID(...)` - returns the `NSManagedObjectID`s for the first objects that match the criteria.
|
||||
|
||||
Each method's purpose is straightforward, but we need to understand how to set the clauses for the fetch.
|
||||
|
||||
**`Where` clause**
|
||||
#### `Where` clause
|
||||
|
||||
The `Where` clause is CoreStore's `NSPredicate` wrapper. It specifies the search filter to use when fetching (or querying). It implements all initializers that `NSPredicate` does (except for `-predicateWithBlock:`, which Core Data does not support):
|
||||
```swift
|
||||
@@ -58,7 +59,7 @@ var people = CoreStore.fetchAll(
|
||||
Where(predicate) // predicate initializer
|
||||
)
|
||||
```
|
||||
`Where` clauses also implement the `&&`, `||`, and `!` logic operators, so you can provide logical conditions without writing too much `AND`, `OR`, and `NOT` strings in the conditions:
|
||||
`Where` clauses also implement the `&&`, `||`, and `!` logic operators, so you can provide logical conditions without writing too much `AND`, `OR`, and `NOT` strings:
|
||||
```swift
|
||||
var people = CoreStore.fetchAll(
|
||||
From(MyPersonEntity),
|
||||
@@ -67,7 +68,7 @@ var people = CoreStore.fetchAll(
|
||||
```
|
||||
If you do not provide a `Where` clause, all objects that belong to the specified `From` will be returned.
|
||||
|
||||
**`OrderBy` clause**
|
||||
#### `OrderBy` clause
|
||||
|
||||
The `OrderBy` clause is CoreStore's `NSSortDescriptor` wrapper. Use it to specify attribute keys in which to sort the fetch (or query) results with.
|
||||
```swift
|
||||
@@ -76,9 +77,9 @@ var mostValuablePeople = CoreStore.fetchAll(
|
||||
OrderBy(.Descending("rating"), .Ascending("surname"))
|
||||
)
|
||||
```
|
||||
As seen above, `OrderBy` accepts a list of `SortKey` enumeration values, which can be either `.Ascending` or `.Descending`. The associated value for the `SortKey` enumeration is the attribute key string.
|
||||
As seen above, `OrderBy` accepts a list of `SortKey` enumeration values, which can be either `.Ascending` or `.Descending`.
|
||||
|
||||
You can use the `+` and `+=` operator to append `OrderBy`'s together. This is useful when sorting conditionally:
|
||||
You can use the `+` and `+=` operator to append `OrderBy`s together. This is useful when sorting conditionally:
|
||||
```swift
|
||||
var orderBy = OrderBy(.Descending("rating"))
|
||||
if sortFromYoungest {
|
||||
@@ -90,9 +91,9 @@ var mostValuablePeople = CoreStore.fetchAll(
|
||||
)
|
||||
```
|
||||
|
||||
**`Tweak` clause**
|
||||
#### `Tweak` clause
|
||||
|
||||
The `Tweak` clause lets you, well, *tweak* the fetch (or query). `Tweak` exposes the `NSFetchRequest` in a closure where you can make changes to its properties:
|
||||
The `Tweak` clause lets you, uh, *tweak* the fetch (or query). `Tweak` exposes the `NSFetchRequest` in a closure where you can make changes to its properties:
|
||||
```swift
|
||||
var people = CoreStore.fetchAll(
|
||||
From(MyPersonEntity),
|
||||
@@ -108,21 +109,22 @@ var people = CoreStore.fetchAll(
|
||||
The clauses are evaluated the order they appear in the fetch/query, so you typically need to set `Tweak` as the last clause.
|
||||
`Tweak`'s closure is executed only just before the fetch occurs, so make sure that any values captured by the closure is not prone to race conditions.
|
||||
|
||||
Do note that while `Tweak` lets you micro-configure its `NSFetchRequest`, don't forget that CoreStore already preconfigured that `NSFetchRequest` to suitable defaults. Only use `Tweak` when you know what you are doing!
|
||||
While `Tweak` lets you micro-configure the `NSFetchRequest`, note that CoreStore already preconfigured that `NSFetchRequest` to suitable defaults. Only use `Tweak` when you know what you are doing!
|
||||
|
||||
#### Querying
|
||||
One of the functionalities overlooked by other Core Data wrapper libraries is raw properties fetching. If you are familiar with `NSDictionaryResultType` and `-[NSFetchedRequest propertiesToFetch]`, you probably know how painful it is to setup a query for raw values and aggregate values. CoreStore makes querying easy by exposing the 2 methods below:
|
||||
### Querying
|
||||
|
||||
- `queryValue(_:_:_:)` - returns a single raw value for an attribute or for an aggregate value. If there are multiple results, `queryValue(...)` only returns the first item.
|
||||
- `queryAttributes(_:_:_:)` - returns an array of dictionaries containing attribute keys with their corresponding values.
|
||||
One of the functionalities overlooked by other Core Data wrapper libraries is raw properties fetching. If you are familiar with `NSDictionaryResultType` and `-[NSFetchedRequest propertiesToFetch]`, you probably know how painful it is to setup a query for raw values and aggregate values. CoreStore makes this easy by exposing the 2 methods below:
|
||||
|
||||
- `queryValue(...)` - returns a single raw value for an attribute or for an aggregate value. If there are multiple results, `queryValue(...)` only returns the first item.
|
||||
- `queryAttributes(...)` - returns an array of dictionaries containing attribute keys with their corresponding values.
|
||||
|
||||
Both methods above accept the same parameters: a required `From` clause, a required `Select<T>` clause, and an optional series of `Where`, `OrderBy`, `GroupBy`, and/or `Tweak` clauses.
|
||||
|
||||
Setting up the `From`, `Where`, `OrderBy`, and `Tweak` clauses is similar to how you would when fetching. For querying, you also need to know how to use the `Select<T>` and `GroupBy` clauses.
|
||||
|
||||
**`Select<T>` clause**
|
||||
#### `Select<T>` clause
|
||||
|
||||
The `Select<T>` clause specifies the target attribute/aggregate key and the return type:
|
||||
The `Select<T>` clause specifies the target attribute/aggregate key, as well as the expected return type:
|
||||
```swift
|
||||
let johnsAge = CoreStore.queryValue(
|
||||
From(MyPersonEntity),
|
||||
@@ -130,7 +132,7 @@ let johnsAge = CoreStore.queryValue(
|
||||
Where("name == %@", "John Smith")
|
||||
)
|
||||
```
|
||||
The example above queries the "age" property for the first object that matches the `Where` condition. `johnsAge` will be bound to type `Int?`, as indicated by the `Select<Int>` generic type. For `queryValue(...)`, the following are allowed as the return type (and as the generic type for `Select<T>`):
|
||||
The example above queries the "age" property for the first object that matches the `Where` condition. `johnsAge` will be bound to type `Int?`, as indicated by the `Select<Int>` generic type. For `queryValue(...)`, the following are allowed as the return type (and therefore as the generic type for `Select<T>`):
|
||||
- `Bool`
|
||||
- `Int8`
|
||||
- `Int16`
|
||||
@@ -147,7 +149,7 @@ The example above queries the "age" property for the first object that matches t
|
||||
- `NSManagedObjectID`
|
||||
- `NSString`
|
||||
|
||||
For `queryAttributes(...)`, only `NSDictionary` is valid for `Select`, thus you are allowed omit the generic type:
|
||||
For `queryAttributes(...)`, only `NSDictionary` is valid for `Select`, thus you are allowed to omit the generic type:
|
||||
```swift
|
||||
let allAges = CoreStore.queryAttributes(
|
||||
From(MyPersonEntity),
|
||||
@@ -159,9 +161,7 @@ If you only need a value for a particular attribute, you can just specify the ke
|
||||
- `.Average(...)`
|
||||
- `.Count(...)`
|
||||
- `.Maximum(...)`
|
||||
- `.Median(...)`
|
||||
- `.Minimum(...)`
|
||||
- `.StandardDeviation(...)`
|
||||
- `.Sum(...)`
|
||||
|
||||
```swift
|
||||
@@ -179,7 +179,7 @@ let personJSON = CoreStore.queryAttributes(
|
||||
)
|
||||
```
|
||||
`personJSON` will then have the value:
|
||||
```json
|
||||
```swift
|
||||
[
|
||||
[
|
||||
"name": "John Smith",
|
||||
@@ -232,9 +232,9 @@ which now returns:
|
||||
]
|
||||
```
|
||||
|
||||
**`GroupBy` clause**
|
||||
#### `GroupBy` clause
|
||||
|
||||
The `GroupBy` clause lets you group results by a specified attribute/aggregate. This is only useful only for `queryAttributes(...)` since `queryValue(...)` just returns the first value anyway.
|
||||
The `GroupBy` clause lets you group results by a specified attribute/aggregate. This is useful only for `queryAttributes(...)` since `queryValue(...)` just returns the first value.
|
||||
```swift
|
||||
let personJSON = CoreStore.queryAttributes(
|
||||
From(MyPersonEntity),
|
||||
|
||||
Reference in New Issue
Block a user