Как добавить несколько или фильтровать условия на основе входящих параметров, используя выставленные? - PullRequest
0 голосов
/ 25 января 2019

Я должен добавить 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>()}

Как правильно его инициализировать, чтобы я мог плавно добавлять в запрос несколько предикатов or и and?

Ответы [ 2 ]

0 голосов
/ 26 января 2019

Прежде всего, я бы посоветовал оптимизировать ваш код следующим образом:

    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 }
    }
}

0 голосов
/ 25 января 2019

Хитрость заключается в том, чтобы инициализировать predicates в null и определить свои or и and для Op<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)
}

Стоит ли это усложнять, я сомневаюсь: как упоминает комментарий Джакомо, база данных, безусловно, оптимизирует ваш исходный false = true выход.

...