# SQLite Overview Let's dive into the [vapor/sqlite](https://github.com/vapor/sqlite) package and see how to connect to and query a database. !!! warning This documentation provides an overview for the SQLite API. If you are using SQLite with Fluent, you will likely never need to use this API. Use [Fluent's APIs](../../fluent/getting-started/getting-started.md) instead. Follow the instructions in the [package](getting-started.md) section to add the SQLite package to your project. Once its added, you should be able to use `import SQLite.` ## Database The first step to making a query is to create a `Database`. ### In Memory In-memory SQLite databases are great for testing as they aren't persisted between application boots. ```swift import SQLite let db = Database(storage: .memory) ``` ### File path SQLite requires a single file to persist the database contents. ```swift import SQLite let db = Database(storage: .file(path: "/tmp/db.sqlite")) ``` !!! tip If the database file does not already exist, it will be created. ## Connection Once you have initialized your database, you can create a connection. ```swift let conn = try db.makeConnection(on: .global()) ``` !!! note Pay special attention to which `DispatchQueue` you pass to `makeConnection(on:)`. This will be the queue SQLite calls you back on. !!! tip If you are using SQLite with Vapor, make sure to pass the [EventLoop](../../async/eventloop.md) here. ## Query Once you have a `Connection`, you can use it to create a `Query`. ```swift let query = conn.query("SELECT * FROM users") ``` ### Binding Values If you are executing a query that has input values, you should bind these using parameters. ```swift let query = conn.query("INSERT INTO users (name, age) VALUES (?, ?)") query.bind("Albert") query.bind(138) ``` You can also bind values using method chaining. ```swift let query = conn.query("INSERT INTO users (name, age) VALUES (?, ?)") .bind("Albert") .bind(138) ``` ### Output Stream If you expect output from your query, you must attach a stream. The easiest way to do this is by using the `drain` convenience. ```swift query.drain { row in print(row) } ``` You can also use `drain(into:)` and pass in a custom `InputStream` to capture the query's results. #### Row The `Query` will output `Row`s. These are simple structs. ```swift struct Row { var fields: [String: Field] subscript(field: String) -> Data? { get } } ``` You can subscript a `Row` object to get the optional `Data`. ```swift let nameData = row["name"] // Data? ``` `Data` is an enum that contains all possible types of SQLite data. ```swift public enum Data { case integer(Int) case float(Double) case text(String) case blob(Foundation.Data) case null } ``` For each option, there are convenience properties for casting the `Data` enum. ```swift let name = row["name"]?.text // String ``` ### Run Once your query is ready to execute, you simply call `.execute()`. This returns a `Future` that will be completed when the query is done executing. ```swift query.execute().then { print("done!") } ``` #### All If you simply want to fetch all of the results, you can use the `.all()` convenience. This will automatically create a stream and return a future containing your results. ```swift query.all().then { rows in print(rows) } ``` #### Sync For situations where blocking is appropriate (perhaps in tests) you can use `.sync()` to block until the query's results are ready and return them directly. ```swift // don't do this unless blocking is OK let rows = try conn.query("SELECT * FROM users").sync() ``` ### Example Now for the complete example: ```swift import SQLite let db = Database(storage: .memory) let conn = try db.makeConnection(on: .global()) // take care to use correct queue conn.query("SELECT * FROM users") .all() .then { rows in print(rows) } .catch { err in print(err) } // wait for results ``` An example with values being bound: ```swift import SQLite let db = Database(storage: .memory) let conn = try db.makeConnection(on: .global()) // take care to use correct queue conn.query("INSERT INTO users (name, age) VALUES (?, ?)") .bind("Albert") .bind(138) .execute() .then { print("done") } .catch { err in print(err) } // wait for results ```