Lighter offers two distinct ways to filter records. Choosing the right one depends on whether you prioritize flexibility or performance.
1. Filtering using Swift Closures (Flexible but Slower)
This method uses a Swift closure that receives a fully populated model. It allows for arbitrary Swift code (like complex Unicode normalization), but it is slower because SQLite cannot use indices; the database must fill the full record before filtering.
2. Filtering using SQL Predicates (Fast and Type-safe)
This method uses SQLPredicate to generate real SQL. It is fast because it allows SQLite to use indices. It is also completely type-safe; the compiler will prevent you from comparing incompatible types (e.g., comparing a number to a string).
Comparison Summary
| Feature | Swift Closure | SQL Predicate |
|---|
| Performance | Slower (Full record fetch) | Faster (Uses indices) |
| Flexibility | Highest (Any Swift code) | High (SQL-compatible logic) |
| Type Safety | Standard Swift | Strict SQL-type binding |
// Method 1: Swift Closure (Flexible)
let products = try database.products.filter { product in
product.name.lowercased().contains("e")
}
// Method 2: SQL Predicate (Fast/Type-safe)
let products = try database.products.fetch { product in
product.name.contains("e") && product.age < 10
}