diff --git a/build/3.0/fluent/models/index.html b/build/3.0/fluent/models/index.html index f577075f..09674537 100644 --- a/build/3.0/fluent/models/index.html +++ b/build/3.0/fluent/models/index.html @@ -93,7 +93,7 @@ - + Skip to content @@ -596,15 +596,15 @@
Models are the heart of Fluent. Unlike ORMs in other languages, Fluent doesn't return untyped -arrays or dictionaries for queries. Instead, you query the database using models. This allows the -Swift compiler to catch many errors that have burdened ORM users for ages.
-In this guide, we will cover the creation of a basic User model.
Every Fluent model starts with a Codable class. You can make any Codable class a Fluent model,
-even ones that come from a different module. All you have to do is conform to Model.
import Foundation -import Vapor +Fluent Models¶
+Models are the heart of Fluent. Unlike ORMs in other languages, Fluent doesn't return untyped arrays or dictionaries for queries. Instead, you query the database using models. This allows the Swift compiler to catch many errors that have burdened ORM users for ages.
+++Info
+This guide provides an overview of the
+Modelprotocol and its associated methods and properties. If you are just getting started, check find the guide for your database at Fluent → Getting Started.+
Modelis a protocol in theFluentmodule. It extends theAnyModelprotocol which can be used for type-erasure.Conformance¶
+Both
+structs andclasses can conform toModel, however you must pay special attention to Fluent's return types if you use astruct. Since Fluent works asynchronously, any mutations to a value-type (struct) model must return a new copy of the model as a future result.Normally, you will conform your model to one of the convenience models available in your database-specific package (i.e.,
+PostgreSQLModel). However, if you want to customize additional properties, such as the model'sidKey, you will want to use theModelprotocol itself.Let's take a look at what a basic
+Modelconformance looks like.-/// A simple user. +final class User: Model { + /// See `Model.Database` + typealias Database = FooDatabase -final class User: Content { - var id: UUID? + /// See `Model.ID` + typealias ID = Int + + /// See `Model.idKey` + static let idKey: IDKey = \.id + + /// 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 + } }Although it's not necessary, adding
-finalto your Swift classes can make them more performant -and also make addinginitmethods in extensions easier.Conforming to Model¶
-Now that we have our
-Userclass, let's conform it toModel.- - -import FluentMySQL - -extension User: Model { - -} -Once you add this conformance requirement, Swift will tell you that it does not yet conform. -Let's add the necessary items to make
Userconform to model.+Tip
-We recommend adding
+Modelconformance in an extension to help keep your code clean.Using
finalprevents your class from being sub-classed. This makes your life easier.Associated Types¶
+
Modeldefines a few associated types that help Fluent create type-safe APIs for you to use. Take a look atAnyModelif you need a type-erased version with no associated types.Database¶
-The first step to conforming to
-Modelis to let Fluent know which type of database you plan -on using this model with. This allows Fluent to enable database-specific features wherever you -use this model.import FluentMySQL - -extension User: Model { - ... - - /// See Model.Database - typealias Database = MySQLDatabase +This type indicates to Fluent which database you intend to use with this model. Using this information, Fluent can dynamically add appropriate methods and data types to any
+QueryBuilders you create with this model.+final class User: Model { + /// See `Model.Database` + typealias Database = FooDatabase + /// ... }It is possible to make this associated type generic by adding a generic type to your class or struct (i.e,
+User<T>). This is useful for cases where you are attempting to create generic extensions to Fluent, like perhaps an additive service provider.+ + +final class User<D>: Model where D: Database { + /// See `Model.Database` + typealias Database = D + /// ... +} +You can add further conditions to
+D, such asQuerySupportingorSchemaSupporting. You can also dynamically extend and conform your generic model usingextension User where D: ... { }.That said, for most cases, you should stick to using a concrete type-alias wherever possible. Fluent 3 is designed to allow you to harness the power of your database by creating a strong connection between your models and the underlying driver.
ID¶
-Now we can tell Fluent what type of ID this model uses. In this example, our
-Usermodel -has an ID property of typeUUIDnamedid.import FluentMySQL -import Foundation - -extension User: Model { - ... - - /// See Model.ID +This property defines the type your model will use for its unique identifier.
+- /// See Model.idKey - static var idKey: IDKey { - return \.id + +final class User: Model { + /// See `Model.ID` typealias ID = UUID + /// ... +} +This will usually be something like
+Int,UUID, orStringalthough you can theoretically use any type you like.Properties¶
+There are several overridable properties on
+Modelthat you can use to customize how Fluent interacts with your database.Name¶
+This
+Stringwill be used as a unique identifier for your model whenever Fluent needs one.+ + +final class User: Model { + /// See `Model.name` + static let name = "user" + /// ... +} +By default, this is the type name of your model lowercased.
+Entity¶
+Entity is a generic word used to mean either "table" or "collection", depending on which type of backend you are using for Fluent.
++ + +final class Goose: Model { + /// See `Model.entity` + static let entity = "geese" + /// ... +} +By default, this property will be name pluralized. Overriding this property is useful in situations where language fails you and the plural form of a word is very irregular.
+ID Key¶
+The ID key is a writeable key path that points to your model's unique identifier property.
+Usually this will be a property named
+id(for some databases it is_id). However you can theoretically use any key you like.+ + +final class User: Model { + /// See `Model.ID` + typealias ID = String + + /// See `Model.entity` + static let idKey = \.username + + /// The user's unique username + var username: String? + + /// ... +} +The
+idKeyproperty must point to an optional, writeable (var) property with type matching ID.Lifecycle¶
+There are several lifecycle methods on
+Modelthat you can override to hook into Fluent events.+ +
++ + + +method +description +throwing ++ ++ willCreateCalled before Fluent saves your model (for the first time) +Cancels the save. ++ ++ didCreateCalled after Fluent saves your model (for the first time) +Save completes. Query fails. ++ ++ willUpdateCalled before Fluent saves your model (subsequent saves) +Cancels the save. ++ ++ didUpdateCalled after Fluent saves your model (subsequent saves) +Save completes. Query fails. ++ ++ willReadCalled before Fluent returns your model from a fetch query. +Cancels the fetch. ++ + ++ willDeleteCalled before Fluent deletes your model. +Cancels the delete. +Here's an example of overriding the
+willUpdate(on:)method.-final class User: Model { + /// ... + + /// See `Model.willUpdate(on:)` + func willUpdate(on connection: Database.Connection) throws -> Future<Self> { + /// Throws an error if the username is invalid + try validateUsername() + + /// Return the user. No async work is being done, so we must create a future manually. + return Future.map(on: connection) { self } } }You can use any type that conforms to
-IDTypeas a Fluent ID. You can also use any property name you'd like for the id.-Warning
-Some databases require certain ID keys. For example, MongoDB requires
+_id.CRUD¶
+The model offers basic CRUD method (create, read, update, delete).
+Create¶
+This method creates a new row / item for an instance of your model in the database.
+If your model does not have an ID, calls to
+.save(on:)will redirect to this method.+ + +let didCreate = user.create(on: req) +print(didCreate) /// Future<User> ++-Info
+If you are using a value-type (
struct), the instance of your model returned by.create(on:)will contain the model's new ID.Example¶
-We now have a fully-conformed Fluent model!
-import FluentMySQL -import Foundation -import Vapor - -final class User: Codable { - var id: UUID? - var name: String - var age: Int -} - -extension User: Model { - /// See Model.Database - typealias Database = MySQLDatabase - - /// See Model.ID - typealias ID = UUID - - /// See Model.idKey - static var idKey: IDKey { - return \.id - } -} +Read¶
+Two methods are important for reading your model from the database,
+find(_:on:)andquery(on:).-/// Finds a user with ID == 1 +let user = User.find(1, on: req) +print(user) /// Future<User?>Done¶
-Now that you have a working Fluent model, you can move onto querying your model. -However, if your database uses schemas, you may need to create a migration for your model first.
++ + +/// Finds all users with name == "Vapor" +let users = User.query(on: req).filter(\.name == "Vapor").all() +print(users) /// Future<[User]> +Update¶
+This method updates the existing row / item associated with an instance of your model in the database.
+If your model already has an ID, calls to
+.save(on:)will redirect to this method.+ + +/// Updates the user +let didUpdate = user.update(on: req) +print(didUpdate) /// Future<User> +Delete¶
+This method deletes the existing row / item associated with an instance of your model from the database.
++ + +/// Deletes the user +let didDelete = user.delete(on: req) +print(didDelete) /// Future<Void> +Methods¶
++
Modeloffers some convenience methods to make working with it easier.Require ID¶
+This method return's the models ID or throws an error.
+diff --git a/build/3.0/getting-started/futures/index.html b/build/3.0/getting-started/futures/index.html index 75f70ed0..1beef821 100644 --- a/build/3.0/getting-started/futures/index.html +++ b/build/3.0/getting-started/futures/index.html @@ -1650,7 +1650,7 @@ -let id = try user.requireID() +If you look at the method signatures for
+mapandflatMaponOptional<T>andArray<T>, you will see the are very similar to the methods available onFuture<T>.If you look at the method signatures for
mapandflatMaponOptional<T>andArray<T>, you will see that they are very similar to the methods available onFuture<T>.Map¶
The
.map(to:_:)method allows you to transform the future's value to another value. Because the future's value may not be available yet (it may be the result of an asynchronous task) we must provide a closure to accept the value./// Assume we get a future string back from some API @@ -1668,7 +1668,7 @@Flat Map¶
-The
+.flatMap(to:_:)method allows you to transform the future's value to another future value. It gets the name "flat" map because it is what allows you to avoid creating nested futures (i.e.,Future<Future<T>>). In other words, it helps you keep your generic futures flat.The
.flatMap(to:_:)method allows you to transform the future's value to another future value. It gets the name "flat" map because it is what allows you to avoid creating nested futures (e.g.,Future<Future<T>>). In other words, it helps you keep your generic futures flat./// Assume we get a future string back from some API let futureString: Future<String> = ... @@ -1805,7 +1805,7 @@Thread Safety¶
Promises can be completed (
succeed(result:)/fail(error:)) from any thread. This is why promises require an event-loop to be initialized. Promises ensure that the completion action gets returned to its event-loop for execution.Event Loop¶
-When your application boots, it will usually create one event loop for each core in the CPU it is running on. Each event loop has exactly one thread. If you are familiar with event loops from Node.js, the one's in Vapor are very similar. The only difference is that Vapor can run multiple event loops in one process since Swift supports multi-threading.
+When your application boots, it will usually create one event loop for each core in the CPU it is running on. Each event loop has exactly one thread. If you are familiar with event loops from Node.js, the ones in Vapor are very similar. The only difference is that Vapor can run multiple event loops in one process since Swift supports multi-threading.
Each time a client connects to your server, it will be assigned to one of the event loops. From that point on, all communication between the server and that client will happen on that same event loop (and by association, that event loop's thread).
The event loop is responsible for keeping track of each connected client's state. If there is a request from the client waiting to be read, the event loop trigger a read notification, causing the data to be read. Once the entire request is read, any futures waiting for that request's data will be completed.
Worker¶
diff --git a/build/3.0/search/search_index.json b/build/3.0/search/search_index.json index 63a1496c..0bd4cb19 100644 --- a/build/3.0/search/search_index.json +++ b/build/3.0/search/search_index.json @@ -452,7 +452,7 @@ }, { "location": "/getting-started/futures/", - "text": "Futures\n\n\nYou may have noticed some APIs in Vapor expect or return a generic \nFuture\n type. If this is your first time hearing about futures, they might seem a little confusing at first. But don't worry, Vapor makes them easy to use.\n\n\n\n\nInfo\n\n\nThe promises, futures, and event loops that Vapor uses all come from the \nSwift NIO\n library. This document covers the basics as well as some type-aliases and extensions that Vapor adds to make things more convenient.\n\n\n\n\nPromises and futures are related, but distinct types. Promises are used to \ncreate\n futures. Most of the time, you will be working with futures returned by Vapor's APIs and you will not need to worry about creating promises.\n\n\n\n\n\n\n\n\ntype\n\n\ndescription\n\n\nmutability\n\n\nmethods\n\n\n\n\n\n\n\n\n\n\nFuture\n\n\nReference to an object that may not be available yet.\n\n\nread-only\n\n\n.map(to:_:)\n \n.flatMap(to:_:)\n \ndo(_:)\n \ncatch(_:)\n\n\n\n\n\n\nPromise\n\n\nA promise to provide some object asynchronously.\n\n\nread/write\n\n\nsucceed(_:)\n \nfail(_:)\n\n\n\n\n\n\n\n\nFutures are an alternative to callback-based asynchronous APIs. Futures can be chained and transformed in ways that simple closures cannot, making them quite powerful.\n\n\nTransforming\n\n\nJust like optionals in Swift, futures can be mapped and flat-mapped. These are the most common operations you will perform on futures.\n\n\n\n\n\n\n\n\nmethod\n\n\nsignature\n\n\ndescription\n\n\n\n\n\n\n\n\n\n\nmap\n\n\nto: U.Type, _: (T) -\n U\n\n\nMaps a future value to a different value.\n\n\n\n\n\n\nflatMap\n\n\nto: U.Type, _: (T) -\n Future\nU\n\n\nMaps a future value to different \nfuture\n value.\n\n\n\n\n\n\ntransform\n\n\nto: U\n\n\nMaps a future to an already available value.\n\n\n\n\n\n\n\n\nIf you look at the method signatures for \nmap\n and \nflatMap\n on \nOptional\nT\n and \nArray\nT\n, you will see the are very similar to the methods available on \nFuture\nT\n.\n\n\nMap\n\n\nThe \n.map(to:_:)\n method allows you to transform the future's value to another value. Because the future's value may not be available yet (it may be the result of an asynchronous task) we must provide a closure to accept the value.\n\n\n/// Assume we get a future string back from some API\n\n\nlet\n \nfutureString\n:\n \nFuture\nString\n \n=\n \n...\n\n\n\n/// Map the future string to an integer\n\n\nlet\n \nfutureInt\n \n=\n \nfutureString\n.\nmap\n(\nto\n:\n \nInt\n.\nself\n)\n \n{\n \nstring\n \nin\n\n \nprint\n(\nstring\n)\n \n// The actual String\n\n \nreturn\n \nInt\n(\nstring\n)\n \n??\n \n0\n\n\n}\n\n\n\n/// We now have a future integer\n\n\nprint\n(\nfutureInt\n)\n \n// Future\nInt\n\n\n\n\n\n\nFlat Map\n\n\nThe \n.flatMap(to:_:)\n method allows you to transform the future's value to another future value. It gets the name \"flat\" map because it is what allows you to avoid creating nested futures (i.e., \nFuture\nFuture\nT\n). In other words, it helps you keep your generic futures flat.\n\n\n/// Assume we get a future string back from some API\n\n\nlet\n \nfutureString\n:\n \nFuture\nString\n \n=\n \n...\n\n\n\n/// Assume we have created an HTTP client\n\n\nlet\n \nclient\n:\n \nClient\n \n=\n \n...\n \n\n\n/// Flat-map the future string to a future response\n\n\nlet\n \nfutureResponse\n \n=\n \nfutureString\n.\nflatMap\n(\nto\n:\n \nResponse\n.\nself\n)\n \n{\n \nstring\n \nin\n\n \nreturn\n \nclient\n.\nget\n(\nstring\n)\n \n// Future\nResponse\n\n\n}\n\n\n\n/// We now have a future response\n\n\nprint\n(\nfutureResponse\n)\n \n// Future\nResponse\n\n\n\n\n\n\n\n\nInfo\n\n\nIf we instead used \n.map(to:_:)\n in the above example, we would have ended up with a \nFuture\nFuture\nResponse\n. Yikes!\n\n\n\n\nTransform\n\n\nThe \n.transform(_:)\n method allows you to modify a future's value, ignoring the existing value. This is especially useful for transforming the results of \nFuture\nVoid\n where the actual value of the future is not important.\n\n\n\n\nTip\n\n\nFuture\nVoid\n, sometimes called a signal, is a future whose sole purpose is to notify you of completion or failure of some async operation.\n\n\n\n\n/// Assume we get a void future back from some API\n\n\nlet\n \nuserDidSave\n:\n \nFuture\nVoid\n \n=\n \n...\n\n\n\n/// Transform the void future to an HTTP status\n\n\nlet\n \nfutureStatus\n \n=\n \nuserDidSave\n.\ntransform\n(\nto\n:\n \nHTTPStatus\n.\nok\n)\n\n\nprint\n(\nfutureStatus\n)\n \n// Future\nHTTPStatus\n\n\n\n\n\n\nEven though we have supplied an already-available value to \ntransform\n, this is still a \ntransformation\n. The future will not complete until all previous futures have completed (or failed).\n\n\nChaining\n\n\nThe great part about transformations on futures is that they can be chained. This allows you to express many conversions and subtasks easily.\n\n\nLet's modify the examples from above to see how we can take advantage of chaining.\n\n\n/// Assume we get a future string back from some API\n\n\nlet\n \nfutureString\n:\n \nFuture\nString\n \n=\n \n...\n\n\n\n/// Assume we have created an HTTP client\n\n\nlet\n \nclient\n:\n \nClient\n \n=\n \n...\n \n\n\n/// Transform the string to a url, then to a response\n\n\nlet\n \nfutureResponse\n \n=\n \nfutureString\n.\nmap\n(\nto\n:\n \nURL\n.\nself\n)\n \n{\n \nstring\n \nin\n\n \nguard\n \nlet\n \nurl\n \n=\n \nURL\n(\nstring\n:\n \nstring\n)\n \nelse\n \n{\n\n \nthrow\n \nAbort\n(.\nbadRequest\n,\n \nreason\n:\n \nInvalid URL string: \n\\(\nstring\n)\n)\n\n \n}\n\n \nreturn\n \nurl\n\n\n}.\nflatMap\n(\nto\n:\n \nResponse\n.\nself\n)\n \n{\n \nurl\n \nin\n\n \nreturn\n \nclient\n.\nget\n(\nurl\n)\n\n\n}\n\n\n\nprint\n(\nfutureResponse\n)\n \n// Future\nResponse\n\n\n\n\n\n\nAfter the initial call to map, there is a temporary \nFuture\nURL\n created. This future is then immediately flat-mapped to a \nFuture\nResponse\n\n\n\n\nTip\n\n\nYou can \nthrow\n errors inside of map and flat-map closures. This will result in the future failing with the error thrown.\n\n\n\n\nFuture\n\n\nLet's take a look at some other, less commonly used methods on \nFuture\nT\n.\n\n\nDo / Catch\n\n\nSimilar to Swift's \ndo\n / \ncatch\n syntax, futures have a \ndo\n and \ncatch\n method for awaiting the future's result.\n\n\n/// Assume we get a future string back from some API\n\n\nlet\n \nfutureString\n:\n \nFuture\nString\n \n=\n \n...\n\n\n\nfutureString\n.\ndo\n \n{\n \nstring\n \nin\n\n \nprint\n(\nstring\n)\n \n// The actual String\n\n\n}.\ncatch\n \n{\n \nerror\n \nin\n\n \nprint\n(\nerror\n)\n \n// A Swift Error\n\n\n}\n\n\n\n\n\n\n\n\nInfo\n\n\n.do\n and \n.catch\n work together. If you forget \n.catch\n, the compiler will warn you about an unused result. Don't forget to handle the error case!\n\n\n\n\nAlways\n\n\nYou can use \nalways\n to add a callback that will be executed whether the future succeeds or fails.\n\n\n/// Assume we get a future string back from some API\n\n\nlet\n \nfutureString\n:\n \nFuture\nString\n \n=\n \n...\n\n\n\nfutureString\n.\nalways\n \n{\n\n \nprint\n(\nThe future is complete!\n)\n\n\n}\n\n\n\n\n\n\n\n\nNote\n\n\nYou can add as many callbacks to a future as you want.\n\n\n\n\nWait\n\n\nYou can use \n.wait()\n to synchronously wait for the future to be completed. Since a future may fail, this call is throwing.\n\n\n/// Assume we get a future string back from some API\n\n\nlet\n \nfutureString\n:\n \nFuture\nString\n \n=\n \n...\n\n\n\n/// Block until the string is ready\n\n\nlet\n \nstring\n \n=\n \ntry\n \nfutureString\n.\nwait\n()\n\n\nprint\n(\nstring\n)\n \n/// String\n\n\n\n\n\n\n\n\nWarning\n\n\nDo not use this method in route closures or controllers. Read the section about \nBlocking\n for more information.\n\n\n\n\nPromise\n\n\nMost of the time, you will be transforming futures returned by calls to Vapor's APIs. However, at some point you may need to create a promise of your own.\n\n\nTo create a promise, you will need access to an \nEventLoop\n. All containers in Vapor have an \neventLoop\n property that you can use. Most commonly, this will be the current \nRequest\n.\n\n\n/// Create a new promise for some string\n\n\nlet\n \npromiseString\n \n=\n \nreq\n.\neventLoop\n.\nnewPromise\n(\nString\n.\nself\n)\n\n\nprint\n(\npromiseString\n)\n \n// Promise\nString\n\n\nprint\n(\npromiseString\n.\nfutureResult\n)\n \n// Future\nString\n\n\n\n/// Completes the associated future\n\n\npromiseString\n.\nsucceed\n(\nresult\n:\n \nHello\n)\n\n\n\n/// Fails the associated future\n\n\npromiseString\n.\nfail\n(\nerror\n:\n \n...)\n\n\n\n\n\n\n\n\nInfo\n\n\nA promise can only be completed once. Any subsequent completions will be ignored.\n\n\n\n\nThread Safety\n\n\nPromises can be completed (\nsucceed(result:)\n / \nfail(error:)\n) from any thread. This is why promises require an event-loop to be initialized. Promises ensure that the completion action gets returned to its event-loop for execution.\n\n\nEvent Loop\n\n\nWhen your application boots, it will usually create one event loop for each core in the CPU it is running on. Each event loop has exactly one thread. If you are familiar with event loops from Node.js, the one's in Vapor are very similar. The only difference is that Vapor can run multiple event loops in one process since Swift supports multi-threading.\n\n\nEach time a client connects to your server, it will be assigned to one of the event loops. From that point on, all communication between the server and that client will happen on that same event loop (and by association, that event loop's thread). \n\n\nThe event loop is responsible for keeping track of each connected client's state. If there is a request from the client waiting to be read, the event loop trigger a read notification, causing the data to be read. Once the entire request is read, any futures waiting for that request's data will be completed. \n\n\nWorker\n\n\nThings that have access to an event loop are called \nWorkers\n. Every container in Vapor is a worker. \n\n\nThe most common containers you will interact with in Vapor are:\n\n\n\n\nApplication\n\n\nRequest\n\n\nResponse\n\n\n\n\nYou can use the \n.eventLoop\n property on these containers to gain access to the event loop.\n\n\nprint\n(\napp\n.\neventLoop\n)\n \n// EventLoop\n\n\n\n\n\n\nThere are many methods in Vapor that require the current worker to be passed along. It will usually be labeled like \non: Worker\n. If you are in a route closure or a controller, pass the current \nRequest\n or \nResponse\n. If you need a worker while booting your app, use the \nApplication\n.\n\n\nBlocking\n\n\nAn absolutely critical rule is the following:\n\n\n\n\nDanger\n\n\nNever make blocking calls directly on an event loop.\n\n\n\n\nAn example of a blocking call would be something like \nlibc.sleep(_:)\n.\n\n\nrouter\n.\nget\n(\nhello\n)\n \n{\n \nreq\n \nin\n\n \n/// Puts the event loop\ns thread to sleep.\n\n \nsleep\n(\n5\n)\n\n\n \n/// Returns a simple string once the thread re-awakens.\n\n \nreturn\n \nHello, world!\n\n\n}\n\n\n\n\n\n\nsleep(_:)\n is a command that blocks the current thread for the number of seconds supplied. If you do blocking work directly on an event loop, the event loop will be unable to respond to any other clients assigned to it for the duration of the blocking work. In other words, if you do \nsleep(5)\n on an event loop, all of the other clients connected to that event loop (possibly hundreds or thousands) will be delayed for at least 5 seconds.\n\n\nMake sure to run any blocking work in the background. Use promises to notify the event loop when this work is done in a non-blocking way.\n\n\nrouter\n.\nget\n(\nhello\n)\n \n{\n \nreq\n \nin\n\n \n/// Create a new void promise\n\n \nlet\n \npromise\n \n=\n \nreq\n.\neventLoop\n.\nnewPromise\n(\nVoid\n.\nself\n)\n\n\n \n/// Dispatch some work to happen on a background thread\n\n \nDispatchQueue\n.\nglobal\n()\n \n{\n\n \n/// Puts the background thread to sleep\n\n \n/// This will not affect any of the event loops\n\n \nsleep\n(\n5\n)\n\n\n \n/// When the \nblocking work\n has completed,\n\n \n/// complete the promise and its associated future.\n\n \npromise\n.\nsucceed\n()\n\n \n}\n\n\n \n/// Wait for the future to be completed, \n\n \n/// then transform the result to a simple String\n\n \nreturn\n \npromise\n.\nfutureResult\n.\ntransform\n(\nto\n:\n \nHello, world!\n)\n\n\n}\n\n\n\n\n\n\nNot all blocking calls will be as obvious as \nsleep(_:)\n. If you are suspicious that a call you are using may be blocking, research the method itself or ask someone. Chances are if the function is doing disk or network IO and uses a synchronous API (no callbacks or futures) it is blocking.\n\n\n\n\nInfo\n\n\nIf doing blocking work is a central part of your application, you should consider using a \nBlockingIOThreadPool\n to control the number of threads you create to do blocking work. This will help you avoid starving your event loops from CPU time while blocking work is being done.", + "text": "Futures\n\n\nYou may have noticed some APIs in Vapor expect or return a generic \nFuture\n type. If this is your first time hearing about futures, they might seem a little confusing at first. But don't worry, Vapor makes them easy to use.\n\n\n\n\nInfo\n\n\nThe promises, futures, and event loops that Vapor uses all come from the \nSwift NIO\n library. This document covers the basics as well as some type-aliases and extensions that Vapor adds to make things more convenient.\n\n\n\n\nPromises and futures are related, but distinct types. Promises are used to \ncreate\n futures. Most of the time, you will be working with futures returned by Vapor's APIs and you will not need to worry about creating promises.\n\n\n\n\n\n\n\n\ntype\n\n\ndescription\n\n\nmutability\n\n\nmethods\n\n\n\n\n\n\n\n\n\n\nFuture\n\n\nReference to an object that may not be available yet.\n\n\nread-only\n\n\n.map(to:_:)\n \n.flatMap(to:_:)\n \ndo(_:)\n \ncatch(_:)\n\n\n\n\n\n\nPromise\n\n\nA promise to provide some object asynchronously.\n\n\nread/write\n\n\nsucceed(_:)\n \nfail(_:)\n\n\n\n\n\n\n\n\nFutures are an alternative to callback-based asynchronous APIs. Futures can be chained and transformed in ways that simple closures cannot, making them quite powerful.\n\n\nTransforming\n\n\nJust like optionals in Swift, futures can be mapped and flat-mapped. These are the most common operations you will perform on futures.\n\n\n\n\n\n\n\n\nmethod\n\n\nsignature\n\n\ndescription\n\n\n\n\n\n\n\n\n\n\nmap\n\n\nto: U.Type, _: (T) -\n U\n\n\nMaps a future value to a different value.\n\n\n\n\n\n\nflatMap\n\n\nto: U.Type, _: (T) -\n Future\nU\n\n\nMaps a future value to different \nfuture\n value.\n\n\n\n\n\n\ntransform\n\n\nto: U\n\n\nMaps a future to an already available value.\n\n\n\n\n\n\n\n\nIf you look at the method signatures for \nmap\n and \nflatMap\n on \nOptional\nT\n and \nArray\nT\n, you will see that they are very similar to the methods available on \nFuture\nT\n.\n\n\nMap\n\n\nThe \n.map(to:_:)\n method allows you to transform the future's value to another value. Because the future's value may not be available yet (it may be the result of an asynchronous task) we must provide a closure to accept the value.\n\n\n/// Assume we get a future string back from some API\n\n\nlet\n \nfutureString\n:\n \nFuture\nString\n \n=\n \n...\n\n\n\n/// Map the future string to an integer\n\n\nlet\n \nfutureInt\n \n=\n \nfutureString\n.\nmap\n(\nto\n:\n \nInt\n.\nself\n)\n \n{\n \nstring\n \nin\n\n \nprint\n(\nstring\n)\n \n// The actual String\n\n \nreturn\n \nInt\n(\nstring\n)\n \n??\n \n0\n\n\n}\n\n\n\n/// We now have a future integer\n\n\nprint\n(\nfutureInt\n)\n \n// Future\nInt\n\n\n\n\n\n\nFlat Map\n\n\nThe \n.flatMap(to:_:)\n method allows you to transform the future's value to another future value. It gets the name \"flat\" map because it is what allows you to avoid creating nested futures (e.g., \nFuture\nFuture\nT\n). In other words, it helps you keep your generic futures flat.\n\n\n/// Assume we get a future string back from some API\n\n\nlet\n \nfutureString\n:\n \nFuture\nString\n \n=\n \n...\n\n\n\n/// Assume we have created an HTTP client\n\n\nlet\n \nclient\n:\n \nClient\n \n=\n \n...\n \n\n\n/// Flat-map the future string to a future response\n\n\nlet\n \nfutureResponse\n \n=\n \nfutureString\n.\nflatMap\n(\nto\n:\n \nResponse\n.\nself\n)\n \n{\n \nstring\n \nin\n\n \nreturn\n \nclient\n.\nget\n(\nstring\n)\n \n// Future\nResponse\n\n\n}\n\n\n\n/// We now have a future response\n\n\nprint\n(\nfutureResponse\n)\n \n// Future\nResponse\n\n\n\n\n\n\n\n\nInfo\n\n\nIf we instead used \n.map(to:_:)\n in the above example, we would have ended up with a \nFuture\nFuture\nResponse\n. Yikes!\n\n\n\n\nTransform\n\n\nThe \n.transform(_:)\n method allows you to modify a future's value, ignoring the existing value. This is especially useful for transforming the results of \nFuture\nVoid\n where the actual value of the future is not important.\n\n\n\n\nTip\n\n\nFuture\nVoid\n, sometimes called a signal, is a future whose sole purpose is to notify you of completion or failure of some async operation.\n\n\n\n\n/// Assume we get a void future back from some API\n\n\nlet\n \nuserDidSave\n:\n \nFuture\nVoid\n \n=\n \n...\n\n\n\n/// Transform the void future to an HTTP status\n\n\nlet\n \nfutureStatus\n \n=\n \nuserDidSave\n.\ntransform\n(\nto\n:\n \nHTTPStatus\n.\nok\n)\n\n\nprint\n(\nfutureStatus\n)\n \n// Future\nHTTPStatus\n\n\n\n\n\n\nEven though we have supplied an already-available value to \ntransform\n, this is still a \ntransformation\n. The future will not complete until all previous futures have completed (or failed).\n\n\nChaining\n\n\nThe great part about transformations on futures is that they can be chained. This allows you to express many conversions and subtasks easily.\n\n\nLet's modify the examples from above to see how we can take advantage of chaining.\n\n\n/// Assume we get a future string back from some API\n\n\nlet\n \nfutureString\n:\n \nFuture\nString\n \n=\n \n...\n\n\n\n/// Assume we have created an HTTP client\n\n\nlet\n \nclient\n:\n \nClient\n \n=\n \n...\n \n\n\n/// Transform the string to a url, then to a response\n\n\nlet\n \nfutureResponse\n \n=\n \nfutureString\n.\nmap\n(\nto\n:\n \nURL\n.\nself\n)\n \n{\n \nstring\n \nin\n\n \nguard\n \nlet\n \nurl\n \n=\n \nURL\n(\nstring\n:\n \nstring\n)\n \nelse\n \n{\n\n \nthrow\n \nAbort\n(.\nbadRequest\n,\n \nreason\n:\n \nInvalid URL string: \n\\(\nstring\n)\n)\n\n \n}\n\n \nreturn\n \nurl\n\n\n}.\nflatMap\n(\nto\n:\n \nResponse\n.\nself\n)\n \n{\n \nurl\n \nin\n\n \nreturn\n \nclient\n.\nget\n(\nurl\n)\n\n\n}\n\n\n\nprint\n(\nfutureResponse\n)\n \n// Future\nResponse\n\n\n\n\n\n\nAfter the initial call to map, there is a temporary \nFuture\nURL\n created. This future is then immediately flat-mapped to a \nFuture\nResponse\n\n\n\n\nTip\n\n\nYou can \nthrow\n errors inside of map and flat-map closures. This will result in the future failing with the error thrown.\n\n\n\n\nFuture\n\n\nLet's take a look at some other, less commonly used methods on \nFuture\nT\n.\n\n\nDo / Catch\n\n\nSimilar to Swift's \ndo\n / \ncatch\n syntax, futures have a \ndo\n and \ncatch\n method for awaiting the future's result.\n\n\n/// Assume we get a future string back from some API\n\n\nlet\n \nfutureString\n:\n \nFuture\nString\n \n=\n \n...\n\n\n\nfutureString\n.\ndo\n \n{\n \nstring\n \nin\n\n \nprint\n(\nstring\n)\n \n// The actual String\n\n\n}.\ncatch\n \n{\n \nerror\n \nin\n\n \nprint\n(\nerror\n)\n \n// A Swift Error\n\n\n}\n\n\n\n\n\n\n\n\nInfo\n\n\n.do\n and \n.catch\n work together. If you forget \n.catch\n, the compiler will warn you about an unused result. Don't forget to handle the error case!\n\n\n\n\nAlways\n\n\nYou can use \nalways\n to add a callback that will be executed whether the future succeeds or fails.\n\n\n/// Assume we get a future string back from some API\n\n\nlet\n \nfutureString\n:\n \nFuture\nString\n \n=\n \n...\n\n\n\nfutureString\n.\nalways\n \n{\n\n \nprint\n(\nThe future is complete!\n)\n\n\n}\n\n\n\n\n\n\n\n\nNote\n\n\nYou can add as many callbacks to a future as you want.\n\n\n\n\nWait\n\n\nYou can use \n.wait()\n to synchronously wait for the future to be completed. Since a future may fail, this call is throwing.\n\n\n/// Assume we get a future string back from some API\n\n\nlet\n \nfutureString\n:\n \nFuture\nString\n \n=\n \n...\n\n\n\n/// Block until the string is ready\n\n\nlet\n \nstring\n \n=\n \ntry\n \nfutureString\n.\nwait\n()\n\n\nprint\n(\nstring\n)\n \n/// String\n\n\n\n\n\n\n\n\nWarning\n\n\nDo not use this method in route closures or controllers. Read the section about \nBlocking\n for more information.\n\n\n\n\nPromise\n\n\nMost of the time, you will be transforming futures returned by calls to Vapor's APIs. However, at some point you may need to create a promise of your own.\n\n\nTo create a promise, you will need access to an \nEventLoop\n. All containers in Vapor have an \neventLoop\n property that you can use. Most commonly, this will be the current \nRequest\n.\n\n\n/// Create a new promise for some string\n\n\nlet\n \npromiseString\n \n=\n \nreq\n.\neventLoop\n.\nnewPromise\n(\nString\n.\nself\n)\n\n\nprint\n(\npromiseString\n)\n \n// Promise\nString\n\n\nprint\n(\npromiseString\n.\nfutureResult\n)\n \n// Future\nString\n\n\n\n/// Completes the associated future\n\n\npromiseString\n.\nsucceed\n(\nresult\n:\n \nHello\n)\n\n\n\n/// Fails the associated future\n\n\npromiseString\n.\nfail\n(\nerror\n:\n \n...)\n\n\n\n\n\n\n\n\nInfo\n\n\nA promise can only be completed once. Any subsequent completions will be ignored.\n\n\n\n\nThread Safety\n\n\nPromises can be completed (\nsucceed(result:)\n / \nfail(error:)\n) from any thread. This is why promises require an event-loop to be initialized. Promises ensure that the completion action gets returned to its event-loop for execution.\n\n\nEvent Loop\n\n\nWhen your application boots, it will usually create one event loop for each core in the CPU it is running on. Each event loop has exactly one thread. If you are familiar with event loops from Node.js, the ones in Vapor are very similar. The only difference is that Vapor can run multiple event loops in one process since Swift supports multi-threading.\n\n\nEach time a client connects to your server, it will be assigned to one of the event loops. From that point on, all communication between the server and that client will happen on that same event loop (and by association, that event loop's thread). \n\n\nThe event loop is responsible for keeping track of each connected client's state. If there is a request from the client waiting to be read, the event loop trigger a read notification, causing the data to be read. Once the entire request is read, any futures waiting for that request's data will be completed. \n\n\nWorker\n\n\nThings that have access to an event loop are called \nWorkers\n. Every container in Vapor is a worker. \n\n\nThe most common containers you will interact with in Vapor are:\n\n\n\n\nApplication\n\n\nRequest\n\n\nResponse\n\n\n\n\nYou can use the \n.eventLoop\n property on these containers to gain access to the event loop.\n\n\nprint\n(\napp\n.\neventLoop\n)\n \n// EventLoop\n\n\n\n\n\n\nThere are many methods in Vapor that require the current worker to be passed along. It will usually be labeled like \non: Worker\n. If you are in a route closure or a controller, pass the current \nRequest\n or \nResponse\n. If you need a worker while booting your app, use the \nApplication\n.\n\n\nBlocking\n\n\nAn absolutely critical rule is the following:\n\n\n\n\nDanger\n\n\nNever make blocking calls directly on an event loop.\n\n\n\n\nAn example of a blocking call would be something like \nlibc.sleep(_:)\n.\n\n\nrouter\n.\nget\n(\nhello\n)\n \n{\n \nreq\n \nin\n\n \n/// Puts the event loop\ns thread to sleep.\n\n \nsleep\n(\n5\n)\n\n\n \n/// Returns a simple string once the thread re-awakens.\n\n \nreturn\n \nHello, world!\n\n\n}\n\n\n\n\n\n\nsleep(_:)\n is a command that blocks the current thread for the number of seconds supplied. If you do blocking work directly on an event loop, the event loop will be unable to respond to any other clients assigned to it for the duration of the blocking work. In other words, if you do \nsleep(5)\n on an event loop, all of the other clients connected to that event loop (possibly hundreds or thousands) will be delayed for at least 5 seconds.\n\n\nMake sure to run any blocking work in the background. Use promises to notify the event loop when this work is done in a non-blocking way.\n\n\nrouter\n.\nget\n(\nhello\n)\n \n{\n \nreq\n \nin\n\n \n/// Create a new void promise\n\n \nlet\n \npromise\n \n=\n \nreq\n.\neventLoop\n.\nnewPromise\n(\nVoid\n.\nself\n)\n\n\n \n/// Dispatch some work to happen on a background thread\n\n \nDispatchQueue\n.\nglobal\n()\n \n{\n\n \n/// Puts the background thread to sleep\n\n \n/// This will not affect any of the event loops\n\n \nsleep\n(\n5\n)\n\n\n \n/// When the \nblocking work\n has completed,\n\n \n/// complete the promise and its associated future.\n\n \npromise\n.\nsucceed\n()\n\n \n}\n\n\n \n/// Wait for the future to be completed, \n\n \n/// then transform the result to a simple String\n\n \nreturn\n \npromise\n.\nfutureResult\n.\ntransform\n(\nto\n:\n \nHello, world!\n)\n\n\n}\n\n\n\n\n\n\nNot all blocking calls will be as obvious as \nsleep(_:)\n. If you are suspicious that a call you are using may be blocking, research the method itself or ask someone. Chances are if the function is doing disk or network IO and uses a synchronous API (no callbacks or futures) it is blocking.\n\n\n\n\nInfo\n\n\nIf doing blocking work is a central part of your application, you should consider using a \nBlockingIOThreadPool\n to control the number of threads you create to do blocking work. This will help you avoid starving your event loops from CPU time while blocking work is being done.", "title": "Futures" }, { @@ -462,7 +462,7 @@ }, { "location": "/getting-started/futures/#transforming", - "text": "Just like optionals in Swift, futures can be mapped and flat-mapped. These are the most common operations you will perform on futures. method signature description map to: U.Type, _: (T) - U Maps a future value to a different value. flatMap to: U.Type, _: (T) - Future U Maps a future value to different future value. transform to: U Maps a future to an already available value. If you look at the method signatures for map and flatMap on Optional T and Array T , you will see the are very similar to the methods available on Future T .", + "text": "Just like optionals in Swift, futures can be mapped and flat-mapped. These are the most common operations you will perform on futures. method signature description map to: U.Type, _: (T) - U Maps a future value to a different value. flatMap to: U.Type, _: (T) - Future U Maps a future value to different future value. transform to: U Maps a future to an already available value. If you look at the method signatures for map and flatMap on Optional T and Array T , you will see that they are very similar to the methods available on Future T .", "title": "Transforming" }, { @@ -472,7 +472,7 @@ }, { "location": "/getting-started/futures/#flat-map", - "text": "The .flatMap(to:_:) method allows you to transform the future's value to another future value. It gets the name \"flat\" map because it is what allows you to avoid creating nested futures (i.e., Future Future T ). In other words, it helps you keep your generic futures flat. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Flat-map the future string to a future response let futureResponse = futureString . flatMap ( to : Response . self ) { string in \n return client . get ( string ) // Future Response } /// We now have a future response print ( futureResponse ) // Future Response Info If we instead used .map(to:_:) in the above example, we would have ended up with a Future Future Response . Yikes!", + "text": "The .flatMap(to:_:) method allows you to transform the future's value to another future value. It gets the name \"flat\" map because it is what allows you to avoid creating nested futures (e.g., Future Future T ). In other words, it helps you keep your generic futures flat. /// Assume we get a future string back from some API let futureString : Future String = ... /// Assume we have created an HTTP client let client : Client = ... /// Flat-map the future string to a future response let futureResponse = futureString . flatMap ( to : Response . self ) { string in \n return client . get ( string ) // Future Response } /// We now have a future response print ( futureResponse ) // Future Response Info If we instead used .map(to:_:) in the above example, we would have ended up with a Future Future Response . Yikes!", "title": "Flat Map" }, { @@ -517,7 +517,7 @@ }, { "location": "/getting-started/futures/#event-loop", - "text": "When your application boots, it will usually create one event loop for each core in the CPU it is running on. Each event loop has exactly one thread. If you are familiar with event loops from Node.js, the one's in Vapor are very similar. The only difference is that Vapor can run multiple event loops in one process since Swift supports multi-threading. Each time a client connects to your server, it will be assigned to one of the event loops. From that point on, all communication between the server and that client will happen on that same event loop (and by association, that event loop's thread). The event loop is responsible for keeping track of each connected client's state. If there is a request from the client waiting to be read, the event loop trigger a read notification, causing the data to be read. Once the entire request is read, any futures waiting for that request's data will be completed.", + "text": "When your application boots, it will usually create one event loop for each core in the CPU it is running on. Each event loop has exactly one thread. If you are familiar with event loops from Node.js, the ones in Vapor are very similar. The only difference is that Vapor can run multiple event loops in one process since Swift supports multi-threading. Each time a client connects to your server, it will be assigned to one of the event loops. From that point on, all communication between the server and that client will happen on that same event loop (and by association, that event loop's thread). The event loop is responsible for keeping track of each connected client's state. If there is a request from the client waiting to be read, the event loop trigger a read notification, causing the data to be read. Once the entire request is read, any futures waiting for that request's data will be completed.", "title": "Event Loop" }, { @@ -692,43 +692,93 @@ }, { "location": "/fluent/models/", - "text": "Getting Started with Models\n\n\nModels are the heart of Fluent. Unlike ORMs in other languages, Fluent doesn't return untyped\narrays or dictionaries for queries. Instead, you query the database using models. This allows the\nSwift compiler to catch many errors that have burdened ORM users for ages.\n\n\nIn this guide, we will cover the creation of a basic \nUser\n model.\n\n\nClass\n\n\nEvery Fluent model starts with a \nCodable\n class. You can make any \nCodable\n class a Fluent model,\neven ones that come from a different module. All you have to do is conform to \nModel\n.\n\n\nimport\n \nFoundation\n\n\nimport\n \nVapor\n\n\n\nfinal\n \nclass\n \nUser\n:\n \nContent\n \n{\n\n \nvar\n \nid\n:\n \nUUID\n?\n\n \nvar\n \nname\n:\n \nString\n\n \nvar\n \nage\n:\n \nInt\n\n\n}\n\n\n\n\n\n\nAlthough it's not necessary, adding \nfinal\n to your Swift classes can make them more performant\nand also make adding \ninit\n methods in extensions easier.\n\n\nConforming to Model\n\n\nNow that we have our \nUser\n class, let's conform it to \nModel\n.\n\n\nimport\n \nFluentMySQL\n\n\n\nextension\n \nUser\n:\n \nModel\n \n{\n\n\n\n}\n\n\n\n\n\n\nOnce you add this conformance requirement, Swift will tell you that it does not yet conform.\nLet's add the necessary items to make \nUser\n conform to model.\n\n\n\n\nTip\n\n\nWe recommend adding \nModel\n conformance in an extension to help keep your code clean.\n\n\n\n\nDatabase\n\n\nThe first step to conforming to \nModel\n is to let Fluent know which type of database you plan\non using this model with. This allows Fluent to enable database-specific features wherever you\nuse this model.\n\n\nimport\n \nFluentMySQL\n\n\n\nextension\n \nUser\n:\n \nModel\n \n{\n\n \n...\n\n\n \n/// See Model.Database\n\n \ntypealias\n \nDatabase\n \n=\n \nMySQLDatabase\n\n\n}\n\n\n\n\n\n\nID\n\n\nNow we can tell Fluent what type of ID this model uses. In this example, our \nUser\n model\nhas an ID property of type \nUUID\n named \nid\n.\n\n\nimport\n \nFluentMySQL\n\n\nimport\n \nFoundation\n\n\n\nextension\n \nUser\n:\n \nModel\n \n{\n\n \n...\n\n\n \n/// See Model.ID\n\n \ntypealias\n \nID\n \n=\n \nUUID\n\n\n \n/// See Model.idKey\n\n \nstatic\n \nvar\n \nidKey\n:\n \nIDKey\n \n{\n\n \nreturn\n \n\\\n.\nid\n\n \n}\n\n\n}\n\n\n\n\n\n\nYou can use any type that conforms to \nIDType\n as a Fluent ID. You can also use any property name you'd like for the id.\n\n\n\n\nWarning\n\n\nSome databases require certain ID keys. For example, MongoDB requires \n_id\n.\n\n\n\n\nExample\n\n\nWe now have a fully-conformed Fluent model!\n\n\nimport\n \nFluentMySQL\n\n\nimport\n \nFoundation\n\n\nimport\n \nVapor\n\n\n\nfinal\n \nclass\n \nUser\n:\n \nCodable\n \n{\n\n \nvar\n \nid\n:\n \nUUID\n?\n\n \nvar\n \nname\n:\n \nString\n\n \nvar\n \nage\n:\n \nInt\n\n\n}\n\n\n\nextension\n \nUser\n:\n \nModel\n \n{\n\n \n/// See Model.Database\n\n \ntypealias\n \nDatabase\n \n=\n \nMySQLDatabase\n\n\n \n/// See Model.ID\n\n \ntypealias\n \nID\n \n=\n \nUUID\n\n\n \n/// See Model.idKey\n\n \nstatic\n \nvar\n \nidKey\n:\n \nIDKey\n \n{\n\n \nreturn\n \n\\\n.\nid\n\n \n}\n\n\n}\n\n\n\n\n\n\nDone\n\n\nNow that you have a working Fluent model, you can move onto \nquerying\n your model.\nHowever, if your database uses schemas, you may need to create a \nmigration\n for your model first.", + "text": "Fluent Models\n\n\nModels are the heart of Fluent. Unlike ORMs in other languages, Fluent doesn't return untyped arrays or dictionaries for queries. Instead, you query the database using models. This allows the Swift compiler to catch many errors that have burdened ORM users for ages.\n\n\n\n\nInfo\n\n\nThis guide provides an overview of the \nModel\n protocol and its associated methods and properties. If you are just getting started, check find the guide for your database at \nFluent \n Getting Started\n.\n\n\n\n\nModel\n is a protocol in the \nFluent\n module. It extends the \nAnyModel\n protocol which can be used for type-erasure. \n\n\nConformance\n\n\nBoth \nstruct\ns and \nclass\nes can conform to \nModel\n, however you must pay special attention to Fluent's return types if you use a \nstruct\n. Since Fluent works asynchronously, any mutations to a value-type (\nstruct\n) model must return a new copy of the model as a future result.\n\n\nNormally, you will conform your model to one of the convenience models available in your database-specific package (i.e., \nPostgreSQLModel\n). However, if you want to customize additional properties, such as the model's \nidKey\n, you will want to use the \nModel\n protocol itself.\n\n\nLet's take a look at what a basic \nModel\n conformance looks like.\n\n\n/// A simple user.\n\n\nfinal\n \nclass\n \nUser\n:\n \nModel\n \n{\n\n \n/// See `Model.Database`\n\n \ntypealias\n \nDatabase\n \n=\n \nFooDatabase\n\n\n \n/// See `Model.ID`\n\n \ntypealias\n \nID\n \n=\n \nInt\n\n\n \n/// See `Model.idKey`\n\n \nstatic\n \nlet\n \nidKey\n:\n \nIDKey\n \n=\n \n\\\n.\nid\n\n\n \n/// The unique identifier for this user.\n\n \nvar\n \nid\n:\n \nInt\n?\n\n\n \n/// The user\ns full name.\n\n \nvar\n \nname\n:\n \nString\n\n\n \n/// The user\ns current age in years.\n\n \nvar\n \nage\n:\n \nInt\n\n\n \n/// Creates a new user.\n\n \ninit\n(\nid\n:\n \nInt\n?\n \n=\n \nnil\n,\n \nname\n:\n \nString\n,\n \nage\n:\n \nInt\n)\n \n{\n\n \nself\n.\nid\n \n=\n \nid\n\n \nself\n.\nname\n \n=\n \nname\n\n \nself\n.\nage\n \n=\n \nage\n\n \n}\n\n\n}\n\n\n\n\n\n\n\n\nTip\n\n\nUsing \nfinal\n prevents your class from being sub-classed. This makes your life easier.\n\n\n\n\nAssociated Types\n\n\nModel\n defines a few associated types that help Fluent create type-safe APIs for you to use. Take a look at \nAnyModel\n if you need a type-erased version with no associated types.\n\n\nDatabase\n\n\nThis type indicates to Fluent which database you intend to use with this model. Using this information, Fluent can dynamically add appropriate methods and data types to any \nQueryBuilder\ns you create with this model.\n\n\nfinal\n \nclass\n \nUser\n:\n \nModel\n \n{\n\n \n/// See `Model.Database`\n\n \ntypealias\n \nDatabase\n \n=\n \nFooDatabase\n\n \n/// ...\n\n\n}\n\n\n\n\n\n\nIt is possible to make this associated type generic by adding a generic type to your class or struct (i.e, \nUser\nT\n). This is useful for cases where you are attempting to create generic extensions to Fluent, like perhaps an additive service provider.\n\n\nfinal\n \nclass\n \nUser\nD\n:\n \nModel\n \nwhere\n \nD\n:\n \nDatabase\n \n{\n\n \n/// See `Model.Database`\n\n \ntypealias\n \nDatabase\n \n=\n \nD\n\n \n/// ...\n\n\n}\n\n\n\n\n\n\nYou can add further conditions to \nD\n, such as \nQuerySupporting\n or \nSchemaSupporting\n. You can also dynamically extend and conform your generic model using \nextension User where D: ... { }\n.\n\n\nThat said, for most cases, you should stick to using a concrete type-alias wherever possible. Fluent 3 is designed to allow you to harness the power of your database by creating a strong connection between your models and the underlying driver. \n\n\nID\n\n\nThis property defines the type your model will use for its unique identifier.\n\n\nfinal\n \nclass\n \nUser\n:\n \nModel\n \n{\n\n \n/// See `Model.ID`\n\n \ntypealias\n \nID\n \n=\n \nUUID\n\n \n/// ...\n\n\n}\n\n\n\n\n\n\nThis will usually be something like \nInt\n, \nUUID\n, or \nString\n although you can theoretically use any type you like.\n\n\nProperties\n\n\nThere are several overridable properties on \nModel\n that you can use to customize how Fluent interacts with your database.\n\n\nName\n\n\nThis \nString\n will be used as a unique identifier for your model whenever Fluent needs one.\n\n\nfinal\n \nclass\n \nUser\n:\n \nModel\n \n{\n\n \n/// See `Model.name`\n\n \nstatic\n \nlet\n \nname\n \n=\n \nuser\n\n \n/// ...\n\n\n}\n\n\n\n\n\n\nBy default, this is the type name of your model lowercased.\n\n\nEntity\n\n\nEntity is a generic word used to mean either \"table\" or \"collection\", depending on which type of backend you are using for Fluent.\n\n\nfinal\n \nclass\n \nGoose\n:\n \nModel\n \n{\n\n \n/// See `Model.entity`\n\n \nstatic\n \nlet\n \nentity\n \n=\n \ngeese\n\n \n/// ...\n\n\n}\n\n\n\n\n\n\nBy default, this property will be \nname\n pluralized. Overriding this property is useful in situations where language fails you and the plural form of a word is very irregular.\n\n\nID Key\n\n\nThe ID key is a writeable \nkey path\n that points to your model's unique identifier property.\n\n\nUsually this will be a property named \nid\n (for some databases it is \n_id\n). However you can theoretically use any key you like.\n\n\nfinal\n \nclass\n \nUser\n:\n \nModel\n \n{\n\n \n/// See `Model.ID`\n\n \ntypealias\n \nID\n \n=\n \nString\n\n\n \n/// See `Model.entity`\n\n \nstatic\n \nlet\n \nidKey\n \n=\n \n\\\n.\nusername\n\n\n \n/// The user\ns unique username\n\n \nvar\n \nusername\n:\n \nString\n?\n\n\n \n/// ...\n\n\n}\n\n\n\n\n\n\nThe \nidKey\n property must point to an optional, writeable (\nvar\n) property with type matching \nID\n.\n\n\nLifecycle\n\n\nThere are several lifecycle methods on \nModel\n that you can override to hook into Fluent events.\n\n\n\n\n\n\n\n\nmethod\n\n\ndescription\n\n\nthrowing\n\n\n\n\n\n\n\n\n\n\nwillCreate\n\n\nCalled before Fluent saves your model (for the first time)\n\n\nCancels the save.\n\n\n\n\n\n\ndidCreate\n\n\nCalled after Fluent saves your model (for the first time)\n\n\nSave completes. Query fails.\n\n\n\n\n\n\nwillUpdate\n\n\nCalled before Fluent saves your model (subsequent saves)\n\n\nCancels the save.\n\n\n\n\n\n\ndidUpdate\n\n\nCalled after Fluent saves your model (subsequent saves)\n\n\nSave completes. Query fails.\n\n\n\n\n\n\nwillRead\n\n\nCalled before Fluent returns your model from a fetch query.\n\n\nCancels the fetch.\n\n\n\n\n\n\nwillDelete\n\n\nCalled before Fluent deletes your model.\n\n\nCancels the delete.\n\n\n\n\n\n\n\n\nHere's an example of overriding the \nwillUpdate(on:)\n method.\n\n\nfinal\n \nclass\n \nUser\n:\n \nModel\n \n{\n\n \n/// ...\n\n\n \n/// See `Model.willUpdate(on:)`\n\n \nfunc\n \nwillUpdate\n(\non\n \nconnection\n:\n \nDatabase\n.\nConnection\n)\n \nthrows\n \n-\n \nFuture\nSelf\n \n{\n\n \n/// Throws an error if the username is invalid\n\n \ntry\n \nvalidateUsername\n()\n\n\n \n/// Return the user. No async work is being done, so we must create a future manually.\n\n \nreturn\n \nFuture\n.\nmap\n(\non\n:\n \nconnection\n)\n \n{\n \nself\n \n}\n\n \n}\n\n\n}\n\n\n\n\n\n\nCRUD\n\n\nThe model offers basic CRUD method (create, read, update, delete).\n\n\nCreate\n\n\nThis method creates a new row / item for an instance of your model in the database.\n\n\nIf your model does not have an ID, calls to \n.save(on:)\n will redirect to this method.\n\n\nlet\n \ndidCreate\n \n=\n \nuser\n.\ncreate\n(\non\n:\n \nreq\n)\n\n\nprint\n(\ndidCreate\n)\n \n/// Future\nUser\n\n\n\n\n\n\n\n\nInfo\n\n\nIf you are using a value-type (\nstruct\n), the instance of your model returned by \n.create(on:)\n will contain the model's new ID.\n\n\n\n\nRead\n\n\nTwo methods are important for reading your model from the database, \nfind(_:on:)\n and \nquery(on:)\n.\n\n\n/// Finds a user with ID == 1\n\n\nlet\n \nuser\n \n=\n \nUser\n.\nfind\n(\n1\n,\n \non\n:\n \nreq\n)\n\n\nprint\n(\nuser\n)\n \n/// Future\nUser?\n\n\n\n\n\n\n/// Finds all users with name == \nVapor\n\n\nlet\n \nusers\n \n=\n \nUser\n.\nquery\n(\non\n:\n \nreq\n).\nfilter\n(\n\\\n.\nname\n \n==\n \nVapor\n).\nall\n()\n\n\nprint\n(\nusers\n)\n \n/// Future\n[User]\n\n\n\n\n\n\nUpdate\n\n\nThis method updates the existing row / item associated with an instance of your model in the database.\n\n\nIf your model already has an ID, calls to \n.save(on:)\n will redirect to this method.\n\n\n/// Updates the user\n\n\nlet\n \ndidUpdate\n \n=\n \nuser\n.\nupdate\n(\non\n:\n \nreq\n)\n\n\nprint\n(\ndidUpdate\n)\n \n/// Future\nUser\n\n\n\n\n\n\nDelete\n\n\nThis method deletes the existing row / item associated with an instance of your model from the database.\n\n\n/// Deletes the user\n\n\nlet\n \ndidDelete\n \n=\n \nuser\n.\ndelete\n(\non\n:\n \nreq\n)\n\n\nprint\n(\ndidDelete\n)\n \n/// Future\nVoid\n\n\n\n\n\n\nMethods\n\n\nModel\n offers some convenience methods to make working with it easier.\n\n\nRequire ID\n\n\nThis method return's the models ID or throws an error.\n\n\nlet\n \nid\n \n=\n \ntry\n \nuser\n.\nrequireID\n()", "title": "Models" }, { - "location": "/fluent/models/#getting-started-with-models", - "text": "Models are the heart of Fluent. Unlike ORMs in other languages, Fluent doesn't return untyped\narrays or dictionaries for queries. Instead, you query the database using models. This allows the\nSwift compiler to catch many errors that have burdened ORM users for ages. In this guide, we will cover the creation of a basic User model.", - "title": "Getting Started with Models" + "location": "/fluent/models/#fluent-models", + "text": "Models are the heart of Fluent. Unlike ORMs in other languages, Fluent doesn't return untyped arrays or dictionaries for queries. Instead, you query the database using models. This allows the Swift compiler to catch many errors that have burdened ORM users for ages. Info This guide provides an overview of the Model protocol and its associated methods and properties. If you are just getting started, check find the guide for your database at Fluent Getting Started . Model is a protocol in the Fluent module. It extends the AnyModel protocol which can be used for type-erasure.", + "title": "Fluent Models" }, { - "location": "/fluent/models/#class", - "text": "Every Fluent model starts with a Codable class. You can make any Codable class a Fluent model,\neven ones that come from a different module. All you have to do is conform to Model . import Foundation import Vapor final class User : Content { \n var id : UUID ? \n var name : String \n var age : Int } Although it's not necessary, adding final to your Swift classes can make them more performant\nand also make adding init methods in extensions easier.", - "title": "Class" + "location": "/fluent/models/#conformance", + "text": "Both struct s and class es can conform to Model , however you must pay special attention to Fluent's return types if you use a struct . Since Fluent works asynchronously, any mutations to a value-type ( struct ) model must return a new copy of the model as a future result. Normally, you will conform your model to one of the convenience models available in your database-specific package (i.e., PostgreSQLModel ). However, if you want to customize additional properties, such as the model's idKey , you will want to use the Model protocol itself. Let's take a look at what a basic Model conformance looks like. /// A simple user. final class User : Model { \n /// See `Model.Database` \n typealias Database = FooDatabase \n\n /// See `Model.ID` \n typealias ID = Int \n\n /// See `Model.idKey` \n static let idKey : IDKey = \\ . id \n\n /// The unique identifier for this user. \n var id : Int ? \n\n /// The user s full name. \n var name : String \n\n /// The user s current age in years. \n var age : Int \n\n /// Creates a new user. \n init ( id : Int ? = nil , name : String , age : Int ) { \n self . id = id \n self . name = name \n self . age = age \n } } Tip Using final prevents your class from being sub-classed. This makes your life easier.", + "title": "Conformance" }, { - "location": "/fluent/models/#conforming-to-model", - "text": "Now that we have our User class, let's conform it to Model . import FluentMySQL extension User : Model { } Once you add this conformance requirement, Swift will tell you that it does not yet conform.\nLet's add the necessary items to make User conform to model. Tip We recommend adding Model conformance in an extension to help keep your code clean.", - "title": "Conforming to Model" + "location": "/fluent/models/#associated-types", + "text": "Model defines a few associated types that help Fluent create type-safe APIs for you to use. Take a look at AnyModel if you need a type-erased version with no associated types.", + "title": "Associated Types" }, { "location": "/fluent/models/#database", - "text": "The first step to conforming to Model is to let Fluent know which type of database you plan\non using this model with. This allows Fluent to enable database-specific features wherever you\nuse this model. import FluentMySQL extension User : Model { \n ... \n\n /// See Model.Database \n typealias Database = MySQLDatabase }", + "text": "This type indicates to Fluent which database you intend to use with this model. Using this information, Fluent can dynamically add appropriate methods and data types to any QueryBuilder s you create with this model. final class User : Model { \n /// See `Model.Database` \n typealias Database = FooDatabase \n /// ... } It is possible to make this associated type generic by adding a generic type to your class or struct (i.e, User T ). This is useful for cases where you are attempting to create generic extensions to Fluent, like perhaps an additive service provider. final class User D : Model where D : Database { \n /// See `Model.Database` \n typealias Database = D \n /// ... } You can add further conditions to D , such as QuerySupporting or SchemaSupporting . You can also dynamically extend and conform your generic model using extension User where D: ... { } . That said, for most cases, you should stick to using a concrete type-alias wherever possible. Fluent 3 is designed to allow you to harness the power of your database by creating a strong connection between your models and the underlying driver.", "title": "Database" }, { "location": "/fluent/models/#id", - "text": "Now we can tell Fluent what type of ID this model uses. In this example, our User model\nhas an ID property of type UUID named id . import FluentMySQL import Foundation extension User : Model { \n ... \n\n /// See Model.ID \n typealias ID = UUID \n\n /// See Model.idKey \n static var idKey : IDKey { \n return \\ . id \n } } You can use any type that conforms to IDType as a Fluent ID. You can also use any property name you'd like for the id. Warning Some databases require certain ID keys. For example, MongoDB requires _id .", + "text": "This property defines the type your model will use for its unique identifier. final class User : Model { \n /// See `Model.ID` \n typealias ID = UUID \n /// ... } This will usually be something like Int , UUID , or String although you can theoretically use any type you like.", "title": "ID" }, { - "location": "/fluent/models/#example", - "text": "We now have a fully-conformed Fluent model! import FluentMySQL import Foundation import Vapor final class User : Codable { \n var id : UUID ? \n var name : String \n var age : Int } extension User : Model { \n /// See Model.Database \n typealias Database = MySQLDatabase \n\n /// See Model.ID \n typealias ID = UUID \n\n /// See Model.idKey \n static var idKey : IDKey { \n return \\ . id \n } }", - "title": "Example" + "location": "/fluent/models/#properties", + "text": "There are several overridable properties on Model that you can use to customize how Fluent interacts with your database.", + "title": "Properties" }, { - "location": "/fluent/models/#done", - "text": "Now that you have a working Fluent model, you can move onto querying your model.\nHowever, if your database uses schemas, you may need to create a migration for your model first.", - "title": "Done" + "location": "/fluent/models/#name", + "text": "This String will be used as a unique identifier for your model whenever Fluent needs one. final class User : Model { \n /// See `Model.name` \n static let name = user \n /// ... } By default, this is the type name of your model lowercased.", + "title": "Name" + }, + { + "location": "/fluent/models/#entity", + "text": "Entity is a generic word used to mean either \"table\" or \"collection\", depending on which type of backend you are using for Fluent. final class Goose : Model { \n /// See `Model.entity` \n static let entity = geese \n /// ... } By default, this property will be name pluralized. Overriding this property is useful in situations where language fails you and the plural form of a word is very irregular.", + "title": "Entity" + }, + { + "location": "/fluent/models/#id-key", + "text": "The ID key is a writeable key path that points to your model's unique identifier property. Usually this will be a property named id (for some databases it is _id ). However you can theoretically use any key you like. final class User : Model { \n /// See `Model.ID` \n typealias ID = String \n\n /// See `Model.entity` \n static let idKey = \\ . username \n\n /// The user s unique username \n var username : String ? \n\n /// ... } The idKey property must point to an optional, writeable ( var ) property with type matching ID .", + "title": "ID Key" + }, + { + "location": "/fluent/models/#lifecycle", + "text": "There are several lifecycle methods on Model that you can override to hook into Fluent events. method description throwing willCreate Called before Fluent saves your model (for the first time) Cancels the save. didCreate Called after Fluent saves your model (for the first time) Save completes. Query fails. willUpdate Called before Fluent saves your model (subsequent saves) Cancels the save. didUpdate Called after Fluent saves your model (subsequent saves) Save completes. Query fails. willRead Called before Fluent returns your model from a fetch query. Cancels the fetch. willDelete Called before Fluent deletes your model. Cancels the delete. Here's an example of overriding the willUpdate(on:) method. final class User : Model { \n /// ... \n\n /// See `Model.willUpdate(on:)` \n func willUpdate ( on connection : Database . Connection ) throws - Future Self { \n /// Throws an error if the username is invalid \n try validateUsername () \n\n /// Return the user. No async work is being done, so we must create a future manually. \n return Future . map ( on : connection ) { self } \n } }", + "title": "Lifecycle" + }, + { + "location": "/fluent/models/#crud", + "text": "The model offers basic CRUD method (create, read, update, delete).", + "title": "CRUD" + }, + { + "location": "/fluent/models/#create", + "text": "This method creates a new row / item for an instance of your model in the database. If your model does not have an ID, calls to .save(on:) will redirect to this method. let didCreate = user . create ( on : req ) print ( didCreate ) /// Future User Info If you are using a value-type ( struct ), the instance of your model returned by .create(on:) will contain the model's new ID.", + "title": "Create" + }, + { + "location": "/fluent/models/#read", + "text": "Two methods are important for reading your model from the database, find(_:on:) and query(on:) . /// Finds a user with ID == 1 let user = User . find ( 1 , on : req ) print ( user ) /// Future User? /// Finds all users with name == Vapor let users = User . query ( on : req ). filter ( \\ . name == Vapor ). all () print ( users ) /// Future [User]", + "title": "Read" + }, + { + "location": "/fluent/models/#update", + "text": "This method updates the existing row / item associated with an instance of your model in the database. If your model already has an ID, calls to .save(on:) will redirect to this method. /// Updates the user let didUpdate = user . update ( on : req ) print ( didUpdate ) /// Future User", + "title": "Update" + }, + { + "location": "/fluent/models/#delete", + "text": "This method deletes the existing row / item associated with an instance of your model from the database. /// Deletes the user let didDelete = user . delete ( on : req ) print ( didDelete ) /// Future Void", + "title": "Delete" + }, + { + "location": "/fluent/models/#methods", + "text": "Model offers some convenience methods to make working with it easier.", + "title": "Methods" + }, + { + "location": "/fluent/models/#require-id", + "text": "This method return's the models ID or throws an error. let id = try user . requireID ()", + "title": "Require ID" }, { "location": "/fluent/migrations/",