All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.seasar.doma.criteria.query.SelectBuilder.kt Maven / Gradle / Ivy

package org.seasar.doma.criteria.query

import org.seasar.doma.criteria.context.Criterion
import org.seasar.doma.criteria.context.JoinKind
import org.seasar.doma.criteria.context.Projection
import org.seasar.doma.criteria.context.SelectContext
import org.seasar.doma.def.EntityDef
import org.seasar.doma.def.PropertyDef
import org.seasar.doma.internal.jdbc.sql.PreparedSqlBuilder
import org.seasar.doma.jdbc.PreparedSql
import org.seasar.doma.jdbc.SqlKind
import org.seasar.doma.jdbc.SqlLogType

class SelectBuilder(
    private val context: SelectContext,
    private val commenter: (String) -> String,
    private val buf: PreparedSqlBuilder,
    aliasManager: AliasManager
) {

    constructor(context: SelectContext, commenter: (String) -> String, logType: SqlLogType) :
            this(context, commenter, PreparedSqlBuilder(context.config, SqlKind.SELECT, logType), AliasManager(context))

    private val config = context.config
    private val support = BuilderSupport(config, commenter, buf, aliasManager)
    fun build(): PreparedSql {
        interpretContext()
        return buf.build(commenter)
    }

    internal fun interpretContext() {
        buf.appendSql("select ")
        if (context.distinct) {
            buf.appendSql("distinct ")
        }
        when (val projection = context.projection) {
            is Projection.All -> {
                context.getProjectionTargets().forEach {
                    it.allPropertyDefs().forEach { prop ->
                        column(prop)
                        buf.appendSql(", ")
                    }
                }
                buf.cutBackSql(2)
            }
            is Projection.Asterisk -> {
                buf.appendSql("*")
            }
            is Projection.Single -> {
                column(projection.propDef)
            }
            is Projection.Pair -> {
                column(projection.first)
                buf.appendSql(", ")
                column(projection.second)
            }
            is Projection.List -> {
                projection.propDefs.forEach {
                    column(it)
                    buf.appendSql(", ")
                }
                buf.cutBackSql(2)
            }
        }
        buf.appendSql(" from ")
        table(context.entityDef)
        if (context.joins.isNotEmpty()) {
            context.joins.forEach { join ->
                when (join.kind) {
                    JoinKind.INNER -> buf.appendSql(" inner join ")
                    JoinKind.LEFT -> buf.appendSql(" left outer join ")
                }
                table(join.entityDef)
                if (join.on.isNotEmpty()) {
                    buf.appendSql(" on (")
                    join.on.forEachIndexed { index, c ->
                        visitCriterion(index, c)
                        buf.appendSql(" and ")
                    }
                    buf.cutBackSql(5)
                    buf.appendSql(")")
                }
            }
        }
        if (context.where.isNotEmpty()) {
            buf.appendSql(" where ")
            context.where.forEachIndexed { index, c ->
                visitCriterion(index, c)
                buf.appendSql(" and ")
            }
            buf.cutBackSql(5)
        }
        if (context.groupBy.isNotEmpty()) {
            buf.appendSql(" group by ")
            context.groupBy.forEach { p ->
                column(p)
                buf.appendSql(", ")
            }
            buf.cutBackSql(2)
        }
        if (context.having.isNotEmpty()) {
            buf.appendSql(" having ")
            context.having.forEachIndexed { index, c ->
                visitCriterion(index, c)
                buf.appendSql(" and ")
            }
            buf.cutBackSql(5)
        }
        if (context.orderBy.isNotEmpty()) {
            buf.appendSql(" order by ")
            context.orderBy.forEach { (p, sort) ->
                column(p)
                buf.appendSql(" $sort")
                buf.appendSql(", ")
            }
            buf.cutBackSql(2)
        }
        context.limit?.let {
            buf.appendSql(" limit $it")
        }
        context.offset?.let {
            buf.appendSql(" offset $it")
        }
        context.forUpdate?.let {
            buf.appendSql(" for update")
            if (it.nowait) {
                buf.appendSql(" nowait")
            }
        }
    }

    private fun table(entityDef: EntityDef<*>) {
        support.table(entityDef)
    }

    private fun column(propDef: PropertyDef<*>) {
        support.column(propDef)
    }

    private fun visitCriterion(index: Int, c: Criterion) {
        support.visitCriterion(index, c)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy