mirror of https://github.com/vapor/docs.git
add concrete links to fluent docs
This commit is contained in:
parent
dca1117b0d
commit
9fdd6d0cd1
|
|
@ -53,7 +53,7 @@ vapor xcode
|
|||
|
||||
Now let's create your first model. Models represent tables in your database and they are the primary method of interacting with your data.
|
||||
|
||||
Each driver provides convenience model protocols (`PostgreSQLModel`, `SQLiteModel`, etc) that extend Fluent's base [`Model`](#fixme) protocol. These convenience types make declaring models more concise by using standard values for ID key and type.
|
||||
Each driver provides convenience model protocols (`PostgreSQLModel`, `SQLiteModel`, etc) that extend Fluent's base [`Model`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html) protocol. These convenience types make declaring models more concise by using standard values for ID key and type.
|
||||
|
||||
Fill in the Xcode placeholders below with the name of your chosen database, i.e., `PostgreSQL`.
|
||||
|
||||
|
|
@ -111,12 +111,15 @@ If you are using default configuration for your database (such as default creden
|
|||
|
||||
See the documentation for your specific database type for more information about custom configuration.
|
||||
|
||||
!!! danger
|
||||
fixme: Add links to config structs.
|
||||
|database|docs|api docs|
|
||||
|-|-|-|
|
||||
|PostgreSQL|[PostgreSQL → Getting Started](../postgresql/getting-started.md)|_Coming soon_|
|
||||
|MySQL|[MySQL → Getting Started](../mysql/getting-started.md)|_Coming soon_|
|
||||
|SQLite|[SQLite → Getting Started](../sqlite/getting-started.md)|[`SQLiteDatabase`](https://api.vapor.codes/sqlite/latest/SQLite/Classes/SQLiteDatabase.html)|
|
||||
|
||||
## Creating a Migration
|
||||
|
||||
If your database driver uses schemas (is a SQL database), you will need to create a [`Migration`](#fixme) for your new model. Migrations allow Fluent to create a table for your model in a reliable, testable way. You can later create additional migrations to update or delete the model's table or even manipulate data in the table.
|
||||
If your database driver uses schemas (is a SQL database), you will need to create a [`Migration`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Migration.html) for your new model. Migrations allow Fluent to create a table for your model in a reliable, testable way. You can later create additional migrations to update or delete the model's table or even manipulate data in the table.
|
||||
|
||||
To create a migration, you will normally first create a new struct or class to hold the migration. However, models can take advantage of a convenient shortcut. When you create a migration from an existing model type, Fluent can infer an appropriate schema from the model's codable properties.
|
||||
|
||||
|
|
@ -133,7 +136,7 @@ Take a look at [Fluent → Migration](../fluent/migrations.md) if you are int
|
|||
|
||||
### Configuring Migrations
|
||||
|
||||
Once you have created a migration, you must register it to Fluent using [`MigrationConfig`](#fixme). This is done in [`configure.swift`](../getting-started/structure.md#configureswift).
|
||||
Once you have created a migration, you must register it to Fluent using [`MigrationConfig`](https://api.vapor.codes/fluent/latest/Fluent/Structs/MigrationConfig.html). This is done in [`configure.swift`](../getting-started/structure.md#configureswift).
|
||||
|
||||
Fill in the database ID (`dbid`) from the table above, i.e., `psql`.
|
||||
|
||||
|
|
@ -150,7 +153,7 @@ services.register(migrations)
|
|||
```
|
||||
|
||||
!!! tip
|
||||
If the migration you are adding is also a model, you can use the [`add(model:on:)`](#fixme) convenience to automatically set the model's [`defaultDatabase`](#fixme) property. Otherwise, use the [`add(migration:on)`](#fixme) method.
|
||||
If the migration you are adding is also a model, you can use the [`add(model:on:)`](https://api.vapor.codes/fluent/latest/Fluent/Structs/MigrationConfig.html#/s:6Fluent15MigrationConfigV3add5model8databaseyxm_11DatabaseKit0G10IdentifierVy0G0AA0B0PQzGtAaKRzAA5ModelRzAjaOPQzAMRSlF) convenience to automatically set the model's [`defaultDatabase`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE15defaultDatabase0D3Kit0D10IdentifierVy0D0QzGSgvpZ) property. Otherwise, use the [`add(migration:on)`](https://api.vapor.codes/fluent/latest/Fluent/Structs/MigrationConfig.html#/s:6Fluent15MigrationConfigV3add9migration8databaseyxm_11DatabaseKit0G10IdentifierVy0G0QzGtAA0B0RzlF) method.
|
||||
|
||||
Once you have the `MigrationConfig` added, you should be able to run your application and see the following:
|
||||
|
||||
|
|
@ -176,7 +179,7 @@ If you run your app, and query that route, you should see an empty array returne
|
|||
|
||||
With Fluent, you always have access to the underlying database driver. Using this underlying driver to perform a query is sometimes called a "raw query".
|
||||
|
||||
To perform raw queries, you need access to a database connection. Vapor's [`Request`](#fixme) type has a number of conveniences for creating new database connections. The recommended method is `withPooledConnection(to:)`. Learn about other methods in [DatabaseKit → Overview → Connections](../database-kit/overview/#connections).
|
||||
To perform raw queries, you need access to a database connection. Vapor's [`Request`](https://api.vapor.codes/vapor/latest/Vapor/Classes/Request.html) type has a number of conveniences for creating new database connections. The recommended method is `withPooledConnection(to:)`. Learn about other methods in [DatabaseKit → Overview → Connections](../database-kit/overview/#connections).
|
||||
|
||||
```swift
|
||||
router.get("raw") { req -> Future<String> in
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ struct Galaxy: <#Database#>Model {
|
|||
|
||||
### Automatic Model Migrations
|
||||
|
||||
Models provide a shortcut for declaring database migrations. If you conform a type that conforms to [`Model`](#fixme) to [`Migration`](#fixme), Fluent can infer the model's properties and automatically implement the `prepare(...)` and `revert(...)` methods.
|
||||
Models provide a shortcut for declaring database migrations. If you conform a type that conforms to [`Model`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html) to [`Migration`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Migration.html), Fluent can infer the model's properties and automatically implement the `prepare(...)` and `revert(...)` methods.
|
||||
|
||||
```swift
|
||||
import Fluent<#Database#>
|
||||
|
|
@ -35,7 +35,7 @@ extension Galaxy: <#Database#>Migration { }
|
|||
|
||||
This method is especially useful for quick prototyping and simple setups. For most other situations you should consider creating a normal, custom migration.
|
||||
|
||||
Add this automatic migration to your [`MigrationConfig`](#fixme) using the `add(model:database:)` method. This is done in [`configure.swift`](../getting-started/structure.md#configureswift).
|
||||
Add this automatic migration to your [`MigrationConfig`](https://api.vapor.codes/fluent/latest/Fluent/Structs/MigrationConfig.html) using the `add(model:database:)` method. This is done in [`configure.swift`](../getting-started/structure.md#configureswift).
|
||||
|
||||
```swift
|
||||
var migrations = MigrationConfig()
|
||||
|
|
@ -43,11 +43,11 @@ migrations.add(model: Galaxy.self, database: .<#dbid#>)
|
|||
services.register(migrations)
|
||||
```
|
||||
|
||||
The `add(model:database:)` method will automatically set the model's [`defaultDatabase`](#fixme) property.
|
||||
The `add(model:database:)` method will automatically set the model's [`defaultDatabase`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE15defaultDatabase0D3Kit0D10IdentifierVy0D0QzGSgvpZ) property.
|
||||
|
||||
### Custom Migrations
|
||||
|
||||
We can customize the table created for our model by creating a migration and using the static `create` and `delete` methods on [`Database`](#fixme).
|
||||
We can customize the table created for our model by creating a migration and using the static `create` and `delete` methods on [`Database`](https://api.vapor.codes/database-kit/latest/DatabaseKit/Protocols/Database.html).
|
||||
|
||||
```swift
|
||||
import Fluent<#Database#>
|
||||
|
|
@ -76,7 +76,7 @@ struct CreateGalaxy: <#Database#>Migration {
|
|||
}
|
||||
```
|
||||
|
||||
To create a schema, you must pass a model type and connection as the first two parameters. The third parameter is a closure that accepts the [`SchemaBuilder`](#fixme). This builder has convenience methods for declaring fields in the schema.
|
||||
To create a schema, you must pass a model type and connection as the first two parameters. The third parameter is a closure that accepts the [`SchemaBuilder`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/SchemaBuilder.html). This builder has convenience methods for declaring fields in the schema.
|
||||
|
||||
You can use the `field(for: <#KeyPath#>)` method to quickly create fields for each of your model's properties. Since this method accepts key paths to the model (indicated by `\.`), Fluent can see what type those properties are. For most common types (`String`, `Int`, `Double`, etc) Fluent will automatically be able to determine the best database field type to use.
|
||||
|
||||
|
|
@ -88,8 +88,11 @@ try builder.field(for: \.name, type: <#DataType#>)
|
|||
|
||||
Each database has it's own unique data types, so refer to your database's documentation for more information.
|
||||
|
||||
!!! danger
|
||||
fixme: links to db's data types
|
||||
|database|docs|api docs|
|
||||
|-|-|-|
|
||||
|PostgreSQL|[PostgreSQL → Getting Started](../postgresql/getting-started.md)|_Coming soon_|
|
||||
|MySQL|[MySQL → Getting Started](../mysql/getting-started.md)|_Coming soon_|
|
||||
|SQLite|[SQLite → Getting Started](../sqlite/getting-started.md)|[`SQLiteDataType`](https://api.vapor.codes/sqlite/latest/SQLite/Enums/SQLiteDataType.html)|
|
||||
|
||||
#### Deleting a Schema
|
||||
|
||||
|
|
@ -115,7 +118,7 @@ To delete a schema, you pass a model type and connection as the two required par
|
|||
|
||||
You can always choose to skip a reversion by simplying returning `conn.future(())`. But note that they are especially useful when testing and debugging your migrations.
|
||||
|
||||
Add this custom migration to your [`MigrationConfig`](#fixme) using the `add(migration:database:)` method. This is done in your [`configure.swift`](../getting-started/structure.md#configureswift) file.
|
||||
Add this custom migration to your [`MigrationConfig`](https://api.vapor.codes/fluent/latest/Fluent/Structs/MigrationConfig.html) using the `add(migration:database:)` method. This is done in your [`configure.swift`](../getting-started/structure.md#configureswift) file.
|
||||
|
||||
```swift
|
||||
var migrations = MigrationConfig()
|
||||
|
|
@ -144,7 +147,7 @@ struct Galaxy: <#Database#>Model {
|
|||
}
|
||||
```
|
||||
|
||||
Since our previous migration created a table with fields for both `id` and `name`, we need to update that table and add a field for `mass`. We can do this by using the static `update` method on [`Database`](#fixme).
|
||||
Since our previous migration created a table with fields for both `id` and `name`, we need to update that table and add a field for `mass`. We can do this by using the static `update` method on [`Database`](https://api.vapor.codes/database-kit/latest/DatabaseKit/Protocols/Database.html).
|
||||
|
||||
```swift
|
||||
import Fluent<#Database#>
|
||||
|
|
@ -168,7 +171,7 @@ struct AddGalaxyMass: <#Database#>Migration {
|
|||
}
|
||||
```
|
||||
|
||||
All methods available when creating a schema will be available while updating alongside some new methods for deleting fields. See [`SchemaUpdater`](#fixme) for a list of all available methods.
|
||||
All methods available when creating a schema will be available while updating alongside some new methods for deleting fields. See [`SchemaUpdater`](https://api.vapor.codes/fluent/latest/Fluent/Classes/SchemaUpdater.html) for a list of all available methods.
|
||||
|
||||
To revert this change, we must delete the `mass` field from the table.
|
||||
|
||||
|
|
@ -183,7 +186,7 @@ struct AddGalaxyMass: <#Database#>Migration {
|
|||
}
|
||||
```
|
||||
|
||||
Add this migration to your [`MigrationConfig`](#fixme) using the `add(migration:database:)` method. This is done in your [`configure.swift`](../getting-started/structure.md#configureswift) file.
|
||||
Add this migration to your [`MigrationConfig`](https://api.vapor.codes/fluent/latest/Fluent/Structs/MigrationConfig.html) using the `add(migration:database:)` method. This is done in your [`configure.swift`](../getting-started/structure.md#configureswift) file.
|
||||
|
||||
```swift
|
||||
var migrations = MigrationConfig()
|
||||
|
|
@ -230,7 +233,7 @@ struct GalaxyMassCleanup: <#Database#>Migration {
|
|||
}
|
||||
```
|
||||
|
||||
Add this migration to your [`MigrationConfig`](#fixme) using the `add(migration:database:)` method. This is done in [`configure.swift`](../getting-started/structure.md#configureswift).
|
||||
Add this migration to your [`MigrationConfig`](https://api.vapor.codes/fluent/latest/Fluent/Structs/MigrationConfig.html) using the `add(migration:database:)` method. This is done in [`configure.swift`](../getting-started/structure.md#configureswift).
|
||||
|
||||
```swift
|
||||
var migrations = MigrationConfig()
|
||||
|
|
|
|||
|
|
@ -1,184 +0,0 @@
|
|||
# Fluent PostgreSQL
|
||||
|
||||
Fluent PostgreSQL ([vapor/fluent-postgresql](https://github.com/vapor/fluent-postgresql)) is a type-safe, fast, and easy-to-use ORM for PostgreSQL built on top of [Fluent](../fluent/getting-started.md).
|
||||
|
||||
!!! seealso
|
||||
The Fluent PostgreSQL package is built on top of [Fluent](../fluent/getting-started.md) and the pure Swift, NIO-based [PostgreSQL Core](../postgresql/getting-started.md). You should refer to their guides for more information about subjects not covered here.
|
||||
|
||||
## Getting Started
|
||||
|
||||
This section will show you how to add Fluent PostgreSQL to your project, create your first `PostgreSQLModel`, and make a database query.
|
||||
|
||||
### Package
|
||||
|
||||
The first step to using Fluent PostgreSQL is adding it as a dependency to your project in your SPM package manifest file.
|
||||
|
||||
```swift
|
||||
// swift-tools-version:4.0
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "MyApp",
|
||||
dependencies: [
|
||||
/// Any other dependencies ...
|
||||
|
||||
// 🖋🐘 Swift ORM (queries, models, relations, etc) built on PostgreSQL.
|
||||
.package(url: "https://github.com/vapor/fluent-postgresql.git", from: "1.0.0"),
|
||||
],
|
||||
targets: [
|
||||
.target(name: "App", dependencies: ["FluentPostgreSQL", ...]),
|
||||
.target(name: "Run", dependencies: ["App"]),
|
||||
.testTarget(name: "AppTests", dependencies: ["App"]),
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
Don't forget to add the module as a dependency in the `targets` array. Once you have added the dependency, regenerate your Xcode project with the following command:
|
||||
|
||||
```sh
|
||||
vapor xcode
|
||||
```
|
||||
|
||||
### Model
|
||||
|
||||
Now let's create your first `PostgreSQLModel`. Models represent tables in your PostgreSQL database and they are the primary method of interacting with your data.
|
||||
|
||||
```swift
|
||||
import FluentPostgreSQL
|
||||
import Vapor
|
||||
|
||||
/// A simple user.
|
||||
final class User: PostgreSQLModel {
|
||||
/// The unique identifier for this user.
|
||||
var id: Int?
|
||||
|
||||
/// The user's full name.
|
||||
var name: String
|
||||
|
||||
/// The user's current age in years.
|
||||
var age: Int
|
||||
|
||||
/// Creates a new user.
|
||||
init(id: Int? = nil, name: String, age: Int) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.age = age
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The example above shows a `PostgreSQLModel` for a simple model representing a user. You can make both `struct`s and `class`es a model. You can even conform types that come from external modules. The only requirement is that these types conform to `Codable`, which must be declared on the base type for synthesized (automatic) conformance.
|
||||
|
||||
Standard practice with PostgreSQL databases is using an auto-generated `BIGINT` for creating and storing unique identifiers in the `id` column. It's also possible to use `UUID`s or even `String`s for your identifiers. There are convenience protocol for that.
|
||||
|
||||
|protocol |type |key|
|
||||
|-----------------------|------|---|
|
||||
|`PostgreSQLModel` |Int |id |
|
||||
|`PostgreSQLUUIDModel` |UUID |id |
|
||||
|`PostgreSQLStringModel`|String|id |
|
||||
|
||||
!!! seealso
|
||||
Take a look at [Fluent → Model](../fluent/models.md) for more information on creating models with custom ID types and keys.
|
||||
|
||||
### Migration
|
||||
|
||||
Most of your models will have a corresponding table—or _schema_—in your database. You can use [Fluent → Migration](../fluent/migrations.md) to setup your schemas in a testable, maintainable way.
|
||||
|
||||
If you are creating models to represent an existing table in your database, you don't need a migration. Just set the `defaultDatabase` property on your model so that Fluent knows which database to use if none is specified explicitly.
|
||||
|
||||
```swift
|
||||
User.defaultDatabase = .psql
|
||||
```
|
||||
|
||||
#### Automatic
|
||||
|
||||
Fluent makes it easy to automatically generate a migration for your model
|
||||
|
||||
```swift
|
||||
/// Allows `User` to be used as a migration.
|
||||
extension User: PostgreSQLMigration { }
|
||||
```
|
||||
|
||||
That's all it takes. Fluent uses Codable to analyze your model and will attempt to create an appropriate schema for it.
|
||||
|
||||
## Configure
|
||||
|
||||
The final step is to configure your database. At a minimum, this requires adding two things to your [`configure.swift`](../getting-started/structure.md#configureswift) file.
|
||||
|
||||
- `FluentPostgreSQLProvider`
|
||||
- `MigrationConfig`
|
||||
|
||||
Let's take a look.
|
||||
|
||||
```swift
|
||||
import FluentPostgreSQL
|
||||
|
||||
/// ...
|
||||
|
||||
/// Register providers first
|
||||
try services.register(FluentPostgreSQLProvider())
|
||||
|
||||
/// Configure migrations
|
||||
var migrations = MigrationConfig()
|
||||
migrations.add(model: User.self, database: .psql)
|
||||
services.register(migrations)
|
||||
|
||||
/// Other services....
|
||||
```
|
||||
|
||||
!!! tip
|
||||
If this migration you are adding is also a model, you can use the [`add(model:on:)`](#fixme) convenience to automatically set the model's [`defaultDatabase`](#fixme) property. Otherwise, use the [`add(migration:on)`](#fixme) method.
|
||||
|
||||
Registering the provider will add all of the services required for Fluent PostgreSQL to work properly. It also includes a default database config struct that uses typical development environment credentials.
|
||||
|
||||
You can of course override this config struct if you have non-standard credentials.
|
||||
|
||||
```swift
|
||||
/// Register custom PostgreSQL Config
|
||||
let psqlConfig = PostgreSQLDatabaseConfig(hostname: "localhost", port: 5432, username: "vapor")
|
||||
services.register(psqlConfig)
|
||||
```
|
||||
|
||||
Once you have the `MigrationConfig` added, you should be able to run your application and see the following:
|
||||
|
||||
```sh
|
||||
Migrating psql DB
|
||||
Migrations complete
|
||||
Server starting on http://localhost:8080
|
||||
```
|
||||
|
||||
## Query
|
||||
|
||||
Now that you have created a model and a corresponding schema in your database, let's make your first query.
|
||||
|
||||
```swift
|
||||
router.get("users") { req in
|
||||
return User.query(on: req).all()
|
||||
}
|
||||
```
|
||||
|
||||
If you run your app, and query that route, you should see an empty array returned. Now you just need to add some users! Congratulations on getting your first Fluent PostgreSQL model and migration working.
|
||||
|
||||
## Connection
|
||||
|
||||
With Fluent, you always have access to the underlying database driver. Using this underlying driver to perform a query is sometimes called a "raw query".
|
||||
|
||||
Let's take a look at a raw PostgreSQL query.
|
||||
|
||||
```swift
|
||||
router.get("psql-version") { req -> Future<String> in
|
||||
struct Version: Decodable {
|
||||
var version: String
|
||||
}
|
||||
|
||||
return req.withPooledConnection(to: .psql) { conn in
|
||||
return try conn.query("SELECT version() as version;", decoding: Version.self).map { rows in
|
||||
return try rows[0].version
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the above example, `withPooledConnection(to:)` is used to create a connection to the database identified by `.psql`. This is the default database identifier. See [Fluent → Database](../fluent/database.md#identifier) to learn more.
|
||||
|
||||
Once you have the `PostgreSQLConnection`, we can perform a query on it. You can learn more about the methods available in [PostgreSQL → Core](core.md).
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
# PostgreSQL Schema Builder
|
||||
|
||||
Fluent lets you customize your schemas with PostgreSQL-specific column types. You can even set default values. Let's take a look at creating a simple `Planet` model with custom PostgreSQL field tpyes.
|
||||
|
||||
```swift
|
||||
/// Type of planet.
|
||||
enum PlanetType: String, Codable, CaseIterable, ReflectionDecodable {
|
||||
case smallRocky
|
||||
case gasGiant
|
||||
case dwarf
|
||||
}
|
||||
|
||||
/// Represents a planet.
|
||||
struct Planet: PostgreSQLModel, PostgreSQLMigration {
|
||||
/// Unique identifier.
|
||||
var id: Int?
|
||||
|
||||
/// Name of the planet.
|
||||
let name: String
|
||||
|
||||
/// Planet's specific type.
|
||||
let type: PlanetType
|
||||
}
|
||||
```
|
||||
|
||||
The above model looks great, but there are a couple of problems with the automatically generated migration:
|
||||
|
||||
- `name` uses a `TEXT` column, but we want to use `VARCHAR(64)`.
|
||||
- `type` is defaulting to a `JSONB` column, but we want to store it as `ENUM()`.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# Querying Models
|
||||
# Fluent Queries
|
||||
|
||||
Once you have a [model](models.md) you can start querying your database to create, read, update, and delete data.
|
||||
|
||||
|
|
@ -8,7 +8,7 @@ The first thing you need to query your database, is a connection to it. Luckily,
|
|||
|
||||
### Request
|
||||
|
||||
The easiest way to connect to your database is simply using the incoming `Request`. This will use the model's [`defaultDatabase`](#fixme) property to automatically fetch a pooled connection to the database.
|
||||
The easiest way to connect to your database is simply using the incoming `Request`. This will use the model's [`defaultDatabase`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE15defaultDatabase0D3Kit0D10IdentifierVy0D0QzGSgvpZ) property to automatically fetch a pooled connection to the database.
|
||||
|
||||
```swift
|
||||
router.get("galaxies") { req in
|
||||
|
|
@ -20,7 +20,7 @@ You can use convenience methods on a `Container` to create connections manually.
|
|||
|
||||
## Create
|
||||
|
||||
One of the first things you will need to do is save some data to your database. You do this by initializing an instance of your model then calling [`create(on:)`](#fixme).
|
||||
One of the first things you will need to do is save some data to your database. You do this by initializing an instance of your model then calling [`create(on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE6create2on3NIO15EventLoopFutureCyxG11DatabaseKit0I11Connectable_p_tF).
|
||||
|
||||
```swift
|
||||
router.post("galaxies") { req in
|
||||
|
|
@ -31,22 +31,22 @@ router.post("galaxies") { req in
|
|||
|
||||
The create method will return the saved model. The returned model will include any generated fields such as the ID or fields with default values.
|
||||
|
||||
If your model also conforms to [`Content`](#fixme) you can return the result of the Fluent query directly.
|
||||
If your model also conforms to [`Content`](https://api.vapor.codes/vapor/latest/Vapor/Protocols/Content.html) you can return the result of the Fluent query directly.
|
||||
|
||||
|
||||
## Read
|
||||
|
||||
To read models from the database, you can use [`query(on:)`](#fixme) or [`find(_:on:)`](#fixme).
|
||||
To read models from the database, you can use [`query(on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE6create2on3NIO15EventLoopFutureCyxG11DatabaseKit0I11Connectable_p_tF) or [`find(_:on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE4find_2on3NIO15EventLoopFutureCyxSgG2IDQz_11DatabaseKit0J11Connectable_ptFZ).
|
||||
|
||||
### Find
|
||||
|
||||
The easiest way to find a single model is by passing its ID to [`find(_:on:)`](#fixme).
|
||||
The easiest way to find a single model is by passing its ID to [`find(_:on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE4find_2on3NIO15EventLoopFutureCyxSgG2IDQz_11DatabaseKit0J11Connectable_ptFZ).
|
||||
|
||||
```swift
|
||||
Galaxy.find(42, on: conn)
|
||||
```
|
||||
|
||||
The result will be a future containing an optional value. You can use [`unwrap(or:)`](#fixme) to unwrap the future value or throw an error.
|
||||
The result will be a future containing an optional value. You can use [`unwrap(or:)`](https://api.vapor.codes/core/latest/Core/Extensions/Future.html#/s:3NIO15EventLoopFutureC4CoreAD12OptionalTypeRzlE6unwrap2orACy07WrappedG0QzGs5Error_pyXA_tF) to unwrap the future value or throw an error.
|
||||
|
||||
```swift
|
||||
Galaxy.find(42, on: conn).unwrap(or: Abort(...))
|
||||
|
|
@ -54,7 +54,7 @@ Galaxy.find(42, on: conn).unwrap(or: Abort(...))
|
|||
|
||||
### Query
|
||||
|
||||
You can use the [`query(on:)`](#fixme) method to build database queries with filters, joins, sorts, and more.
|
||||
You can use the [`query(on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE6create2on3NIO15EventLoopFutureCyxG11DatabaseKit0I11Connectable_p_tF) method to build database queries with filters, joins, sorts, and more.
|
||||
|
||||
```swift
|
||||
Galaxy.query(on: conn).filter(\.name == "Milky Way")
|
||||
|
|
@ -62,7 +62,7 @@ Galaxy.query(on: conn).filter(\.name == "Milky Way")
|
|||
|
||||
### Filter
|
||||
|
||||
The [`filter(_:)`](#fixme) method accepts filters created from Fluent's operators. This provides a concise, Swifty way for building Fluent queries.
|
||||
The [`filter(_:)`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC6filteryACyxq_GXDAA14FilterOperatorVyxq_GF) method accepts filters created from Fluent's operators. This provides a concise, Swifty way for building Fluent queries.
|
||||
|
||||
Calls to filter can be chained and even grouped.
|
||||
|
||||
|
|
@ -122,11 +122,11 @@ Galaxy.query(on: conn).join(\Planet.galaxyID, to: \Galaxy.id)
|
|||
.filter(\Planet.name == "Earth")
|
||||
```
|
||||
|
||||
Once a table has been joined using [`join(_:to:)`](#fixme), you can use fully-qualified key paths to filter results based on data in the joined table.
|
||||
Once a table has been joined using [`join(_:to:)`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderCA2A14JoinSupportingRzrlE4join_2to6methodACyxq_GXDs7KeyPathCyqd__qd_0_G_AJyqd_1_qd_2_G0bD6MethodQztr2_lF), you can use fully-qualified key paths to filter results based on data in the joined table.
|
||||
|
||||
The above query fetches all galaxies that have a planet named Earth.
|
||||
|
||||
You can even decode the joined models using [`alsoDecode(...)`](#fixme).
|
||||
You can even decode the joined models using [`alsoDecode(...)`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC10alsoDecodeyACyxq__qd__tGqd__mAA5ModelRd__lF).
|
||||
|
||||
```swift
|
||||
Galaxy.query(on: conn)
|
||||
|
|
@ -138,7 +138,7 @@ The above query will decode an array of `(Galaxy, Planet)` tuples.
|
|||
|
||||
### Fetch
|
||||
|
||||
To fetch the results of a query, use [`all()`](#fixme), [`chunk(max:)`](#fixme), [`first()`](#fixme) or an aggregate method.
|
||||
To fetch the results of a query, use [`all()`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC3all3NIO15EventLoopFutureCySayq_GGyF), [`chunk(max:closure:)`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC5chunk3max7closure3NIO15EventLoopFutureCyytGSi_ySayq_GKctF), [`first()`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC5first3NIO15EventLoopFutureCyq_SgGyF) or an aggregate method.
|
||||
|
||||
#### All
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ The most common method for fetching results is with `all()`. This will return al
|
|||
Galaxy.query(on: conn).all()
|
||||
```
|
||||
|
||||
When combined with [`range(_:)`](#fixme), you can efficiently limit how many results are returned by the database.
|
||||
When combined with [`range(_:)`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC5rangeyACyxq_GXDSnySiGF), you can efficiently limit how many results are returned by the database.
|
||||
|
||||
```swift
|
||||
Galaxy.query(on: conn).range(..<50).all()
|
||||
|
|
@ -156,7 +156,7 @@ Galaxy.query(on: conn).range(..<50).all()
|
|||
|
||||
#### Chunk
|
||||
|
||||
For situations where memory conservation is important, use [`chunk(...)`](#fixme). This method returns the result set in multiple calls of a maximum chunk size.
|
||||
For situations where memory conservation is important, use [`chunk(...)`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC5chunk3max7closure3NIO15EventLoopFutureCyytGSi_ySayq_GKctF). This method returns the result set in multiple calls of a maximum chunk size.
|
||||
|
||||
```swift
|
||||
Galaxy.query(on: conn).chunk(max: 32) { galaxies in
|
||||
|
|
@ -166,7 +166,7 @@ Galaxy.query(on: conn).chunk(max: 32) { galaxies in
|
|||
|
||||
#### First
|
||||
|
||||
The [`first()`](#fixme) method is a convenience for fetching the first result of a query. It will automatically apply a range restriction to avoid transferring unnecessary data.
|
||||
The [`first()`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html#/s:6Fluent12QueryBuilderC5first3NIO15EventLoopFutureCyq_SgGyF) method is a convenience for fetching the first result of a query. It will automatically apply a range restriction to avoid transferring unnecessary data.
|
||||
|
||||
```swift
|
||||
Galaxy.query(on: conn).filter(\.name == "Milky Way").first()
|
||||
|
|
@ -176,7 +176,7 @@ This method is more efficient than calling `all` and getting the first item in t
|
|||
|
||||
## Update
|
||||
|
||||
After a model has been fetched from the database and mutated, you can use [`update(on:)`](#fixme) to save the changes.
|
||||
After a model has been fetched from the database and mutated, you can use [`update(on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE6update2on10originalID3NIO15EventLoopFutureCyxG11DatabaseKit0K11Connectable_p_0F0QzSgtF) to save the changes.
|
||||
|
||||
```swift
|
||||
var planet: Planet ... // fetched from database
|
||||
|
|
@ -186,7 +186,7 @@ planet.update(on: conn)
|
|||
|
||||
## Delete
|
||||
|
||||
After a model has been fetched from the database, you can use [`delete(on:)`](#fixme) to delete it.
|
||||
After a model has been fetched from the database, you can use [`delete(on:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE6delete5force2on3NIO15EventLoopFutureCyytGSb_11DatabaseKit0J11Connectable_ptF) to delete it.
|
||||
|
||||
```swift
|
||||
var planet: Planet ... // fetched from database
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ struct Planet: Model {
|
|||
|
||||
For more information on defining models see [Fluent → Models](models.md).
|
||||
|
||||
Fluent provides two helpers for working with parent-child relations: [`Parent`](#fixme) and [`Children`](#fixme). These helpers can be created using extensions on the related models for convenient access.
|
||||
Fluent provides two helpers for working with parent-child relations: [`Parent`](https://api.vapor.codes/fluent/latest/Fluent/Structs/Parent.html) and [`Children`](https://api.vapor.codes/fluent/latest/Fluent/Structs/Children.html). These helpers can be created using extensions on the related models for convenient access.
|
||||
|
||||
```swift
|
||||
extension Galaxy {
|
||||
|
|
@ -47,7 +47,7 @@ extension Galaxy {
|
|||
}
|
||||
```
|
||||
|
||||
Here the [`children(_:)`](#fixme) method is used on `Galaxy` to create the relation. The resulting type has two generic arguments in the signature that can be thought of as `<From, To`>. Since this relation goes _from_ galaxy _to_ planet, they are ordered as such in the generic arguments.
|
||||
Here the [`children(_:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE8childrenyAA8ChildrenVyxqd__Gs7KeyPathCyqd__2IDQzGAaBRd__8DatabaseQyd__AMRtzlF) method is used on `Galaxy` to create the relation. The resulting type has two generic arguments in the signature that can be thought of as `<From, To`>. Since this relation goes _from_ galaxy _to_ planet, they are ordered as such in the generic arguments.
|
||||
|
||||
Note that this method is not static. That is because it must access the galaxy's identifier to perform the relation lookup.
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ extension Planet {
|
|||
}
|
||||
```
|
||||
|
||||
Here the [`parent(_:)`](#fixme) method is used on `Planet` to create the inverse relation. The resulting type also has two generic arguments. In this case, they are reversed since this relation now goes _from_ planet _to_ galaxy.
|
||||
Here the [`parent(_:)`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/Model.html#/s:6Fluent5ModelPAAE6parentyAA6ParentVyxqd__Gs7KeyPathCyx2IDQyd__GAaBRd__8DatabaseQyd__AMRtzlF) method is used on `Planet` to create the inverse relation. The resulting type also has two generic arguments. In this case, they are reversed since this relation now goes _from_ planet _to_ galaxy.
|
||||
|
||||
Note that this method is also not static. That is because it must access the referenced identifier to perform the relation lookup.
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ let galaxy: Galaxy = ...
|
|||
let planets = galaxy.planets.query(on: ...).all()
|
||||
```
|
||||
|
||||
The `query(on:)` method on a relation creates an instance of [`QueryBuilder`](#fixme) filtered to the related models. See [Fluent → Querying](querying.md) for more information on working with the query builder.
|
||||
The `query(on:)` method on a relation creates an instance of [`QueryBuilder`](https://api.vapor.codes/fluent/latest/Fluent/Classes/QueryBuilder.html) filtered to the related models. See [Fluent → Querying](querying.md) for more information on working with the query builder.
|
||||
|
||||
```swift
|
||||
let planet: Planet = ...
|
||||
|
|
@ -174,7 +174,7 @@ planet.tags.query(on: ...).all()
|
|||
|
||||
### Modifiable Pivot
|
||||
|
||||
If the pivot conforms to [`ModifiablePivot`](#fixme), then Fluent can help to create and delete pivots (called attaching and detaching).
|
||||
If the pivot conforms to [`ModifiablePivot`](https://api.vapor.codes/fluent/latest/Fluent/Protocols/ModifiablePivot.html), then Fluent can help to create and delete pivots (called attaching and detaching).
|
||||
|
||||
Conforming a pivot is fairly simple. Fluent just needs to be able to initialize the pivot from two related models.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
# Fluent Schema Builder
|
||||
|
||||
# Schema Builder
|
||||
|
||||
#### Custom
|
||||
|
||||
You can also implement custom migrations for more fine-grain control over the schemas generated. For example, you may want to store a User's name using a `VARCHAR(64)` instead of `TEXT`. Just like `PostgreSQLModel`, any `struct` or `class` can conform to `PostgreSQLMigration`.
|
||||
|
||||
```swift
|
||||
/// Creates a table for `User`s.
|
||||
struct CreateUser: PostgreSQLMigration {
|
||||
static func prepare(on conn: PostgreSQLConnection) -> Future<Void> {
|
||||
return PostgreSQLDatabase.create(User.self, on: conn) { builder in
|
||||
builder.field(for: \.id)
|
||||
builder.field(for: \.name, type: .varchar(64))
|
||||
}
|
||||
}
|
||||
|
||||
static func revert(on conn: PostgreSQLConnection) -> Future<Void> {
|
||||
return PostgreSQLDatabase.delete(User.self, on: conn)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Migrations consist of two methods: `prepare(...)` and `revert(...)`. The prepare method runs once and should prepare the database for storing and fetching your model. The revert method runs only if you need to undo changes to your database and should undo anything you do in the prepare method.
|
||||
|
||||
Custom migrations are also useful for situations where you may need to _alter_ an existing table, like to add a new column.
|
||||
|
||||
```swift
|
||||
/// Adds a new field to `User`'s table.
|
||||
struct AddUsernameToUser: PostgreSQLMigration {
|
||||
static func prepare(on conn: PostgreSQLConnection) -> Future<Void> {
|
||||
return PostgreSQLDatabase.update(User.self, on: conn) { builder in
|
||||
builder.field(for: \.username)
|
||||
}
|
||||
}
|
||||
|
||||
static func revert(on conn: PostgreSQLConnection) -> Future<Void> {
|
||||
return PostgreSQLDatabase.update(User.self) { builder in
|
||||
builder.deleteField(for: \.username, on: conn)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Constraints
|
||||
|
||||
You can also add foreign key and unique constraints to your models during a migration.
|
||||
|
||||
```swift
|
||||
// creates a foreign key constraint ensuring Post.userID is a valid User.id
|
||||
builder.foreignKey(from: \Post.userID, to: \User.id)
|
||||
// creates a unique constraint ensuring no other posts have the same slug
|
||||
builder.unique(on: \Post.slug)
|
||||
```
|
||||
|
||||
!!! seealso
|
||||
Take a look at [Fluent → Migration](../fluent/migrations.md) if you are interested in learning more about migrations.
|
||||
|
||||
|
||||
## Create
|
||||
|
||||
Coming soon.
|
||||
|
||||
## Update
|
||||
|
||||
Coming soon.
|
||||
|
||||
## Delete
|
||||
|
||||
Coming soon.
|
||||
|
||||
## References
|
||||
|
||||
Coming soon.
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
# Fluent Transactions
|
||||
|
||||
Coming soon.
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Transactions allow you to ensure multiple operations complete succesfully before saving data to your database. Once a transaction is started, you may run Fluent queries normally. However, no data will be saved to the database until the transaction completes. If an error is thrown at any point during the transaction (by you or the database), none of the changes will take effect.
|
||||
|
||||
To perform a transaction, you need access to something that can connect to the database. This is usually an incoming HTTP request. Use the [`transaction(on:_:)`](#fixme) method.
|
||||
To perform a transaction, you need access to something that can connect to the database. This is usually an incoming HTTP request. Use the [`transaction(on:_:)`](https://api.vapor.codes/fluent/latest/Fluent/Extensions/DatabaseConnectable.html#/s:11DatabaseKit0A11ConnectableP6FluentE11transaction2on_3NIO15EventLoopFutureCyqd_0_GAA0A10IdentifierVyqd__G_AJ10ConnectionQyd__KctAD21TransactionSupportingRd__r0_lF) method.
|
||||
|
||||
Fill in the Xcode placeholders below with your database's name from [Getting Started → Choosing a Driver](getting-started/#choosing-a-driver).
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ Check out [Database Kit → Overview → Connections](../database-kit/over
|
|||
|
||||
## Select
|
||||
|
||||
Use the [`select()`](#fixme) method on a connection to create a [`SQLSelectBuilder`](#fixme). This builder helps you create `SELECT` statements and supports:
|
||||
Use the [`select()`](https://api.vapor.codes/sql/latest/SQL/Protocols/SQLConnection.html#/s:3SQL13SQLConnectionPAAE6selectAA16SQLSelectBuilderCyxGyF) method on a connection to create a [`SQLSelectBuilder`](https://api.vapor.codes/sql/latest/SQL/Classes/SQLSelectBuilder.html). This builder helps you create `SELECT` statements and supports:
|
||||
|
||||
- `*`, columns, and expressions like functions
|
||||
- `FROM`
|
||||
|
|
@ -38,7 +38,7 @@ Use the [`select()`](#fixme) method on a connection to create a [`SQLSelectBuild
|
|||
- `GROUP BY`
|
||||
- `ORDER BY`
|
||||
|
||||
The select builder conforms to [`SQLPredicateBuilder`](#fixme) for building `WHERE` predicates. It also conforms to [`SQLQueryFetcher`](#fixme) for decoding `Codable` models from the result set.
|
||||
The select builder conforms to [`SQLPredicateBuilder`](https://api.vapor.codes/sql/latest/SQL/Protocols/SQLPredicateBuilder.html) for building `WHERE` predicates. It also conforms to [`SQLQueryFetcher`](https://api.vapor.codes/sql/latest/SQL/Protocols/SQLQueryFetcher.html) for decoding `Codable` models from the result set.
|
||||
|
||||
Let's take a look at an example `SELECT` query. Replace the Xcode placeholder with the name of the database you are using, i.e., `SQLite`.
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,37 @@ User.query(on: req).all()
|
|||
|
||||
See [DatabaseKit → Getting Started](../database-kit/getting-started.md) to learn more.
|
||||
|
||||
### Migrating SQL Database
|
||||
|
||||
When migrating from Fluent 2 to 3 you may need to update your `fluent` table to support the new format. In Fluent 3, the migration log table has the following changes:
|
||||
|
||||
- `id` is now a `UUID`.
|
||||
- `createdAt` and `updatedAt` must now be `camelCase`.
|
||||
|
||||
Depending on how your Fluent database was configured, your tables may already be in the correct format. If not, you can run the following queries to transfer the table data.
|
||||
|
||||
Use this query if your column names were already set to `camelCase`.
|
||||
|
||||
```sql
|
||||
ALTER TABLE fluent RENAME TO fluent_old;
|
||||
CREATE TABLE fluent
|
||||
AS (SELECT UUID() as id, name, batch, createdAt, updatedAt from fluent_old);
|
||||
```
|
||||
|
||||
Use this query if your column names were `snake_case`.
|
||||
|
||||
```sql
|
||||
ALTER TABLE fluent RENAME TO fluent_old;
|
||||
CREATE TABLE fluent
|
||||
AS (SELECT UUID() as id, name, batch, created_at as createdAt, updated_at as updatedAt from fluent_old);
|
||||
```
|
||||
|
||||
After you have verified the table was transferred properly, you can drop the old fluent table.
|
||||
|
||||
```sql
|
||||
DROP TABLE fluent_old;
|
||||
```
|
||||
|
||||
### Work in progress
|
||||
|
||||
This migration guide is a work in progress. Please feel free to add any migration tips here by submitting a PR.
|
||||
|
|
|
|||
Loading…
Reference in New Issue