Rob Elliot
02/22/2023, 10:42 AMfun <R : Record> SelectConditionStep<R>.andIf(
check: () -> Boolean,
clause: () -> Condition,
): SelectConditionStep<R> = if (check()) this.and(clause()) else this
The idea is you can do something like this:
val name: String = TODO()
val maybeId: Id? = TODO()
dsl
.select(MY_TABLE.fields())
.from(MY_TABLE)
.where(MY_TABLE.NAME.eq(name))
.andIf({ maybeId != null }) { MY_TABLE.COLLECTION_ID.eq(maybeId.value) }
.fetch()
but of course the compiler cannot infer that maybeId
is not null in the second lambda... could a custom contract make it possible for the compiler to work this out?val name: String = TODO()
val maybeId: Id? = TODO()
dsl
.select(MY_TABLE.fields())
.from(MY_TABLE)
.where(MY_TABLE.NAME.eq(name))
.run { if (catalogueId != null) and(MY_TABLE.COLLECTION_ID.eq(maybeId.value)) else this }
.fetch()
where the compiler can do the smart cast - but the run
and the if
and the else
rather obscure the legibility of the DSL.fun <R : Record, T : Any> SelectConditionStep<R>.andIf(
nullable: T?,
clause: (T) -> Condition,
): SelectConditionStep<R> = nullable?.let { notNull -> this.and(clause(notNull)) } ?: this
but apart from being less flexible it's also a bit more implicit - I like the explicitness of the first one where it's completely explicit inline that the check is for the nullness.David Kubecka
02/22/2023, 10:47 AMtakeIf
, e.g.
something.takeIf(check())?.let { clause(something) }
Rob Elliot
02/22/2023, 11:01 AMandIf
, and I'm still constrained to there just being the one argument that can be cast from nullable to not null.check
returning true
can be assumed to be true in the lambda passed as clause
David Kubecka
02/22/2023, 11:08 AMandIf
to be. If you want to pass 1) any value, 2) perform an arbitrary check on it, and 3) if that check succeeds do something with the value, I think you need those 3 parameters.
But you are talking specifically about nullability checks, so not sure how generic you want that to be...check
and clause
parameters can share a contract 😞Rob Elliot
02/22/2023, 11:19 AMfun <R : Record> SelectOnConditionStep<R>.and(clause: () -> Condition?): SelectOnConditionStep<R> {
val maybeCondition = clause()
return if (maybeCondition != null) and(maybeCondition) else this
}
dsl
.select(MY_TABLE.fields())
.from(MY_TABLE)
.where(MY_TABLE.NAME.eq(name))
.and { if (maybeId != null) MY_TABLE.COLLECTION_ID.eq(maybeId.value) else null }
.fetch()
Shame about that ugly little else null
at the end... guess we'd need partial application to avoid that though.David Kubecka
02/22/2023, 11:32 AMandIfNotNull(maybeId) { MY_TABLE.COLLECTION_ID.eq(maybeId.value) }
? Or are there also functional concerns?Rob Elliot
02/22/2023, 11:34 AMandIfNotNull(maybeId) { id -> MY_TABLE.COLLECTION_ID.eq(id.value) }
.and { if (x is String && y != null) MY_TABLE.COLLECTION_ID.eq("$x_$y") else null }
.and { maybeId?.run { MY_TABLE.COLLECTION_ID.eq(maybeId.value) } }
to lose the ugly else null
. Though it feels a bit less legible.dmitriy.novozhilov
02/22/2023, 12:11 PMRob Elliot
02/22/2023, 12:12 PMdmitriy.novozhilov
02/22/2023, 12:12 PM