mirror of https://github.com/vapor/docs.git
Merge branch 'master' of github.com:qutheory/documentation
This commit is contained in:
commit
fc67a8f81b
|
|
@ -20,7 +20,7 @@ Not all drivers have providers yet, and not all drivers or providers are up to d
|
||||||
|
|
||||||
## Creating a Driver
|
## Creating a Driver
|
||||||
|
|
||||||
Fluent is a power, database agnostic package for persisting your models. It was designed from the beginnign to work with both SQL and NoSQL databases alike.
|
Fluent is a powerful, database agnostic package for persisting your models. It was designed from the beginning to work with both SQL and NoSQL databases alike.
|
||||||
|
|
||||||
Any database that conforms to `Fluent.Driver` will be able to power the models in Fluent and Vapor.
|
Any database that conforms to `Fluent.Driver` will be able to power the models in Fluent and Vapor.
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ The protocol itself is fairly simple:
|
||||||
```swift
|
```swift
|
||||||
public protocol Driver {
|
public protocol Driver {
|
||||||
var idKey: String { get }
|
var idKey: String { get }
|
||||||
func query<T: Entity>(_ query: Query<T>) throws -> Node
|
func query<T: Entity>(_ query: Query<T>) throws -> Node
|
||||||
func schema(_ schema: Schema) throws
|
func schema(_ schema: Schema) throws
|
||||||
func raw(_ raw: String, _ values: [Node]) throws -> Node
|
func raw(_ raw: String, _ values: [Node]) throws -> Node
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,10 @@ public protocol Model: Entity, JSONRepresentable, StringInitializable, ResponseR
|
||||||
|
|
||||||
As can be seen in the protocol, Vapor models can automatically convert to `JSON`, `Response`, and even be used in type-safe routing.
|
As can be seen in the protocol, Vapor models can automatically convert to `JSON`, `Response`, and even be used in type-safe routing.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
Change the table/collection name
|
||||||
|
```swift
|
||||||
|
static var entity = "new_name"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ currentMenu: fluent-query
|
||||||
|
|
||||||
# Query
|
# Query
|
||||||
|
|
||||||
The `Query` class is what powers every interaction with Fluent. Whether you're fetching a model with `.find()` or saving to the database, there is a `Query` involved somewhere.
|
The `Query` class is what powers every interaction with Fluent. Whether you're fetching a model with `.find()` or saving to the database, there is a `Query` involved somewhere.
|
||||||
|
|
||||||
## Querying Models
|
## Querying Models
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ Every type that conforms to [Model](model.md) gets a static `.query()` method.
|
||||||
let query = try User.query()
|
let query = try User.query()
|
||||||
```
|
```
|
||||||
|
|
||||||
This is how you can create a `Query<User>`.
|
This is how you can create a `Query<User>`.
|
||||||
|
|
||||||
### No Database
|
### No Database
|
||||||
|
|
||||||
|
|
@ -24,11 +24,11 @@ The `.query()` method is marked with `try` because it can throw an error if the
|
||||||
User.database = drop.database
|
User.database = drop.database
|
||||||
```
|
```
|
||||||
|
|
||||||
This property is set automatically when you pass the Model as a preparation.
|
This property is set automatically when you pass the Model as a preparation.
|
||||||
|
|
||||||
## Filter
|
## Filter
|
||||||
|
|
||||||
The most common types of queries involve filtering data.
|
The most common types of queries involve filtering data.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let smithsQuery = try User.query().filter("last_name", "Smith")
|
let smithsQuery = try User.query().filter("last_name", "Smith")
|
||||||
|
|
@ -61,7 +61,7 @@ Partially matching filters can also be applied.
|
||||||
let statesWithNew = try State.query().filter("name", contains: "New")
|
let statesWithNew = try State.query().filter("name", contains: "New")
|
||||||
```
|
```
|
||||||
|
|
||||||
## Retrieving
|
## Retrieving
|
||||||
|
|
||||||
There are two methods for running a query.
|
There are two methods for running a query.
|
||||||
|
|
||||||
|
|
@ -75,7 +75,7 @@ let usersOver21 = try User.query().filter("age", .greaterThanOrEquals, 21).all()
|
||||||
|
|
||||||
### First
|
### First
|
||||||
|
|
||||||
The first matching entity can be fetch. This returns an optional `Model?`, in this case a user.
|
The first matching entity can be fetched. This returns an optional `Model?`, in this case a user.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let firstSmith = try User.query().filter("last_name", "Smith").first()
|
let firstSmith = try User.query().filter("last_name", "Smith").first()
|
||||||
|
|
@ -111,7 +111,7 @@ Custom foreign keys can be provided through overloads to `union`.
|
||||||
|
|
||||||
## Raw Queries
|
## Raw Queries
|
||||||
|
|
||||||
Since Fluent is focused on interacting with models, each Query requires a model type. If you want to do raw database queries that aren't based on a model, you should use the underlying Fluent Driver to do so.
|
Since Fluent is focused on interacting with models, each Query requires a model type. If you want to do raw database queries that aren't based on a model, you should use the underlying Fluent Driver to do so.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
if let mysql = drop.database?.driver as? MySQLDriver {
|
if let mysql = drop.database?.driver as? MySQLDriver {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ let owner = try pet.parent(pet.ownerId, Owner.self).get()
|
||||||
|
|
||||||
The parent method requires the foreign key for the parent as well as the type.
|
The parent method requires the foreign key for the parent as well as the type.
|
||||||
|
|
||||||
### Convenience
|
### Convenience
|
||||||
|
|
||||||
To make requesting a parent easier, a method can be added to the model.
|
To make requesting a parent easier, a method can be added to the model.
|
||||||
|
|
||||||
|
|
@ -50,7 +50,7 @@ extension Pet {
|
||||||
|
|
||||||
Since we are extending `Pet`, we no longer need to use `pet.` before the `ownerId`. Furthermore, because we are providing the type information about `Owner` in the return type of the method, we no longer need to pass that as an argument.
|
Since we are extending `Pet`, we no longer need to use `pet.` before the `ownerId`. Furthermore, because we are providing the type information about `Owner` in the return type of the method, we no longer need to pass that as an argument.
|
||||||
|
|
||||||
The `Parent<T>` type is a queryable object, meaning you could `delete()` the parent, `filter()`, etc.
|
The `Parent<T>` type is a queryable object, meaning you could `delete()` the parent, `filter()`, etc.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
try pet.owner().delete()
|
try pet.owner().delete()
|
||||||
|
|
@ -64,7 +64,7 @@ let owner = try pet.owner().get()
|
||||||
|
|
||||||
## Children
|
## Children
|
||||||
|
|
||||||
`Children` are the opposite side of the `Parent` relationship. Assuming the schema from the previous example, the pets could be retreived from an owner like so:
|
`Children` are the opposite side of the `Parent` relationship. Assuming the schema from the previous example, the pets could be retrieved from an owner like so:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let owner: Owner = ...
|
let owner: Owner = ...
|
||||||
|
|
@ -95,7 +95,7 @@ let coolPets = try owner.pets().filter("type", .in, ["Dog", "Ferret"]).all()
|
||||||
|
|
||||||
## Siblings
|
## Siblings
|
||||||
|
|
||||||
`Sibilings` work differently from `Children` or `Parent` since they require a `Pivot`.
|
`Siblings` work differently from `Children` or `Parent` since they require a `Pivot`.
|
||||||
|
|
||||||
For an example, let's say we want to allow our pets to have multiple toys. But we also want the toys to be shared by multiple pets. We need a pivot entity for this.
|
For an example, let's say we want to allow our pets to have multiple toys. But we also want the toys to be shared by multiple pets. We need a pivot entity for this.
|
||||||
|
|
||||||
|
|
@ -139,7 +139,7 @@ extension Toy {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Now you are free to query pets and toys simiarly to children.
|
Now you are free to query pets and toys similarly to children.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let pet: Pet = ...
|
let pet: Pet = ...
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ The response is returned and will chain back up any remaining middleware and bac
|
||||||
|
|
||||||
## Request
|
## Request
|
||||||
|
|
||||||
The middleware can also modify or intereact with the request.
|
The middleware can also modify or interact with the request.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
func respond(to request: Request, chainingTo next: Responder) throws -> Response {
|
func respond(to request: Request, chainingTo next: Responder) throws -> Response {
|
||||||
|
|
@ -98,7 +98,7 @@ app.get("foo") { request in
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This solution works, but it would get repetative if repeated throughout multiple routes. It can also easily lead to code duplication. Luckily, this error could be caught in a middleware instead.
|
This solution works, but it would get repetitive if repeated throughout multiple routes. It can also easily lead to code duplication. Luckily, this error could be caught in a middleware instead.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
final class FooErrorMiddleware: Middleware {
|
final class FooErrorMiddleware: Middleware {
|
||||||
|
|
@ -146,7 +146,7 @@ final class PokemonMiddleware: Middleware {
|
||||||
|
|
||||||
func respond(to request: Request, chainingTo next: Responder) throws -> Response {
|
func respond(to request: Request, chainingTo next: Responder) throws -> Response {
|
||||||
let response = try next.respond(to: request)
|
let response = try next.respond(to: request)
|
||||||
|
|
||||||
if let pokemon = response.pokemon {
|
if let pokemon = response.pokemon {
|
||||||
request.accept.prefers("html") {
|
request.accept.prefers("html") {
|
||||||
response.view = try drop.view("pokemon.mustache", context: pokemon)
|
response.view = try drop.view("pokemon.mustache", context: pokemon)
|
||||||
|
|
@ -210,4 +210,3 @@ drop.get("pokemon", Pokemon.self) { request, pokemon in
|
||||||
Middleware is incredibly powerful. Combined with extensions, it allows you to add functionality that feels native to the framework.
|
Middleware is incredibly powerful. Combined with extensions, it allows you to add functionality that feels native to the framework.
|
||||||
|
|
||||||
For those that are curious, this is how Vapor manages JSON internally. Whenever you return JSON in a closure, it sets the `json: JSON?` property on `Response`. The `JSONMiddleware` then detects this property and serializes the JSON into the body of the response.
|
For those that are curious, this is how Vapor manages JSON internally. Whenever you return JSON in a closure, it sets the `json: JSON?` property on `Response`. The `JSONMiddleware` then detects this property and serializes the JSON into the body of the response.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ extension VPRFile: HTTP.BodyRepresentable {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
> You may have noticed above, that the protocol throws, but our implementation does not. This is compeletely valid in Swift and will allow you to not throw if you're ever calling the function manually.
|
> You may have noticed above, that the protocol throws, but our implementation does not. This is completely valid in Swift and will allow you to not throw if you're ever calling the function manually.
|
||||||
|
|
||||||
Now we're able to include our `VPR` file directly in our `Responses`.
|
Now we're able to include our `VPR` file directly in our `Responses`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,4 +76,4 @@ This can be used as a jumping off point for applications looking to implement fe
|
||||||
|
|
||||||
## Client
|
## Client
|
||||||
|
|
||||||
The `HTTP.Client` is itself a `Responder` although, instead of handling the `Request` itsself, it passes it on to the underlying uri.
|
The `HTTP.Client` is itself a `Responder` although, instead of handling the `Request` itself, it passes it on to the underlying uri.
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ Vapor has a plethora of functionality for routing including route builders, grou
|
||||||
The most basic route includes a method, path, and closure.
|
The most basic route includes a method, path, and closure.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
drop.get("welcome") { request in
|
drop.get("welcome") { request in
|
||||||
return "Hello"
|
return "Hello"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -21,7 +21,7 @@ drop.get("welcome") { request in
|
||||||
The standard HTTP methods are available including `get`, `post`, `put`, `patch`, `delete`, and `options`.
|
The standard HTTP methods are available including `get`, `post`, `put`, `patch`, `delete`, and `options`.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
drop.post("form") { request in
|
drop.post("form") { request in
|
||||||
return "Submitted with a POST request"
|
return "Submitted with a POST request"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -42,7 +42,7 @@ You can also use `/`, but commas are often easier to type and work better with t
|
||||||
|
|
||||||
## Alternate
|
## Alternate
|
||||||
|
|
||||||
An alternate syntax that accepts a `Method` as the first parameter is also available.
|
An alternate syntax that accepts a `Method` as the first parameter is also available.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
drop.add(.trace, "welcome") { request in
|
drop.add(.trace, "welcome") { request in
|
||||||
|
|
@ -54,7 +54,7 @@ This may be useful if you want to register routes dynamically or use a less comm
|
||||||
|
|
||||||
## Request
|
## Request
|
||||||
|
|
||||||
Each route closure is given a single [Request](../http/request.md). This contains all of the data associated with the request that led to your route closure being called.
|
Each route closure is given a single [Request](../http/request.md). This contains all of the data associated with the request that led to your route closure being called.
|
||||||
|
|
||||||
## Response Representable
|
## Response Representable
|
||||||
|
|
||||||
|
|
@ -132,7 +132,7 @@ If you want to override this behavior, remove the `AbortMiddleware` from the `Dr
|
||||||
Fallback routes allow you to match multiple layers of nesting slashes.
|
Fallback routes allow you to match multiple layers of nesting slashes.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
app.get("anything", "*") { request in
|
app.get("anything", "*") { request in
|
||||||
return "Matches anything after /anything"
|
return "Matches anything after /anything"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ Traditional web frameworks leave room for error in routing by using strings for
|
||||||
|
|
||||||
## Type Safe
|
## Type Safe
|
||||||
|
|
||||||
To create a type safe route simply replace one of the parts of your path with a `Type`.
|
To create a type safe route simply replace one of the parts of your path with a `Type`.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
drop.get("users", Int.self) { request, userId in
|
drop.get("users", Int.self) { request, userId in
|
||||||
|
|
@ -19,7 +19,7 @@ drop.get("users", Int.self) { request, userId in
|
||||||
This creates a route that matches `users/:id` where the `:id` is an `Int`. Here's what it would look like using manual route parameters.
|
This creates a route that matches `users/:id` where the `:id` is an `Int`. Here's what it would look like using manual route parameters.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
drop.get("users", ":id") { request in
|
drop.get("users", ":id") { request in
|
||||||
guard let userId = request.parameters["id"].int else {
|
guard let userId = request.parameters["id"].int else {
|
||||||
throw Abort.badRequest
|
throw Abort.badRequest
|
||||||
}
|
}
|
||||||
|
|
@ -28,7 +28,7 @@ drop.get("users", ":id") { request in
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Here you can see that type safe routing saves ~3 lines of code and also prevents runtime errors like mispelling `:id`.
|
Here you can see that type safe routing saves ~3 lines of code and also prevents runtime errors like misspelling `:id`.
|
||||||
|
|
||||||
## String Initializable
|
## String Initializable
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ Any type that conforms to `StringInitializable` can be used as a type-safe routi
|
||||||
- Int
|
- Int
|
||||||
- Model
|
- Model
|
||||||
|
|
||||||
`String` is the most generic and always matches. `Int` only matches when the string supplied can be turned into an integer. `Model` only matches when the string, used as an identifier, can be used to find the model in the database.
|
`String` is the most generic and always matches. `Int` only matches when the string supplied can be turned into an integer. `Model` only matches when the string, used as an identifier, can be used to find the model in the database.
|
||||||
|
|
||||||
Our previous example with users can be further simplified.
|
Our previous example with users can be further simplified.
|
||||||
|
|
||||||
|
|
@ -126,7 +126,7 @@ Manual request parameters also work with [groups](group.md).
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
let userGroup = drop.grouped("users", ":userId")
|
let userGroup = drop.grouped("users", ":userId")
|
||||||
userGroup.get("messages") { req in
|
userGroup.get("messages") { req in
|
||||||
let user = try req.parameters.extract("userId") as User
|
let user = try req.parameters.extract("userId") as User
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue