代码之家  ›  专栏  ›  技术社区  ›  nPn

如何在公开的Kotlin中组合查询?

  •  0
  • nPn  · 技术社区  · 7 年前

    我想使用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
    

    最后,我想把它下推到测量对象或测量类中,这样我就可以做这样的事情

    Measurement.withDefaultRegion.where( Measurements.name.eq("someName")
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   nPn    7 年前

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

    第一个提供了“范围”

    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
    }