diff --git a/core/src/main/kotlin/ch/ergon/dope/QueryBuilder.kt b/core/src/main/kotlin/ch/ergon/dope/QueryBuilder.kt index 6a50c5b1..eb923176 100644 --- a/core/src/main/kotlin/ch/ergon/dope/QueryBuilder.kt +++ b/core/src/main/kotlin/ch/ergon/dope/QueryBuilder.kt @@ -8,8 +8,9 @@ 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 -import ch.ergon.dope.resolvable.fromable.Bucket +import ch.ergon.dope.resolvable.fromable.Deletable import ch.ergon.dope.resolvable.fromable.Fromable +import ch.ergon.dope.resolvable.fromable.Updatable class QueryBuilder { fun select(expression: Expression, vararg expressions: Expression) = SelectClause(expression, *expressions) @@ -22,7 +23,7 @@ class QueryBuilder { fun selectFrom(fromable: Fromable) = SelectClause(AsteriskExpression()).from(fromable) - fun deleteFrom(bucket: Bucket) = DeleteClause(bucket) + fun deleteFrom(deletable: Deletable) = DeleteClause(deletable) - fun update(bucket: Bucket) = UpdateClause(bucket) + fun update(updatable: Updatable) = UpdateClause(updatable) } diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/QueryStringBuilder.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/QueryStringBuilder.kt index 3599bd2b..cad6dc5d 100644 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/QueryStringBuilder.kt +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/QueryStringBuilder.kt @@ -1,5 +1,7 @@ package ch.ergon.dope.resolvable +import ch.ergon.dope.DopeQuery + fun formatToQueryString(left: String, vararg right: String) = "$left ${right.joinToString()}" @@ -10,6 +12,7 @@ fun formatToQueryStringWithSeparator(symbol: String, separator: String, vararg a "$symbol$separator${argument.joinToString(separator = ", ")}" fun formatToQueryStringWithBrackets(left: String, symbol: String, right: String) = "($left $symbol $right)" + fun formatToQueryStringWithBrackets(symbol: String, vararg argument: String) = "$symbol(${argument.joinToString(separator = ", ")})" @@ -19,3 +22,12 @@ fun formatPathToQueryString(name: String, path: String) = } else { "`$path`.`$name`" } + +fun formatStringListToQueryStringWithBrackets(dopeQueries: List, seperator: String = ", ", prefix: String = "(", postfix: String = ")") = + dopeQueries.joinToString(seperator, prefix, postfix) + +fun formatListToQueryStringWithBrackets(dopeQueries: List, seperator: String = ", ", prefix: String = "(", postfix: String = ")") = + dopeQueries.joinToString(seperator, prefix, postfix) { it.queryString } + +fun formatIndexToQueryString(indexName: String?, indexType: String?) = + listOfNotNull(indexName?.let { "`$it`" }, indexType).joinToString(separator = " ") 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 index fe216d19..fa1d83e5 100644 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/IDeleteClause.kt +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/IDeleteClause.kt @@ -3,15 +3,12 @@ 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.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 IDeleteReturningClause : Clause @@ -30,15 +27,6 @@ interface IDeleteWhereClause : IDeleteLimitClause { fun limit(number: Number) = limit(number.toDopeType()) } -interface IDeleteUseKeysClause : IDeleteWhereClause { +interface IDeleteClause : IDeleteWhereClause { fun where(booleanExpression: TypeExpression) = DeleteWhereClause(booleanExpression, this) } - -interface IDeleteClause : IDeleteUseKeysClause { - fun useKeys(key: TypeExpression) = DeleteUseKeysClause(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>) = DeleteUseKeysClause(key, 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 e3c2f98d..f2b4b424 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 @@ -11,7 +11,6 @@ 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.SelectUseKeys.Companion.SelectUseKeysClause import ch.ergon.dope.resolvable.clause.model.SelectWhereClause import ch.ergon.dope.resolvable.clause.model.StandardJoinClause import ch.ergon.dope.resolvable.clause.model.UnnestClause @@ -22,6 +21,7 @@ import ch.ergon.dope.resolvable.expression.unaliased.type.toDopeType import ch.ergon.dope.resolvable.fromable.AliasedSelectClause import ch.ergon.dope.resolvable.fromable.Bucket import ch.ergon.dope.resolvable.fromable.Fromable +import ch.ergon.dope.resolvable.fromable.Joinable import ch.ergon.dope.validtype.ArrayType import ch.ergon.dope.validtype.BooleanType import ch.ergon.dope.validtype.NumberType @@ -49,33 +49,26 @@ interface ISelectWhereClause : ISelectGroupByClause { fun groupBy(field: Field, vararg fields: Field) = GroupByClause(field, *fields, parentClause = this) } -interface ISelectUseKeysClause : ISelectWhereClause { +interface ISelectFromClause : ISelectWhereClause { fun where(whereExpression: TypeExpression) = SelectWhereClause(whereExpression, this) } -interface ISelectFromClause : ISelectUseKeysClause { - fun useKeys(key: TypeExpression) = SelectUseKeysClause(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(keys: TypeExpression>) = SelectUseKeysClause(keys, this) -} - interface ISelectJoinClause : ISelectFromClause { - fun join(bucket: Bucket, onCondition: TypeExpression) = StandardJoinClause(bucket, onCondition, this) - fun join(bucket: Bucket, onKeys: Field) = StandardJoinClause(bucket, onKeys, this) - fun join(bucket: Bucket, onKey: Field, forBucket: Bucket) = StandardJoinClause(bucket, onKey, forBucket, this) + fun join(joinable: Joinable, onCondition: TypeExpression) = StandardJoinClause(joinable, onCondition, this) + fun join(joinable: Joinable, onKeys: Field) = StandardJoinClause(joinable, onKeys, this) + fun join(joinable: Joinable, onKey: Field, forBucket: Bucket) = StandardJoinClause(joinable, onKey, forBucket, this) + + fun innerJoin(joinable: Joinable, onCondition: TypeExpression) = InnerJoinClause(joinable, onCondition, this) + fun innerJoin(joinable: Joinable, onKeys: Field) = InnerJoinClause(joinable, onKeys, this) + fun innerJoin(joinable: Joinable, onKey: Field, forBucket: Bucket) = InnerJoinClause(joinable, onKey, forBucket, this) - fun innerJoin(bucket: Bucket, onCondition: TypeExpression) = InnerJoinClause(bucket, onCondition, this) - fun innerJoin(bucket: Bucket, onKeys: Field) = InnerJoinClause(bucket, onKeys, this) - fun innerJoin(bucket: Bucket, onKey: Field, forBucket: Bucket) = InnerJoinClause(bucket, onKey, forBucket, this) + fun leftJoin(joinable: Joinable, onCondition: TypeExpression) = LeftJoinClause(joinable, onCondition, this) + fun leftJoin(joinable: Joinable, onKeys: Field) = LeftJoinClause(joinable, onKeys, this) + fun leftJoin(joinable: Joinable, onKey: Field, forBucket: Bucket) = LeftJoinClause(joinable, onKey, forBucket, this) - fun leftJoin(bucket: Bucket, onCondition: TypeExpression) = LeftJoinClause(bucket, onCondition, this) - fun leftJoin(bucket: Bucket, onKeys: Field) = LeftJoinClause(bucket, onKeys, this) - fun leftJoin(bucket: Bucket, onKey: Field, forBucket: Bucket) = LeftJoinClause(bucket, onKey, forBucket, this) + fun rightJoin(joinable: Joinable, onCondition: TypeExpression) = RightJoinClause(joinable, onCondition, this) - fun rightJoin(bucket: Bucket, onCondition: TypeExpression) = RightJoinClause(bucket, onCondition, this) + fun alias(alias: String) = AliasedSelectClause(alias, this) } interface ISelectUnnestClause : ISelectJoinClause { @@ -85,6 +78,4 @@ interface ISelectUnnestClause : ISelectJoinClause { 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/IUpdateClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/IUpdateClause.kt index f8d1f4cf..dadaffc3 100644 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/IUpdateClause.kt +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/IUpdateClause.kt @@ -4,13 +4,11 @@ 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 @@ -36,18 +34,9 @@ interface IUpdateSetClause : IUpdateUnsetClause { fun unset(field: Field) = UnsetClause(field, parentClause = this) } -interface IUpdateUseKeysClause : IUpdateSetClause { +interface IUpdateClause : IUpdateSetClause { fun set(field: Field, value: TypeExpression) = SetClause(field.to(value), parentClause = this) fun set(field: Field, value: Number) = SetClause(field.to(value.toDopeType()), parentClause = this) fun set(field: Field, value: String) = SetClause(field.to(value.toDopeType()), parentClause = this) fun set(field: Field, value: Boolean) = SetClause(field.to(value.toDopeType()), parentClause = this) } - -interface IUpdateClause : IUpdateUseKeysClause { - fun useKeys(key: TypeExpression) = 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>) = UpdateUseKeysClause(key, this) -} 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 index 4c6de207..f8820569 100644 --- 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 @@ -4,14 +4,13 @@ import ch.ergon.dope.DopeQuery import ch.ergon.dope.DopeQueryManager import ch.ergon.dope.resolvable.clause.IDeleteClause import ch.ergon.dope.resolvable.fromable.AliasedBucket -import ch.ergon.dope.resolvable.fromable.Bucket - -class DeleteClause(private val bucket: Bucket) : IDeleteClause { +import ch.ergon.dope.resolvable.fromable.Deletable +class DeleteClause(private val deletable: Deletable) : IDeleteClause { override fun toDopeQuery(manager: DopeQueryManager): DopeQuery { - val bucketDopeQuery = when (bucket) { - is AliasedBucket -> bucket.asBucketDefinition().toDopeQuery(manager) - else -> bucket.toDopeQuery(manager) + val bucketDopeQuery = when (deletable) { + is AliasedBucket -> deletable.asBucketDefinition().toDopeQuery(manager) + else -> deletable.toDopeQuery(manager) } return DopeQuery( queryString = "DELETE FROM ${bucketDopeQuery.queryString}", 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 index 1871d7b8..ced8e524 100644 --- 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 @@ -15,6 +15,7 @@ import ch.ergon.dope.resolvable.expression.TypeExpression import ch.ergon.dope.resolvable.expression.unaliased.type.Field import ch.ergon.dope.resolvable.fromable.AliasedBucket import ch.ergon.dope.resolvable.fromable.Bucket +import ch.ergon.dope.resolvable.fromable.Joinable import ch.ergon.dope.validtype.BooleanType import ch.ergon.dope.validtype.ValidType @@ -33,7 +34,7 @@ private enum class OnType { sealed class SelectJoinClause : ISelectJoinClause { private val joinType: JoinType - private val bucket: Bucket + private val joinable: Joinable private val onCondition: TypeExpression? private val onKeys: Field? private val onKey: Field? @@ -43,13 +44,13 @@ sealed class SelectJoinClause : ISelectJoinClause { constructor( joinType: JoinType, - bucket: Bucket, + joinable: Joinable, onCondition: TypeExpression, parentClause: ISelectFromClause, ) { this.onType = ON this.joinType = joinType - this.bucket = bucket + this.joinable = joinable this.onCondition = onCondition this.parentClause = parentClause this.onKeys = null @@ -59,13 +60,13 @@ sealed class SelectJoinClause : ISelectJoinClause { constructor( joinType: JoinType, - bucket: Bucket, + joinable: Joinable, onKeys: Field, parentClause: ISelectFromClause, ) { this.onType = ON_KEYS this.joinType = joinType - this.bucket = bucket + this.joinable = joinable this.onKeys = onKeys this.parentClause = parentClause this.onCondition = null @@ -75,14 +76,14 @@ sealed class SelectJoinClause : ISelectJoinClause { constructor( joinType: JoinType, - bucket: Bucket, + joinable: Joinable, onKey: Field, forBucket: Bucket, parentClause: ISelectFromClause, ) { this.onType = ON_KEY_FOR this.joinType = joinType - this.bucket = bucket + this.joinable = joinable this.onKey = onKey this.forBucket = forBucket this.parentClause = parentClause @@ -92,12 +93,12 @@ sealed class SelectJoinClause : ISelectJoinClause { override fun toDopeQuery(manager: DopeQueryManager): DopeQuery { val parentDopeQuery = parentClause.toDopeQuery(manager) - val bucketDopeQuery = when (bucket) { - is AliasedBucket -> bucket.asBucketDefinition().toDopeQuery(manager) - else -> bucket.toDopeQuery(manager) + val joinableDopeQuery = when (joinable) { + is AliasedBucket -> joinable.asBucketDefinition().toDopeQuery(manager) + else -> joinable.toDopeQuery(manager) } - val joinQueryString = "${parentDopeQuery.queryString} ${joinType.type} ${bucketDopeQuery.queryString}" - val joinParameters = parentDopeQuery.parameters + bucketDopeQuery.parameters + val joinQueryString = "${parentDopeQuery.queryString} ${joinType.type} ${joinableDopeQuery.queryString}" + val joinParameters = parentDopeQuery.parameters + joinableDopeQuery.parameters return when (onType) { ON -> { @@ -130,37 +131,37 @@ sealed class SelectJoinClause : ISelectJoinClause { } class StandardJoinClause : SelectJoinClause { - constructor(bucket: Bucket, onCondition: TypeExpression, parentClause: ISelectFromClause) : - super(JOIN, bucket, onCondition, parentClause) + constructor(joinable: Joinable, onCondition: TypeExpression, parentClause: ISelectFromClause) : + super(JOIN, joinable, onCondition, parentClause) - constructor(bucket: Bucket, onKeys: Field, parentClause: ISelectFromClause) : - super(JOIN, bucket, onKeys, parentClause) + constructor(joinable: Joinable, onKeys: Field, parentClause: ISelectFromClause) : + super(JOIN, joinable, onKeys, parentClause) - constructor(bucket: Bucket, onKey: Field, forBucket: Bucket, parentClause: ISelectFromClause) : - super(JOIN, bucket, onKey, forBucket, parentClause) + constructor(joinable: Joinable, onKey: Field, forBucket: Bucket, parentClause: ISelectFromClause) : + super(JOIN, joinable, onKey, forBucket, parentClause) } class LeftJoinClause : SelectJoinClause { - constructor(bucket: Bucket, onCondition: TypeExpression, parentClause: ISelectFromClause) : - super(LEFT_JOIN, bucket, onCondition, parentClause) + constructor(joinable: Joinable, onCondition: TypeExpression, parentClause: ISelectFromClause) : + super(LEFT_JOIN, joinable, onCondition, parentClause) - constructor(bucket: Bucket, onKeys: Field, parentClause: ISelectFromClause) : - super(LEFT_JOIN, bucket, onKeys, parentClause) + constructor(joinable: Joinable, onKeys: Field, parentClause: ISelectFromClause) : + super(LEFT_JOIN, joinable, onKeys, parentClause) - constructor(bucket: Bucket, onKey: Field, forBucket: Bucket, parentClause: ISelectFromClause) : - super(LEFT_JOIN, bucket, onKey, forBucket, parentClause) + constructor(joinable: Joinable, onKey: Field, forBucket: Bucket, parentClause: ISelectFromClause) : + super(LEFT_JOIN, joinable, onKey, forBucket, parentClause) } class InnerJoinClause : SelectJoinClause { - constructor(bucket: Bucket, onCondition: TypeExpression, parentClause: ISelectFromClause) : - super(INNER_JOIN, bucket, onCondition, parentClause) + constructor(joinable: Joinable, onCondition: TypeExpression, parentClause: ISelectFromClause) : + super(INNER_JOIN, joinable, onCondition, parentClause) - constructor(bucket: Bucket, onKeys: Field, parentClause: ISelectFromClause) : - super(INNER_JOIN, bucket, onKeys, parentClause) + constructor(joinable: Joinable, onKeys: Field, parentClause: ISelectFromClause) : + super(INNER_JOIN, joinable, onKeys, parentClause) - constructor(bucket: Bucket, onKey: Field, forBucket: Bucket, parentClause: ISelectFromClause) : - super(INNER_JOIN, bucket, onKey, forBucket, parentClause) + constructor(joinable: Joinable, onKey: Field, forBucket: Bucket, parentClause: ISelectFromClause) : + super(INNER_JOIN, joinable, onKey, forBucket, parentClause) } -class RightJoinClause(bucket: Bucket, onCondition: TypeExpression, parentClause: ISelectFromClause) : - SelectJoinClause(RIGHT_JOIN, bucket, onCondition, parentClause) +class RightJoinClause(joinable: Joinable, onCondition: TypeExpression, parentClause: ISelectFromClause) : + SelectJoinClause(RIGHT_JOIN, joinable, onCondition, parentClause) diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/UpdateClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/UpdateClause.kt index 4924a7b8..83542e4f 100644 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/UpdateClause.kt +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/UpdateClause.kt @@ -4,17 +4,17 @@ import ch.ergon.dope.DopeQuery import ch.ergon.dope.DopeQueryManager import ch.ergon.dope.resolvable.clause.IUpdateClause import ch.ergon.dope.resolvable.fromable.AliasedBucket -import ch.ergon.dope.resolvable.fromable.Bucket +import ch.ergon.dope.resolvable.fromable.Updatable -class UpdateClause(private val bucket: Bucket) : IUpdateClause { +class UpdateClause(private val updatable: Updatable) : IUpdateClause { override fun toDopeQuery(manager: DopeQueryManager): DopeQuery { - val resolvableDopeQuery = when (bucket) { - is AliasedBucket -> bucket.asBucketDefinition().toDopeQuery(manager) - else -> bucket.toDopeQuery(manager) + val updatableDopeQuery = when (updatable) { + is AliasedBucket -> updatable.asBucketDefinition().toDopeQuery(manager) + else -> updatable.toDopeQuery(manager) } return DopeQuery( - queryString = "UPDATE ${resolvableDopeQuery.queryString}", - parameters = resolvableDopeQuery.parameters, + queryString = "UPDATE ${updatableDopeQuery.queryString}", + parameters = updatableDopeQuery.parameters, ) } } diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/UseKeysClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/UseKeysClause.kt deleted file mode 100644 index 4f53788c..00000000 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/clause/model/UseKeysClause.kt +++ /dev/null @@ -1,97 +0,0 @@ -package ch.ergon.dope.resolvable.clause.model - -import ch.ergon.dope.DopeQuery -import ch.ergon.dope.DopeQueryManager -import ch.ergon.dope.resolvable.clause.IDeleteClause -import ch.ergon.dope.resolvable.clause.IDeleteUseKeysClause -import ch.ergon.dope.resolvable.clause.ISelectFromClause -import ch.ergon.dope.resolvable.clause.ISelectUseKeysClause -import ch.ergon.dope.resolvable.clause.IUpdateClause -import ch.ergon.dope.resolvable.clause.IUpdateUseKeysClause -import ch.ergon.dope.resolvable.expression.TypeExpression -import ch.ergon.dope.resolvable.formatToQueryStringWithSymbol -import ch.ergon.dope.validtype.ArrayType -import ch.ergon.dope.validtype.StringType -import ch.ergon.dope.validtype.ValidType - -private const val USE_KEYS = "USE KEYS" - -class SelectUseKeys private constructor( - private val useKeys: TypeExpression, - private val parentClause: ISelectFromClause, -) : ISelectUseKeysClause { - companion object { - @JvmName("selectSingleUseKeysClauseConstructor") - fun SelectUseKeysClause(key: TypeExpression, parentClause: ISelectFromClause) = - SelectUseKeys(key, parentClause) - - @JvmName("selectMultipleUseKeysClauseConstructor") - fun SelectUseKeysClause(keys: TypeExpression>, parentClause: ISelectFromClause) = - SelectUseKeys(keys, parentClause) - } - - override fun toDopeQuery(manager: DopeQueryManager): DopeQuery { - val parentDopeQuery = parentClause.toDopeQuery(manager) - val keysDopeQuery = useKeys.toDopeQuery(manager) - return DopeQuery( - queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, USE_KEYS, keysDopeQuery.queryString), - parameters = parentDopeQuery.parameters + keysDopeQuery.parameters, - ) - } -} - -class DeleteUseKeys private constructor( - private val useKeys: TypeExpression, - private val parentClause: IDeleteClause, -) : IDeleteUseKeysClause { - companion object { - @JvmName("deleteSingleUseKeysClauseConstructor") - fun DeleteUseKeysClause(key: TypeExpression, parentClause: IDeleteClause) = - DeleteUseKeys(key, parentClause) - - @JvmName("deleteMultipleUseKeysClauseConstructor") - fun DeleteUseKeysClause(keys: TypeExpression>, parentClause: IDeleteClause) = - DeleteUseKeys(keys, parentClause) - } - - override fun toDopeQuery(manager: DopeQueryManager): DopeQuery { - val parentDopeQuery = parentClause.toDopeQuery(manager) - val keysDopeQuery = useKeys.toDopeQuery(manager) - return DopeQuery( - queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, USE_KEYS, keysDopeQuery.queryString), - parameters = parentDopeQuery.parameters + keysDopeQuery.parameters, - ) - } -} - -class UpdateUseKeys : IUpdateUseKeysClause { - private lateinit var useKeys: TypeExpression - private lateinit var parentClause: IUpdateClause - - companion object { - @JvmName("updateSingleUseKeysClauseConstructor") - fun UpdateUseKeysClause(key: TypeExpression, parentClause: IUpdateClause): UpdateUseKeys { - val instance = UpdateUseKeys() - instance.useKeys = key - instance.parentClause = parentClause - return instance - } - - @JvmName("updateMultipleUseKeysClauseConstructor") - fun UpdateUseKeysClause(keys: TypeExpression>, parentClause: IUpdateClause): UpdateUseKeys { - val instance = UpdateUseKeys() - instance.useKeys = keys - instance.parentClause = parentClause - return instance - } - } - - override fun toDopeQuery(manager: DopeQueryManager): DopeQuery { - val parentDopeQuery = parentClause.toDopeQuery(manager) - val keysDopeQuery = useKeys.toDopeQuery(manager) - return DopeQuery( - queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, USE_KEYS, keysDopeQuery.queryString), - parameters = parentDopeQuery.parameters + keysDopeQuery.parameters, - ) - } -} 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 index 8f99a72a..c7862c9f 100644 --- 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 @@ -3,9 +3,9 @@ package ch.ergon.dope.resolvable.clause.model import ch.ergon.dope.DopeQuery import ch.ergon.dope.DopeQueryManager import ch.ergon.dope.resolvable.clause.Clause -import ch.ergon.dope.resolvable.clause.IDeleteUseKeysClause +import ch.ergon.dope.resolvable.clause.IDeleteClause import ch.ergon.dope.resolvable.clause.IDeleteWhereClause -import ch.ergon.dope.resolvable.clause.ISelectUseKeysClause +import ch.ergon.dope.resolvable.clause.ISelectFromClause import ch.ergon.dope.resolvable.clause.ISelectWhereClause import ch.ergon.dope.resolvable.clause.IUpdateUnsetClause import ch.ergon.dope.resolvable.clause.IUpdateWhereClause @@ -27,10 +27,10 @@ sealed class WhereClause( } } -class SelectWhereClause(whereExpression: TypeExpression, parentClause: ISelectUseKeysClause) : +class SelectWhereClause(whereExpression: TypeExpression, parentClause: ISelectFromClause) : ISelectWhereClause, WhereClause(whereExpression, parentClause) -class DeleteWhereClause(whereExpression: TypeExpression, parentClause: IDeleteUseKeysClause) : +class DeleteWhereClause(whereExpression: TypeExpression, parentClause: IDeleteClause) : IDeleteWhereClause, WhereClause(whereExpression, parentClause) class UpdateWhereClause(whereExpression: TypeExpression, parentClause: IUpdateUnsetClause) : diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/expression/unaliased/type/Primitive.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/expression/unaliased/type/Primitive.kt index a08e7186..b3847053 100644 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/expression/unaliased/type/Primitive.kt +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/expression/unaliased/type/Primitive.kt @@ -3,6 +3,7 @@ package ch.ergon.dope.resolvable.expression.unaliased.type import ch.ergon.dope.DopeQuery import ch.ergon.dope.DopeQueryManager import ch.ergon.dope.resolvable.expression.TypeExpression +import ch.ergon.dope.resolvable.formatListToQueryStringWithBrackets import ch.ergon.dope.validtype.ArrayType import ch.ergon.dope.validtype.BooleanType import ch.ergon.dope.validtype.MissingType @@ -58,7 +59,7 @@ class ArrayPrimitive(collection: Collection manager: DopeQueryManager -> collection.map { it.toDopeQuery(manager) }.let { dopeQueries -> DopeQuery( - queryString = dopeQueries.joinToString(", ", prefix = "[", postfix = "]") { it.queryString }, + queryString = formatListToQueryStringWithBrackets(dopeQueries, prefix = "[", postfix = "]"), parameters = dopeQueries.fold(emptyMap()) { parameters, dopeQueryElement -> parameters + dopeQueryElement.parameters }, ) } diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/expression/unaliased/type/function/stringfunction/TokensExpression.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/expression/unaliased/type/function/stringfunction/TokensExpression.kt index d10e2582..817a43a5 100644 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/expression/unaliased/type/function/stringfunction/TokensExpression.kt +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/expression/unaliased/type/function/stringfunction/TokensExpression.kt @@ -4,6 +4,7 @@ import ch.ergon.dope.DopeQuery import ch.ergon.dope.DopeQueryManager import ch.ergon.dope.resolvable.expression.TypeExpression import ch.ergon.dope.resolvable.expression.unaliased.type.function.stringfunction.factory.CustomTokenOptions +import ch.ergon.dope.resolvable.formatStringListToQueryStringWithBrackets import ch.ergon.dope.resolvable.operator.FunctionOperator import ch.ergon.dope.validtype.StringType @@ -19,7 +20,7 @@ class TokensExpression( return DopeQuery( queryString = toFunctionQueryString( symbol = "TOKENS", - inStr.joinToString(prefix = "[\"", postfix = "\"]"), + formatStringListToQueryStringWithBrackets(inStr, prefix = "[\"", postfix = "\"]"), optDopeQuery.queryString, ), parameters = optDopeQuery.parameters, diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/AliasedSelectClause.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/AliasedSelectClause.kt index 71a200ee..0f989768 100644 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/AliasedSelectClause.kt +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/AliasedSelectClause.kt @@ -2,14 +2,14 @@ package ch.ergon.dope.resolvable.fromable import ch.ergon.dope.DopeQuery import ch.ergon.dope.DopeQueryManager -import ch.ergon.dope.resolvable.clause.ISelectClause +import ch.ergon.dope.resolvable.clause.ISelectJoinClause -class AliasedSelectClause(private val alias: String, private val selectClause: ISelectClause) : Fromable { +class AliasedSelectClause(private val alias: String, private val parentClause: ISelectJoinClause) : Fromable { override fun toDopeQuery(manager: DopeQueryManager): DopeQuery { - val selectClauseDopeQuery = selectClause.toDopeQuery(manager) + val parentClauseDopeQuery = parentClause.toDopeQuery(manager) return DopeQuery( - queryString = "(${selectClauseDopeQuery.queryString}) AS `$alias`", - parameters = selectClauseDopeQuery.parameters, + queryString = "(${parentClauseDopeQuery.queryString}) AS `$alias`", + parameters = parentClauseDopeQuery.parameters, ) } } diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/Bucket.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/Bucket.kt index 1e8292f1..a6aa817c 100644 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/Bucket.kt +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/Bucket.kt @@ -6,7 +6,7 @@ import ch.ergon.dope.resolvable.Resolvable import ch.ergon.dope.resolvable.expression.AsteriskExpression import ch.ergon.dope.resolvable.expression.Expression -sealed class Bucket(open val name: String) : Fromable, Expression { +sealed class Bucket(open val name: String) : Fromable, Joinable, Deletable, Updatable, Expression { override fun toDopeQuery(manager: DopeQueryManager) = DopeQuery("`$name`", emptyMap()) } diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/Fromable.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/Fromable.kt index caf011a8..0804a053 100644 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/Fromable.kt +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/Fromable.kt @@ -3,3 +3,9 @@ package ch.ergon.dope.resolvable.fromable import ch.ergon.dope.resolvable.Resolvable interface Fromable : Resolvable + +interface Joinable : Resolvable + +interface Deletable : Resolvable + +interface Updatable : Resolvable diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/UseIndex.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/UseIndex.kt new file mode 100644 index 00000000..f78c039e --- /dev/null +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/UseIndex.kt @@ -0,0 +1,56 @@ +package ch.ergon.dope.resolvable.fromable + +import ch.ergon.dope.DopeQuery +import ch.ergon.dope.DopeQueryManager +import ch.ergon.dope.resolvable.Resolvable +import ch.ergon.dope.resolvable.formatIndexToQueryString +import ch.ergon.dope.resolvable.formatListToQueryStringWithBrackets +import ch.ergon.dope.resolvable.formatToQueryStringWithSymbol +import ch.ergon.dope.resolvable.fromable.IndexType.USING_FTS +import ch.ergon.dope.resolvable.fromable.IndexType.USING_GSI + +private const val USE_INDEX = "USE INDEX" + +enum class IndexType(val type: String) { + USING_GSI("USING GSI"), + USING_FTS("USING FTS"), +} + +class IndexReference( + private val indexName: String? = null, + private val indexType: IndexType? = null, +) : Resolvable { + override fun toDopeQuery(manager: DopeQueryManager) = DopeQuery(formatIndexToQueryString(indexName, indexType?.type), emptyMap()) +} + +class UseIndex( + val bucket: Bucket, + vararg val indexReference: IndexReference, +) : Joinable, Deletable, Fromable { + override fun toDopeQuery(manager: DopeQueryManager): DopeQuery { + val bucketDopeQuery = bucket.toDopeQuery(manager) + val indexReferenceDopeQueries = indexReference.map { it.toDopeQuery(manager) } + return DopeQuery( + queryString = formatToQueryStringWithSymbol( + bucketDopeQuery.queryString, + USE_INDEX, + formatListToQueryStringWithBrackets(indexReferenceDopeQueries, seperator = ", ", prefix = "(", postfix = ")"), + ), + parameters = bucketDopeQuery.parameters + indexReferenceDopeQueries.fold(emptyMap()) { indexReferenceParameters, field -> + indexReferenceParameters + field.parameters + }, + ) + } +} + +fun UseIndex.useIndex(indexName: String) = UseIndex(bucket, *indexReference, IndexReference(indexName)) + +fun UseIndex.useGsiIndex(indexName: String? = null) = UseIndex(bucket, *indexReference, IndexReference(indexName, USING_GSI)) + +fun UseIndex.useFtsIndex(indexName: String? = null) = UseIndex(bucket, *indexReference, IndexReference(indexName, USING_FTS)) + +fun Bucket.useIndex(indexName: String? = null) = UseIndex(this, IndexReference(indexName)) + +fun Bucket.useGsiIndex(indexName: String? = null) = UseIndex(this, IndexReference(indexName, USING_GSI)) + +fun Bucket.useFtsIndex(indexName: String? = null) = UseIndex(this, IndexReference(indexName, USING_FTS)) diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/UseKeys.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/UseKeys.kt new file mode 100644 index 00000000..8d7ce221 --- /dev/null +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/fromable/UseKeys.kt @@ -0,0 +1,52 @@ +package ch.ergon.dope.resolvable.fromable + +import ch.ergon.dope.DopeQuery +import ch.ergon.dope.DopeQueryManager +import ch.ergon.dope.resolvable.expression.TypeExpression +import ch.ergon.dope.resolvable.expression.unaliased.type.toDopeType +import ch.ergon.dope.resolvable.formatToQueryStringWithSymbol +import ch.ergon.dope.resolvable.fromable.UseKeysClass.Companion.UseKeys +import ch.ergon.dope.validtype.ArrayType +import ch.ergon.dope.validtype.StringType +import ch.ergon.dope.validtype.ValidType + +private const val USE_KEYS = "USE KEYS" + +class UseKeysClass private constructor( + private val useKeys: TypeExpression, + private val bucket: Bucket, +) : Joinable, Deletable, Updatable, Fromable { + companion object { + @JvmName("singleUseKeysClauseConstructor") + fun UseKeys(key: TypeExpression, bucket: Bucket) = + UseKeysClass(key, bucket) + + @JvmName("multipleUseKeysClauseConstructor") + fun UseKeys(keys: TypeExpression>, bucket: Bucket) = + UseKeysClass(keys, bucket) + } + + override fun toDopeQuery(manager: DopeQueryManager): DopeQuery { + val bucketDopeQuery = when (bucket) { + is AliasedBucket -> bucket.asBucketDefinition().toDopeQuery(manager) + else -> bucket.toDopeQuery(manager) + } + val keysDopeQuery = useKeys.toDopeQuery(manager) + return DopeQuery( + queryString = formatToQueryStringWithSymbol(bucketDopeQuery.queryString, USE_KEYS, keysDopeQuery.queryString), + parameters = bucketDopeQuery.parameters + keysDopeQuery.parameters, + ) + } +} + +fun Bucket.useKeys(key: TypeExpression) = UseKeys(key, this) + +fun Bucket.useKeys(key: String) = useKeys(key.toDopeType()) + +@JvmName("useKeysArray") +fun Bucket.useKeys(keys: TypeExpression>) = UseKeys(keys, this) + +fun Bucket.useKeys(keys: Collection>) = useKeys(keys.toDopeType()) + +fun Bucket.useKeys(firstKey: String, secondKey: String, vararg additionalKeys: String) = + useKeys(listOf(firstKey.toDopeType(), secondKey.toDopeType(), *additionalKeys.map { it.toDopeType() }.toTypedArray()).toDopeType()) diff --git a/core/src/main/kotlin/ch/ergon/dope/resolvable/operator/FunctionOperator.kt b/core/src/main/kotlin/ch/ergon/dope/resolvable/operator/FunctionOperator.kt index b3c75203..4995ae66 100644 --- a/core/src/main/kotlin/ch/ergon/dope/resolvable/operator/FunctionOperator.kt +++ b/core/src/main/kotlin/ch/ergon/dope/resolvable/operator/FunctionOperator.kt @@ -2,21 +2,15 @@ package ch.ergon.dope.resolvable.operator import ch.ergon.dope.DopeQuery import ch.ergon.dope.resolvable.expression.unaliased.aggregator.AggregateQuantifier +import ch.ergon.dope.resolvable.formatListToQueryStringWithBrackets +import ch.ergon.dope.resolvable.formatStringListToQueryStringWithBrackets interface FunctionOperator { - fun toFunctionQueryString(symbol: String, vararg arguments: DopeQuery?) = arguments.filterNotNull().joinToString( - ", ", - prefix = "$symbol(", - postfix = ")", - ) { - it.queryString - } + fun toFunctionQueryString(symbol: String, vararg arguments: DopeQuery?) = + formatListToQueryStringWithBrackets(arguments.filterNotNull(), prefix = "$symbol(") - fun toFunctionQueryString(symbol: String, vararg arguments: String) = arguments.joinToString( - ", ", - prefix = "$symbol(", - postfix = ")", - ) + fun toFunctionQueryString(symbol: String, vararg arguments: String) = + formatStringListToQueryStringWithBrackets(arguments.toList(), prefix = "$symbol(") fun toFunctionQueryString(symbol: String, quantifier: AggregateQuantifier?, argument: String) = quantifier?.let { diff --git a/core/src/test/kotlin/ch/ergon/dope/buildTest/JoinClauseTest.kt b/core/src/test/kotlin/ch/ergon/dope/buildTest/JoinClauseTest.kt index fae23ba2..bc951867 100644 --- a/core/src/test/kotlin/ch/ergon/dope/buildTest/JoinClauseTest.kt +++ b/core/src/test/kotlin/ch/ergon/dope/buildTest/JoinClauseTest.kt @@ -11,6 +11,7 @@ import ch.ergon.dope.resolvable.expression.unaliased.type.logical.and import ch.ergon.dope.resolvable.expression.unaliased.type.meta.meta import ch.ergon.dope.resolvable.expression.unaliased.type.relational.isEqualTo import ch.ergon.dope.resolvable.expression.unaliased.type.toDopeType +import ch.ergon.dope.resolvable.fromable.useIndex import org.junit.jupiter.api.Assertions.assertEquals import kotlin.test.BeforeTest import kotlin.test.Test @@ -53,12 +54,13 @@ class JoinClauseTest { @Test fun `Should support left join`() { val expected = - "SELECT * FROM `route` LEFT JOIN `airline` ON `route`.`airlineid` = META(`airline`).`id` WHERE `route`.`sourceairport` = \"SFO\"" + "SELECT * FROM `route` USE INDEX () LEFT JOIN `airline` ON `route`.`airlineid` = META(`airline`).`id` " + + "WHERE `route`.`sourceairport` = \"SFO\"" val actual = create .selectAsterisk() .from( - route, + route.useIndex(), ).leftJoin( airline, onCondition = someStringField("airlineid", route).isEqualTo( diff --git a/core/src/test/kotlin/ch/ergon/dope/buildTest/SubQueryTest.kt b/core/src/test/kotlin/ch/ergon/dope/buildTest/SubQueryTest.kt index 43e4cbf9..d99ad79c 100644 --- a/core/src/test/kotlin/ch/ergon/dope/buildTest/SubQueryTest.kt +++ b/core/src/test/kotlin/ch/ergon/dope/buildTest/SubQueryTest.kt @@ -1,6 +1,7 @@ package ch.ergon.dope.buildTest import ch.ergon.dope.QueryBuilder +import ch.ergon.dope.helper.someBucket import ch.ergon.dope.helper.someStringField import kotlin.test.BeforeTest import kotlin.test.Test @@ -16,11 +17,11 @@ class SubQueryTest { @Test fun `should support sub select in from`() { - val expected = "SELECT `stringField` FROM (SELECT *) AS `asdf`" + val expected = "SELECT `stringField` FROM (SELECT * FROM `someBucket`) AS `asdf`" val actual: String = create .select(someStringField()) - .from(create.selectAsterisk().alias("asdf")) + .from(create.selectAsterisk().from(someBucket()).alias("asdf")) .build().queryString assertEquals(expected, actual) diff --git a/core/src/test/kotlin/ch/ergon/dope/buildTest/UpdateTest.kt b/core/src/test/kotlin/ch/ergon/dope/buildTest/UpdateTest.kt index ef57ff27..09bf3b87 100644 --- a/core/src/test/kotlin/ch/ergon/dope/buildTest/UpdateTest.kt +++ b/core/src/test/kotlin/ch/ergon/dope/buildTest/UpdateTest.kt @@ -4,12 +4,12 @@ import ch.ergon.dope.QueryBuilder import ch.ergon.dope.helper.someBooleanField import ch.ergon.dope.helper.someBucket import ch.ergon.dope.helper.someNumberField -import ch.ergon.dope.helper.someString import ch.ergon.dope.helper.someStringField import ch.ergon.dope.resolvable.expression.unaliased.type.arithmetic.add import ch.ergon.dope.resolvable.expression.unaliased.type.meta.meta import ch.ergon.dope.resolvable.expression.unaliased.type.relational.isEqualTo import ch.ergon.dope.resolvable.expression.unaliased.type.toDopeType +import ch.ergon.dope.resolvable.fromable.useKeys import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals @@ -34,20 +34,6 @@ class UpdateTest { assertEquals(expected, actual) } - @Test - fun `should support update clause with use keys`() { - val expected = "UPDATE `someBucket` USE KEYS \"someString\"" - - val actual = create - .update( - someBucket(), - ).useKeys( - someString().toDopeType(), - ).build().queryString - - assertEquals(expected, actual) - } - @Test fun `should support update clause with set`() { val expected = "UPDATE `someBucket` SET META().`expiration` = 10, `stringField` = \"test\"" @@ -138,9 +124,7 @@ class UpdateTest { val actual = create .update( - bucket, - ).useKeys( - "keyString".toDopeType(), + bucket.useKeys("keyString"), ).set( someNumberField("setThisNumberField"), 1.toDopeType(), diff --git a/core/src/test/kotlin/ch/ergon/dope/buildTest/UseClauseTest.kt b/core/src/test/kotlin/ch/ergon/dope/buildTest/UseTest.kt similarity index 60% rename from core/src/test/kotlin/ch/ergon/dope/buildTest/UseClauseTest.kt rename to core/src/test/kotlin/ch/ergon/dope/buildTest/UseTest.kt index e3fa3f05..658c263f 100644 --- a/core/src/test/kotlin/ch/ergon/dope/buildTest/UseClauseTest.kt +++ b/core/src/test/kotlin/ch/ergon/dope/buildTest/UseTest.kt @@ -2,17 +2,19 @@ package ch.ergon.dope.buildTest import ch.ergon.dope.QueryBuilder import ch.ergon.dope.helper.someBucket -import ch.ergon.dope.helper.someNumberField import ch.ergon.dope.helper.someStringArrayField import ch.ergon.dope.helper.someStringField import ch.ergon.dope.resolvable.expression.unaliased.type.function.stringfunction.concat -import ch.ergon.dope.resolvable.expression.unaliased.type.relational.isEqualTo import ch.ergon.dope.resolvable.expression.unaliased.type.toDopeType +import ch.ergon.dope.resolvable.fromable.useFtsIndex +import ch.ergon.dope.resolvable.fromable.useGsiIndex +import ch.ergon.dope.resolvable.fromable.useIndex +import ch.ergon.dope.resolvable.fromable.useKeys +import junit.framework.TestCase.assertEquals import kotlin.test.BeforeTest import kotlin.test.Test -import kotlin.test.assertEquals -class UseClauseTest { +class UseTest { private lateinit var create: QueryBuilder @BeforeTest @@ -27,10 +29,7 @@ class UseClauseTest { val actual: String = create .selectAsterisk() .from( - someBucket(), - ) - .useKeys( - "someId".toDopeType(), + someBucket().useKeys("someId"), ) .build().queryString @@ -44,10 +43,7 @@ class UseClauseTest { val actual: String = create .selectAsterisk() .from( - someBucket(), - ) - .useKeys( - someStringField(), + someBucket().useKeys(someStringField()), ) .build().queryString @@ -61,11 +57,11 @@ class UseClauseTest { val actual: String = create .selectAsterisk() .from( - someBucket(), + someBucket().useKeys( + listOf("someId".toDopeType(), "anotherId".toDopeType()).toDopeType(), + ), ) - .useKeys( - listOf("someId".toDopeType(), "anotherId".toDopeType()).toDopeType(), - ).build().queryString + .build().queryString assertEquals(expected, actual) } @@ -77,30 +73,11 @@ class UseClauseTest { val actual: String = create .selectAsterisk() .from( - someBucket(), + someBucket().useKeys( + someStringArrayField(), + ), ) - .useKeys( - someStringArrayField(), - ).build().queryString - - assertEquals(expected, actual) - } - - @Test - fun `should support use keys clause with where clause`() { - val expected = "SELECT * FROM `someBucket` USE KEYS \"someId\" WHERE `numberField` = 1" - - val actual: String = create - .selectAsterisk() - .from( - someBucket(), - ) - .useKeys( - "someId".toDopeType(), - ) - .where( - someNumberField().isEqualTo(1), - ).build().queryString + .build().queryString assertEquals(expected, actual) } @@ -112,10 +89,9 @@ class UseClauseTest { val actual: String = create .selectAsterisk() .from( - someBucket(), - ) - .useKeys( - concat("some", "Id"), + someBucket().useKeys( + concat("some", "Id"), + ), ) .build().queryString @@ -128,10 +104,9 @@ class UseClauseTest { val actual: String = create .deleteFrom( - someBucket(), - ) - .useKeys( - "someId".toDopeType(), + someBucket().useKeys( + "someId", + ), ) .build().queryString @@ -144,10 +119,9 @@ class UseClauseTest { val actual: String = create .deleteFrom( - someBucket(), - ) - .useKeys( - someStringField(), + someBucket().useKeys( + someStringField(), + ), ) .build().queryString @@ -160,11 +134,11 @@ class UseClauseTest { val actual: String = create .deleteFrom( - someBucket(), + someBucket().useKeys( + listOf("someId".toDopeType(), "anotherId".toDopeType()).toDopeType(), + ), ) - .useKeys( - listOf("someId".toDopeType(), "anotherId".toDopeType()).toDopeType(), - ).build().queryString + .build().queryString assertEquals(expected, actual) } @@ -175,29 +149,11 @@ class UseClauseTest { val actual: String = create .deleteFrom( - someBucket(), + someBucket().useKeys( + someStringArrayField(), + ), ) - .useKeys( - someStringArrayField(), - ).build().queryString - - assertEquals(expected, actual) - } - - @Test - fun `should support delete use keys clause with where clause`() { - val expected = "DELETE FROM `someBucket` USE KEYS \"someId\" WHERE `numberField` = 1" - - val actual: String = create - .deleteFrom( - someBucket(), - ) - .useKeys( - "someId".toDopeType(), - ) - .where( - someNumberField().isEqualTo(1), - ).build().queryString + .build().queryString assertEquals(expected, actual) } @@ -208,11 +164,11 @@ class UseClauseTest { val actual: String = create .deleteFrom( - someBucket(), + someBucket().useKeys( + concat("some", "Id"), + ), ) - .useKeys( - concat("some", "Id"), - ).build().queryString + .build().queryString assertEquals(expected, actual) } @@ -223,10 +179,9 @@ class UseClauseTest { val actual: String = create .update( - someBucket(), - ) - .useKeys( - "someId".toDopeType(), + someBucket().useKeys( + "someId", + ), ) .build().queryString @@ -239,10 +194,9 @@ class UseClauseTest { val actual: String = create .update( - someBucket(), - ) - .useKeys( - someStringField(), + someBucket().useKeys( + someStringField(), + ), ) .build().queryString @@ -255,11 +209,11 @@ class UseClauseTest { val actual: String = create .update( - someBucket(), + someBucket().useKeys( + listOf("someId".toDopeType(), "anotherId".toDopeType()).toDopeType(), + ), ) - .useKeys( - listOf("someId".toDopeType(), "anotherId".toDopeType()).toDopeType(), - ).build().queryString + .build().queryString assertEquals(expected, actual) } @@ -270,44 +224,40 @@ class UseClauseTest { val actual: String = create .update( - someBucket(), + someBucket().useKeys( + someStringArrayField(), + ), ) - .useKeys( - someStringArrayField(), - ).build().queryString + .build().queryString assertEquals(expected, actual) } @Test - fun `should support update use keys clause with where clause`() { - val expected = "UPDATE `someBucket` USE KEYS \"someId\" WHERE `numberField` = 1" + fun `should support update use keys clause with string function`() { + val expected = "UPDATE `someBucket` USE KEYS CONCAT(\"some\", \"Id\")" val actual: String = create .update( - someBucket(), + someBucket().useKeys( + concat("some", "Id"), + ), ) - .useKeys( - "someId".toDopeType(), - ) - .where( - someNumberField().isEqualTo(1), - ).build().queryString + .build().queryString assertEquals(expected, actual) } @Test - fun `should support update use keys clause with string function`() { - val expected = "UPDATE `someBucket` USE KEYS CONCAT(\"some\", \"Id\")" + fun `should support select use index clause`() { + val expected = "SELECT * FROM `someBucket` USE INDEX (`someIndex` USING FTS, `otherIndex`, `index3` USING GSI)" val actual: String = create - .update( - someBucket(), + .selectAsterisk() + .from( + someBucket().useFtsIndex("someIndex").useIndex("otherIndex").useGsiIndex("index3"), ) - .useKeys( - concat("some", "Id"), - ).build().queryString + .build().queryString assertEquals(expected, actual) } diff --git a/core/src/test/kotlin/ch/ergon/dope/resolvable/clause/UseKeysClauseTest.kt b/core/src/test/kotlin/ch/ergon/dope/resolvable/clause/UseKeysClauseTest.kt deleted file mode 100644 index b6dbcfb3..00000000 --- a/core/src/test/kotlin/ch/ergon/dope/resolvable/clause/UseKeysClauseTest.kt +++ /dev/null @@ -1,200 +0,0 @@ -package ch.ergon.dope.resolvable.clause - -import ch.ergon.dope.DopeQuery -import ch.ergon.dope.DopeQueryManager -import ch.ergon.dope.helper.ManagerDependentTest -import ch.ergon.dope.helper.someDeleteClause -import ch.ergon.dope.helper.someSelectClause -import ch.ergon.dope.helper.someString -import ch.ergon.dope.helper.someUpdateClause -import ch.ergon.dope.resolvable.clause.model.DeleteUseKeys.Companion.DeleteUseKeysClause -import ch.ergon.dope.resolvable.clause.model.SelectUseKeys.Companion.SelectUseKeysClause -import ch.ergon.dope.resolvable.clause.model.UpdateUseKeys.Companion.UpdateUseKeysClause -import ch.ergon.dope.resolvable.expression.unaliased.type.asParameter -import ch.ergon.dope.resolvable.expression.unaliased.type.toDopeType -import kotlin.test.Test -import kotlin.test.assertEquals - -class UseKeysClauseTest : ManagerDependentTest { - override lateinit var manager: DopeQueryManager - - @Test - fun `should support select single use keys`() { - val expected = DopeQuery( - "SELECT * USE KEYS \"someString\"", - emptyMap(), - ) - val underTest = SelectUseKeysClause( - "someString".toDopeType(), - someSelectClause(), - ) - - val actual = underTest.toDopeQuery(manager) - - assertEquals(expected, actual) - } - - @Test - fun `should support select array use keys`() { - val expected = DopeQuery( - "SELECT * USE KEYS [\"someString\", \"anotherString\"]", - emptyMap(), - ) - val underTest = SelectUseKeysClause( - listOf("someString".toDopeType(), "anotherString".toDopeType()).toDopeType(), - someSelectClause(), - ) - - val actual = underTest.toDopeQuery(manager) - - assertEquals(expected, actual) - } - - @Test - fun `should support select use keys with parameter`() { - val parameterValue = someString() - val expected = DopeQuery( - "SELECT * USE KEYS $1", - mapOf("$1" to parameterValue), - ) - val underTest = SelectUseKeysClause( - parameterValue.asParameter(), - someSelectClause(), - ) - - val actual = underTest.toDopeQuery(manager) - - assertEquals(expected, actual) - } - - @Test - fun `should support select use keys extension`() { - val useKeysString = someString().toDopeType() - val parentClause = someSelectClause() - val expected = SelectUseKeysClause(useKeysString, parentClause = parentClause) - - val actual = parentClause.useKeys(useKeysString) - - assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) - } - - @Test - fun `should support delete single use keys`() { - val expected = DopeQuery( - "DELETE FROM `someBucket` USE KEYS \"someString\"", - emptyMap(), - ) - val underTest = DeleteUseKeysClause( - "someString".toDopeType(), - someDeleteClause(), - ) - - val actual = underTest.toDopeQuery(manager) - - assertEquals(expected, actual) - } - - @Test - fun `should support delete array use keys`() { - val expected = DopeQuery( - "DELETE FROM `someBucket` USE KEYS [\"someString\", \"anotherString\"]", - emptyMap(), - ) - val underTest = DeleteUseKeysClause( - listOf("someString".toDopeType(), "anotherString".toDopeType()).toDopeType(), - someDeleteClause(), - ) - - val actual = underTest.toDopeQuery(manager) - - assertEquals(expected, actual) - } - - @Test - fun `should support delete use keys with parameter`() { - val parameterValue = someString() - val expected = DopeQuery( - "DELETE FROM `someBucket` USE KEYS $1", - mapOf("$1" to parameterValue), - ) - val underTest = DeleteUseKeysClause( - parameterValue.asParameter(), - someDeleteClause(), - ) - - val actual = underTest.toDopeQuery(manager) - - assertEquals(expected, actual) - } - - @Test - fun `should support delete use keys extension`() { - val useKeysString = someString().toDopeType() - val parentClause = someDeleteClause() - val expected = DeleteUseKeysClause(useKeysString, parentClause = parentClause) - - val actual = parentClause.useKeys(useKeysString) - - assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) - } - - @Test - fun `should support update single use keys`() { - val expected = DopeQuery( - "UPDATE `someBucket` USE KEYS \"someString\"", - emptyMap(), - ) - val underTest = UpdateUseKeysClause( - "someString".toDopeType(), - someUpdateClause(), - ) - - val actual = underTest.toDopeQuery(manager) - - assertEquals(expected, actual) - } - - @Test - fun `should support update array use keys`() { - val expected = DopeQuery( - "UPDATE `someBucket` USE KEYS [\"someString\", \"anotherString\"]", - emptyMap(), - ) - val underTest = UpdateUseKeysClause( - listOf("someString".toDopeType(), "anotherString".toDopeType()).toDopeType(), - someUpdateClause(), - ) - - val actual = underTest.toDopeQuery(manager) - - assertEquals(expected, actual) - } - - @Test - fun `should support update use keys with parameter`() { - val parameterValue = someString() - val expected = DopeQuery( - "UPDATE `someBucket` USE KEYS $1", - mapOf("$1" to parameterValue), - ) - val underTest = UpdateUseKeysClause( - parameterValue.asParameter(), - someUpdateClause(), - ) - - val actual = underTest.toDopeQuery(manager) - - assertEquals(expected, actual) - } - - @Test - fun `should support update use keys extension`() { - val useKeysString = someString().toDopeType() - val parentClause = someUpdateClause() - val expected = UpdateUseKeysClause(useKeysString, parentClause = parentClause) - - val actual = parentClause.useKeys(useKeysString) - - assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) - } -} diff --git a/core/src/test/kotlin/ch/ergon/dope/resolvable/fromable/UseTest.kt b/core/src/test/kotlin/ch/ergon/dope/resolvable/fromable/UseTest.kt new file mode 100644 index 00000000..9938debb --- /dev/null +++ b/core/src/test/kotlin/ch/ergon/dope/resolvable/fromable/UseTest.kt @@ -0,0 +1,241 @@ +package ch.ergon.dope.resolvable.fromable + +import ch.ergon.dope.DopeQuery +import ch.ergon.dope.DopeQueryManager +import ch.ergon.dope.helper.ManagerDependentTest +import ch.ergon.dope.helper.someBucket +import ch.ergon.dope.helper.someString +import ch.ergon.dope.resolvable.expression.unaliased.type.asParameter +import ch.ergon.dope.resolvable.expression.unaliased.type.toDopeType +import ch.ergon.dope.resolvable.fromable.IndexType.USING_FTS +import ch.ergon.dope.resolvable.fromable.IndexType.USING_GSI +import ch.ergon.dope.resolvable.fromable.UseKeysClass.Companion.UseKeys +import kotlin.test.Test +import kotlin.test.assertEquals + +class UseTest : ManagerDependentTest { + override lateinit var manager: DopeQueryManager + + @Test + fun `should support empty use index`() { + val expected = DopeQuery( + "`someBucket` USE INDEX ()", + emptyMap(), + ) + val underTest = UseIndex(someBucket()) + + val actual = underTest.toDopeQuery(manager) + + assertEquals(expected, actual) + } + + @Test + fun `should support single use index with string name`() { + val expected = DopeQuery( + "`someBucket` USE INDEX (`index`)", + emptyMap(), + ) + val underTest = UseIndex( + someBucket(), + IndexReference("index"), + ) + + val actual = underTest.toDopeQuery(manager) + + assertEquals(expected, actual) + } + + @Test + fun `should support multiple use index with name and type mixed`() { + val expected = DopeQuery( + "`someBucket` USE INDEX (`index` USING GSI, USING FTS, `secondIndex`)", + emptyMap(), + ) + val underTest = UseIndex( + someBucket(), + IndexReference("index", USING_GSI), + IndexReference(indexType = USING_FTS), + IndexReference("secondIndex"), + ) + + val actual = underTest.toDopeQuery(manager) + + assertEquals(expected, actual) + } + + @Test + fun `should support single use index with parameter`() { + val expected = DopeQuery( + "`someBucket` USE INDEX (`index`)", + emptyMap(), + ) + val underTest = UseIndex( + someBucket(), + IndexReference("index"), + ) + + val actual = underTest.toDopeQuery(manager) + + assertEquals(expected, actual) + } + + @Test + fun `should support use index extension function without index name`() { + val bucket = someBucket() + val expected = UseIndex(bucket) + + val actual = bucket.useIndex() + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support use index extension function`() { + val indexName = "index" + val bucket = someBucket() + val expected = UseIndex(bucket, IndexReference(indexName)) + + val actual = bucket.useIndex(indexName) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support use gsi index extension function`() { + val indexName = "index" + val bucket = someBucket() + val expected = UseIndex(bucket, IndexReference(indexName, USING_GSI)) + + val actual = bucket.useGsiIndex(indexName) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support use fts index extension function`() { + val indexName = "index" + val bucket = someBucket() + val expected = UseIndex(bucket, IndexReference(indexName, USING_FTS)) + + val actual = bucket.useFtsIndex(indexName) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support multiple use index extension function`() { + val indexName = "index" + val indexName2 = "index" + val bucket = someBucket() + val expected = UseIndex(bucket, IndexReference(indexName), IndexReference(indexName2)) + + val actual = bucket.useIndex(indexName).useIndex(indexName2) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support multiple different use index extension function`() { + val indexName = "index" + val indexName2 = "index" + val bucket = someBucket() + val expected = UseIndex( + bucket, + IndexReference(indexName, USING_GSI), + IndexReference(indexName2), + IndexReference(indexType = USING_FTS), + IndexReference(indexType = USING_GSI), + ) + + val actual = bucket.useGsiIndex(indexName).useIndex(indexName2).useFtsIndex().useGsiIndex() + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select single use keys`() { + val expected = DopeQuery( + "`someBucket` USE KEYS \"someString\"", + emptyMap(), + ) + val underTest = UseKeys( + "someString".toDopeType(), + someBucket(), + ) + + val actual = underTest.toDopeQuery(manager) + + assertEquals(expected, actual) + } + + @Test + fun `should support select array use keys`() { + val expected = DopeQuery( + "`someBucket` USE KEYS [\"someString\", \"anotherString\"]", + emptyMap(), + ) + val underTest = UseKeys( + listOf("someString".toDopeType(), "anotherString".toDopeType()).toDopeType(), + someBucket(), + ) + + val actual = underTest.toDopeQuery(manager) + + assertEquals(expected, actual) + } + + @Test + fun `should support use keys with parameter`() { + val parameterValue = someString() + val expected = DopeQuery( + "`someBucket` USE KEYS $1", + mapOf("$1" to parameterValue), + ) + val underTest = UseKeys( + parameterValue.asParameter(), + someBucket(), + ) + + val actual = underTest.toDopeQuery(manager) + + assertEquals(expected, actual) + } + + @Test + fun `should support use keys extension`() { + val useKeysString = someString().toDopeType() + val bucket = someBucket() + val expected = UseKeys(useKeysString, bucket = bucket) + + val actual = bucket.useKeys(useKeysString) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support use keys extension with collection`() { + val useKeysString = listOf(someString().toDopeType()) + val bucket = someBucket() + val expected = UseKeys(useKeysString.toDopeType(), bucket = bucket) + + val actual = bucket.useKeys(useKeysString) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support use keys extension with strings`() { + val useKeysString1 = someString() + val useKeysString2 = someString() + val useKeysString3 = someString() + val bucket = someBucket() + val expected = UseKeys( + listOf(useKeysString1.toDopeType(), useKeysString2.toDopeType(), useKeysString3.toDopeType()).toDopeType(), + bucket = bucket, + ) + + val actual = bucket.useKeys(useKeysString1, useKeysString2, useKeysString3) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } +} diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/DeleteClause.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/DeleteClause.kt index 79d287f7..5d4556dc 100644 --- a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/DeleteClause.kt +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/DeleteClause.kt @@ -3,11 +3,9 @@ package ch.ergon.dope.extension.clause import ch.ergon.dope.resolvable.clause.IDeleteClause import ch.ergon.dope.resolvable.clause.IDeleteLimitClause import ch.ergon.dope.resolvable.clause.IDeleteOffsetClause -import ch.ergon.dope.resolvable.clause.IDeleteUseKeysClause import ch.ergon.dope.resolvable.clause.IDeleteWhereClause import ch.ergon.dope.toDopeType import com.schwarz.crystalapi.schema.CMJsonField -import com.schwarz.crystalapi.schema.CMJsonList import com.schwarz.crystalapi.schema.CMType fun IDeleteOffsetClause.returning(field: CMType, vararg fields: CMType) = @@ -17,7 +15,4 @@ fun IDeleteLimitClause.offset(numberExpression: CMJsonField) = offset(nu fun IDeleteWhereClause.limit(numberExpression: CMJsonField) = limit(numberExpression.toDopeType()) -fun IDeleteUseKeysClause.where(booleanExpression: CMJsonField) = where(booleanExpression.toDopeType()) - -fun IDeleteClause.useKeys(useKeys: CMJsonField) = useKeys(useKeys.toDopeType()) -fun IDeleteClause.useKeys(useKeys: CMJsonList) = useKeys(useKeys.toDopeType()) +fun IDeleteClause.where(booleanExpression: CMJsonField) = where(booleanExpression.toDopeType()) diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/SelectClause.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/SelectClause.kt index d0f6d97b..c9294a56 100644 --- a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/SelectClause.kt +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/SelectClause.kt @@ -6,10 +6,10 @@ import ch.ergon.dope.resolvable.clause.ISelectJoinClause import ch.ergon.dope.resolvable.clause.ISelectLimitClause import ch.ergon.dope.resolvable.clause.ISelectOrderByClause import ch.ergon.dope.resolvable.clause.ISelectUnnestClause -import ch.ergon.dope.resolvable.clause.ISelectUseKeysClause import ch.ergon.dope.resolvable.clause.ISelectWhereClause import ch.ergon.dope.resolvable.clause.model.OrderByType import ch.ergon.dope.resolvable.fromable.Bucket +import ch.ergon.dope.resolvable.fromable.Joinable import ch.ergon.dope.toDopeType import com.schwarz.crystalapi.schema.CMJsonField import com.schwarz.crystalapi.schema.CMJsonList @@ -27,21 +27,18 @@ fun ISelectGroupByClause.orderBy(stringField: CMJsonField, orderByType: fun ISelectWhereClause.groupBy(field: CMType, vararg fields: CMType) = groupBy(field.toDopeType(), *fields.map { it.toDopeType() }.toTypedArray()) -fun ISelectUseKeysClause.where(whereExpression: CMJsonField) = where(whereExpression.toDopeType()) +fun ISelectFromClause.where(whereExpression: CMJsonField) = where(whereExpression.toDopeType()) -fun ISelectFromClause.useKeys(useKeys: CMJsonField) = useKeys(useKeys.toDopeType()) -fun ISelectFromClause.useKeys(useKeys: CMJsonList) = useKeys(useKeys.toDopeType()) +fun ISelectJoinClause.join(joinable: Joinable, onKeys: CMJsonField) = join(joinable, onKeys.toDopeType()) +fun ISelectJoinClause.join(joinable: Joinable, onKey: CMJsonField, forBucket: Bucket) = join(joinable, onKey.toDopeType(), forBucket) -fun ISelectJoinClause.join(bucket: Bucket, onKeys: CMJsonField) = join(bucket, onKeys.toDopeType()) -fun ISelectJoinClause.join(bucket: Bucket, onKey: CMJsonField, forBucket: Bucket) = join(bucket, onKey.toDopeType(), forBucket) +fun ISelectJoinClause.innerJoin(joinable: Joinable, onKeys: CMJsonField) = innerJoin(joinable, onKeys.toDopeType()) +fun ISelectJoinClause.innerJoin(joinable: Joinable, onKey: CMJsonField, forBucket: Bucket) = + innerJoin(joinable, onKey.toDopeType(), forBucket) -fun ISelectJoinClause.innerJoin(bucket: Bucket, onKeys: CMJsonField) = innerJoin(bucket, onKeys.toDopeType()) -fun ISelectJoinClause.innerJoin(bucket: Bucket, onKey: CMJsonField, forBucket: Bucket) = - innerJoin(bucket, onKey.toDopeType(), forBucket) - -fun ISelectJoinClause.leftJoin(bucket: Bucket, onKeys: CMJsonField) = leftJoin(bucket, onKeys.toDopeType()) -fun ISelectJoinClause.leftJoin(bucket: Bucket, onKey: CMJsonField, forBucket: Bucket) = - leftJoin(bucket, onKey.toDopeType(), forBucket) +fun ISelectJoinClause.leftJoin(joinable: Joinable, onKeys: CMJsonField) = leftJoin(joinable, onKeys.toDopeType()) +fun ISelectJoinClause.leftJoin(joinable: Joinable, onKey: CMJsonField, forBucket: Bucket) = + leftJoin(joinable, onKey.toDopeType(), forBucket) @JvmName("unnestString") fun ISelectUnnestClause.unnest(arrayField: CMJsonList) = unnest(arrayField.toDopeType()) diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/UpdateClause.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/UpdateClause.kt index f3b689de..3853f42c 100644 --- a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/UpdateClause.kt +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/UpdateClause.kt @@ -4,7 +4,6 @@ import ch.ergon.dope.resolvable.clause.IUpdateClause import ch.ergon.dope.resolvable.clause.IUpdateLimitClause import ch.ergon.dope.resolvable.clause.IUpdateSetClause import ch.ergon.dope.resolvable.clause.IUpdateUnsetClause -import ch.ergon.dope.resolvable.clause.IUpdateUseKeysClause import ch.ergon.dope.resolvable.clause.IUpdateWhereClause import ch.ergon.dope.resolvable.clause.model.SetClause import ch.ergon.dope.resolvable.clause.model.UnsetClause @@ -46,7 +45,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value.toDopeType()) @JvmName("setCMStringFieldToCMStringField") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonField, value: CMJsonField, ) = set(field.toDopeType(), value.toDopeType()) @@ -58,7 +57,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value.toDopeType()) @JvmName("setCMBooleanFieldToCMBooleanField") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonField, value: CMJsonField, ) = set(field.toDopeType(), value.toDopeType()) @@ -70,7 +69,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value.toDopeType()) @JvmName("setCMNumberListToCMNumberList") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonList, value: CMJsonList, ) = set(field.toDopeType(), value.toDopeType()) @@ -82,7 +81,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value.toDopeType()) @JvmName("setCMStringListToCMStringList") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonList, value: CMJsonList, ) = set(field.toDopeType(), value.toDopeType()) @@ -94,7 +93,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value.toDopeType()) @JvmName("setCMBooleanListToCMBooleanList") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonList, value: CMJsonList, ) = set(field.toDopeType(), value.toDopeType()) @@ -106,7 +105,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value.toDopeType()) @JvmName("setCMNumberFieldToNumberTypeExpression") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonField, value: TypeExpression, ) = set(field.toDopeType(), value) @@ -118,7 +117,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value) @JvmName("setCMStringFieldToStringTypeExpression") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonField, value: TypeExpression, ) = set(field.toDopeType(), value) @@ -130,7 +129,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value) @JvmName("setCMBooleanFieldToBooleanTypeExpression") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonField, value: TypeExpression, ) = set(field.toDopeType(), value) @@ -142,7 +141,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value) @JvmName("setCMNumberListToNumberArrayTypeExpression") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonList, value: TypeExpression>, ) = set(field.toDopeType(), value) @@ -154,7 +153,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value) @JvmName("setCMStringListToStringArrayTypeExpression") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonList, value: TypeExpression>, ) = set(field.toDopeType(), value) @@ -166,7 +165,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value) @JvmName("setCMBooleanListToBooleanArrayTypeExpression") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonList, value: TypeExpression>, ) = set(field.toDopeType(), value) @@ -178,7 +177,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value) @JvmName("setCMNumberFieldToNumber") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonField, value: Number, ) = set(field.toDopeType(), value) @@ -190,7 +189,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value) @JvmName("setCMConverterNumberFieldToNumber") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMConverterField, value: Convertable, ) = set(field.toDopeType(), field.toDopeType(value)) @@ -202,7 +201,7 @@ fun SetClause.set( ) = set(field.toDopeType(), field.toDopeType(value)) @JvmName("setCMStringFieldToString") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonField, value: String, ) = set(field.toDopeType(), value) @@ -214,7 +213,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value) @JvmName("setCMConverterStringFieldToNumber") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMConverterField, value: Convertable, ) = set(field.toDopeType(), field.toDopeType(value)) @@ -226,7 +225,7 @@ fun SetClause.set( ) = set(field.toDopeType(), field.toDopeType(value)) @JvmName("setCMBooleanFieldToBoolean") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMJsonField, value: Boolean, ) = set(field.toDopeType(), value) @@ -238,7 +237,7 @@ fun SetClause.set( ) = set(field.toDopeType(), value) @JvmName("setCMConverterBooleanFieldToNumber") -fun IUpdateUseKeysClause.set( +fun IUpdateClause.set( field: CMConverterField, value: Convertable, ) = set(field.toDopeType(), field.toDopeType(value)) @@ -248,6 +247,3 @@ fun SetClause.set( field: CMConverterField, value: Convertable, ) = set(field.toDopeType(), field.toDopeType(value)) - -fun IUpdateClause.useKeys(useKeys: CMJsonField) = useKeys(useKeys.toDopeType()) -fun IUpdateClause.useKeys(useKeys: CMJsonList) = useKeys(useKeys.toDopeType()) diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/fromable/Use.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/fromable/Use.kt new file mode 100644 index 00000000..d70bd899 --- /dev/null +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/fromable/Use.kt @@ -0,0 +1,11 @@ +package ch.ergon.dope.extension.fromable + +import ch.ergon.dope.resolvable.fromable.Bucket +import ch.ergon.dope.resolvable.fromable.useKeys +import ch.ergon.dope.toDopeType +import com.schwarz.crystalapi.schema.CMJsonField +import com.schwarz.crystalapi.schema.CMJsonList + +fun Bucket.useKeys(useKeys: CMJsonField) = useKeys(useKeys.toDopeType()) + +fun Bucket.useKeys(useKeys: CMJsonList) = useKeys(useKeys.toDopeType()) diff --git a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteClauseTest.kt b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteClauseTest.kt index d1cb40be..3a36ec2b 100644 --- a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteClauseTest.kt +++ b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteClauseTest.kt @@ -4,19 +4,16 @@ import ch.ergon.dope.DopeQueryManager import ch.ergon.dope.extension.clause.limit import ch.ergon.dope.extension.clause.offset import ch.ergon.dope.extension.clause.returning -import ch.ergon.dope.extension.clause.useKeys import ch.ergon.dope.extension.clause.where import ch.ergon.dope.helper.ManagerDependentTest import ch.ergon.dope.helper.someCMBooleanField import ch.ergon.dope.helper.someCMNumberField import ch.ergon.dope.helper.someCMNumberList import ch.ergon.dope.helper.someCMStringField -import ch.ergon.dope.helper.someCMStringList import ch.ergon.dope.helper.someDelete 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.toDopeType import kotlin.test.Test @@ -25,28 +22,6 @@ import kotlin.test.assertEquals class DeleteClauseTest : ManagerDependentTest { override lateinit var manager: DopeQueryManager - @Test - fun `should support delete single use keys with CM`() { - val useKeys = someCMStringField() - val parentClause = someDelete() - val expected = DeleteUseKeysClause(useKeys.toDopeType(), parentClause) - - val actual = parentClause.useKeys(useKeys) - - assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) - } - - @Test - fun `should support delete list use keys with CM`() { - val useKeys = someCMStringList() - val parentClause = someDelete() - val expected = DeleteUseKeysClause(useKeys.toDopeType(), parentClause) - - val actual = parentClause.useKeys(useKeys) - - assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) - } - @Test fun `should support delete where with CM`() { val field = someCMBooleanField() diff --git a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectClauseTest.kt b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectClauseTest.kt index ab7bfa83..f66cd400 100644 --- a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectClauseTest.kt +++ b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectClauseTest.kt @@ -9,7 +9,6 @@ import ch.ergon.dope.extension.clause.limit import ch.ergon.dope.extension.clause.offset import ch.ergon.dope.extension.clause.orderBy import ch.ergon.dope.extension.clause.unnest -import ch.ergon.dope.extension.clause.useKeys import ch.ergon.dope.extension.clause.where import ch.ergon.dope.helper.ManagerDependentTest import ch.ergon.dope.helper.someBucket @@ -29,7 +28,6 @@ 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.SelectUseKeys.Companion.SelectUseKeysClause import ch.ergon.dope.resolvable.clause.model.SelectWhereClause import ch.ergon.dope.resolvable.clause.model.StandardJoinClause import ch.ergon.dope.resolvable.clause.model.UnnestClause @@ -40,28 +38,6 @@ import kotlin.test.assertEquals class SelectClauseTest : ManagerDependentTest { override lateinit var manager: DopeQueryManager - @Test - fun `should support select single use keys with CM`() { - val useKeys = someCMStringField() - val parentClause = someSelect() - val expected = SelectUseKeysClause(useKeys.toDopeType(), parentClause) - - val actual = parentClause.useKeys(useKeys) - - assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) - } - - @Test - fun `should support select list use keys with CM`() { - val useKeys = someCMStringList() - val parentClause = someSelect() - val expected = SelectUseKeysClause(useKeys.toDopeType(), parentClause) - - val actual = parentClause.useKeys(useKeys) - - assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) - } - @Test fun `should support select where with CM`() { val field = someCMBooleanField() diff --git a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/UpdateClauseTest.kt b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/UpdateClauseTest.kt index 5fa0e0e0..a6caac49 100644 --- a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/UpdateClauseTest.kt +++ b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/UpdateClauseTest.kt @@ -5,7 +5,6 @@ import ch.ergon.dope.extension.clause.limit import ch.ergon.dope.extension.clause.returning import ch.ergon.dope.extension.clause.set import ch.ergon.dope.extension.clause.unset -import ch.ergon.dope.extension.clause.useKeys import ch.ergon.dope.extension.clause.where import ch.ergon.dope.helper.ManagerDependentTest import ch.ergon.dope.helper.someBoolean @@ -26,7 +25,6 @@ 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.unaliased.type.toDopeType @@ -37,28 +35,6 @@ import kotlin.test.assertEquals class UpdateClauseTest : ManagerDependentTest { override lateinit var manager: DopeQueryManager - @Test - fun `should support update single use keys with CM`() { - val useKeys = someCMStringField() - val parentClause = someUpdate() - val expected = UpdateUseKeysClause(useKeys.toDopeType(), parentClause) - - val actual = parentClause.useKeys(useKeys) - - assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) - } - - @Test - fun `should support update list use keys with CM`() { - val useKeys = someCMStringList() - val parentClause = someUpdate() - val expected = UpdateUseKeysClause(useKeys.toDopeType(), parentClause) - - val actual = parentClause.useKeys(useKeys) - - assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) - } - @Test fun `should support update set CMJsonField number to CMJsonField number`() { val field = someCMNumberField() diff --git a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/fromable/UseTest.kt b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/fromable/UseTest.kt new file mode 100644 index 00000000..d9eb54ff --- /dev/null +++ b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/fromable/UseTest.kt @@ -0,0 +1,49 @@ +package ch.ergon.dope.extensions.fromable + +import ch.ergon.dope.DopeQueryManager +import ch.ergon.dope.extension.fromable.useKeys +import ch.ergon.dope.helper.ManagerDependentTest +import ch.ergon.dope.helper.someBucket +import ch.ergon.dope.helper.someCMStringField +import ch.ergon.dope.helper.someCMStringList +import ch.ergon.dope.resolvable.fromable.UseKeysClass.Companion.UseKeys +import ch.ergon.dope.toDopeType +import kotlin.test.Test +import kotlin.test.assertEquals + +class UseTest : ManagerDependentTest { + override lateinit var manager: DopeQueryManager + + @Test + fun `should support single use keys with CM`() { + val useKeys = someCMStringField() + val bucket = someBucket() + val expected = UseKeys(useKeys.toDopeType(), bucket) + + val actual = bucket.useKeys(useKeys) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support single use keys with CM on aliased bucket`() { + val useKeys = someCMStringField() + val bucket = someBucket().alias("asdf") + val expected = UseKeys(useKeys.toDopeType(), bucket) + + val actual = bucket.useKeys(useKeys) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support single multiple keys with CM`() { + val useKeys = someCMStringList() + val bucket = someBucket() + val expected = UseKeys(useKeys.toDopeType(), bucket) + + val actual = bucket.useKeys(useKeys) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } +}