• Stars
    star
    239
  • Rank 168,763 (Top 4 %)
  • Language
    Swift
  • License
    MIT License
  • Created over 6 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

*️⃣ Build SQL queries in Swift. Extensible, protocol-based design that supports DQL, DML, and DDL.

SQLKit

Documentation Team Chat MIT License Continuous Integration Swift 5.6


Build SQL queries in Swift. Extensible, protocol-based design that supports DQL, DML, and DDL.

Using SQLKit

Use standard SwiftPM syntax to include SQLKit as a dependency in your Package.swift file.

.package(url: "https://github.com/vapor/sql-kit.git", from: "3.0.0")

SQLKit 3.x requires SwiftNIO 2.x or later. Previous major versions are no longer supported.

Supported Platforms

SQLKit supports the following platforms:

  • Ubuntu 20.04+
  • macOS 10.15+
  • iOS 13+
  • tvOS 13+ and watchOS 7+ (experimental)

Overview

SQLKit is an API for building and serializing SQL queries in Swift. SQLKit attempts to abstract away SQL dialect inconsistencies where possible allowing you to write queries that can run on multiple database flavors. Where abstraction is not possible, SQLKit provides powerful APIs for custom or dynamic behavior.

Supported Databases

These database packages are drivers for SQLKit:

Configuration

SQLKit does not deal with creating or managing database connections itself. This package is focused entirely around building and serializing SQL queries. To connect to your SQL database, refer to your specific database package's documentation. Once you are connected to your database and have an instance of SQLDatabase, you are ready to continue.

Database

Instances of SQLDatabase are capable of serializing and executing SQLExpression.

let db: any SQLDatabase = ...
db.execute(sql: any SQLExpression, onRow: (any SQLRow) -> ())

SQLExpression is a protocol that represents a SQL query string and optional bind values. It can represent an entire SQL query or just a fragment.

SQLKit provides SQLExpressions for common queries like SELECT, UPDATE, INSERT, DELETE, CREATE TABLE, and many more.

var select = SQLSelect()
select.columns = [...]
select.tables = [...]
select.predicate = ...

SQLDatabase can be used to create fluent query builders for most of these query types.

struct Planet: Codable { var id: Int, name: String }

let db: some SQLDatabase = ...
try await db.create(table: "planets")
    .column("id", type: .int, .primaryKey(autoIncrement: true), .notNull)
    .column("name", type: .string, .notNull)
    .run()
try await db.insert(into: "planets")
    .columns("id", "name")
    .values(SQLLiteral.default, SQLBind("Earth"))
    .values(SQLLiteral.default, SQLBind("Mars"))
    .run()
let planets = try await db.select()
    .columns("id", "name")
    .from("planets")
    .all(decoding: Planet.self)
print(planets) // [Planet(id: 1, name: "Earth"), Planet(id: 2, name: "Mars")]

You can execute a query builder by calling run().

Rows

For query builders that support returning results (e.g. any builder conforming to the SQLQueryFetcher protocol), there are additional methods for handling the database output:

  • all(): Returns an array of rows.
  • first(): Returns an optional row.
  • run(_:): Accepts a closure that handles rows as they are returned.

Each of these methods returns SQLRow, which has methods for access column values.

let row: any SQLRow
let name = try row.decode(column: "name", as: String.self)
print(name) // String

Codable

SQLRow also supports decoding Codable models directly from a row.

struct Planet: Codable {
    var name: String
}

let planet = try row.decode(model: Planet.self)

Query builders that support returning results have convenience methods for automatically decoding models.

let planets: [Planet] = try await db.select()
    ...
    .all(decoding: Planet.self)

Select

The SQLDatabase.select() method creates a SELECT query builder:

let planets: [any SQLRow] = try await db.select()
    .columns("id", "name")
    .from("planets")
    .where("name", .equal, "Earth")
    .all()

This code generates the following SQL when used with the PostgresKit driver:

SELECT "id", "name" FROM "planets" WHERE "name" = $1 -- bindings: ["Earth"]

Notice that Encodable values are automatically bound as parameters instead of being serialized directly to the query.

The select builder includes the following methods (typically with several variations):

  • columns() (specify a list of columns and/or expressions to return)
  • from() (specify a table to select from)
  • join() (specify additional tables and how to relate them to others)
  • where() and orWhere() (specify conditions that narrow down the possible results)
  • limit() and offset() (specify a limited and/or offsetted range of results to return)
  • orderBy() (specify how to sort results before returning them)
  • groupBy() (specify columns and/or expressions for aggregating results)
  • having() and orHaving() (specify secondary conditions to apply to the results after aggregation)
  • distinct() (specify coalescing of duplicate results)
  • for() and lockingClause() (specify locking behavior for rows that appear in results)

