3.7 KiB
MySQL Basics
This guide assumes you've set up MySQL and are connected to MySQL using a connection pool as described in the getting started guide.
Type safety
The MySQL driver is written to embrace type-safety and Codable. We currently only expose Codable based results.
Queries
Queries are any type conforming to the protocol Query, which requires being convertible to a String.
String is a Query by default.
You can receive results from Queries in 4 kinds of formats.
- Stream
- Future
- forEach
- Future
All examples assume the following model:
struct User: Codable {
var username: String
var passwordHash: String
var age: Int
}
Futures
Futures are often easier to use but significantly heavier on your memory and thus performance. They are thoroughly described here
Querying a database for a future is achieved through the all function and requires specifying the Decodable type that the results need to be deserialized into.
// Future<[User]>
let users = connection.all(User.self, in: "SELECT * FROM users")
For partial results (SELECT username, age FROM) it is recommended to create a second decodable struct specifically for this query to ensure correctness and type-safety.
struct UserLoginDetails: Codable {
var username: String
var age: Int
}
Streams
Streams, as described on this page, are a source of information that calls a single reader's callback. Streams are best used in larger datasets to prevent the query from consuming a large amount of memory. The downside of a stream is that you cannot return all results in a single future. You'll need to stream the results to the other endpoint, too. For HTTP this is described here.
Querying a database for a stream of results is achieved through the stream function and requires specifying the Decodable type that the results need to be deserialized into.
try connection.stream(User.self, in: "SELECT * FROM users", to: inputStream)
This will put all Users into the inputStream. This requires inputStream to be an InputStream accepting User as Input.
ForEach
If you don't need to stream complex results to a third party such as using an HTTP Response you can use forEach. This is particularly useful for asynchronous actions such as sending a lot of email to the results of a query without depending on the completion/success of one email for the next email.
connection.forEach(User.self, in: "SELECT * FROM users") { user in
print(user.username)
}
forEach returns a future that you can optionally capture. It will be completed when all users have been processed.
let completed = connection.forEach(User.self, in: "SELECT * FROM users") { user in
print(user.username)
}
completed.do {
print("All users printed")
}.catch { error in
print("An error occurred while printing the users: \(error)")
}
Single column rows
When the query returns only one column, you can decode resulting rows as a single value.
let usernames = connection.all(String.self, in: "SELECT username FROM users") // Future<[String]>
Resultless queries
Some queries (mostly administrative queries) do not require/return a response. Instead, they only indicate success or error.
You can execute these queries using the administrativeQuery command.
connection.administrativeQuery("DROP TABLE users")
You can handle success or response using the returned future.
connection.administrativeQuery("DROP TABLE users").then {
print("success")
}.catch {
print("failure")
}