Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/dope 212 parameter extraction #15

Merged
merged 12 commits into from
May 15, 2024
3 changes: 3 additions & 0 deletions core/src/main/kotlin/ch/ergon/dope/DopeQuery.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package ch.ergon.dope

data class DopeQuery(val queryString: String, val parameters: Map<String, Any>)
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
package ch.ergon.dope.resolvable

fun formatToQueryString(left: String, right: String) = "$left $right"
fun formatToQueryString(left: Resolvable, right: String) = "${left.toQueryString()} $right"
fun formatToQueryString(left: String, symbol: String, right: String) = "$left $symbol $right"
fun formatToQueryString(left: Resolvable, symbol: String, vararg right: Resolvable) =
"${left.toQueryString()} $symbol ${right.joinToString { it.toQueryString() }}"
fun formatToQueryString(symbol: String, vararg argument: Resolvable) =
formatToQueryString(symbol, separator = " ", *argument)
fun formatToQueryString(left: String, vararg right: String) =
"$left ${right.joinToString()}"

fun formatToQueryString(symbol: String, separator: String, vararg argument: Resolvable) =
"$symbol$separator${argument.joinToString(separator = ", ") { it.toQueryString() }}"
fun formatToQueryStringWithSymbol(left: String, symbol: String, vararg right: String) =
"$left $symbol ${right.joinToString()}"

fun formatToQueryStringWithSeparator(symbol: String, separator: String, vararg argument: String) =
"$symbol$separator${argument.joinToString(separator = ", ")}"

fun formatToQueryStringWithBrackets(left: String, symbol: String, right: String) = "($left $symbol $right)"
fun formatToQueryStringWithBrackets(symbol: String, vararg argument: Resolvable) =
"$symbol(${argument.joinToString(separator = ", ") { it.toQueryString() }})"
fun formatToQueryStringWithBrackets(symbol: String, vararg argument: String) =
"$symbol(${argument.joinToString(separator = ", ")})"

