mirror of https://github.com/vapor/docs.git
242 lines
6.5 KiB
Markdown
242 lines
6.5 KiB
Markdown
# Database
|
|
|
|
A Fluent database is responsible for managing connections to your underlying data store and sending queries to the implementation-specific driver you have chosen.
|
|
|
|
## Drivers
|
|
|
|
By default, Fluent includes in-memory and SQLite drivers. There are several drivers available to add to your Vapor application.
|
|
|
|
### Available
|
|
|
|
| Type | Key | Package | Class | Official |
|
|
|------------|------------|------------------------------------------------------------------------------|-------------------------|----------|
|
|
| Memory | memory | [Fluent Provider](../fluent/package.md) | Fluent.MemoryDriver | Yes |
|
|
| SQlite | sqlite | [Fluent Provider](../fluent/package.md) | Fluent.SQLiteDriver | Yes |
|
|
| MySQL | mysql | [MySQLProvider](../mysql/package.md) | MySQLDriver.Driver | Yes |
|
|
| PostgreSQL | postgresql | [PostgreSQLProvider](https://github.com/vapor-community/postgresql-provider) | PostgreSQLDriver.Driver | No |
|
|
| MongoDB | N/A | [MongoProvider](https://github.com/vapor-community/mongo-provider) | N/A | No |
|
|
|
|
Click on the provider package for more information about how to use it.
|
|
|
|
You can search for a list of available [Vapor database providers](https://github.com/search?utf8=✓&q=topic%3Avapor-provider+topic%3Adatabase&type=Repositories) on GitHub.
|
|
|
|
## Droplet
|
|
|
|
You can access the database from the Droplet.
|
|
|
|
```swift
|
|
drop.database // Database?
|
|
```
|
|
|
|
## Preparations
|
|
|
|
Most databases, like SQL databases, require the schema for a model to be created before it is stored.
|
|
Adding a preparation to your model will allow you to prepare the database while your app boots.
|
|
|
|
```swift
|
|
extension User: Preparation {
|
|
/// Prepares a table/collection in the database
|
|
/// for storing Users
|
|
static func prepare(_ database: Database) throws {
|
|
try database.create(self) { builder in
|
|
builder.id()
|
|
builder.string("name")
|
|
builder.int("age")
|
|
}
|
|
}
|
|
|
|
/// Undoes what was done in `prepare`
|
|
static func revert(_ database: Database) throws {
|
|
try database.delete(self)
|
|
}
|
|
}
|
|
```
|
|
|
|
The above prepare statement results in SQL similar to the following:
|
|
|
|
```sql
|
|
CREATE TABLE `users` (`id` INTEGER PRIMARY KEY NOT NULL, `name` TEXT NOT NULL, `age` INTEGER NOT NULL)
|
|
```
|
|
|
|
Once you have created you preparation, add it to the Config's prepratations array.
|
|
|
|
```swift
|
|
config.preparations.append(User.self)
|
|
```
|
|
|
|
### Create
|
|
|
|
The following methods are available on while creating and modifing the database.
|
|
|
|
| Method | Type |
|
|
|-----------|--------------------|
|
|
| id | Primary Identifier |
|
|
| foreignId | Foreign Identifier |
|
|
| int | Integer |
|
|
| string | String |
|
|
| double | Double |
|
|
| bool | Boolean |
|
|
| bytes | Data |
|
|
| date | Date + Time |
|
|
|
|
You can use any of these methods on a builder inside `.create()`.
|
|
|
|
```swift
|
|
try database.create(self) { builder in
|
|
builder.double("latitude")
|
|
builder.double("longitude")
|
|
}
|
|
```
|
|
|
|
### Foreign Keys
|
|
|
|
Foreign keys are automatically added with `.foreignId()`. To add a foreign key manually, use the
|
|
`.foreignKey` method.
|
|
|
|
```swift
|
|
try database.create(self) { builder in
|
|
builder.foreignKey("user_id", references: "id", on: User.self)
|
|
}
|
|
```
|
|
|
|
To disable automatic foreign keys, set `autoForeignKeys` to false in the `Config/fluent.json` file.
|
|
|
|
```json
|
|
{
|
|
"autoForeignKeys": false
|
|
}
|
|
|
|
```
|
|
|
|
### Modifier
|
|
|
|
Existing schema can be modified using the `.modify()` property. All of the methods from `.create()`
|
|
are available here as well.
|
|
|
|
```swift
|
|
try database.modify(self) { builder in
|
|
builder.string("name")
|
|
builder.delete("age")
|
|
}
|
|
```
|
|
|
|
### Migrations
|
|
|
|
Other times, you may want to make some modifications to your data set while migrating to a new version or
|
|
just performing general cleanup.
|
|
|
|
```swift
|
|
struct DeleteOldEntries: Preparation {
|
|
static func prepare(_ database: Database) throws {
|
|
try Log.makeQuery().filter(...).delete()
|
|
}
|
|
|
|
...
|
|
}
|
|
```
|
|
|
|
### Run
|
|
|
|
Your preparations will run every time you run your application. You can run your preparations without booting
|
|
your server by calling:
|
|
|
|
|
|
```sh
|
|
vapor run prepare
|
|
```
|
|
|
|
### Revert
|
|
|
|
Use the revert method to undo any work you did in the prepare method.
|
|
|
|
```swift
|
|
extension User: Preparation {
|
|
...
|
|
|
|
|
|
static func revert(_ database: Database) throws {
|
|
try database.delete(self)
|
|
}
|
|
}
|
|
```
|
|
|
|
You can run the reversions by calling:
|
|
|
|
```
|
|
vapor run prepare --revert
|
|
```
|
|
|
|
This will revert the latest batch of preparations. To revert the entire database, run the following:
|
|
|
|
```
|
|
vapor run prepare --revert --all
|
|
```
|
|
|
|
## Log
|
|
|
|
Logging queries is a great way to find optimizations for your application and track down bugs.
|
|
|
|
The easiest way to log queries is to enable logging in your `fluent.json` file.
|
|
|
|
`Config/fluent.json`
|
|
```json
|
|
{
|
|
...,
|
|
"log": true,
|
|
...
|
|
}
|
|
```
|
|
|
|
This will emit info-level logs for all database queries.
|
|
|
|
### Custom
|
|
|
|
You can also hook into the database's query logging callback to execute custom logic.
|
|
|
|
```swift
|
|
drop.database?.log = { query in
|
|
print(query)
|
|
}
|
|
```
|
|
|
|
You can assign a closure to the `log` property on the database. Any time a query is run, the closure
|
|
will be called with a `QueryLog` object containing a string describing the statement and the time it ran.
|
|
|
|
## Transactions
|
|
|
|
Transactions allow you to group multiple queries into one single unit of work. If any one of the
|
|
queries experiences a problem, the entire transaction will be rolled back.
|
|
|
|
```swift
|
|
drop.database?.transaction { conn in
|
|
try user.pets.makeQuery(conn).delete()
|
|
try user.makeQuery(conn).delete()
|
|
}
|
|
```
|
|
|
|
Drivers that do not support transactions will throw an error if this method is called.
|
|
|
|
You can use the `.makeQuery(_: Executor)` method to create queries that will run on the
|
|
connection supplied to the closure.
|
|
|
|
!!! warning
|
|
You must use the connection supplied to the closure for queries you want to include
|
|
in the transaction.
|
|
|
|
|
|
## Indexes
|
|
|
|
An index is a copy of selected columns of data from a table that can be searched very efficiently.
|
|
|
|
You can add them to your database by calling `.index()`
|
|
|
|
```swift
|
|
try database.index("name", for: User.self)
|
|
```
|
|
|
|
You can delete them by calling `.deleteIndex()`
|
|
|
|
```swift
|
|
try database.deleteIndex("name", for: User.self)
|
|
```
|