I have a vapor 4 application. I do a query from database for getting some items and I want to perform some manual calculation based on the returned values before finishing the request. here a sample code of what I am trying to achieve.
final class Todo: Model, Content {
static var schema: String = "todos"
@ID(custom: .id)
var id: Int?
@Field(key: "title")
var title: String
var someValue: Int?
}
/// Allows `Todo` to be used as a dynamic migration.
struct CreateTodo: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
database.schema(Todo.schema)
.field("id", .int, .identifier(auto: true))
.field("title", .string, .required)
.create()
}
func revert(on database: Database) -> EventLoopFuture<Void> {
database.schema(Todo.schema).delete()
}
}
final class TodoController:RouteCollection{
func boot(routes: RoutesBuilder) throws {
routes.get("tmp", use: temp)
}
func temp(_ req:Request) throws -> EventLoopFuture<[Todo]> {
Todo.query(on: req.db).all().map { todos in
todos.map {
$0.someValue = (0...10).randomElement()!
return $0
}
}
}
}
The problem is that those manual changes, aren't available in response. In this case someValue
property.
Thanks.
[
{
"title": "item 1",
"id": 1
},
{
"title": "item 2",
"id": 2
}
]
The problem you're hitting is that Model
s override the Codable
implementations. This allows you to do things like passing around parents and not adding children etc.
However, this breaks your case. What you should do, is create a new type if you want to return a Todo
with another field that isn't stored in the database, something like:
struct TodoResponse: Content {
let id: Int
let title: String
let someValue: Int
}
And then convert from your database type to your response type in your route handler (this is a pretty common pattern and the recommended way to do it in Vapor)