Skip to content

Commit

Permalink
Merge pull request #43 from ergon/feature/dope-224-update-clause
Browse files Browse the repository at this point in the history
DOPE-224: added update clause, CM functions and tests
  • Loading branch information
martinagallati-ergon committed Aug 13, 2024
2 parents e62f031 + 2fb367c commit fe3addc
Show file tree
Hide file tree
Showing 31 changed files with 2,039 additions and 80 deletions.
3 changes: 3 additions & 0 deletions core/src/main/kotlin/ch/ergon/dope/QueryBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ch.ergon.dope.resolvable.clause.model.DeleteClause
import ch.ergon.dope.resolvable.clause.model.SelectClause
import ch.ergon.dope.resolvable.clause.model.SelectDistinctClause
import ch.ergon.dope.resolvable.clause.model.SelectRawClause
import ch.ergon.dope.resolvable.clause.model.UpdateClause
import ch.ergon.dope.resolvable.expression.AsteriskExpression
import ch.ergon.dope.resolvable.expression.Expression
import ch.ergon.dope.resolvable.expression.SingleExpression
Expand All @@ -22,4 +23,6 @@ class QueryBuilder {
fun selectFrom(fromable: Fromable) = SelectClause(AsteriskExpression()).from(fromable)

fun deleteFrom(bucket: Bucket) = DeleteClause(bucket)

fun update(bucket: Bucket) = UpdateClause(bucket)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package ch.ergon.dope.resolvable.clause

import ch.ergon.dope.resolvable.clause.model.DeleteLimitClause
import ch.ergon.dope.resolvable.clause.model.DeleteOffsetClause
import ch.ergon.dope.resolvable.clause.model.DeleteReturningClause
import ch.ergon.dope.resolvable.clause.model.DeleteUseKeys.Companion.DeleteUseKeysClause
import ch.ergon.dope.resolvable.clause.model.DeleteWhereClause
import ch.ergon.dope.resolvable.clause.model.ReturningClause
import ch.ergon.dope.resolvable.expression.TypeExpression
import ch.ergon.dope.resolvable.expression.unaliased.type.Field
import ch.ergon.dope.resolvable.expression.unaliased.type.toDopeType
Expand All @@ -17,7 +17,7 @@ import ch.ergon.dope.validtype.ValidType
interface IDeleteReturningClause : Clause

interface IDeleteOffsetClause : IDeleteReturningClause {
fun returning(field: Field<out ValidType>, vararg fields: Field<out ValidType>) = ReturningClause(field, *fields, parentClause = this)
fun returning(field: Field<out ValidType>, vararg fields: Field<out ValidType>) = DeleteReturningClause(field, *fields, parentClause = this)
}

interface IDeleteLimitClause : IDeleteOffsetClause {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package ch.ergon.dope.resolvable.clause

import ch.ergon.dope.resolvable.clause.model.SetClause
import ch.ergon.dope.resolvable.clause.model.UnsetClause
import ch.ergon.dope.resolvable.clause.model.UpdateLimitClause
import ch.ergon.dope.resolvable.clause.model.UpdateReturningClause
import ch.ergon.dope.resolvable.clause.model.UpdateUseKeys.Companion.UpdateUseKeysClause
import ch.ergon.dope.resolvable.clause.model.UpdateWhereClause
import ch.ergon.dope.resolvable.clause.model.to
import ch.ergon.dope.resolvable.expression.TypeExpression
import ch.ergon.dope.resolvable.expression.unaliased.type.Field
import ch.ergon.dope.resolvable.expression.unaliased.type.toDopeType
import ch.ergon.dope.validtype.ArrayType
import ch.ergon.dope.validtype.BooleanType
import ch.ergon.dope.validtype.NumberType
import ch.ergon.dope.validtype.StringType
import ch.ergon.dope.validtype.ValidType

interface IUpdateReturningClause : Clause

interface IUpdateLimitClause : IUpdateReturningClause {
fun returning(field: Field<out ValidType>, vararg fields: Field<out ValidType>) =
UpdateReturningClause(field, *fields, parentClause = this)
}

interface IUpdateWhereClause : IUpdateLimitClause {
fun limit(numberExpression: TypeExpression<NumberType>) = UpdateLimitClause(numberExpression, this)
fun limit(numberExpression: Number) = UpdateLimitClause(numberExpression.toDopeType(), this)
}

interface IUpdateUnsetClause : IUpdateWhereClause {
fun where(booleanExpression: TypeExpression<BooleanType>) = UpdateWhereClause(booleanExpression, this)
}

interface IUpdateSetClause : IUpdateUnsetClause {
fun unset(field: Field<out ValidType>) = UnsetClause(field, parentClause = this)
}

interface IUpdateUseKeysClause : IUpdateSetClause {
fun <T : ValidType> set(field: Field<T>, value: TypeExpression<T>) = SetClause(field.to(value), parentClause = this)
fun set(field: Field<NumberType>, value: Number) = SetClause(field.to(value.toDopeType()), parentClause = this)
fun set(field: Field<StringType>, value: String) = SetClause(field.to(value.toDopeType()), parentClause = this)
fun set(field: Field<BooleanType>, value: Boolean) = SetClause(field.to(value.toDopeType()), parentClause = this)
}

interface IUpdateClause : IUpdateUseKeysClause {
fun useKeys(key: TypeExpression<StringType>) = UpdateUseKeysClause(key, this)

// JvmName annotation in interfaces is currently not supported. https://youtrack.jetbrains.com/issue/KT-20068
@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("useKeysArray")
fun useKeys(key: TypeExpression<ArrayType<StringType>>) = UpdateUseKeysClause(key, this)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import ch.ergon.dope.resolvable.clause.IDeleteClause
import ch.ergon.dope.resolvable.fromable.Bucket

class DeleteClause(private val bucket: Bucket) : IDeleteClause {

override fun toDopeQuery(): DopeQuery {
val bucketDopeQuery = bucket.toDopeQuery()
return DopeQuery(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ class GroupByClause(
private vararg val fields: Field<out ValidType>,
private val parentClause: ISelectWhereClause,
) : ISelectGroupByClause {

override fun toDopeQuery(): DopeQuery {
val parentDopeQuery = parentClause.toDopeQuery()
val fieldDopeQuery = field.toDopeQuery()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,36 @@
package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.clause.Clause
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.clause.IUpdateLimitClause
import ch.ergon.dope.resolvable.clause.IUpdateWhereClause
import ch.ergon.dope.resolvable.expression.TypeExpression
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 toDopeQuery(): DopeQuery {
sealed class LimitClause(
private val numberExpression: TypeExpression<NumberType>,
private val parentClause: Clause,
) {
fun toDopeQuery(): DopeQuery {
val parentDopeQuery = parentClause.toDopeQuery()
val numberDopeQuery = numberExpression.toDopeQuery()
return DopeQuery(
queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, LIMIT, numberDopeQuery.queryString),
queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, "LIMIT", numberDopeQuery.queryString),
parameters = numberDopeQuery.parameters + parentDopeQuery.parameters,
)
}
}

class DeleteLimitClause(private val numberExpression: TypeExpression<NumberType>, private val parentClause: IDeleteWhereClause) :
IDeleteLimitClause {
class SelectLimitClause(numberExpression: TypeExpression<NumberType>, parentClause: ISelectOrderByClause) :
ISelectLimitClause, LimitClause(numberExpression, parentClause)

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(numberExpression: TypeExpression<NumberType>, parentClause: IDeleteWhereClause) :
IDeleteLimitClause, LimitClause(numberExpression, parentClause)

class UpdateLimitClause(numberExpression: TypeExpression<NumberType>, parentClause: IUpdateWhereClause) :
IUpdateLimitClause, LimitClause(numberExpression, parentClause)
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.clause.Clause
import ch.ergon.dope.resolvable.clause.IDeleteLimitClause
import ch.ergon.dope.resolvable.clause.IDeleteOffsetClause
import ch.ergon.dope.resolvable.clause.ISelectLimitClause
Expand All @@ -9,30 +10,22 @@ import ch.ergon.dope.resolvable.expression.TypeExpression
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 toDopeQuery(): DopeQuery {
sealed class OffsetClause(
private val numberExpression: TypeExpression<NumberType>,
private val parentClause: Clause,
) {
fun toDopeQuery(): DopeQuery {
val parentDopeQuery = parentClause.toDopeQuery()
val numberDopeQuery = numberExpression.toDopeQuery()
return DopeQuery(
queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, OFFSET, numberDopeQuery.queryString),
queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, "OFFSET", numberDopeQuery.queryString),
parameters = numberDopeQuery.parameters + parentDopeQuery.parameters,
)
}
}

class DeleteOffsetClause(private val numberExpression: TypeExpression<NumberType>, private val parentClause: IDeleteLimitClause) :
IDeleteOffsetClause {
class SelectOffsetClause(numberExpression: TypeExpression<NumberType>, parentClause: ISelectLimitClause) :
ISelectOffsetClause, OffsetClause(numberExpression, parentClause)

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(numberExpression: TypeExpression<NumberType>, parentClause: IDeleteLimitClause) :
IDeleteOffsetClause, OffsetClause(numberExpression, parentClause)
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
package ch.ergon.dope.resolvable.clause.model

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

class ReturningClause(
sealed class ReturningClause(
private val field: Field<out ValidType>,
private vararg val fields: Field<out ValidType>,
private val parentClause: IDeleteOffsetClause,
) : IDeleteReturningClause {

override fun toDopeQuery(): DopeQuery {
private val parentClause: Clause,
) {
fun toDopeQuery(): DopeQuery {
val fieldsDopeQuery = fields.map { it.toDopeQuery() }
val fieldDopeQuery = field.toDopeQuery()
val parentDopeQuery = parentClause.toDopeQuery()
Expand All @@ -30,3 +32,15 @@ class ReturningClause(
)
}
}

class DeleteReturningClause(
field: Field<out ValidType>,
vararg fields: Field<out ValidType>,
parentClause: IDeleteOffsetClause,
) : IDeleteReturningClause, ReturningClause(field, *fields, parentClause = parentClause)

class UpdateReturningClause(
field: Field<out ValidType>,
vararg fields: Field<out ValidType>,
parentClause: IUpdateLimitClause,
) : IUpdateReturningClause, ReturningClause(field, *fields, parentClause = parentClause)
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.clause.IUpdateSetClause
import ch.ergon.dope.resolvable.expression.TypeExpression
import ch.ergon.dope.resolvable.expression.unaliased.type.Field
import ch.ergon.dope.resolvable.expression.unaliased.type.toDopeType
import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.validtype.BooleanType
import ch.ergon.dope.validtype.NumberType
import ch.ergon.dope.validtype.StringType
import ch.ergon.dope.validtype.ValidType

class SetClause(
private val fieldAssignment: SetAssignment<out ValidType>,
private vararg val fieldAssignments: SetAssignment<out ValidType>,
private val parentClause: IUpdateSetClause,
) : IUpdateSetClause {
override fun toDopeQuery(): DopeQuery {
val fieldAssignmentDopeQuery = fieldAssignment.toDopeQuery()
val fieldAssignmentsDopeQuery = fieldAssignments.map { it.toDopeQuery() }
val parentClauseDopeQuery = parentClause.toDopeQuery()
return DopeQuery(
queryString = formatToQueryString(
"${parentClauseDopeQuery.queryString} SET",
fieldAssignmentDopeQuery.queryString,
*fieldAssignmentsDopeQuery.map { it.queryString }.toTypedArray(),
),
parameters = fieldAssignmentsDopeQuery.fold(fieldAssignmentDopeQuery.parameters) {
setAssignmentsParameters, field ->
setAssignmentsParameters + field.parameters
} + parentClauseDopeQuery.parameters,
)
}

fun <T : ValidType> set(field: Field<T>, value: TypeExpression<T>) =
SetClause(this.fieldAssignment, *this.fieldAssignments, field.to(value), parentClause = this.parentClause)

fun set(field: Field<NumberType>, value: Number) =
SetClause(
this.fieldAssignment,
*this.fieldAssignments,
field.to(value.toDopeType()),
parentClause = this.parentClause,
)

fun set(field: Field<StringType>, value: String) =
SetClause(
this.fieldAssignment,
*this.fieldAssignments,
field.to(value.toDopeType()),
parentClause = this.parentClause,
)

fun set(field: Field<BooleanType>, value: Boolean) =
SetClause(
this.fieldAssignment,
*this.fieldAssignments,
field.to(value.toDopeType()),
parentClause = this.parentClause,
)
}

class SetAssignment<T : ValidType>(
private val field: Field<T>,
private val value: TypeExpression<T>,
) {
fun toDopeQuery(): DopeQuery {
val fieldDopeQuery = field.toDopeQuery()
val valueDopeQuery = value.toDopeQuery()
return DopeQuery(
queryString = "${fieldDopeQuery.queryString} = ${valueDopeQuery.queryString}",
parameters = fieldDopeQuery.parameters + valueDopeQuery.parameters,
)
}
}

fun <T : ValidType> Field<T>.to(value: TypeExpression<T>) = SetAssignment(this, value)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.resolvable.clause.IUpdateUnsetClause
import ch.ergon.dope.resolvable.expression.unaliased.type.Field
import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.validtype.ValidType

class UnsetClause(
private val field: Field<out ValidType>,
private vararg val fields: Field<out ValidType>,
private val parentClause: IUpdateUnsetClause,
) : IUpdateUnsetClause {
override fun toDopeQuery(): DopeQuery {
val fieldDopeQuery = field.toDopeQuery()
val fieldsDopeQuery = fields.map { it.toDopeQuery() }
val parentClauseDopeQuery = parentClause.toDopeQuery()
return DopeQuery(
queryString = formatToQueryString(
"${parentClauseDopeQuery.queryString} UNSET",
fieldDopeQuery.queryString,
*fieldsDopeQuery.map { it.queryString }.toTypedArray(),
),
parameters = parentClauseDopeQuery.parameters,
)
}

fun unset(field: Field<out ValidType>) =
UnsetClause(this.field, *this.fields, field, parentClause = this.parentClause)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ch.ergon.dope.resolvable.clause.model

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

class UpdateClause(private val bucket: Bucket) : IUpdateClause {
override fun toDopeQuery(): DopeQuery {
val bucketDopeQuery = bucket.toDopeQuery()
return DopeQuery(
queryString = "UPDATE ${bucketDopeQuery.queryString}",
parameters = bucketDopeQuery.parameters,
)
}
}
Loading

0 comments on commit fe3addc

Please sign in to comment.