GRDB/Documentation.docc/DatabaseConnections.md
Open database connections to SQLite databases.
GRDB provides two classes for accessing SQLite databases: DatabaseQueue and DatabasePool:
import GRDB
// Pick one:
let dbQueue = try DatabaseQueue(path: "/path/to/database.sqlite")
let dbPool = try DatabasePool(path: "/path/to/database.sqlite")
The differences are:
DatabasePool allows concurrent database accesses (this can improve the performance of multithreaded applications).DatabasePool opens your SQLite database in the WAL mode.DatabaseQueue supports doc:DatabaseQueue#In-Memory-Databases.If you are not sure, choose DatabaseQueue. You will always be able to switch to DatabasePool later.
You need a path to a database file in order to open a database connection.
When the SQLite file is ready-made, and you do not intend to modify its content, then add the database file as a resource of your Xcode project or Swift package, and open a read-only database connection:
// HOW TO open a read-only connection to a database resource
// Get the path to the database resource.
// Replace `Bundle.main` with `Bundle.module` when you write a Swift Package.
if let dbPath = Bundle.main.path(forResource: "db", ofType: "sqlite")
if let dbPath {
// If the resource exists, open a read-only connection.
// Writes are disallowed because resources can not be modified.
var config = Configuration()
config.readonly = true
let dbQueue = try DatabaseQueue(path: dbPath, configuration: config)
} else {
// The database resource can not be found.
// Fix your setup, or report the problem to the user.
}
If the application creates or writes in the database, then first choose a proper location for the database file. Document-based applications will let the user pick a location. Apps that use the database as a global storage will prefer the Application Support directory.
Tip: Regardless of the database location, it is recommended that you wrap the database file inside a dedicated directory. This directory will bundle the main database file and its related SQLite temporary files together.
The dedicated directory helps moving or deleting the whole database when needed: just move or delete the directory.
On iOS, the directory can be encrypted with data protection, in order to help securing all database files in one shot. When a database is protected, an application that runs in the background on a locked device won't be able to read or write from it. Instead, it will catch
DatabaseErrorwith codeSQLITE_IOERR(10) "disk I/O error", orSQLITE_AUTH(23) "not authorized".
The sample code below creates or opens a database file inside its dedicated directory. On the first run, a new empty database file is created. On subsequent runs, the directory and database file already exist, so it just opens a connection:
// HOW TO create an empty database, or open an existing database file
// Create the "Application Support/MyDatabase" directory if needed
let fileManager = FileManager.default
let appSupportURL = try fileManager.url(
for: .applicationSupportDirectory, in: .userDomainMask,
appropriateFor: nil, create: true)
let directoryURL = appSupportURL.appendingPathComponent("MyDatabase", isDirectory: true)
try fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true)
// Open or create the database
let databaseURL = directoryURL.appendingPathComponent("db.sqlite")
let dbQueue = try DatabaseQueue(path: databaseURL.path)
Database connections are automatically closed when DatabaseQueue or DatabasePool instances are deinitialized.
If the correct execution of your program depends on precise database closing, perform an explicit call to DatabaseReader/close(). This method may fail and create zombie connections, so please check its detailed documentation.
Once connected to the database, your next steps are probably:
Even if you plan to keep your project mundane and simple, take the time to read the doc:Concurrency guide eventually.
ConfigurationDatabaseQueueDatabasePoolDatabaseSnapshotDatabaseSnapshotPoolDatabaseDatabaseError