如何在Kotlin Exposed中撰写查询?

时间:2018-08-10 04:32:24

标签: kotlin kotlin-exposed

我想使用Kotlin Exposed创建类似于Ruby的ActiveRecord范围的东西。

例如,我想分解以下查询,以使第一部分的作用像作用域。

此查询返回我想要的。

val m1 = Measurement.wrapRows(Measurements.innerJoin(Runs).select {
        ((exists(Tags.select { Tags.run.eq(Runs.sequelId) and Tags.name.eq("region") and Tags.value.eq("default") })) or notExists(Tags.select {
            Tags.run.eq(Runs.sequelId) and Tags.name.eq("region")
        })) and Measurements.name.eq("someName")

我想将此部分用作范围:

val q1 = Measurements.innerJoin(Runs).select {
    ((exists(Tags.select { Tags.run.eq(Runs.sequelId) and Tags.name.eq("region") and Tags.value.eq("default") })) or notExists(Tags.select {
        Tags.run.eq(Runs.sequelId) and Tags.name.eq("region")
    }))
}

,然后能够使用q1“作用域”优化查询

是这样的:

val q2 = q1.having { Measurements.name.eq("someName")  } // which does not work

最终我想将其向下推到Measurements对象或Measurement类中,这样我就可以做类似的事情

Measurement.withDefaultRegion.where( Measurements.name.eq("someName")

1 个答案:

答案 0 :(得分:1)

通过向模型的伴随对象添加几个函数,我可以得到想要的东西。

第一个提供“范围”

fun defaultRegion() :Op<Boolean> {
    return Op.build {(exists(Tags.select { Tags.run.eq(Runs.sequelId) and Tags.name.eq("region") and Tags.value.eq("default") })) or notExists(Tags.select {
        Tags.run.eq(Runs.sequelId) and Tags.name.eq("region")
    })}
}

第二个函数使用范围和传入的所有细化进行查询,并返回对象的“集合”。

fun withDefaultRegionAnd( refinedBy: (SqlExpressionBuilder.()->Op<Boolean>)) : SizedIterable<Measurement> {
    return Measurement.wrapRows(Measurements.innerJoin(Runs).select(Measurement.defaultRegion() and SqlExpressionBuilder.refinedBy() ))
}

在客户端级别,我可以简单地做到这一点:

val measurements = Measurement.withDefaultRegionAnd { Measurements.name.eq("someName") }

这是近表对象和实体类:

object Measurements : IntIdTable("measurements") {

    val sequelId = integer("id").primaryKey()
    val run = reference("run_id", Runs)
    // more properties
}

class Measurement(id: EntityID<Int>) : IntEntity(id) {
    companion object : IntEntityClass<Measurement>(Measurements) {
        fun defaultRegion() :Op<Boolean> {
            return Op.build {(exists(Tags.select { Tags.run.eq(Runs.sequelId) and Tags.name.eq("region") and Tags.value.eq("default") })) or notExists(Tags.select {
                Tags.run.eq(Runs.sequelId) and Tags.name.eq("region")
            })}
        }
        fun withDefaultRegionAnd( refinedBy: (SqlExpressionBuilder.()->Op<Boolean>)) : SizedIterable<Measurement> {
            return Measurement.wrapRows(Measurements.innerJoin(Runs).select(Measurement.defaultRegion() and SqlExpressionBuilder.refinedBy() ))
        }
    }

    var run by Run referencedOn Measurements.run
    var name by Measurements.name
    // more properties
}