简体   繁体   中英

Sequent database access with swift, vapor and fluent

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM