如何使用暴露的传入参数添加多个条件或过滤条件?

时间:2019-01-25 08:26:11

标签: kotlin kotlin-exposed

我必须使用参数值向查询添加or条件。

示例:select * from users where email = "abc@xyz.com" or phone="1234123412";

用户可以发送两个字段或仅发送一个字段。我想为每个字段循环执行此操作,并以or where条件添加其中的每个字段。

val query = Users.selectAll()
**var predicates = Op.build { Users.id inList listOf<Int>()}**
for((k, v) in params) {
    val value = URLDecoder.decode(v.first(), "UTF-8")
    predicates = when(k) {
        "email" -> predicates.or(Users.email eq value)
        "phone" -> predicates.or(Users.phone eq value)
    }
}
query.andWhere { predicates }

上面的DSL产生下面的SQL。

SELECT * from users where (((false = true) OR (users.email = "abc@xyz.com")) OR (users.phone = "1234567890"))

看到false = true吗?这是因为要使用.or方法,我必须使用条件进行初始化。下面给出的代码段是用于初始化谓词的不必要的代码行。

var predicates = Op.build { Users.id inList listOf<Int>()}

什么是正确的初始化方式,以便我可以无缝地向查询中添加多个orand谓词?

2 个答案:

答案 0 :(得分:1)

首先,我建议您优化代码,例如:

    val params = mapOf<String, List<String>>()
    val emails = params.filterKeys { it == "email" }.map { URLDecoder.decode(it.value.first(), "UTF-8") }
    val phones = params.filterKeys { it == "phone" }.map { URLDecoder.decode(it.value.first(), "UTF-8") }

    if (emails.isEmpty() && phones.isEmpty()) {
        error("No suitable params were provided")
    } else {
        Users.select {
            Users.email inList emails or (Users.phone inList phones)
        }
    }

如果您想使用模式匹配(when),请按照orWhere的工作方式定义本地andWhere函数:

fun Query.orWhere(andPart: SqlExpressionBuilder.() -> Op<Boolean>) = adjustWhere {
    val expr = Op.build { andPart() }
    if(this == null) expr
    else this or expr
}

并像这样使用它:

val query = Users.selectAll()
for((k, v) in params) {
    val value = URLDecoder.decode(v.first(), "UTF-8")
    predicates = when(k) {
        "email" -> query.orWhere { Users.email eq value }
        "phone" -> query.orWhere{ Users.phone eq value }
    }
}

答案 1 :(得分:0)

一种技巧是将predicates初始化为null并在or上定义自己的andOp<Boolean>?

// not sure x's type is correct here, the wiki doesn't give exact signatures
// may also need @JvmName to allow overloading
fun Op<Boolean>?.or(x: Op<Boolean>) = if (this != null) this.or(x) else x

...
var predicates: Op<Boolean>? = null
...
predicates = when(k) {
    "email" -> predicates.or(Users.email eq value)
    "phone" -> predicates.or(Users.phone eq value)
}

是否值得为此付出麻烦,我怀疑:正如Giacomo的评论所提到的,数据库肯定会优化您原来的false = true