A library for building SQL in a safe, expressive, and composable manner.
This library was motivated and designed over the course of many episodes on Point-Free, a video series exploring advanced programming topics in the Swift language, hosted by Brandon Williams and Stephen Celis. To support the continued development of this library, subscribe today.
StructuredQueries provides a suite of tools that empower you to write safe, expressive, composable SQL with Swift. By simply attaching macros to types that represent your database schema:
@Table
struct Reminder {
let id: Int
var title = ""
var isCompleted = false
var priority: Int?
var dueDate: Date?
}
You get instant access to a rich set of query building APIs, from simple:
Swift | SQL |
---|---|
Reminder.all
// => [Reminder] |
SELECT
"reminders"."id",
"reminders"."title",
"reminders"."isCompleted",
"reminders"."priority",
"reminders"."dueDate"
FROM "reminders" |
To complex:
Swift | SQL |
---|---|
Reminder
.select {
($0.priority,
$0.title.groupConcat())
}
.where { !$0.isCompleted }
.group(by: \.priority)
.order { $0.priority.desc() }
// => [(Int?, String)] |
SELECT
"reminders"."priority",
group_concat("reminders"."title")
FROM "reminders"
WHERE (NOT "reminders"."isCompleted")
GROUP BY "reminders"."priority"
ORDER BY "reminders"."priority" DESC |
These APIs help you avoid runtime issues caused by typos and type errors, but they still embrace SQL for what it is. StructuredQueries is not an ORM or a new query language you have to learn: its APIs are designed to read closely to the SQL it generates, though they are often more succinct, and always safer.
You are also never constrained by the query builder. You are free to introduce safe SQL strings at
the granularity of your choice using the #sql
macro. From small expressions:
Reminder.where {
!$0.isCompleted && #sql("\($0.dueDate) < date()")
}
To entire statements:
#sql(
"""
SELECT \(Reminder.columns) FROM \(Reminder.self)
WHERE \(Reminder.priority) >= \(selectedPriority)
""",
as: Reminder.self
)
The library supports building everything from SELECT
, INSERT
, UPDATE
, and DELETE
statements,
to type-safe outer joins and recursive common table expressions. To learn more about building SQL
with StructuredQueries, check out the
documentation.
Important
This library does not come with any database drivers for making actual database requests, e.g., to SQLite, Postgres, MySQL. This library focuses only on building SQL statements and providing the tools to integrate with another library that makes the actual database requests. See Database drivers for more information.
The documentation for the latest unstable and stable releases are available here:
There are a number of articles in the documentation that you may find helpful as you become more comfortable with the library:
As well as more comprehensive example usage:
- Selects
- Inserts
- Updates
- Deletes
- "Where" clauses
- Common table expressions
- Aggregate functions
- Operators
- Scalar functions
There are a number of sample applications that demonstrate how to use StructuredQueries in the SharingGRDB repo. Check out this directory to see them all, including:
-
Case Studies: A number of case studies demonstrating the built-in features of the library.
-
Reminders: A rebuild of Apple's Reminders app that uses a SQLite database to model the reminders, lists and tags. It features many advanced queries, such as searching, and stats aggregation.
-
SyncUps: We also rebuilt Apple's Scrumdinger demo application using modern, best practices for SwiftUI development, including using this library to query and persist state using SQLite.
StructuredQueries is built with the goal of supporting any SQL database (SQLite, MySQL, Postgres, etc.), but is currently tuned to work with SQLite. It currently has one official driver:
- SharingGRDB: A lightweight replacement for
SwiftData and the
@Query
macro. SharingGRDB includesStructuredQueriesGRDB
, a library that integrates this one with the popular GRDB SQLite library.
If you are interested in building a StructuredQueries integration for another database library, please see Integrating with database libraries, and start a discussion to let us know of any challenges you encounter.
You can add StructuredQueries to an Xcode project by adding it to your project as a package.
If you want to use StructuredQueries in a SwiftPM project,
it's as simple as adding it to your Package.swift
:
dependencies: [
.package(url: "https://github.com/pointfreeco/swift-structured-queries", from: "0.4.0"),
]
And then adding the product to any target that needs access to the library:
.product(name: "StructuredQueries", package: "swift-structured-queries"),
If you want to discuss this library or have a question about how to use it to solve a particular problem, there are a number of places you can discuss with fellow Point-Free enthusiasts:
-
For long-form discussions, we recommend the discussions tab of this repo.
-
For casual chat, we recommend the Point-Free Community Slack.
This library is released under the MIT license. See LICENSE for details.