🐘 Non-blocking, event-driven Swift client for PostgreSQL built on SwiftNIO.
Features:
A PostgresConnection which allows you to connect to, authorize with, query, and retrieve results from a PostgreSQL server
An async/await interface that supports backpressure
Automatic conversions between Swift primitive types and the Postgres wire format
Integrated with the Swift server ecosystem, including use of SwiftLog.
Designed to run efficiently on all supported platforms (tested extensively on Linux and Darwin systems)
Support for Network.framework when available (e.g. on Apple platforms)
Supports running on Unix Domain Sockets
PostgresNIO does not provide a ConnectionPool as of today, but this is a feature high on our list. If you need a ConnectionPool today, please have a look at Vapor’s PostgresKit.
API Docs
Check out the PostgresNIO API docs for a
detailed look at all of the classes, structs, protocols, and more.
Getting started
Adding the dependency
Add PostgresNIO as dependency to your Package.swift:
A connection must be created on a SwiftNIO EventLoop. In most server use cases, an
EventLoopGroup is created at app startup and closed during app shutdown.
import NIOPosix
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
// Much later
try await eventLoopGroup.shutdownGracefully()
import Logging
let logger = Logger(label: "postgres-logger")
Now we can put it together:
import PostgresNIO
import NIOPosix
import Logging
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
let logger = Logger(label: "postgres-logger")
let config = PostgresConnection.Configuration(
host: "localhost",
port: 5432,
username: "my_username",
password: "my_password",
database: "my_database",
tls: .disable
)
let connection = try await PostgresConnection.connect(
on: eventLoopGroup.next(),
configuration: config,
id: 1,
logger: logger
)
// Close your connection once done
try await connection.close()
// Shutdown the EventLoopGroup, once all connections are closed.
try await eventLoopGroup.shutdownGracefully()
Querying
Once a connection is established, queries can be sent to the server. This is very straightforward:
let rows = try await connection.query("SELECT id, username, birthday FROM users", logger: logger)
The query will return a PostgresRowSequence, which is an AsyncSequence of PostgresRows. The rows can be iterated one-by-one:
for try await row in rows {
// do something with the row
}
Decoding from PostgresRow
However, in most cases it is much easier to request a row’s fields as a set of Swift types:
for try await (id, username, birthday) in rows.decode((Int, String, Date).self) {
// do something with the datatypes.
}
A type must implement the PostgresDecodable protocol in order to be decoded from a row. PostgresNIO provides default implementations for most of Swift’s builtin types, as well as some types provided by Foundation:
Bool
Bytes, Data, ByteBuffer
Date
UInt8, Int16, Int32, Int64, Int
Float, Double
String
UUID
Querying with parameters
Sending parameterized queries to the database is also supported (in the coolest way possible):
let id = 1
let username = "fancyuser"
let birthday = Date()
try await connection.query("""
INSERT INTO users (id, username, birthday) VALUES (\(id), \(username), \(birthday))
""",
logger: logger
)
While this looks at first glance like a classic case of SQL injection 😱, PostgresNIO’s API ensures that this usage is safe. The first parameter of the query(_:logger:) method is not a plain String, but a PostgresQuery, which implements Swift’s ExpressibleByStringInterpolation protocol. PostgresNIO uses the literal parts of the provided string as the SQL query and replaces each interpolated value with a parameter binding. Only values which implement the PostgresEncodable protocol may be interpolated in this way. As with PostgresDecodable, PostgresNIO provides default implementations for most common types.
Some queries do not receive any rows from the server (most often INSERT, UPDATE, and DELETE queries with no RETURNING clause, not to mention most DDL queries). To support this, the query(_:logger:) method is marked @discardableResult, so that the compiler does not issue a warning if the return value is not used.
Security
Please see SECURITY.md for details on the security process.
🐘 Non-blocking, event-driven Swift client for PostgreSQL built on SwiftNIO.
Features:
PostgresConnection
which allows you to connect to, authorize with, query, and retrieve results from a PostgreSQL serverNetwork.framework
when available (e.g. on Apple platforms)PostgresNIO does not provide a
ConnectionPool
as of today, but this is a feature high on our list. If you need aConnectionPool
today, please have a look at Vapor’s PostgresKit.API Docs
Check out the PostgresNIO API docs for a detailed look at all of the classes, structs, protocols, and more.
Getting started
Adding the dependency
Add
PostgresNIO
as dependency to yourPackage.swift
:Add
PostgresNIO
to the target you want to use it in:Creating a connection
To create a connection, first create a connection configuration object:
A connection must be created on a SwiftNIO
EventLoop
. In most server use cases, anEventLoopGroup
is created at app startup and closed during app shutdown.A
Logger
is also required.Now we can put it together:
Querying
Once a connection is established, queries can be sent to the server. This is very straightforward:
The query will return a
PostgresRowSequence
, which is an AsyncSequence ofPostgresRow
s. The rows can be iterated one-by-one:Decoding from PostgresRow
However, in most cases it is much easier to request a row’s fields as a set of Swift types:
A type must implement the
PostgresDecodable
protocol in order to be decoded from a row. PostgresNIO provides default implementations for most of Swift’s builtin types, as well as some types provided by Foundation:Bool
Bytes
,Data
,ByteBuffer
Date
UInt8
,Int16
,Int32
,Int64
,Int
Float
,Double
String
UUID
Querying with parameters
Sending parameterized queries to the database is also supported (in the coolest way possible):
While this looks at first glance like a classic case of SQL injection 😱, PostgresNIO’s API ensures that this usage is safe. The first parameter of the
query(_:logger:)
method is not a plainString
, but aPostgresQuery
, which implements Swift’sExpressibleByStringInterpolation
protocol. PostgresNIO uses the literal parts of the provided string as the SQL query and replaces each interpolated value with a parameter binding. Only values which implement thePostgresEncodable
protocol may be interpolated in this way. As withPostgresDecodable
, PostgresNIO provides default implementations for most common types.Some queries do not receive any rows from the server (most often
INSERT
,UPDATE
, andDELETE
queries with noRETURNING
clause, not to mention most DDL queries). To support this, thequery(_:logger:)
method is marked@discardableResult
, so that the compiler does not issue a warning if the return value is not used.Security
Please see SECURITY.md for details on the security process.