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?Rob Elliot
02/22/2023, 10:45 AMval 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.Rob Elliot
02/22/2023, 10:46 AMfun <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.Rob Elliot
02/22/2023, 11:04 AMcheck
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...David Kubecka
02/22/2023, 11:10 AMcheck
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) }
Rob Elliot
02/22/2023, 11:36 AM.and { if (x is String && y != null) MY_TABLE.COLLECTION_ID.eq("$x_$y") else null }
Rob Elliot
02/22/2023, 12:10 PM.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