Sworm provides a very simple API for safe data queries.
A complete query looks like this:
<T: ManagedObjectConvertible>
.all
.where(<predicate>)
.sort(<property>, ascending: <true|false>)
.limit(<integer value>)
.offset(<integer value>)
You can use any combination of where
sort
limit
offset
.
We will not focus on limit/offset, so let's go straight to sorting and predicates.
The most important part of any query is the search predicate. To generate it, you need to write a strongly typed expression like the following:
\T.count == 10 || \T.date > Date() && !(\T.id === [1, 2, 3])
Note: The ===
operator is an "IN" operation.
This form of notation is very intuitive and fully corresponds to the logic that is usually used in classical conditional expressions: comparison operators (==,! =,>, <,> =, <=), logical operators (!, &&, ||) and so on.
Comparison operations are applicable to those attributes whose target primitives support these operations, i.e. are Equatable and / or Comparable.
Each of the operators calls the corresponding method (eg >
<-> greaterThan
) of the Query entity.
In addition to operator-method pairs, Query
contains methods for text queries (beginsWith
, endsWith
, and contains
) for which there are no built-in operators. And they need to be used directly:
\T.count == 10 || Query.endsWith(\T.name, "foo")
You may have noticed that everywhere attribute keypaths are specified in their full form (with a type) and you cannot omit the type. This was done to help the compiler quickly parse predicate expressions - tradeoff between speed of compilation and verbosity.
Queries in the CoreData are, of course, more complex - for example, aggregate functions of relations (@count), specifying indices (indexed:by:), etc. But in Sworm, type system usage is limited to attributes only. To prevent this limitation from becoming a problem, Sworm allows you to combine raw strings and swift expressions:
\T.id == 4 && !"foo.bars.@count > 0"
Since such queries are used much less often than exclusively attribute queries, this should not be a big problem.
For sorting by attribute to be possible, the target primitive of the attribute must be Comparable. And that's all you need to know about sorting in Sworm.
At the end i will give an example to make the picture very clear:
let query = T
.all
.where(\T.marker === ["a", "d"] || \T.amount > 10 || Query.endsWith(\T.name, "ex"))
.sort(\.name)
.limit(5)
let result = try db.perform { ctx in
try ctx.fetch(query).map { try $0.decode() }
}