fun formatPathToQueryString(name: String, path: String) =
if (path.isBlank()) {
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/kotlin/ch/ergon/dope/resolvable/Resolvable.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package ch.ergon.dope.resolvable

import ch.ergon.dope.DopeQuery

interface Resolvable {
fun toQueryString(): String
fun toDopeQuery(): DopeQuery
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package ch.ergon.dope.resolvable.clause

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.Resolvable
import ch.ergon.dope.resolvable.expression.unaliased.type.resetCounter
import ch.ergon.dope.resolvable.expression.unaliased.type.ParameterManager

interface Clause : Resolvable {
fun build(): String {
resetCounter()
return toQueryString()
fun build(): DopeQuery {
ParameterManager.resetCounter()
return toDopeQuery()
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.clause.IDeleteClause
import ch.ergon.dope.resolvable.fromable.Bucket

class DeleteClause(private val bucket: Bucket) : IDeleteClause {
override fun toQueryString(): String = "DELETE FROM ${bucket.toQueryString()}"

override fun toDopeQuery(): DopeQuery {
val bucketDopeQuery = bucket.toDopeQuery()
return DopeQuery(
queryString = "DELETE FROM ${bucketDopeQuery.queryString}",
parameters = bucketDopeQuery.parameters,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.clause.ISelectClause
import ch.ergon.dope.resolvable.clause.ISelectUnnestClause
import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.resolvable.formatToQueryStringWithSymbol
import ch.ergon.dope.resolvable.fromable.Fromable

class FromClause(private val fromable: Fromable, private val parentClause: ISelectClause) : ISelectUnnestClause {
override fun toQueryString(): String = formatToQueryString(parentClause, "FROM", fromable)
override fun toDopeQuery(): DopeQuery {
val parentDopeQuery = parentClause.toDopeQuery()
val fromableDopeQuery = fromable.toDopeQuery()
return DopeQuery(
queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, "FROM", fromableDopeQuery.queryString),
parameters = fromableDopeQuery.parameters + parentDopeQuery.parameters,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.clause.ISelectGroupByClause
import ch.ergon.dope.resolvable.clause.ISelectWhereClause
import ch.ergon.dope.resolvable.expression.unaliased.type.Field
import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.resolvable.formatToQueryStringWithSymbol
import ch.ergon.dope.validtype.ValidType

class GroupByClause(
private val field: Field<out ValidType>,
private vararg val fields: Field<out ValidType>,
private val parentClause: ISelectWhereClause,
) : ISelectGroupByClause {
override fun toQueryString(): String = formatToQueryString(parentClause, "GROUP BY", field, *fields)

override fun toDopeQuery(): DopeQuery {
val parentDopeQuery = parentClause.toDopeQuery()
val fieldDopeQuery = field.toDopeQuery()
val fieldsDopeQuery = fields.map { it.toDopeQuery() }
return DopeQuery(
queryString = formatToQueryStringWithSymbol(
parentDopeQuery.queryString,
"GROUP BY",
fieldDopeQuery.queryString,
*fieldsDopeQuery.map { it.queryString }.toTypedArray(),
),
parameters = fieldsDopeQuery.fold(fieldDopeQuery.parameters) { fieldParameters, field ->
fieldParameters + field.parameters
} + parentDopeQuery.parameters,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.clause.ISelectFromClause
import ch.ergon.dope.resolvable.clause.ISelectJoinClause
import ch.ergon.dope.resolvable.expression.TypeExpression
Expand All @@ -9,17 +10,29 @@ import ch.ergon.dope.validtype.BooleanType
import ch.ergon.dope.validtype.ValidType

sealed class SelectJoinClause : ISelectJoinClause {
private val queryString: String
private val dopeQuery: DopeQuery

constructor(joinType: String, bucket: Bucket, onCondition: TypeExpression<BooleanType>, parentClause: ISelectFromClause) {
queryString = "${parentClause.toQueryString()} $joinType ${bucket.toQueryString()} ON ${onCondition.toQueryString()}"
val parentDopeQuery = parentClause.toDopeQuery()
val bucketDopeQuery = bucket.toDopeQuery()
val onConditionDopeQuery = onCondition.toDopeQuery()
dopeQuery = DopeQuery(
queryString = "${parentDopeQuery.queryString} $joinType ${bucketDopeQuery.queryString} ON ${onConditionDopeQuery.queryString}",
parameters = parentDopeQuery.parameters + bucketDopeQuery.parameters + onConditionDopeQuery.parameters,
)
}

constructor(joinType: String, bucket: Bucket, key: Field<out ValidType>, parentClause: ISelectFromClause) {
queryString = "${parentClause.toQueryString()} $joinType ${bucket.toQueryString()} ON KEYS ${key.toQueryString()}"
val parentDopeQuery = parentClause.toDopeQuery()
val bucketDopeQuery = bucket.toDopeQuery()
val keyDopeQuery = key.toDopeQuery()
dopeQuery = DopeQuery(
queryString = "${parentDopeQuery.queryString} $joinType ${bucketDopeQuery.queryString} ON KEYS ${keyDopeQuery.queryString}",
parameters = parentDopeQuery.parameters + bucketDopeQuery.parameters + keyDopeQuery.parameters,
)
}

override fun toQueryString(): String = queryString
override fun toDopeQuery(): DopeQuery = dopeQuery
}

class StandardJoinClause : SelectJoinClause {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.clause.IDeleteLimitClause
import ch.ergon.dope.resolvable.clause.IDeleteWhereClause
import ch.ergon.dope.resolvable.clause.ISelectLimitClause
import ch.ergon.dope.resolvable.clause.ISelectOrderByClause
import ch.ergon.dope.resolvable.expression.TypeExpression
import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.resolvable.formatToQueryStringWithSymbol
import ch.ergon.dope.validtype.NumberType

private const val LIMIT = "LIMIT"

class SelectLimitClause(private val numberExpression: TypeExpression<NumberType>, private val parentClause: ISelectOrderByClause) :
ISelectLimitClause {
override fun toQueryString(): String = formatToQueryString(parentClause, LIMIT, numberExpression)

override fun toDopeQuery(): DopeQuery {
val parentDopeQuery = parentClause.toDopeQuery()
val numberDopeQuery = numberExpression.toDopeQuery()
return DopeQuery(
queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, LIMIT, numberDopeQuery.queryString),
parameters = numberDopeQuery.parameters + parentDopeQuery.parameters,
)
}
}

class DeleteLimitClause(private val numberExpression: TypeExpression<NumberType>, private val parentClause: IDeleteWhereClause) :
IDeleteLimitClause {
override fun toQueryString(): String = formatToQueryString(parentClause, LIMIT, numberExpression)

override fun toDopeQuery(): DopeQuery {
val parentDopeQuery = parentClause.toDopeQuery()
val numberDopeQuery = numberExpression.toDopeQuery()
return DopeQuery(
queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, LIMIT, numberDopeQuery.queryString),
parameters = numberDopeQuery.parameters + parentDopeQuery.parameters,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.clause.IDeleteLimitClause
import ch.ergon.dope.resolvable.clause.IDeleteOffsetClause
import ch.ergon.dope.resolvable.clause.ISelectLimitClause
import ch.ergon.dope.resolvable.clause.ISelectOffsetClause
import ch.ergon.dope.resolvable.expression.TypeExpression
import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.resolvable.formatToQueryStringWithSymbol
import ch.ergon.dope.validtype.NumberType

private const val OFFSET = "OFFSET"

class SelectOffsetClause(private val numberExpression: TypeExpression<NumberType>, private val parentClause: ISelectLimitClause) :
ISelectOffsetClause {
override fun toQueryString(): String = formatToQueryString(parentClause, OFFSET, numberExpression)

override fun toDopeQuery(): DopeQuery {
val parentDopeQuery = parentClause.toDopeQuery()
val numberDopeQuery = numberExpression.toDopeQuery()
return DopeQuery(
queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, OFFSET, numberDopeQuery.queryString),
parameters = numberDopeQuery.parameters + parentDopeQuery.parameters,
)
}
}

class DeleteOffsetClause(private val numberExpression: TypeExpression<NumberType>, private val parentClause: IDeleteLimitClause) :
IDeleteOffsetClause {
override fun toQueryString(): String = formatToQueryString(parentClause, OFFSET, numberExpression)

override fun toDopeQuery(): DopeQuery {
val parentDopeQuery = parentClause.toDopeQuery()
val numberDopeQuery = numberExpression.toDopeQuery()
return DopeQuery(
queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, OFFSET, numberDopeQuery.queryString),
parameters = numberDopeQuery.parameters + parentDopeQuery.parameters,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,44 @@
package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.clause.ISelectGroupByClause
import ch.ergon.dope.resolvable.clause.ISelectOrderByClause
import ch.ergon.dope.resolvable.expression.unaliased.type.Field
import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.resolvable.formatToQueryStringWithSymbol
import ch.ergon.dope.validtype.StringType

enum class OrderByType(val type: String) {
ASC("ASC"),
DESC("DESC"),
}

private const val ORDER_BY = "ORDER BY"

open class SelectOrderByClause(private val stringField: Field<StringType>, private val parentClause: ISelectGroupByClause) :
ISelectOrderByClause {
override fun toQueryString(): String = formatToQueryString(parentClause, "ORDER BY", stringField)

override fun toDopeQuery(): DopeQuery {
val parentDopeQuery = parentClause.toDopeQuery()
val stringDopeQuery = stringField.toDopeQuery()
return DopeQuery(
queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, ORDER_BY, stringDopeQuery.queryString),
parameters = stringDopeQuery.parameters + parentDopeQuery.parameters,
)
}
}

class SelectOrderByTypeClause(
stringField: Field<StringType>,
private val stringField: Field<StringType>,
private val orderByType: OrderByType,
parentClause: ISelectGroupByClause,
private val parentClause: ISelectGroupByClause,
) : SelectOrderByClause(stringField, parentClause) {
override fun toQueryString(): String = super.toQueryString() + " ${orderByType.type}"

override fun toDopeQuery(): DopeQuery {
val parentDopeQuery = parentClause.toDopeQuery()
val stringDopeQuery = stringField.toDopeQuery()
return DopeQuery(
queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, ORDER_BY, stringDopeQuery.queryString + " $orderByType"),
parameters = stringDopeQuery.parameters + parentDopeQuery.parameters,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.clause.IDeleteOffsetClause
import ch.ergon.dope.resolvable.clause.IDeleteReturningClause
import ch.ergon.dope.resolvable.expression.unaliased.type.Field
import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.resolvable.formatToQueryStringWithSymbol
import ch.ergon.dope.validtype.ValidType

class ReturningClause(
private val field: Field<out ValidType>,
private vararg val fields: Field<out ValidType>,
private val parentClause: IDeleteOffsetClause,
) : IDeleteReturningClause {
override fun toQueryString(): String = formatToQueryString(parentClause, "RETURNING", field, *fields)

override fun toDopeQuery(): DopeQuery {
val fieldsDopeQuery = fields.map { it.toDopeQuery() }
val fieldDopeQuery = field.toDopeQuery()
val parentDopeQuery = parentClause.toDopeQuery()
return DopeQuery(
queryString = formatToQueryStringWithSymbol(
parentDopeQuery.queryString,
"RETURNING",
fieldDopeQuery.queryString,
*fieldsDopeQuery.map { it.queryString }.toTypedArray(),
),
parameters = fieldsDopeQuery.fold(fieldDopeQuery.parameters) { fieldParameters, field ->
fieldParameters + field.parameters
} + parentDopeQuery.parameters,
)
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,52 @@
package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.clause.ISelectClause
import ch.ergon.dope.resolvable.expression.Expression
import ch.ergon.dope.resolvable.formatToQueryString

class SelectClause(private val expression: Expression, private vararg val expressions: Expression) : ISelectClause {
override fun toQueryString(): String = formatToQueryString("SELECT", expression, *expressions)

override fun toDopeQuery(): DopeQuery {
val expressionDopeQuery = expression.toDopeQuery()
val expressionsDopeQuery = expressions.map { it.toDopeQuery() }
return DopeQuery(
queryString = formatToQueryString(
"SELECT",
expressionDopeQuery.queryString,
*expressionsDopeQuery.map { it.queryString }.toTypedArray(),
),
parameters = expressionsDopeQuery.fold(expressionDopeQuery.parameters) { expressionParameters, field ->
expressionParameters + field.parameters
},
)
}
}

class SelectRawClause(private val expression: Expression) : ISelectClause {
override fun toQueryString(): String = formatToQueryString("SELECT RAW", expression)

override fun toDopeQuery(): DopeQuery {
val expressionDopeQuery = expression.toDopeQuery()
return DopeQuery(
formatToQueryString("SELECT RAW", expressionDopeQuery.queryString),
expressionDopeQuery.parameters,
)
}
}

class SelectDistinctClause(private val expression: Expression, private vararg val expressions: Expression) : ISelectClause {
override fun toQueryString(): String = formatToQueryString("SELECT DISTINCT", expression, *expressions)
override fun toDopeQuery(): DopeQuery {
val expressionsDopeQuery = expressions.map { it.toDopeQuery() }
val expressionDopeQuery = expression.toDopeQuery()
return DopeQuery(
queryString = formatToQueryString(
"SELECT DISTINCT",
expressionDopeQuery.queryString,
*expressionsDopeQuery.map { it.queryString }.toTypedArray(),
),
parameters = expressionsDopeQuery.fold(expressionDopeQuery.parameters) { expressionParameters, field ->
expressionParameters + field.parameters
},
)
}
}
Loading
Loading