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-209: added DeleteClause #13

Merged
merged 7 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
4 changes: 4 additions & 0 deletions core/src/main/kotlin/ch/ergon/dope/QueryBuilder.kt
jansigi marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package ch.ergon.dope

import ch.ergon.dope.resolvable.clause.DeleteClause
import ch.ergon.dope.resolvable.clause.FromClause
import ch.ergon.dope.resolvable.clause.SelectClause
import ch.ergon.dope.resolvable.clause.SelectDistinctClause
import ch.ergon.dope.resolvable.clause.SelectRawClause
import ch.ergon.dope.resolvable.expression.AsteriskExpression
import ch.ergon.dope.resolvable.expression.Expression
import ch.ergon.dope.resolvable.expression.SingleExpression
import ch.ergon.dope.resolvable.fromable.Bucket
import ch.ergon.dope.resolvable.fromable.Fromable

class QueryBuilder {
Expand All @@ -20,4 +22,6 @@ class QueryBuilder {
fun selectRaw(expression: SingleExpression): SelectRawClause = SelectRawClause(expression)

fun selectFrom(fromable: Fromable): FromClause = SelectClause(AsteriskExpression()).from(fromable)

fun deleteFrom(from: Bucket): DeleteClause = DeleteClause(from)
jansigi marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ch.ergon.dope.resolvable.clause

import ch.ergon.dope.resolvable.fromable.Bucket

class DeleteClause(private val from: Bucket) : IDeleteClause {
jansigi marked this conversation as resolved.
Show resolved Hide resolved
override fun toQueryString(): String = "DELETE FROM ${from.toQueryString()}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ch.ergon.dope.resolvable.clause

import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.resolvable.fromable.Fromable

class FromClause(private val fromable: Fromable, private val parentClause: ISelectClause) : IJoinClause {
override fun toQueryString(): String = formatToQueryString(parentClause, "FROM", fromable)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ch.ergon.dope.resolvable.clause

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

class GroupByClause(
private val field: Field<out ValidType>,
private vararg val fields: Field<out ValidType>,
private val parentClause: IWhereClause,
) : IGroupByClause {
override fun toQueryString(): String = formatToQueryString(parentClause, "GROUP BY", field, *fields)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package ch.ergon.dope.resolvable.clause

import ch.ergon.dope.resolvable.expression.TypeExpression
import ch.ergon.dope.resolvable.expression.unaliased.type.Field
import ch.ergon.dope.validtype.BooleanType
import ch.ergon.dope.validtype.NumberType
import ch.ergon.dope.validtype.ValidType

interface IReturningClause : Clause

interface IDeleteOffsetClass : IReturningClause {
fun returning(field: Field<out ValidType>, vararg fields: Field<out ValidType>) = ReturningClause(field, *fields, parent = this)
}

interface IDeleteLimitClass : IDeleteOffsetClass {
fun offset(numberExpression: TypeExpression<NumberType>) = DeleteOffsetClause(numberExpression, this)
}

interface IDeleteWhereClause : IDeleteLimitClass {
fun limit(numberExpression: TypeExpression<NumberType>) = DeleteLimitClause(numberExpression, this)
jansigi marked this conversation as resolved.
Show resolved Hide resolved
}

interface IDeleteClause : IDeleteWhereClause {
fun where(booleanExpression: TypeExpression<BooleanType>) = DeleteWhereClause(booleanExpression, this)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ch.ergon.dope.resolvable.clause

import ch.ergon.dope.resolvable.expression.TypeExpression
import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.validtype.NumberType

private const val LIMIT = "LIMIT"

class LimitClause(private val numberExpression: TypeExpression<NumberType>, private val parentClause: IOrderByClause) : ILimitClause {
jansigi marked this conversation as resolved.
Show resolved Hide resolved
override fun toQueryString(): String = formatToQueryString(parentClause, LIMIT, numberExpression)
}

class DeleteLimitClause(private val numberExpression: TypeExpression<NumberType>, private val parent: IDeleteWhereClause) :
jansigi marked this conversation as resolved.
Show resolved Hide resolved
IDeleteLimitClass {
override fun toQueryString(): String {
return formatToQueryString(parent, LIMIT, numberExpression)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ch.ergon.dope.resolvable.clause

import ch.ergon.dope.resolvable.expression.TypeExpression
import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.validtype.NumberType

private const val OFFSET = "OFFSET"

class OffsetClause(private val numberExpression: TypeExpression<NumberType>, private val parentClause: ILimitClause) : IOffsetClause {
override fun toQueryString(): String = formatToQueryString(parentClause, OFFSET, numberExpression)
}

class DeleteOffsetClause(private val numberExpression: TypeExpression<NumberType>, private val parent: IDeleteLimitClass) :
jansigi marked this conversation as resolved.
Show resolved Hide resolved
IDeleteOffsetClass {
override fun toQueryString(): String = formatToQueryString(parent, OFFSET, numberExpression)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ch.ergon.dope.resolvable.clause

import ch.ergon.dope.resolvable.expression.unaliased.type.Field
import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.validtype.StringType

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

open class OrderByClause(private val stringField: Field<StringType>, private val parentClause: IGroupByClause) :
IOrderByClause {
override fun toQueryString(): String = formatToQueryString(parentClause, "ORDER BY", stringField)
}

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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ch.ergon.dope.resolvable.clause

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

class ReturningClause(
private val field: Field<out ValidType>,
private vararg val fields: Field<out ValidType>,
private val parent: IDeleteOffsetClass,
jansigi marked this conversation as resolved.
Show resolved Hide resolved
) : IReturningClause {
override fun toQueryString(): String = formatToQueryString(parent, "RETURNING", field, *fields)
}
Original file line number Diff line number Diff line change
@@ -1,49 +1,10 @@
package ch.ergon.dope.resolvable.clause

import ch.ergon.dope.resolvable.expression.Expression
import ch.ergon.dope.resolvable.expression.TypeExpression
import ch.ergon.dope.resolvable.expression.unaliased.type.Field
import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.resolvable.fromable.Fromable
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 OffsetClause(private val numberExpression: TypeExpression<NumberType>, private val parentClause: ILimitClause) : IOffsetClause {
override fun toQueryString(): String = formatToQueryString(parentClause, "OFFSET", numberExpression)
}

class LimitClause(private val numberExpression: TypeExpression<NumberType>, private val parentClause: IOrderByClause) : ILimitClause {
override fun toQueryString(): String = formatToQueryString(parentClause, "LIMIT", numberExpression)
}

open class OrderByClause(private val stringField: Field<StringType>, private val parentClause: IGroupByClause) : IOrderByClause {
override fun toQueryString(): String = formatToQueryString(parentClause, "ORDER BY", stringField)
}

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

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

class WhereClause(private val whereExpression: TypeExpression<BooleanType>, private val parentClause: IFromClause) : IWhereClause {
override fun toQueryString(): String = formatToQueryString(parentClause, "WHERE", whereExpression)
}

class FromClause(private val fromable: Fromable, private val parentClause: ISelectClause) : IJoinClause {
override fun toQueryString(): String = formatToQueryString(parentClause, "FROM", fromable)
class SelectClause(private val expression: Expression, private vararg val expressions: Expression) : ISelectClause {
override fun toQueryString(): String = formatToQueryString("SELECT", expression, *expressions)
}

class SelectRawClause(private val expression: Expression) : ISelectClause {
Expand All @@ -53,7 +14,3 @@ class SelectRawClause(private val expression: Expression) : ISelectClause {
class SelectDistinctClause(private val expression: Expression, private vararg val expressions: Expression) : ISelectClause {
override fun toQueryString(): String = formatToQueryString("SELECT DISTINCT", expression, *expressions)
}

class SelectClause(private val expression: Expression, private vararg val expressions: Expression) : ISelectClause {
override fun toQueryString(): String = formatToQueryString("SELECT", expression, *expressions)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ch.ergon.dope.resolvable.clause

import ch.ergon.dope.resolvable.expression.TypeExpression
import ch.ergon.dope.resolvable.formatToQueryString
import ch.ergon.dope.validtype.BooleanType

private const val WHERE = "WHERE"

class WhereClause(private val whereExpression: TypeExpression<BooleanType>, private val parentClause: IFromClause) : IWhereClause {
override fun toQueryString(): String = formatToQueryString(parentClause, WHERE, whereExpression)
}

class DeleteWhereClause(private val booleanExpression: TypeExpression<BooleanType>, private val parent: IDeleteClause) : IDeleteWhereClause {
override fun toQueryString(): String {
return formatToQueryString(parent, WHERE, booleanExpression)
}
}
107 changes: 107 additions & 0 deletions core/src/test/kotlin/ch/ergon/dope/DeleteTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package ch.ergon.dope

import ch.ergon.dope.helper.someBucket
import ch.ergon.dope.helper.someNumberField
import ch.ergon.dope.helper.someStringField
import ch.ergon.dope.resolvable.expression.unaliased.type.Primitive.Companion.TRUE
import ch.ergon.dope.resolvable.expression.unaliased.type.logical.and
import ch.ergon.dope.resolvable.expression.unaliased.type.relational.isEqualTo
import ch.ergon.dope.resolvable.expression.unaliased.type.toNumberType
import junit.framework.TestCase.assertEquals
import kotlin.test.BeforeTest
import kotlin.test.Test

class DeleteTest {
private lateinit var create: QueryBuilder

@BeforeTest
fun setup() {
create = QueryBuilder()
}

@Test
fun `should support delete from`() {
val expected = "DELETE FROM someBucket"

val actual: String = create
.deleteFrom(someBucket())
.build()

assertEquals(expected, actual)
}

@Test
fun `should support delete from with where`() {
val expected = "DELETE FROM someBucket WHERE TRUE"

val actual: String = create
.deleteFrom(someBucket())
.where(TRUE)
.build()

assertEquals(expected, actual)
}

@Test
fun `should support delete from with limit`() {
val expected = "DELETE FROM someBucket LIMIT 10"

val actual: String = create
.deleteFrom(someBucket())
.limit(10.toNumberType())
.build()

assertEquals(expected, actual)
}

@Test
fun `should support delete from with offset`() {
val expected = "DELETE FROM someBucket OFFSET 10"

val actual: String = create
.deleteFrom(someBucket())
.offset(10.toNumberType())
.build()

assertEquals(expected, actual)
}

@Test
fun `should support delete from with returning`() {
val expected = "DELETE FROM someBucket RETURNING stringField"

val actual: String = create
.deleteFrom(someBucket())
.returning(someStringField())
.build()

assertEquals(expected, actual)
}

@Test
fun `should support delete from with multiple returning`() {
val expected = "DELETE FROM someBucket RETURNING stringField, numberField"

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

assertEquals(expected, actual)
}

@Test
fun `should support delete`() {
val expected = "DELETE FROM someBucket WHERE someBucket.age = 2 AND TRUE LIMIT 7 OFFSET 10 RETURNING stringField"

val actual: String = create
.deleteFrom(someBucket())
.where(someNumberField("age", someBucket()).isEqualTo(2).and(TRUE))
.limit(7.toNumberType())
.offset(10.toNumberType())
.returning(someStringField())
.build()

assertEquals(expected, actual)
}
}
Loading