【问题标题】:Vapor 4 case insensitive queryVapor 4 不区分大小写的查询
【发布时间】:2020-08-25 17:09:00
【问题描述】:

在 Vapor 3 中,您可以使用带有 SQLiteBinaryOperator 的 filter 方法,因此您可以使用 like 运算符创建查询。我试图在 Vapor 4 中做同样的事情,但找不到任何东西。 这是我的代码

蒸汽 4

func queryUserMovies(_ req: Request) throws -> Future<[Users]> {
    let title = req.parameters.get("title")!
    return Movies.query(on: req.db).filter(\.$title == title).first().unwrap(or:Abort(.notFound, reason: "There's no movie")).flatMap{ movie in
        return movie.$users.query(on: req.db).all()
    }
}

蒸汽 3

func queryUserMovies(_ req: Request) throws -> Future<[Users]> {
    guard let movie = req.query[String.self, at: "movie"] else {
        throw Abort(.badRequest, reason: "Not such movie")
    }
    return Movies.query(on: req).filter(\.title, .like, movie).first().unwrap(or:Abort(.notFound, reason: "There's no movie")).flatMap{ movie in
        return movie.users.query(on: req).all()
    }
}

Vapor 4 中是否有类似的东西,还是我需要在 SQL 中执行原始查询?

【问题讨论】:

    标签: swift fluent vapor vapor-fluent


    【解决方案1】:

    Vapor 4 中的等价物是:

    func queryUserMovies(_ req: Request) throws -> Future<[Users]> {
        let title = try req.query.get(String.self, at: "title")
        return Movies.query(on: req.db)
            .filter(\.$title, .custom("ilike"), title)
            .first()
            .unwrap(or:Abort(.notFound, reason: "There's no movie"))
            .flatMap{ movie in
                return movie.$users.query(on: req.db).all()
        }
    }
    

    您甚至可以执行更广泛的搜索来查找包含该标题的任何内容:

    .filter(\.$title, .custom("ilike"), "%\(title)%")
    

    【讨论】:

    • 此保存是否与用户输入的标题一起使用,例如防止 SQL 注入?
    • 是的,see this answer 至于为什么
    【解决方案2】:

    我也遇到了同样的问题,但还有一个障碍!

    设置是一个与 Category 关系结合的 Machine 关系,我想在 Machine.name 中搜索一个或多个搜索词的出现Category.name 用一个表达式。

    MachineCategory 关系都有一个 name 属性。)

    search 属于 [String.SubSequence] 类型,因此我们可以遍历多个搜索词关键字,这些关键字必须都出现在名称中的某处。

    我的解决方案是:

    return Machine
      .query(on: req.db)
      .join(Category.self, on: \Category.$id == \Machine.$category.$id)
      // For each search-term the must be at least one fit with Machine.name and/or Category.name
      .group(.and) {
        var result = $0
        for term in search.map({ "%\(String($0))%" }) {
          // One or both must fit the search-term ...
          result = result.group(.or) {
            $0
              // Does the Machine name fit?
              .filter(\Machine.$name, .custom("ilike"), term)
              // Does the Category.path name fit?
              .filter(
                DatabaseQuery.Field.path(
                  Category.path(for: \Category.$name),
                  schema: Category.schema
                ),
                DatabaseQuery.Filter.Method.custom("ilike"),
                DatabaseQuery.Value.bind(term)
              )
          }
        }
      }
    

    如您所见,有两个 .group(...) 函数。外组 (.or) 表示“对于每个搜索词,必须有一个合适的内组规则”,而内组 (.or) 表示“必须有至少一个合适的 Machine.name 或 Category.name”。

    由于“joined-relation-filter”不支持 .custom("ilike"),我使用了我找到的解决方法 here

    即使这个问题可能已经回答了,我花了一些时间来解决这个问题,并认为我可以在这里分享它。

    【讨论】:

      【解决方案3】:

      有一个包含操作符~~,可以用来做这个:

      Movie.query(on: req).filter(\.$title ~~ movie)
      

      不区分大小写。

      【讨论】:

      • 我使用的是~~,但它对我来说不是不区分大小写的。
      • @LinusGeffarth,我正在使用 MySQL,它可以是底层数据库吗?我还没有在 Fluent 中找到实现。刚刚检查了我的代码,它没有进行任何折叠等操作。
      • 也许是的,我正在使用 PostgreSQL。我发现 0xTim 的答案的 Vapor 3.0.0 版本对我有用,而不幸的是,这个操作员没有。
      【解决方案4】:

      如果你想做不区分大小写的排序,你可以这样做:

      Movie.query(on: req).sort(.custom("lower(title)"))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-16
        相关资源
        最近更新 更多