Conditional expressions provided to where() or having() are joined with AND. Corresponding orWhere() and orHaving() methods join conditions with OR instead.

builder.where("name", .equal, "Earth").orWhere("name", .equal, "Mars")

This code generates the following SQL when used with the MySQL driver:

WHERE `name` = ? OR `name` = ? -- bindings: ["Earth", "Mars"]

where(), orWhere(), having(), and orHaving() also support creating grouped clauses:

builder.where("name", .notEqual, SQLLiteral.null).where {
    $0.where("name", .equal, SQLBind("Milky Way"))
      .orWhere("name", .equal, SQLBind("Andromeda"))
}

This code generates the following SQL when used with the SQLite driver:

WHERE "name" <> NULL AND ("name" = ?1 OR "name" = ?2) -- bindings: ["Milky Way", "Andromeda"]

Insert

The insert(into:) method creates an INSERT query builder:

try await db.insert(into: "galaxies")
    .columns("id", "name")
    .values(SQLLiteral.default, SQLBind("Milky Way"))
    .values(SQLLiteral.default, SQLBind("Andromeda"))
    .run()

This code generates the following SQL when used with the PostgreSQL driver:

INSERT INTO "galaxies" ("id", "name") VALUES (DEFAULT, $1), (DEFAULT, $2) -- bindings: ["Milky Way", "Andromeda"]

The insert builder also has a method for encoding a Codable type as a set of values:

struct Galaxy: Codable {
    var name: String
}

try builder.model(Galaxy(name: "Milky Way"))

This code generates the same SQL as would builder.columns("name").values("Milky Way").

Update

The update(_:) method creates an UPDATE query builder:

try await db.update("planets")
    .set("name", to: "Jupiter")
    .where("name", .equal, "Jupiter")
    .run()

This code generates the following SQL when used with the MySQL driver:

UPDATE `planets` SET `name` = ? WHERE `name` = ? -- bindings: ["Jupiter", "Jupiter"]

The update builder supports the same where() and orWhere() methods as the select builder, via the SQLPredicateBuilder protocol.

Delete

The delete(from:) method creates a DELETE query builder:

try await db.delete(from: "planets")
    .where("name", .equal, "Jupiter")
    .run()

This code generates the following SQL when used with the SQLite driver:

DELETE FROM "planets" WHERE "name" = ?1 -- bindings: ["Jupiter"]

The delete builder is also an SQLPredicateBuilder.

Raw

The raw(_:) method allows passing custom SQL query strings, with support for parameterized bindings and correctly-quoted identifiers:

let planets = try await db.raw("SELECT \(SQLLiteral.all) FROM \(ident: table) WHERE \(ident: name) = \(bind: "planet")")
    .all()

This code generates the following SQL when used with the PostgreSQL driver:

SELECT * FROM "planets" WHERE "name" = $1 -- bindings: ["planet"]

The \(bind:) interpolation should be used for any user input to avoid SQL injection. The \(ident:) interpolation is used to safely specify identifiers such as table and column names.

⚠️ **Important!**⚠️

Always prefer a structured query (i.e. one for which a builder or expression type exists) over raw queries. Consider writing your own SQLExpressions, and even your own SQLQueryBuilders, rather than using raw queries, and don't hesitate to open an issue to ask for additional feature support.

More Repositories

1

vapor

💧 A server-side Swift HTTP web framework.
Swift
24,188
star
2

fluent

Vapor ORM (queries, models, and relations) for NoSQL and SQL databases
Swift
1,308
star
3

redis

Vapor provider for RediStack
Swift
458
star
4

console-kit

💻 APIs for creating interactive CLI tools.
Swift
456
star
5

leaf

🍃 An expressive, performant, and extensible templating language built for Swift.
Swift
432
star
6

postgres-nio

🐘 Non-blocking, event-driven Swift client for PostgreSQL.
Swift
325
star
7

jwt

Vapor JWT provider
Swift
317
star
8

docs

📖 Documentation markdown for all Vapor packages.
Swift
316
star
9

toolbox

Simplifies common command line tasks when using Vapor
Swift
283
star
10

websocket-kit

WebSocket client library built on SwiftNIO
Swift
272
star
11

http

🚀 Non-blocking, event-driven HTTP built on Swift NIO.
Swift
238
star
12

mysql-kit

🐬 Pure Swift MySQL client built on non-blocking, event-driven sockets.
Swift
222
star
13

fluent-kit

Swift ORM (queries, models, and relations) for NoSQL and SQL databases
Swift
206
star
14

postgres-kit

🐘 Non-blocking, event-driven Swift client for PostgreSQL.
Swift
187
star
15

jwt-kit

🔑 JSON Web Token (JWT) signing and verification (HMAC, ECDSA, EdDSA, RSA, PSS) with support for JWS and JWK
Swift
180
star
16

queues

A queue system for Vapor.
Swift
163
star
17

fluent-postgres-driver

🐘 PostgreSQL driver for Fluent.
Swift
145
star
18

api-template

💧 A starting point for Vapor APIs.
Swift
135
star
19

open-crypto

🔑 Hashing (BCrypt, SHA2, HMAC), encryption (AES), public-key (RSA), and random data generation.
Swift
134
star
20

multipart-kit

🏞 Parses and serializes multipart-encoded data with Codable support.
Swift
132
star
21

routing-kit

🚍 High-performance trie-node router.
Swift
122
star
22

apns

Helpful extensions and abstractions for using APNSwift
Swift
115
star
23

mysql-nio

🐬 Non-blocking, event-driven Swift client for MySQL.
Swift
88
star
24

service

📦 Dependency injection / inversion of control framework.
Swift
85
star
25

core

🌎 Utility package containing tools for byte manipulation, Codable, OS APIs, and debugging.
Swift
80
star
26

fluent-mysql-driver

🖋🐬 Swift ORM (queries, models, relations, etc) built on MySQL.
Swift
76
star
27

async-kit

Sugary extensions for the SwiftNIO library
Swift
71
star
28

template

Used by Vapor Toolbox’s new project command
Swift
70
star
29

fluent-sqlite-driver

Fluent driver for SQLite
Swift
67
star
30

sqlite-kit

Non-blocking SQLite client library with SQL builder built on SwiftNIO
Swift
58
star
31

sqlite-nio

Non-blocking wrapper for libsqlite3-dev using SwiftNIO
C
58
star
32

validation

✅ Extensible data validation library (name, email, etc)
Swift
56
star
33

auth

👤 Authentication and Authorization framework for Fluent.
Swift
53
star
34

leaf-kit

🍃 An expressive, performant, and extensible templating language built for Swift.
Swift
47
star
35

template-kit

📄 Easy-to-use foundation for building powerful templating languages in Swift.
Swift
45
star
36

website

Vapor's website running on Swift
Swift
45
star
37

docs-cn

🇨🇳 Chinese translation of Vapor's documentation markdown.
HTML
43
star
38

web-template

A starting point for web applications
Swift
41
star
39

url-encoded-form

📝 Parse and serialize url-encoded form data with Codable support.
Swift
41
star
40

database-kit

🗄 Core services for creating database integrations.
Swift
40
star
41

auth-template

A starting point for Vapor applications using the auth provider.
Swift
35
star
42

university

Web application, iOS app, and API providing access to tutorials for the Vapor web framework.
Swift
24
star
43

fluent-mongo-driver

MongoDB support for Fluent built on MongoKittten.
Swift
24
star
44

queues-redis-driver

A Redis implementation for https://github.com/vapor/queues
Swift
22
star
45

design

Contains the reference designs and build pipeline to generate all design files for Vapor's sites
Swift
22
star
46

email

A common API for Vapor to integrate with different email providers
Swift
20
star
47

codable-kit

Conveniences for working with Swift's Codable protocols.
Swift
19
star
48

kafka

Swift Apacha Kafka (real-time data pipelines and streaming apps)
Swift
19
star
49

apt

Manage Vapor's Swift APT repository
Shell
17
star
50

blog

The Vapor Blog
Swift
16
star
51

penny-bot

The code that runs Penny 🤖
Swift
15
star
52

template-bare

A barebones template ready for use
Swift
12
star
53

docker

Swift
12
star
54

api-docs

Scripts and assets for Vapor's API documentation site at https://api.vapor.codes
Swift
11
star
55

redis-kit

Helpful extensions and abstractions for using RediStack
Swift
8
star
56

swift-getting-started-web-server

The source code for the Getting Started Guide on Vapor on swift.org
Swift
7
star
57

homebrew-tap

Homebrew Taps
Ruby
7
star
58

template-fluent-postgres

A template ready for use configured with Fluent and PostgreSQL
Swift
6
star
59

release-bot

Webhook-based GitHub bot that automatically tags new releases and posts to Discord when you merge PRs
Swift
6
star
60

ci

Support files and configurations for Vapor's CI
Swift
5
star
61

bot-github

A github bot to do things like interact with CI for the Vapor organization
Swift
5
star
62

template-fluent-postgres-leaf

A template ready for use configured with Leaf, Fluent and PostgreSQL
Swift
4
star
63

swiftly-action

Simple one-step access to the Swiftly toolchain manager from GitHub Actions workflows
3
star
64

swift-codecov-action

A GitHub Action which performs Codecov.io uploads with additional support for Swift projects
Swift
3
star
65

template-fluent-mysql

A template ready for use configured with Fluent and MySQL
Swift
2
star
66

docs-de

Deutsche Übersetzung der Vapor-Dokumentation
HTML
1
star