Tengo que agregar or condiciones usando los valores de los parámetros a la consulta.
Ejemplo: select * from users where email = "abc@xyz.com" or phone="1234123412";
El usuario puede enviar ambos campos o solo uno. Quiero hacer esto en un bucle para cada campo y agregar cada uno de ellos en la condición 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 }El DSL anterior produce el siguiente SQL.
SELECT * from users where (((false = true) OR (users.email = "abc@xyz.com")) OR (users.phone = "1234567890")) ¿Ves que false = true ? Eso es porque, para usar el método .or , tengo que inicializar con una condición. El fragmento dado a continuación es una línea de código innecesaria agregada para inicializar el predicado.
var predicates = Op.build { Users.id inList listOf<Int>()} ¿Cuál es la forma correcta de inicializarlo para que pueda agregar sin problemas varios predicados or and and a la consulta?
En primer lugar, recomendaría optimizar su código como:
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) } }UPD: o la función Where está disponible en Exposed desde la versión 0.16.1.
Si desea utilizar la coincidencia de patrones ( when ), defina su función local o orWhere de la misma manera andWhere funciona:
fun Query.orWhere(andPart: SqlExpressionBuilder.() -> Op<Boolean>) = adjustWhere { val expr = Op.build { andPart() } if(this == null) expr else this or expr }Y usarlo como:
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 } } }Un truco sería inicializar los predicates en null y definir su propio or and and en 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) } Si vale la pena la complicación, lo dudo: como menciona el comentario de Giacomo, la base de datos sin duda optimizará su false = true original.