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

DOPE-271: added missing returning clause functionality #73

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ class DeleteIntegrationTest : BaseIntegrationTest() {
)
.returning(
idField,
).build()
).thenReturningAsterisk()
.build()

tryUntil {
val queryResult = queryWithoutParameters(dopeQuery)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class UpdateIntegrationTest : BaseIntegrationTest() {
)
.returning(
newField,
)
.thenReturning(
nameField,
).build()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,35 @@ 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.DeleteReturningSingleClause
import ch.ergon.dope.resolvable.clause.model.DeleteWhereClause
import ch.ergon.dope.resolvable.clause.model.ReturningExpression
import ch.ergon.dope.resolvable.clause.model.ReturningType.ELEMENT
import ch.ergon.dope.resolvable.clause.model.ReturningType.RAW
import ch.ergon.dope.resolvable.clause.model.ReturningType.VALUE
import ch.ergon.dope.resolvable.expression.AsteriskExpression
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.fromable.Returnable
import ch.ergon.dope.validtype.BooleanType
import ch.ergon.dope.validtype.NumberType
import ch.ergon.dope.validtype.ValidType

interface IDeleteReturningClause : Clause

interface IDeleteOffsetClause : IDeleteReturningClause {
fun returning(field: Field<out ValidType>, vararg fields: Field<out ValidType>) = DeleteReturningClause(field, *fields, parentClause = this)
fun returning(returningExpression: Returnable, vararg additionalReturningExpressions: Returnable) =
DeleteReturningClause(returningExpression, *additionalReturningExpressions, parentClause = this)
fun returning(typeExpression: TypeExpression<out ValidType>) =
DeleteReturningClause(ReturningExpression(typeExpression), parentClause = this)
fun returningAsterisk() = DeleteReturningClause(AsteriskExpression(), parentClause = this)

fun returningRaw(typeExpression: TypeExpression<out ValidType>) =
DeleteReturningSingleClause(typeExpression, returningType = RAW, parentClause = this)
fun returningValue(typeExpression: TypeExpression<out ValidType>) =
DeleteReturningSingleClause(typeExpression, returningType = VALUE, parentClause = this)
fun returningElement(typeExpression: TypeExpression<out ValidType>) =
DeleteReturningSingleClause(typeExpression, returningType = ELEMENT, parentClause = this)
}

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

import ch.ergon.dope.resolvable.clause.model.ReturningExpression
import ch.ergon.dope.resolvable.clause.model.ReturningType.ELEMENT
import ch.ergon.dope.resolvable.clause.model.ReturningType.RAW
import ch.ergon.dope.resolvable.clause.model.ReturningType.VALUE
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.UpdateReturningSingleClause
import ch.ergon.dope.resolvable.clause.model.UpdateWhereClause
import ch.ergon.dope.resolvable.clause.model.to
import ch.ergon.dope.resolvable.expression.AsteriskExpression
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.fromable.Returnable
import ch.ergon.dope.validtype.BooleanType
import ch.ergon.dope.validtype.NumberType
import ch.ergon.dope.validtype.StringType
Expand All @@ -17,8 +24,18 @@ 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)
fun returning(returningExpression: Returnable, vararg additionalReturningExpressions: Returnable) =
UpdateReturningClause(returningExpression, *additionalReturningExpressions, parentClause = this)
fun returning(typeExpression: TypeExpression<out ValidType>) =
UpdateReturningClause(ReturningExpression(typeExpression), parentClause = this)
fun returningAsterisk() = UpdateReturningClause(AsteriskExpression(), parentClause = this)

fun returningRaw(typeExpression: TypeExpression<out ValidType>) =
UpdateReturningSingleClause(typeExpression, returningType = RAW, parentClause = this)
fun returningValue(typeExpression: TypeExpression<out ValidType>) =
UpdateReturningSingleClause(typeExpression, returningType = VALUE, parentClause = this)
fun returningElement(typeExpression: TypeExpression<out ValidType>) =
UpdateReturningSingleClause(typeExpression, returningType = ELEMENT, parentClause = this)
}

