diff --git a/core/src/main/kotlin/ch/ergon/dope/QueryBuilder.kt b/core/src/main/kotlin/ch/ergon/dope/QueryBuilder.kt index aa4afff7..d9e4a9f0 100644 --- a/core/src/main/kotlin/ch/ergon/dope/QueryBuilder.kt +++ b/core/src/main/kotlin/ch/ergon/dope/QueryBuilder.kt @@ -1,12 +1,14 @@ package ch.ergon.dope -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.clause.model.DeleteClause +import ch.ergon.dope.resolvable.clause.model.FromClause +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.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 { @@ -20,4 +22,6 @@ class QueryBuilder { fun selectRaw(expression: SingleExpression): SelectRawClause = SelectRawClause(expression) fun selectFrom(fromable: Fromable): FromClause = SelectClause(AsteriskExpression()).from(fromable) + + fun deleteFrom(bucket: Bucket): DeleteClause = DeleteClause(bucket) } diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/IDeleteClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/IDeleteClause.kt new file mode 100644 index 00000000..6cba056f --- /dev/null +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/IDeleteClause.kt @@ -0,0 +1,32 @@ +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.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.toNumberType +import ch.ergon.dope.validtype.BooleanType +import ch.ergon.dope.validtype.NumberType +import ch.ergon.dope.validtype.ValidType + +interface IDeleteReturningClause : Clause + +interface IDeleteOffsetClass : IDeleteReturningClause { + fun returning(field: Field, vararg fields: Field) = ReturningClause(field, *fields, parentClause = this) +} + +interface IDeleteLimitClass : IDeleteOffsetClass { + fun offset(numberExpression: TypeExpression) = DeleteOffsetClause(numberExpression, this) + fun offset(number: Number): DeleteOffsetClause = offset(number.toNumberType()) +} + +interface IDeleteWhereClause : IDeleteLimitClass { + fun limit(numberExpression: TypeExpression) = DeleteLimitClause(numberExpression, this) + fun limit(number: Number): DeleteLimitClause = limit(number.toNumberType()) +} + +interface IDeleteClause : IDeleteWhereClause { + fun where(booleanExpression: TypeExpression) = DeleteWhereClause(booleanExpression, this) +} diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/ISelectClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/ISelectClause.kt index c08a65cb..59eaaedd 100644 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/ISelectClause.kt +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/ISelectClause.kt @@ -1,5 +1,17 @@ package ch.ergon.dope.resolvable.clause +import ch.ergon.dope.resolvable.clause.model.FromClause +import ch.ergon.dope.resolvable.clause.model.GroupByClause +import ch.ergon.dope.resolvable.clause.model.InnerJoinClause +import ch.ergon.dope.resolvable.clause.model.LeftJoinClause +import ch.ergon.dope.resolvable.clause.model.OrderByType +import ch.ergon.dope.resolvable.clause.model.RightJoinClause +import ch.ergon.dope.resolvable.clause.model.SelectLimitClause +import ch.ergon.dope.resolvable.clause.model.SelectOffsetClause +import ch.ergon.dope.resolvable.clause.model.SelectOrderByClause +import ch.ergon.dope.resolvable.clause.model.SelectOrderByTypeClause +import ch.ergon.dope.resolvable.clause.model.SelectWhereClause +import ch.ergon.dope.resolvable.clause.model.StandardJoinClause import ch.ergon.dope.resolvable.expression.TypeExpression import ch.ergon.dope.resolvable.expression.unaliased.type.Field import ch.ergon.dope.resolvable.expression.unaliased.type.toNumberType @@ -11,32 +23,34 @@ import ch.ergon.dope.validtype.NumberType import ch.ergon.dope.validtype.StringType import ch.ergon.dope.validtype.ValidType -interface IOffsetClause : Clause +interface ISelectOffsetClause : Clause -interface ILimitClause : IOffsetClause { - fun offset(numberExpression: TypeExpression): OffsetClause = OffsetClause(numberExpression, this) +interface ISelectLimitClause : ISelectOffsetClause { + fun offset(numberExpression: TypeExpression): SelectOffsetClause = SelectOffsetClause(numberExpression, this) + fun offset(number: Number): SelectOffsetClause = offset(number.toNumberType()) } -interface IOrderByClause : ILimitClause { - fun limit(numberExpression: TypeExpression): LimitClause = LimitClause(numberExpression, this) - fun limit(number: Number): LimitClause = limit(number.toNumberType()) +interface ISelectOrderByClause : ISelectLimitClause { + fun limit(numberExpression: TypeExpression): SelectLimitClause = SelectLimitClause(numberExpression, this) + fun limit(number: Number): SelectLimitClause = limit(number.toNumberType()) } -interface IGroupByClause : IOrderByClause { - fun orderBy(stringField: Field): OrderByClause = OrderByClause(stringField, this) - fun orderBy(stringField: Field, orderByType: OrderByType): OrderByTypeClause = OrderByTypeClause(stringField, orderByType, this) +interface ISelectGroupByClause : ISelectOrderByClause { + fun orderBy(stringField: Field): SelectOrderByClause = SelectOrderByClause(stringField, this) + fun orderBy(stringField: Field, orderByType: OrderByType): SelectOrderByTypeClause = + SelectOrderByTypeClause(stringField, orderByType, this) } -interface IWhereClause : IGroupByClause { +interface ISelectWhereClause : ISelectGroupByClause { fun groupBy(field: Field, vararg fields: Field): GroupByClause = GroupByClause(field, *fields, parentClause = this) } -interface IFromClause : IWhereClause { - fun where(whereExpression: TypeExpression) = WhereClause(whereExpression, this) +interface ISelectFromClause : ISelectWhereClause { + fun where(whereExpression: TypeExpression) = SelectWhereClause(whereExpression, this) } -interface IJoinClause : IFromClause { +interface ISelectJoinClause : ISelectFromClause { fun join(bucket: Bucket, onCondition: TypeExpression) = StandardJoinClause(this, bucket, onCondition) fun join(bucket: Bucket, onKeys: Field) = StandardJoinClause(this, bucket, onKeys) @@ -50,7 +64,7 @@ interface IJoinClause : IFromClause { fun rightJoin(bucket: Bucket, onKeys: Field) = RightJoinClause(this, bucket, onKeys) } -interface ISelectClause : IFromClause { +interface ISelectClause : ISelectFromClause { fun from(fromable: Fromable) = FromClause(fromable, this) fun alias(alias: String) = AliasedSelectClause(alias, this) diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/JoinClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/JoinClause.kt deleted file mode 100644 index 07129c76..00000000 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/JoinClause.kt +++ /dev/null @@ -1,53 +0,0 @@ -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.resolvable.fromable.Bucket -import ch.ergon.dope.validtype.BooleanType -import ch.ergon.dope.validtype.ValidType - -sealed class JoinClause : IJoinClause { - private val queryString: String - - constructor(parentClause: IFromClause, joinType: String, bucket: Bucket, onCondition: TypeExpression) { - queryString = "${parentClause.toQueryString()} $joinType ${bucket.toQueryString()} ON ${onCondition.toQueryString()}" - } - - constructor(parentClause: IFromClause, joinType: String, bucket: Bucket, key: Field) { - queryString = "${parentClause.toQueryString()} $joinType ${bucket.toQueryString()} ON KEYS ${key.toQueryString()}" - } - - override fun toQueryString(): String = queryString -} - -class StandardJoinClause : JoinClause { - constructor(parentClause: IFromClause, bucket: Bucket, onCondition: TypeExpression) : - super(parentClause, "JOIN", bucket, onCondition) - - constructor(parentClause: IFromClause, bucket: Bucket, onKeys: Field) : - super(parentClause, "JOIN", bucket, onKeys) -} - -class LeftJoinClause : JoinClause { - constructor(parentClause: IFromClause, bucket: Bucket, onCondition: TypeExpression) : - super(parentClause, "LEFT JOIN", bucket, onCondition) - - constructor(parentClause: IFromClause, bucket: Bucket, onKeys: Field) : - super(parentClause, "LEFT JOIN", bucket, onKeys) -} - -class InnerJoinClause : JoinClause { - constructor(parentClause: IFromClause, bucket: Bucket, onCondition: TypeExpression) : - super(parentClause, "INNER JOIN", bucket, onCondition) - - constructor(parentClause: IFromClause, bucket: Bucket, onKeys: Field) : - super(parentClause, "INNER JOIN", bucket, onKeys) -} - -class RightJoinClause : JoinClause { - constructor(parentClause: IFromClause, bucket: Bucket, onCondition: TypeExpression) : - super(parentClause, "RIGHT JOIN", bucket, onCondition) - - constructor(parentClause: IFromClause, bucket: Bucket, onKeys: Field) : - super(parentClause, "RIGHT JOIN", bucket, onKeys) -} diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/OrderByType.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/OrderByType.kt deleted file mode 100644 index 7d4d6d9c..00000000 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/OrderByType.kt +++ /dev/null @@ -1,6 +0,0 @@ -package ch.ergon.dope.resolvable.clause - -enum class OrderByType(val type: String) { - ASC("ASC"), - DESC("DESC"), -} diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/SelectClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/SelectClause.kt deleted file mode 100644 index f806d4ea..00000000 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/SelectClause.kt +++ /dev/null @@ -1,59 +0,0 @@ -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, private val parentClause: ILimitClause) : IOffsetClause { - override fun toQueryString(): String = formatToQueryString(parentClause, "OFFSET", numberExpression) -} - -class LimitClause(private val numberExpression: TypeExpression, private val parentClause: IOrderByClause) : ILimitClause { - override fun toQueryString(): String = formatToQueryString(parentClause, "LIMIT", numberExpression) -} - -open class OrderByClause(private val stringField: Field, private val parentClause: IGroupByClause) : IOrderByClause { - override fun toQueryString(): String = formatToQueryString(parentClause, "ORDER BY", stringField) -} - -class OrderByTypeClause( - stringField: Field, - private val orderByType: OrderByType, - parentClause: IGroupByClause, -) : OrderByClause(stringField, parentClause) { - override fun toQueryString(): String = super.toQueryString() + " ${orderByType.type}" -} - -class GroupByClause( - private val field: Field, - private vararg val fields: Field, - private val parentClause: IWhereClause, -) : IGroupByClause { - override fun toQueryString(): String = formatToQueryString(parentClause, "GROUP BY", field, *fields) -} - -class WhereClause(private val whereExpression: TypeExpression, 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 SelectRawClause(private val expression: Expression) : ISelectClause { - override fun toQueryString(): String = formatToQueryString("SELECT RAW", expression) -} - -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) -} diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/DeleteClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/DeleteClause.kt new file mode 100644 index 00000000..e36665b3 --- /dev/null +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/DeleteClause.kt @@ -0,0 +1,8 @@ +package ch.ergon.dope.resolvable.clause.model + +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()}" +} diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/FromClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/FromClause.kt new file mode 100644 index 00000000..d1f33aae --- /dev/null +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/FromClause.kt @@ -0,0 +1,10 @@ +package ch.ergon.dope.resolvable.clause.model + +import ch.ergon.dope.resolvable.clause.ISelectClause +import ch.ergon.dope.resolvable.clause.ISelectJoinClause +import ch.ergon.dope.resolvable.formatToQueryString +import ch.ergon.dope.resolvable.fromable.Fromable + +class FromClause(private val fromable: Fromable, private val parentClause: ISelectClause) : ISelectJoinClause { + override fun toQueryString(): String = formatToQueryString(parentClause, "FROM", fromable) +} diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/GroupByClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/GroupByClause.kt new file mode 100644 index 00000000..4d4ae09e --- /dev/null +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/GroupByClause.kt @@ -0,0 +1,15 @@ +package ch.ergon.dope.resolvable.clause.model + +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.validtype.ValidType + +class GroupByClause( + private val field: Field, + private vararg val fields: Field, + private val parentClause: ISelectWhereClause, +) : ISelectGroupByClause { + override fun toQueryString(): String = formatToQueryString(parentClause, "GROUP BY", field, *fields) +} diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/JoinClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/JoinClause.kt new file mode 100644 index 00000000..5b3a55b0 --- /dev/null +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/JoinClause.kt @@ -0,0 +1,55 @@ +package ch.ergon.dope.resolvable.clause.model + +import ch.ergon.dope.resolvable.clause.ISelectFromClause +import ch.ergon.dope.resolvable.clause.ISelectJoinClause +import ch.ergon.dope.resolvable.expression.TypeExpression +import ch.ergon.dope.resolvable.expression.unaliased.type.Field +import ch.ergon.dope.resolvable.fromable.Bucket +import ch.ergon.dope.validtype.BooleanType +import ch.ergon.dope.validtype.ValidType + +sealed class SelectJoinClause : ISelectJoinClause { + private val queryString: String + + constructor(parentClause: ISelectFromClause, joinType: String, bucket: Bucket, onCondition: TypeExpression) { + queryString = "${parentClause.toQueryString()} $joinType ${bucket.toQueryString()} ON ${onCondition.toQueryString()}" + } + + constructor(parentClause: ISelectFromClause, joinType: String, bucket: Bucket, key: Field) { + queryString = "${parentClause.toQueryString()} $joinType ${bucket.toQueryString()} ON KEYS ${key.toQueryString()}" + } + + override fun toQueryString(): String = queryString +} + +class StandardJoinClause : SelectJoinClause { + constructor(parentClause: ISelectFromClause, bucket: Bucket, onCondition: TypeExpression) : + super(parentClause, "JOIN", bucket, onCondition) + + constructor(parentClause: ISelectFromClause, bucket: Bucket, onKeys: Field) : + super(parentClause, "JOIN", bucket, onKeys) +} + +class LeftJoinClause : SelectJoinClause { + constructor(parentClause: ISelectFromClause, bucket: Bucket, onCondition: TypeExpression) : + super(parentClause, "LEFT JOIN", bucket, onCondition) + + constructor(parentClause: ISelectFromClause, bucket: Bucket, onKeys: Field) : + super(parentClause, "LEFT JOIN", bucket, onKeys) +} + +class InnerJoinClause : SelectJoinClause { + constructor(parentClause: ISelectFromClause, bucket: Bucket, onCondition: TypeExpression) : + super(parentClause, "INNER JOIN", bucket, onCondition) + + constructor(parentClause: ISelectFromClause, bucket: Bucket, onKeys: Field) : + super(parentClause, "INNER JOIN", bucket, onKeys) +} + +class RightJoinClause : SelectJoinClause { + constructor(parentClause: ISelectFromClause, bucket: Bucket, onCondition: TypeExpression) : + super(parentClause, "RIGHT JOIN", bucket, onCondition) + + constructor(parentClause: ISelectFromClause, bucket: Bucket, onKeys: Field) : + super(parentClause, "RIGHT JOIN", bucket, onKeys) +} diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/LimitClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/LimitClause.kt new file mode 100644 index 00000000..c8111af4 --- /dev/null +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/LimitClause.kt @@ -0,0 +1,21 @@ +package ch.ergon.dope.resolvable.clause.model + +import ch.ergon.dope.resolvable.clause.IDeleteLimitClass +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.validtype.NumberType + +private const val LIMIT = "LIMIT" + +class SelectLimitClause(private val numberExpression: TypeExpression, private val parentClause: ISelectOrderByClause) : + ISelectLimitClause { + override fun toQueryString(): String = formatToQueryString(parentClause, LIMIT, numberExpression) +} + +class DeleteLimitClause(private val numberExpression: TypeExpression, private val parentClause: IDeleteWhereClause) : + IDeleteLimitClass { + override fun toQueryString(): String = formatToQueryString(parentClause, LIMIT, numberExpression) +} diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/OffsetClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/OffsetClause.kt new file mode 100644 index 00000000..76dad6b3 --- /dev/null +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/OffsetClause.kt @@ -0,0 +1,21 @@ +package ch.ergon.dope.resolvable.clause.model + +import ch.ergon.dope.resolvable.clause.IDeleteLimitClass +import ch.ergon.dope.resolvable.clause.IDeleteOffsetClass +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.validtype.NumberType + +private const val OFFSET = "OFFSET" + +class SelectOffsetClause(private val numberExpression: TypeExpression, private val parentClause: ISelectLimitClause) : + ISelectOffsetClause { + override fun toQueryString(): String = formatToQueryString(parentClause, OFFSET, numberExpression) +} + +class DeleteOffsetClause(private val numberExpression: TypeExpression, private val parentClause: IDeleteLimitClass) : + IDeleteOffsetClass { + override fun toQueryString(): String = formatToQueryString(parentClause, OFFSET, numberExpression) +} diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/OrderByClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/OrderByClause.kt new file mode 100644 index 00000000..3538d423 --- /dev/null +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/OrderByClause.kt @@ -0,0 +1,25 @@ +package ch.ergon.dope.resolvable.clause.model + +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.validtype.StringType + +enum class OrderByType(val type: String) { + ASC("ASC"), + DESC("DESC"), +} + +open class SelectOrderByClause(private val stringField: Field, private val parentClause: ISelectGroupByClause) : + ISelectOrderByClause { + override fun toQueryString(): String = formatToQueryString(parentClause, "ORDER BY", stringField) +} + +class SelectOrderByTypeClause( + stringField: Field, + private val orderByType: OrderByType, + parentClause: ISelectGroupByClause, +) : SelectOrderByClause(stringField, parentClause) { + override fun toQueryString(): String = super.toQueryString() + " ${orderByType.type}" +} diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/ReturningClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/ReturningClause.kt new file mode 100644 index 00000000..9a962cfd --- /dev/null +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/ReturningClause.kt @@ -0,0 +1,15 @@ +package ch.ergon.dope.resolvable.clause.model + +import ch.ergon.dope.resolvable.clause.IDeleteOffsetClass +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.validtype.ValidType + +class ReturningClause( + private val field: Field, + private vararg val fields: Field, + private val parentClause: IDeleteOffsetClass, +) : IDeleteReturningClause { + override fun toQueryString(): String = formatToQueryString(parentClause, "RETURNING", field, *fields) +} diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/SelectClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/SelectClause.kt new file mode 100644 index 00000000..5535a4ca --- /dev/null +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/SelectClause.kt @@ -0,0 +1,17 @@ +package ch.ergon.dope.resolvable.clause.model + +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) +} + +class SelectRawClause(private val expression: Expression) : ISelectClause { + override fun toQueryString(): String = formatToQueryString("SELECT RAW", expression) +} + +class SelectDistinctClause(private val expression: Expression, private vararg val expressions: Expression) : ISelectClause { + override fun toQueryString(): String = formatToQueryString("SELECT DISTINCT", expression, *expressions) +} diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/WhereClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/WhereClause.kt new file mode 100644 index 00000000..545ee900 --- /dev/null +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/WhereClause.kt @@ -0,0 +1,21 @@ +package ch.ergon.dope.resolvable.clause.model + +import ch.ergon.dope.resolvable.clause.IDeleteClause +import ch.ergon.dope.resolvable.clause.IDeleteWhereClause +import ch.ergon.dope.resolvable.clause.ISelectFromClause +import ch.ergon.dope.resolvable.clause.ISelectWhereClause +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 SelectWhereClause(private val whereExpression: TypeExpression, private val parentClause: ISelectFromClause) : + ISelectWhereClause { + override fun toQueryString(): String = formatToQueryString(parentClause, WHERE, whereExpression) +} + +class DeleteWhereClause(private val booleanExpression: TypeExpression, private val parentClause: IDeleteClause) : + IDeleteWhereClause { + override fun toQueryString(): String = formatToQueryString(parentClause, WHERE, booleanExpression) +} diff --git a/core/src/test/kotlin/ch/ergon/dope/DeleteTest.kt b/core/src/test/kotlin/ch/ergon/dope/DeleteTest.kt new file mode 100644 index 00000000..76728a28 --- /dev/null +++ b/core/src/test/kotlin/ch/ergon/dope/DeleteTest.kt @@ -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) + } +} diff --git a/core/src/test/kotlin/ch/ergon/dope/OrderByTest.kt b/core/src/test/kotlin/ch/ergon/dope/OrderByTest.kt index 7086a0e3..b7507da9 100644 --- a/core/src/test/kotlin/ch/ergon/dope/OrderByTest.kt +++ b/core/src/test/kotlin/ch/ergon/dope/OrderByTest.kt @@ -2,7 +2,7 @@ package ch.ergon.dope import ch.ergon.dope.helper.someBucket import ch.ergon.dope.helper.someStringField -import ch.ergon.dope.resolvable.clause.OrderByType +import ch.ergon.dope.resolvable.clause.model.OrderByType import junit.framework.TestCase.assertEquals import kotlin.test.BeforeTest import kotlin.test.Test diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt index f7e51ff2..890fd3f3 100644 --- a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt @@ -1,19 +1,20 @@ package ch.ergon.dope.extension.clause import ch.ergon.dope.asField -import ch.ergon.dope.resolvable.clause.IGroupByClause -import ch.ergon.dope.resolvable.clause.ILimitClause -import ch.ergon.dope.resolvable.clause.IOrderByClause -import ch.ergon.dope.resolvable.clause.LimitClause -import ch.ergon.dope.resolvable.clause.OffsetClause -import ch.ergon.dope.resolvable.clause.OrderByClause -import ch.ergon.dope.resolvable.clause.OrderByType +import ch.ergon.dope.resolvable.clause.ISelectGroupByClause +import ch.ergon.dope.resolvable.clause.ISelectLimitClause +import ch.ergon.dope.resolvable.clause.ISelectOrderByClause +import ch.ergon.dope.resolvable.clause.model.OrderByType +import ch.ergon.dope.resolvable.clause.model.SelectLimitClause +import ch.ergon.dope.resolvable.clause.model.SelectOffsetClause +import ch.ergon.dope.resolvable.clause.model.SelectOrderByClause import com.schwarz.crystalapi.schema.CMField -fun ILimitClause.offset(numberField: CMField): OffsetClause = offset(numberField.asField()) +fun ISelectLimitClause.offset(numberField: CMField): SelectOffsetClause = offset(numberField.asField()) -fun IOrderByClause.limit(numberField: CMField): LimitClause = limit(numberField.asField()) +fun ISelectOrderByClause.limit(numberField: CMField): SelectLimitClause = limit(numberField.asField()) -fun IGroupByClause.orderBy(stringField: CMField, orderByType: OrderByType): OrderByClause = orderBy(stringField.asField(), orderByType) +fun ISelectGroupByClause.orderBy(stringField: CMField, orderByType: OrderByType): SelectOrderByClause = + orderBy(stringField.asField(), orderByType) -fun IGroupByClause.orderBy(stringField: CMField): OrderByClause = orderBy(stringField.asField()) +fun ISelectGroupByClause.orderBy(stringField: CMField): SelectOrderByClause = orderBy(stringField.asField())