[![CI Status](http://img.shields.io/travis/Olivier Thierry/FacadeSwift.svg?style=flat)](https://travis-ci.org/Olivier Thierry/FacadeSwift)
DOCUMENTATION IN PROGRESS
Facade
acts as a facade between your app and CoreData
. It makes configuration and usage a lot easier, provides flexible parent-child architecture and powerful querying APIs.
Facade.Stack
builds an optimized Parent/Child
stack architecture that allows efficient read and asynchronous write operations for persistence phase along with detached transactions.
FacadeSwift is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod "FacadeSwift"
facade_stack.config.storeName = "MyApp"
facade_stack.connect()
That's all you need to do to start using Facade
. More deeper configuration and usage, see the documentation bellow.
You can use a seed when setting up your database for the first time.
facade_stack.config.seedURL = NSBundle.mainBundle()
.URLForResource(
"myseed",
withExtension: "sqlite")
// Install the seed
try! facade_stack.seed()
try! facade_stack.connect()
// Check that database exists before trying to drop it
if facade_stack.installed {
try! facade_stack.drop()
}
If your datamodel schema is not in your main bundle (in a framework or resource bundle), you will have to provide the URL so that CoreData can fetch it.
facade_stack.config.modelURL = myBundle
.URLForResource(
"MyAppDataModel",
withExtension: "momd")
Of course you can use CoreData built-in options by using the attribute options
of the shared Config
facade_stack.config.options[NSMigratePersistentStoresAutomaticallyOption] = true
facade_stack.config.options[NSInferMappingModelAutomaticallyOption] = true
After the configuration phase, you must establish a connection to the database. This operation adds the persistent store to the persistent store coordinator.
try! facade_stack.connect()
The Query API is flexible and powerful. You don't need to take care of the backend of NSFetchRequest
or SQLite
or anything. You can just use high level APIs and focus of the functional part of your app.
-
Matching options
CaseInsensitive
DiacriticInsensitive
-
Customizing query
limit(_:)
: Documentation in progressoffset(_:)
: Documentation in progressfetchBatchSize(_:)
: Documentation in progressprefetch(_:)
: Documentation in progressfaults(_:)
: Documentation in progressgroupBy(_:)
: Documentation in progressrefresh(_:)
: Documentation in progress
By default, a request always executes in facade_stack.mainManagedObjectContext
. You can override this behaviour by giving the context is which the query must execute.
let user = facade_query(User)
.inManagedObjectContext(myCustomContext)
.first()
let recipes = facade_query(Recipe)
.with("difficulty", equalTo: 3)
.all()
let users = facade_query(User)
.with(
"firstname",
notEqualTo: "olivier",
options: [
.CaseInsensitive,
.DiacriticInsensitive])
.all()
let user = facade_query(User)
.with(
"email",
containedIn: [
"olivier@save.co",
"olivier.thierry42@gmail.com"])
.first()
let roles = facade_query(Role)
.limit(2)
.all()
let users = facade_query(User)
.with(
"role",
notContainedIn: roles)
.all()
let recipes = facade_query(Recipe)
.with("ingredients", containingAll: listOfAvailableIngredients)
.all()
let recipes = facade_query(Recipe)
.with("ingredients", containingAny: listOfAvailableIngredients)
.all()
let recipes = facade_query(Recipe)
.with("ingredients", containingNone: listOfAvailableIngredients)
.all()
let users = facade_query(User)
.with(
"firstname",
containing: "liv")
.all()
let users = facade_query(User)
.with(
"firstname",
like: "oliv%",
options: [.CaseInsensitive])
.all()
Predicate to match property that exists (!= nil
) or don't exists (== nil
)
let usersWithoutEmail = facade_query(User)
.with("email", existing: false)
.all()
These functions are syntatic functions for LIKE pattern%
and LIKE %pattern
let users = facade_query(User)
.with("email", endingWith: "@gmail.com")
.all()
let users = facade_query(User)
.with("age", greaterThanOrEqual: 18)
.all()
let recipes = facade_queryOr([
// Vegan AND difficulty maximum (5)
facade_query(Recipe)
.with("difficulty", equalTo: 5)
.with("vegan", equalTo: true),
// Non-vegan AND difficulty between 3-5
facade_query(Recipe)
.with("difficulty", greaterThanOrEqualTo: 3)
.with("vegan", equalTo: false)
])
// In both case, we want recipes to take less than 30 mins to cook
.with("time", lessThanOrEqualTo: 30)
.sort("difficulty")
.all()
By default, using sort(_:)
will sort results in ascending order.
facade_query(User)
.sort("email")
.all()
// Is exactly the same as
facade_query(User)
.sort("email ASC")
.all()
You can add DESC
or desc
(case insensitive) to your sort predidcate to change sorting order,
facade_query(User)
.sort("email DESC")
.all()
You can directly delete/batch delete matching results from the query object
facade_query(Recipe)
.with("favorite", equalTo: false)
.delete()
facade_query(Recipe)
.with("favorite", equalTo: false)
.batchDelete() // Async delete using NSBatchDeleteRequest
There's 3 ways to execute a query.
count()
will as its name says, returns a simple count of matching entities.all()
will always return an array of [A] where A is your entity type.execute()
has 3 signaturesexecute() -> [A]
: Behaves the same way asall()
execute() -> [NSManagedObjectID]
: Will set the result type of the fetch request to.ManagedObjectIDResultType
and returns an array ofNSManagedObjectID
s.execute() -> [NSDictionary]
: Will set the result type of the fetch request to.DictionaryResultType
and returns a raw representation of the objects as instances ofNSDictionary
s
On most case, I just use execute()
and let the compiler infer the type I am waiting for, which it is pretty good at <3.
In some case, you want to fetch the first or last object matching your query. By default, first()
and last()
will behave exactly the same. By default, this means that query.first() === query.last()
. Because those 2 methods set a limit of 1 and sort the results set by facade_stack.config.modelPrimaryKey
which will have no effect if you did not set it in first place.
During your stack configuration. Add the following
facade_stack.config.modelPrimaryKey = "id"
From now on, query.first() != query.last()
(unless of course query.count() <= 1
) as Facade
will detect the default primary key and sort the result accordingly.
Documentation in progress
Documentation in progress
Documentation in progress
<->
: Documentation in progress<=>
: Documentation in progress</>
: Documentation in progress<-
: Documentation in progress
Olivier Thierry, olivier.thierry42@gmail.com
FacadeSwift is available under the MIT license. See the LICENSE file for more info.