interface IUpdateWhereClause : IUpdateLimitClause {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,132 @@ package ch.ergon.dope.resolvable.clause.model

import ch.ergon.dope.DopeQuery
import ch.ergon.dope.DopeQueryManager
import ch.ergon.dope.resolvable.Resolvable
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.clause.model.ReturningType.RAW
import ch.ergon.dope.resolvable.expression.AsteriskExpression
import ch.ergon.dope.resolvable.expression.TypeExpression
import ch.ergon.dope.resolvable.formatToQueryStringWithSymbol
import ch.ergon.dope.resolvable.fromable.Returnable
import ch.ergon.dope.validtype.ValidType

enum class ReturningType(val queryString: String) {
ELEMENT("ELEMENT"),
RAW("RAW"),
VALUE("VALUE"),
}

sealed class ReturningClause(
private val field: Field<out ValidType>,
private vararg val fields: Field<out ValidType>,
private val returnable: Returnable,
private vararg val additionalReturnables: Returnable,
private val parentClause: Clause,
) {
fun toDopeQuery(manager: DopeQueryManager): DopeQuery {
val fieldsDopeQuery = fields.map { it.toDopeQuery(manager) }
val fieldDopeQuery = field.toDopeQuery(manager)
) : Resolvable {
override fun toDopeQuery(manager: DopeQueryManager): DopeQuery {
val parentDopeQuery = parentClause.toDopeQuery(manager)
val returnableDopeQuery = returnable.toDopeQuery(manager)
val additionalReturnableDopeQueries = additionalReturnables.map { it.toDopeQuery(manager) }
return DopeQuery(
queryString = formatToQueryStringWithSymbol(
parentDopeQuery.queryString,
"RETURNING",
fieldDopeQuery.queryString,
*fieldsDopeQuery.map { it.queryString }.toTypedArray(),
returnableDopeQuery.queryString,
*additionalReturnableDopeQueries.map { it.queryString }.toTypedArray(),
),
parameters = parentDopeQuery.parameters.merge(
fieldDopeQuery.parameters,
*fieldsDopeQuery.map { it.parameters }.toTypedArray(),
returnableDopeQuery.parameters,
*additionalReturnableDopeQueries.map { it.parameters }.toTypedArray(),
),
)
}
}

class ReturningExpression(private val typeExpression: TypeExpression<out ValidType>) : Returnable {
override fun toDopeQuery(manager: DopeQueryManager): DopeQuery {
return typeExpression.toDopeQuery(manager)
}
}

class DeleteReturningClause(
field: Field<out ValidType>,
vararg fields: Field<out ValidType>,
parentClause: IDeleteOffsetClause,
) : IDeleteReturningClause, ReturningClause(field, *fields, parentClause = parentClause)
private val returnable: Returnable,
private vararg val additionalReturnables: Returnable,
private val parentClause: IDeleteOffsetClause,
) : IDeleteReturningClause, ReturningClause(
returnable,
*additionalReturnables,
parentClause = parentClause,
) {
fun thenReturning(typeExpression: TypeExpression<out ValidType>) = DeleteReturningClause(
this.returnable,
*this.additionalReturnables,
ReturningExpression(typeExpression),
parentClause = this.parentClause,
)

fun thenReturningAsterisk() = DeleteReturningClause(
this.returnable,
*this.additionalReturnables,
AsteriskExpression(),
parentClause = this.parentClause,
)
}

class UpdateReturningClause(
field: Field<out ValidType>,
vararg fields: Field<out ValidType>,
private val returnable: Returnable,
private vararg val additionalReturnables: Returnable,
private val parentClause: IUpdateLimitClause,
) : IUpdateReturningClause, ReturningClause(
returnable,
*additionalReturnables,
parentClause = parentClause,
) {
fun thenReturning(typeExpression: TypeExpression<out ValidType>) = UpdateReturningClause(
this.returnable,
*this.additionalReturnables,
ReturningExpression(typeExpression),
parentClause = this.parentClause,
)

fun thenReturningAsterisk() = UpdateReturningClause(
this.returnable,
*this.additionalReturnables,
AsteriskExpression(),
parentClause = this.parentClause,
)
}

sealed class ReturningSingleClause(
private val typeExpression: TypeExpression<out ValidType>,
private val returningType: ReturningType = RAW,
private val parentClause: Clause,
) : Resolvable {
override fun toDopeQuery(manager: DopeQueryManager): DopeQuery {
val parentDopeQuery = parentClause.toDopeQuery(manager)
val typeExpressionDopeQuery = typeExpression.toDopeQuery(manager)
return DopeQuery(
queryString = formatToQueryStringWithSymbol(
parentDopeQuery.queryString,
"RETURNING " + returningType.queryString,
typeExpressionDopeQuery.queryString,
),
parameters = parentDopeQuery.parameters.merge(
typeExpressionDopeQuery.parameters,
),
)
}
}

class DeleteReturningSingleClause(
typeExpression: TypeExpression<out ValidType>,
returningType: ReturningType = RAW,
parentClause: IDeleteOffsetClause,
) : IDeleteReturningClause, ReturningSingleClause(typeExpression, returningType, parentClause = parentClause)

class UpdateReturningSingleClause(
typeExpression: TypeExpression<out ValidType>,
returningType: ReturningType = RAW,
parentClause: IUpdateLimitClause,
) : IUpdateReturningClause, ReturningClause(field, *fields, parentClause = parentClause)
) : IUpdateReturningClause, ReturningSingleClause(typeExpression, returningType, parentClause = parentClause)
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package ch.ergon.dope.resolvable.expression
import ch.ergon.dope.DopeQuery
import ch.ergon.dope.DopeQueryManager
import ch.ergon.dope.resolvable.fromable.Bucket
import ch.ergon.dope.resolvable.fromable.Returnable

const val ASTERISK_STRING = "*"

class AsteriskExpression(private val bucket: Bucket? = null) : Expression {
class AsteriskExpression(private val bucket: Bucket? = null) : Expression, Returnable {
override fun toDopeQuery(manager: DopeQueryManager): DopeQuery {
val queryString = bucket?.toDopeQuery(manager)?.queryString?.let { "$it.$ASTERISK_STRING" } ?: ASTERISK_STRING
return DopeQuery(queryString = queryString)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ interface Joinable : Resolvable
interface Deletable : Resolvable

interface Updatable : Resolvable

interface Returnable : Resolvable
2 changes: 1 addition & 1 deletion core/src/test/kotlin/ch/ergon/dope/buildTest/DeleteTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class DeleteTest {

val actual: String = create
.deleteFrom(someBucket())
.returning(someStringField(), someNumberField())
.returning(someStringField()).thenReturning(someNumberField())
.build().queryString

assertEquals(expected, actual)
Expand Down
Loading
Loading