Skip to content

pointfreeco/swift-structured-queries

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

56 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

StructuredQueries

CI Slack

A library for building SQL in a safe, expressive, and composable manner.

Learn more

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.

video poster image

Overview

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.

Documentation

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:

Demos

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.

Database drivers

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 includes StructuredQueriesGRDB, 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.

Installation

You can add StructuredQueries to an Xcode project by adding it to your project as a package.

https://github.com/pointfreeco/swift-structured-queries

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"),

Community

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:

License

This library is released under the MIT license. See LICENSE for details.