I am experimenting with some Server-Side-Swift tutorial. I have the two tables:
acronyms(id: uuid, short: text, long: text, userID: uuid)
users(id: uuid, name: text, username: text)
The following is working fine, a can insert new records in the acronyms-table via post-request:
import Vapor
import Fluent
struct AcronymsController: RouteCollection{
func boot(routes: RoutesBuilder) throws {
let acronymsRoutes = routes.grouped("api", "acronyms")
// acronymsRoutes.get(use: getAllHandler)
acronymsRoutes.post(use: createHandler)
}
func createHandler(_ req: Request) throws -> EventLoopFuture<Acronym> {
let formData = try req.content.decode(FormData.self)
let acronym = Acronym(id: formData.id,
short: formData.short,
long: formData.long,
userID: formData.userID
)
return acronym.save(on: req.db).map { acronym }
}
}
struct FormData: Content{
let id: UUID
let short: String
let long: String
let userID: UUID
}
Now I would like to use the username (unique) to run a query for user.id against the user table and use the result to insert a new acronym record (see below).
I understand, that I cannot call the asyncronous function getUserIDByName
from within a sync function. So how is that to be done right?
Or, probably much faster, how can I directly send the following (p)sql-statement:
insert into acronyms values (
'5bfc01d6-1b6a-45f0-86d7-5833a9c59fcd',
'bawdsf', 'bier auf wein, das schmeckt fein',
(select id from users where username like 'otto')
);
Many thanks in advance.
Michael
...
func createHandler(_ req: Request) throws -> EventLoopFuture<Acronym> {
let formData = try req.content.decode(FormData.self)
let uid: UUID = try await getUserIDByName(req, username: formData.username)
let acronym = Acronym(id: formData.id,
short: formData.short,
long: formData.long,
userID: uid
)
return acronym.save(on: req.db).map { acronym }
}
}
struct FormData: Content{
let id: UUID
let short: String
let long: String
let username: String
}
func getUserIDByName(_ req: Request, username: String ) async throws -> UUID {
return
try await
User.query(on: req.db)
.filter(\.$username == username)
.first()
.get()!.id!
}
You can use your getUserIDByName
function to do this, just make it return a Future.
func getUserIDByName(_ req: Request, username: String ) -> EventLoopFuture<User?> {
return
User.query(on: req.db)
.filter(\.$username == username)
.first()
}
Then, flatMap
this value and use it in your original route, modified:
func createHandler(_ req: Request) throws -> EventLoopFuture<Acronym> {
return getUserIDByName(req, username:"otto").flatMap { user in
guard let user = user, let userID = user.id else { throw SomeError() }
let formData = try req.content.decode(FormData.self)
let acronym = Acronym(id: formData.id,
short: formData.short,
long: formData.long,
userID: userID)
return acronym.save(on: req.db).flatMap { acronym }
}
}
Alternatively, make it all async:
func getUserIDByName(_ req: Request, username: String ) async throws -> User {
return
try await
User.query(on: req.db)
.filter(\.$username == username)
.first()
}
And then:
func createHandler(_ req: Request) async throws -> Acronym {
let formData = try req.content.decode(FormData.self)
guard let uid = try await getUserIDByName(req, username: formData.username).id
else { throw SomeError() }
let acronym = Acronym(id: formData.id,
short: formData.short,
long: formData.long,
userID: uid)
try await acronym.save(on: req.db)
return acronym
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.