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 c73b31f5..a0bc0808 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 @@ -6,11 +6,11 @@ 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.OrderExpression 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.clause.model.UnnestClause @@ -27,7 +27,6 @@ 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 -import ch.ergon.dope.validtype.StringType import ch.ergon.dope.validtype.ValidType interface ISelectOffsetClause : Clause { @@ -46,9 +45,10 @@ interface ISelectOrderByClause : ISelectLimitClause { } interface ISelectGroupByClause : ISelectOrderByClause { - fun orderBy(stringField: Field) = SelectOrderByClause(stringField, this) - fun orderBy(stringField: Field, orderByType: OrderByType) = - SelectOrderByTypeClause(stringField, orderByType, this) + fun orderBy(expression: TypeExpression, orderByType: OrderByType? = null) = SelectOrderByClause( + OrderExpression(expression, orderByType), + parentClause = this, + ) } interface ISelectWhereClause : ISelectGroupByClause { 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 index d80d8aca..69869cbf 100644 --- 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 @@ -2,49 +2,58 @@ package ch.ergon.dope.resolvable.clause.model import ch.ergon.dope.DopeQuery import ch.ergon.dope.DopeQueryManager +import ch.ergon.dope.resolvable.Resolvable import ch.ergon.dope.resolvable.clause.ISelectGroupByClause import ch.ergon.dope.resolvable.clause.ISelectOrderByClause -import ch.ergon.dope.resolvable.expression.unaliased.type.Field +import ch.ergon.dope.resolvable.expression.TypeExpression import ch.ergon.dope.resolvable.formatToQueryStringWithSymbol -import ch.ergon.dope.validtype.StringType import ch.ergon.dope.validtype.ValidType -enum class OrderByType(val type: String) { +enum class OrderByType(val queryString: String) { ASC("ASC"), DESC("DESC"), } private const val ORDER_BY = "ORDER BY" -open class SelectOrderByClause(private val stringField: Field, private val parentClause: ISelectGroupByClause) : - ISelectOrderByClause { - +class SelectOrderByClause( + private val orderExpression: OrderExpression, + private vararg val additionalOrderExpressions: OrderExpression, + private val parentClause: ISelectGroupByClause, +) : ISelectOrderByClause { override fun toDopeQuery(manager: DopeQueryManager): DopeQuery { val parentDopeQuery = parentClause.toDopeQuery(manager) - val stringDopeQuery = stringField.toDopeQuery(manager) + val orderExpressionDopeQuery = orderExpression.toDopeQuery(manager) + val additionalOrderExpressions = additionalOrderExpressions.map { it.toDopeQuery(manager) } return DopeQuery( - queryString = formatToQueryStringWithSymbol(parentDopeQuery.queryString, ORDER_BY, stringDopeQuery.queryString), - parameters = parentDopeQuery.parameters.merge(stringDopeQuery.parameters), + queryString = formatToQueryStringWithSymbol( + parentDopeQuery.queryString, + ORDER_BY, + orderExpressionDopeQuery.queryString, + *additionalOrderExpressions.map { it.queryString }.toTypedArray(), + ), + parameters = parentDopeQuery.parameters.merge( + orderExpressionDopeQuery.parameters, + *additionalOrderExpressions.map { it.parameters }.toTypedArray(), + ), ) } -} -class SelectOrderByTypeClause( - private val stringField: Field, - private val orderByType: OrderByType, - private val parentClause: ISelectGroupByClause, -) : SelectOrderByClause(stringField, parentClause) { + fun thenOrderBy(typeExpression: TypeExpression, orderByType: OrderByType? = null) = + SelectOrderByClause( + this.orderExpression, + *additionalOrderExpressions, + OrderExpression(typeExpression, orderByType), + parentClause = this.parentClause, + ) +} +class OrderExpression(private val expression: TypeExpression, private val orderByType: OrderByType? = null) : Resolvable { override fun toDopeQuery(manager: DopeQueryManager): DopeQuery { - val parentDopeQuery = parentClause.toDopeQuery(manager) - val stringDopeQuery = stringField.toDopeQuery(manager) + val typeDopeQuery = expression.toDopeQuery(manager) return DopeQuery( - queryString = formatToQueryStringWithSymbol( - parentDopeQuery.queryString, - ORDER_BY, - stringDopeQuery.queryString + " $orderByType", - ), - parameters = parentDopeQuery.parameters.merge(stringDopeQuery.parameters), + queryString = listOfNotNull(typeDopeQuery.queryString, orderByType?.queryString).joinToString(separator = " "), + parameters = typeDopeQuery.parameters, ) } } diff --git a/core/src/test/kotlin/ch/ergon/dope/buildTest/OrderByTest.kt b/core/src/test/kotlin/ch/ergon/dope/buildTest/OrderByTest.kt index f4721885..50a4d43b 100644 --- a/core/src/test/kotlin/ch/ergon/dope/buildTest/OrderByTest.kt +++ b/core/src/test/kotlin/ch/ergon/dope/buildTest/OrderByTest.kt @@ -2,8 +2,10 @@ 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.someStringField import ch.ergon.dope.resolvable.clause.model.OrderByType +import ch.ergon.dope.resolvable.expression.unaliased.type.function.stringfunction.lower import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals @@ -62,4 +64,25 @@ class OrderByTest { assertEquals(expected, actual) } + + @Test + fun `should support multiple Order By clause`() { + val expected = "SELECT * FROM `someBucket` ORDER BY `stringField` DESC, `numberField`, LOWER(\"SOMETHING\") ASC" + + val actual: String = create + .selectAsterisk() + .from( + someBucket(), + ).orderBy( + someStringField(), + OrderByType.DESC, + ).thenOrderBy( + someNumberField(), + ).thenOrderBy( + lower("SOMETHING"), + OrderByType.ASC, + ).build().queryString + + assertEquals(expected, actual) + } } diff --git a/core/src/test/kotlin/ch/ergon/dope/helper/Builder.kt b/core/src/test/kotlin/ch/ergon/dope/helper/Builder.kt index cf9c8603..b7629229 100644 --- a/core/src/test/kotlin/ch/ergon/dope/helper/Builder.kt +++ b/core/src/test/kotlin/ch/ergon/dope/helper/Builder.kt @@ -1,5 +1,8 @@ package ch.ergon.dope.helper +import ch.ergon.dope.resolvable.clause.model.OrderByType +import ch.ergon.dope.resolvable.clause.model.OrderByType.ASC +import ch.ergon.dope.resolvable.clause.model.OrderExpression import ch.ergon.dope.resolvable.expression.TypeExpression import ch.ergon.dope.resolvable.expression.UnaliasedExpression import ch.ergon.dope.resolvable.expression.unaliased.aggregator.CountAsteriskExpression @@ -64,3 +67,8 @@ fun someStringSearchNumberResult( searchExpression: UnaliasedExpression = someString().toDopeType(), resultExpression: UnaliasedExpression = someNumber().toDopeType(), ) = SearchResult(searchExpression, resultExpression) + +fun someOrderExpression(typeExpression: TypeExpression = someStringField(), orderByType: OrderByType = ASC) = OrderExpression( + typeExpression, + orderByType, +) diff --git a/core/src/test/kotlin/ch/ergon/dope/resolvable/clause/OrderByClauseTest.kt b/core/src/test/kotlin/ch/ergon/dope/resolvable/clause/OrderByClauseTest.kt index 953be509..c48327bd 100644 --- a/core/src/test/kotlin/ch/ergon/dope/resolvable/clause/OrderByClauseTest.kt +++ b/core/src/test/kotlin/ch/ergon/dope/resolvable/clause/OrderByClauseTest.kt @@ -4,24 +4,78 @@ import ch.ergon.dope.DopeParameters import ch.ergon.dope.DopeQuery import ch.ergon.dope.DopeQueryManager import ch.ergon.dope.helper.ManagerDependentTest +import ch.ergon.dope.helper.someBooleanField +import ch.ergon.dope.helper.someNumberField +import ch.ergon.dope.helper.someOrderExpression import ch.ergon.dope.helper.someSelectClause import ch.ergon.dope.helper.someStringField -import ch.ergon.dope.resolvable.clause.model.OrderByType +import ch.ergon.dope.resolvable.clause.model.OrderByType.ASC +import ch.ergon.dope.resolvable.clause.model.OrderByType.DESC +import ch.ergon.dope.resolvable.clause.model.OrderExpression import ch.ergon.dope.resolvable.clause.model.SelectOrderByClause -import ch.ergon.dope.resolvable.clause.model.SelectOrderByTypeClause import ch.ergon.dope.resolvable.expression.unaliased.type.asParameter +import ch.ergon.dope.resolvable.expression.unaliased.type.function.stringfunction.concat +import ch.ergon.dope.resolvable.expression.unaliased.type.function.stringfunction.lower import kotlin.test.Test import kotlin.test.assertEquals class OrderByClauseTest : ManagerDependentTest { override lateinit var manager: DopeQueryManager + @Test + fun `should support order expression without order type`() { + val expected = DopeQuery( + queryString = "`stringField`", + ) + val underTest = OrderExpression(someStringField()) + + val actual = underTest.toDopeQuery(manager) + + assertEquals(expected, actual) + } + + @Test + fun `should support order expression with asc`() { + val expected = DopeQuery( + queryString = "`stringField` ASC", + ) + val underTest = OrderExpression(someStringField(), ASC) + + val actual = underTest.toDopeQuery(manager) + + assertEquals(expected, actual) + } + + @Test + fun `should support order expression with desc`() { + val expected = DopeQuery( + queryString = "`stringField` DESC", + ) + val underTest = OrderExpression(someStringField(), DESC) + + val actual = underTest.toDopeQuery(manager) + + assertEquals(expected, actual) + } + + @Test + fun `should support order expression with complex typeExpression`() { + val expected = DopeQuery( + queryString = "LOWER(CONCAT(\"A\", \"B\")) DESC", + ) + val underTest = OrderExpression(lower(concat("A", "B")), DESC) + + val actual = underTest.toDopeQuery(manager) + + assertEquals(expected, actual) + } + @Test fun `should support order by`() { val expected = DopeQuery( - queryString = "SELECT * ORDER BY `stringField`", + queryString = "SELECT * ORDER BY `stringField` ASC", ) - val underTest = SelectOrderByClause(someStringField(), someSelectClause()) + val underTest = SelectOrderByClause(someOrderExpression(), parentClause = someSelectClause()) val actual = underTest.toDopeQuery(manager) @@ -33,10 +87,10 @@ class OrderByClauseTest : ManagerDependentTest { val parameterValue = "asdf" val parameterName = "param" val expected = DopeQuery( - queryString = "SELECT \$$parameterName ORDER BY `stringField`", + queryString = "SELECT \$$parameterName ORDER BY `stringField` ASC", DopeParameters(namedParameters = mapOf(parameterName to parameterValue)), ) - val underTest = SelectOrderByClause(someStringField(), someSelectClause(parameterValue.asParameter(parameterName))) + val underTest = SelectOrderByClause(someOrderExpression(), parentClause = someSelectClause(parameterValue.asParameter(parameterName))) val actual = underTest.toDopeQuery(manager) @@ -47,10 +101,10 @@ class OrderByClauseTest : ManagerDependentTest { fun `should support order by with positional parameter in parent`() { val parameterValue = "asdf" val expected = DopeQuery( - queryString = "SELECT $1 ORDER BY `stringField`", + queryString = "SELECT $1 ORDER BY `stringField` ASC", DopeParameters(positionalParameters = listOf(parameterValue)), ) - val underTest = SelectOrderByClause(someStringField(), someSelectClause(parameterValue.asParameter())) + val underTest = SelectOrderByClause(someOrderExpression(), parentClause = someSelectClause(parameterValue.asParameter())) val actual = underTest.toDopeQuery(manager) @@ -62,7 +116,7 @@ class OrderByClauseTest : ManagerDependentTest { val expected = DopeQuery( queryString = "SELECT * ORDER BY `stringField` ASC", ) - val underTest = SelectOrderByTypeClause(someStringField(), OrderByType.ASC, someSelectClause()) + val underTest = SelectOrderByClause(OrderExpression(someStringField(), ASC), parentClause = someSelectClause()) val actual = underTest.toDopeQuery(manager) @@ -77,7 +131,10 @@ class OrderByClauseTest : ManagerDependentTest { queryString = "SELECT \$$parameterName ORDER BY `stringField` ASC", DopeParameters(namedParameters = mapOf(parameterName to parameterValue)), ) - val underTest = SelectOrderByTypeClause(someStringField(), OrderByType.ASC, someSelectClause(parameterValue.asParameter(parameterName))) + val underTest = SelectOrderByClause( + OrderExpression(someStringField(), ASC), + parentClause = someSelectClause(parameterValue.asParameter(parameterName)), + ) val actual = underTest.toDopeQuery(manager) @@ -91,7 +148,10 @@ class OrderByClauseTest : ManagerDependentTest { queryString = "SELECT $1 ORDER BY `stringField` ASC", DopeParameters(positionalParameters = listOf(parameterValue)), ) - val underTest = SelectOrderByTypeClause(someStringField(), OrderByType.ASC, someSelectClause(parameterValue.asParameter())) + val underTest = SelectOrderByClause( + OrderExpression(someStringField(), ASC), + parentClause = someSelectClause(parameterValue.asParameter()), + ) val actual = underTest.toDopeQuery(manager) @@ -103,7 +163,7 @@ class OrderByClauseTest : ManagerDependentTest { val expected = DopeQuery( queryString = "SELECT * ORDER BY `stringField` DESC", ) - val underTest = SelectOrderByTypeClause(someStringField(), OrderByType.DESC, someSelectClause()) + val underTest = SelectOrderByClause(OrderExpression(someStringField(), DESC), parentClause = someSelectClause()) val actual = underTest.toDopeQuery(manager) @@ -118,7 +178,10 @@ class OrderByClauseTest : ManagerDependentTest { queryString = "SELECT \$$parameterName ORDER BY `stringField` DESC", DopeParameters(namedParameters = mapOf(parameterName to parameterValue)), ) - val underTest = SelectOrderByTypeClause(someStringField(), OrderByType.DESC, someSelectClause(parameterValue.asParameter(parameterName))) + val underTest = SelectOrderByClause( + OrderExpression(someStringField(), DESC), + parentClause = someSelectClause(parameterValue.asParameter(parameterName)), + ) val actual = underTest.toDopeQuery(manager) @@ -132,7 +195,27 @@ class OrderByClauseTest : ManagerDependentTest { queryString = "SELECT $1 ORDER BY `stringField` DESC", DopeParameters(positionalParameters = listOf(parameterValue)), ) - val underTest = SelectOrderByTypeClause(someStringField(), OrderByType.DESC, someSelectClause(parameterValue.asParameter())) + val underTest = SelectOrderByClause( + OrderExpression(someStringField(), DESC), + parentClause = someSelectClause(parameterValue.asParameter()), + ) + + val actual = underTest.toDopeQuery(manager) + + assertEquals(expected, actual) + } + + @Test + fun `should support multiple order by`() { + val expected = DopeQuery( + queryString = "SELECT * ORDER BY `stringField` DESC, `numberField`, `booleanField` ASC", + ) + val underTest = SelectOrderByClause( + OrderExpression(someStringField(), DESC), + OrderExpression(someNumberField()), + OrderExpression(someBooleanField(), ASC), + parentClause = someSelectClause(), + ) val actual = underTest.toDopeQuery(manager) @@ -143,7 +226,7 @@ class OrderByClauseTest : ManagerDependentTest { fun `should support order by function`() { val stringField = someStringField() val parentClause = someSelectClause() - val expected = SelectOrderByClause(stringField, parentClause) + val expected = SelectOrderByClause(OrderExpression(stringField), parentClause = parentClause) val actual = parentClause.orderBy(stringField) @@ -154,11 +237,29 @@ class OrderByClauseTest : ManagerDependentTest { fun `should support order by function with type`() { val stringField = someStringField() val parentClause = someSelectClause() - val orderType = OrderByType.ASC - val expected = SelectOrderByTypeClause(stringField, orderType, parentClause) + val orderType = ASC + val expected = SelectOrderByClause(OrderExpression(stringField, orderType), parentClause = parentClause) val actual = parentClause.orderBy(stringField, orderType) assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) } + + @Test + fun `should support order by function with then order by`() { + val stringField = someStringField() + val numberField = someNumberField() + val parentClause = someSelectClause() + val orderType = ASC + val orderType2 = DESC + val expected = SelectOrderByClause( + OrderExpression(stringField, orderType), + OrderExpression(numberField, orderType2), + parentClause = parentClause, + ) + + val actual = parentClause.orderBy(stringField, orderType).thenOrderBy(numberField, orderType2) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } } 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 c3d6795e..b8d7b7bf 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 @@ -8,6 +8,7 @@ import ch.ergon.dope.resolvable.clause.ISelectOrderByClause import ch.ergon.dope.resolvable.clause.ISelectUnnestClause import ch.ergon.dope.resolvable.clause.ISelectWhereClause import ch.ergon.dope.resolvable.clause.model.OrderByType +import ch.ergon.dope.resolvable.clause.model.SelectOrderByClause import ch.ergon.dope.resolvable.clause.model.joinHint.HashOrNestedLoopHint import ch.ergon.dope.resolvable.clause.model.joinHint.KeysOrIndexHint import ch.ergon.dope.resolvable.fromable.Bucket @@ -22,10 +23,77 @@ fun ISelectLimitClause.offset(numberField: CMJsonField ISelectOrderByClause.limit(numberField: CMJsonField) = limit(numberField.toDopeType()) -fun ISelectGroupByClause.orderBy(stringField: CMJsonField) = orderBy(stringField.toDopeType()) +@JvmName("orderByNumber") +fun ISelectGroupByClause.orderBy( + numberField: CMJsonField, + orderByType: OrderByType? = null, +) = orderBy(numberField.toDopeType(), orderByType) -fun ISelectGroupByClause.orderBy(stringField: CMJsonField, orderByType: OrderByType) = - orderBy(stringField.toDopeType(), orderByType) +@JvmName("orderByString") +fun ISelectGroupByClause.orderBy( + stringField: CMJsonField, + orderByType: OrderByType? = null, +) = orderBy(stringField.toDopeType(), orderByType) + +@JvmName("orderByBoolean") +fun ISelectGroupByClause.orderBy( + booleanField: CMJsonField, + orderByType: OrderByType? = null, +) = orderBy(booleanField.toDopeType(), orderByType) + +@JvmName("orderByListNumber") +fun ISelectGroupByClause.orderBy( + numberField: CMJsonList, + orderByType: OrderByType? = null, +) = orderBy(numberField.toDopeType(), orderByType) + +@JvmName("orderByListString") +fun ISelectGroupByClause.orderBy( + stringField: CMJsonList, + orderByType: OrderByType? = null, +) = orderBy(stringField.toDopeType(), orderByType) + +@JvmName("orderByListBoolean") +fun ISelectGroupByClause.orderBy( + booleanField: CMJsonList, + orderByType: OrderByType? = null, +) = orderBy(booleanField.toDopeType(), orderByType) + +@JvmName("thenOrderByNumber") +fun SelectOrderByClause.thenOrderBy( + numberField: CMJsonField, + orderByType: OrderByType? = null, +) = thenOrderBy(numberField.toDopeType(), orderByType) + +@JvmName("thenOrderByString") +fun SelectOrderByClause.thenOrderBy( + stringField: CMJsonField, + orderByType: OrderByType? = null, +) = thenOrderBy(stringField.toDopeType(), orderByType) + +@JvmName("thenOrderByBoolean") +fun SelectOrderByClause.thenOrderBy( + booleanField: CMJsonField, + orderByType: OrderByType? = null, +) = thenOrderBy(booleanField.toDopeType(), orderByType) + +@JvmName("thenOrderByListNumber") +fun SelectOrderByClause.thenOrderBy( + numberField: CMJsonList, + orderByType: OrderByType? = null, +) = thenOrderBy(numberField.toDopeType(), orderByType) + +@JvmName("thenOrderByListString") +fun SelectOrderByClause.thenOrderBy( + stringField: CMJsonList, + orderByType: OrderByType? = null, +) = thenOrderBy(stringField.toDopeType(), orderByType) + +@JvmName("thenOrderByListBoolean") +fun SelectOrderByClause.thenOrderBy( + booleanField: CMJsonList, + orderByType: OrderByType? = null, +) = thenOrderBy(booleanField.toDopeType(), orderByType) fun ISelectWhereClause.groupBy(field: CMType, vararg fields: CMType) = groupBy(field.toDopeType(), *fields.map { it.toDopeType() }.toTypedArray()) 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 87e73cf0..16406583 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,6 +9,7 @@ import ch.ergon.dope.extension.clause.leftJoin 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.thenOrderBy import ch.ergon.dope.extension.clause.unnest import ch.ergon.dope.extension.clause.where import ch.ergon.dope.helper.ManagerDependentTest @@ -21,15 +22,16 @@ import ch.ergon.dope.helper.someCMStringField import ch.ergon.dope.helper.someCMStringList import ch.ergon.dope.helper.someFrom import ch.ergon.dope.helper.someNumberField +import ch.ergon.dope.helper.someOrderBy import ch.ergon.dope.helper.someSelect 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.OrderExpression 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.clause.model.UnnestClause @@ -219,10 +221,33 @@ class SelectClauseTest : ManagerDependentTest { } @Test - fun `should support select order by with CM`() { + fun `should support select order by with CMNumberField`() { + val field = someCMNumberField() + val parentClause = someSelect() + val expected = SelectOrderByClause(OrderExpression(field.toDopeType()), parentClause = parentClause) + + val actual = parentClause.orderBy(field) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select order by with type and CMNumberField`() { + val field = someCMNumberField() + val parentClause = someSelect() + val orderByType = OrderByType.ASC + val expected = SelectOrderByClause(OrderExpression(field.toDopeType(), orderByType), parentClause = parentClause) + + val actual = parentClause.orderBy(field, orderByType) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select order by with CMStringField`() { val field = someCMStringField() val parentClause = someSelect() - val expected = SelectOrderByClause(field.toDopeType(), parentClause) + val expected = SelectOrderByClause(OrderExpression(field.toDopeType()), parentClause = parentClause) val actual = parentClause.orderBy(field) @@ -230,17 +255,295 @@ class SelectClauseTest : ManagerDependentTest { } @Test - fun `should support select order by with type and CM`() { + fun `should support select order by with type and CMStringField`() { val field = someCMStringField() val parentClause = someSelect() val orderByType = OrderByType.ASC - val expected = SelectOrderByTypeClause(field.toDopeType(), orderByType, parentClause) + val expected = SelectOrderByClause(OrderExpression(field.toDopeType(), orderByType), parentClause = parentClause) + + val actual = parentClause.orderBy(field, orderByType) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select order by with CMBooleanField`() { + val field = someCMBooleanField() + val parentClause = someSelect() + val expected = SelectOrderByClause(OrderExpression(field.toDopeType()), parentClause = parentClause) + + val actual = parentClause.orderBy(field) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select order by with type and CMBooleanField`() { + val field = someCMBooleanField() + val parentClause = someSelect() + val orderByType = OrderByType.ASC + val expected = SelectOrderByClause(OrderExpression(field.toDopeType(), orderByType), parentClause = parentClause) val actual = parentClause.orderBy(field, orderByType) assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) } + @Test + fun `should support select order by with CMNumberList`() { + val field = someCMNumberList() + val parentClause = someSelect() + val expected = SelectOrderByClause(OrderExpression(field.toDopeType()), parentClause = parentClause) + + val actual = parentClause.orderBy(field) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select order by with type and CMNumberList`() { + val field = someCMNumberList() + val parentClause = someSelect() + val orderByType = OrderByType.ASC + val expected = SelectOrderByClause(OrderExpression(field.toDopeType(), orderByType), parentClause = parentClause) + + val actual = parentClause.orderBy(field, orderByType) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select order by with CMStringList`() { + val field = someCMStringList() + val parentClause = someSelect() + val expected = SelectOrderByClause(OrderExpression(field.toDopeType()), parentClause = parentClause) + + val actual = parentClause.orderBy(field) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select order by with type and CMStringList`() { + val field = someCMStringList() + val parentClause = someSelect() + val orderByType = OrderByType.ASC + val expected = SelectOrderByClause(OrderExpression(field.toDopeType(), orderByType), parentClause = parentClause) + + val actual = parentClause.orderBy(field, orderByType) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select order by with CMBooleanList`() { + val field = someCMBooleanList() + val parentClause = someSelect() + val expected = SelectOrderByClause(OrderExpression(field.toDopeType()), parentClause = parentClause) + + val actual = parentClause.orderBy(field) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select order by with type and CMBooleanList`() { + val field = someCMBooleanList() + val parentClause = someSelect() + val orderByType = OrderByType.ASC + val expected = SelectOrderByClause(OrderExpression(field.toDopeType(), orderByType), parentClause = parentClause) + + val actual = parentClause.orderBy(field, orderByType) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select then order by with CMNumberField`() { + val field = someCMNumberField() + val parentClause = someSelect() + val expected = SelectOrderByClause( + OrderExpression(someNumberField(), OrderByType.ASC), + OrderExpression(field.toDopeType()), + parentClause = parentClause, + ) + + val actual = someOrderBy(parentClause).thenOrderBy(field) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select then order by with type and CMNumberField`() { + val field = someCMNumberField() + val parentClause = someSelect() + val orderByType = OrderByType.ASC + val expected = SelectOrderByClause( + OrderExpression(someNumberField(), OrderByType.ASC), + OrderExpression(field.toDopeType(), orderByType), + parentClause = parentClause, + ) + + val actual = someOrderBy(parentClause).thenOrderBy(field, orderByType) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select then order by with CMStringField`() { + val field = someCMStringField() + val parentClause = someSelect() + val expected = SelectOrderByClause( + OrderExpression(someNumberField(), OrderByType.ASC), + OrderExpression(field.toDopeType()), + parentClause = parentClause, + ) + + val actual = someOrderBy(parentClause).thenOrderBy(field) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select then order by with type and CMStringField`() { + val field = someCMStringField() + val parentClause = someSelect() + val orderByType = OrderByType.ASC + val expected = SelectOrderByClause( + OrderExpression(someNumberField(), OrderByType.ASC), + OrderExpression(field.toDopeType(), orderByType), + parentClause = parentClause, + ) + + val actual = someOrderBy(parentClause).thenOrderBy(field, orderByType) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select then order by with CMBooleanField`() { + val field = someCMBooleanField() + val parentClause = someSelect() + val expected = SelectOrderByClause( + OrderExpression(someNumberField(), OrderByType.ASC), + OrderExpression(field.toDopeType()), + parentClause = parentClause, + ) + + val actual = someOrderBy(parentClause).thenOrderBy(field) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select then order by with type and CMBooleanField`() { + val field = someCMBooleanField() + val parentClause = someSelect() + val orderByType = OrderByType.ASC + val expected = SelectOrderByClause( + OrderExpression(someNumberField(), OrderByType.ASC), + OrderExpression(field.toDopeType(), orderByType), + parentClause = parentClause, + ) + + val actual = someOrderBy(parentClause).thenOrderBy(field, orderByType) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select then order by with CMNumberList`() { + val field = someCMNumberList() + val parentClause = someSelect() + val expected = SelectOrderByClause( + OrderExpression(someNumberField(), OrderByType.ASC), + OrderExpression(field.toDopeType()), + parentClause = parentClause, + ) + + val actual = someOrderBy(parentClause).thenOrderBy(field) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select then order by with type and CMNumberList`() { + val field = someCMNumberList() + val parentClause = someSelect() + val orderByType = OrderByType.ASC + val expected = SelectOrderByClause( + OrderExpression(someNumberField(), OrderByType.ASC), + OrderExpression(field.toDopeType(), orderByType), + parentClause = parentClause, + ) + + val actual = someOrderBy(parentClause).thenOrderBy(field, orderByType) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select then order by with CMStringList`() { + val field = someCMStringList() + val parentClause = someSelect() + val expected = SelectOrderByClause( + OrderExpression(someNumberField(), OrderByType.ASC), + OrderExpression(field.toDopeType()), + parentClause = parentClause, + ) + + val actual = someOrderBy(parentClause).thenOrderBy(field) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select then order by with type and CMStringList`() { + val field = someCMStringList() + val parentClause = someSelect() + val orderByType = OrderByType.ASC + val expected = SelectOrderByClause( + OrderExpression(someNumberField(), OrderByType.ASC), + OrderExpression(field.toDopeType(), orderByType), + parentClause = parentClause, + ) + + val actual = someOrderBy(parentClause).thenOrderBy(field, orderByType) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select then order by with CMBooleanList`() { + val field = someCMBooleanList() + val parentClause = someSelect() + val expected = SelectOrderByClause( + OrderExpression(someNumberField(), OrderByType.ASC), + OrderExpression(field.toDopeType()), + parentClause = parentClause, + ) + + val actual = someOrderBy(parentClause).thenOrderBy(field) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + + @Test + fun `should support select then order by with type and CMBooleanList`() { + val field = someCMBooleanList() + val parentClause = someSelect() + val orderByType = OrderByType.ASC + val expected = SelectOrderByClause( + OrderExpression(someNumberField(), OrderByType.ASC), + OrderExpression(field.toDopeType(), orderByType), + parentClause = parentClause, + ) + + val actual = someOrderBy(parentClause).thenOrderBy(field, orderByType) + + assertEquals(expected.toDopeQuery(manager), actual.toDopeQuery(manager)) + } + @Test fun `should support select limit with CM`() { val field = someCMNumberField() diff --git a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/helper/Builder.kt b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/helper/Builder.kt index 09d79029..55028543 100644 --- a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/helper/Builder.kt +++ b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/helper/Builder.kt @@ -2,6 +2,7 @@ package ch.ergon.dope.helper import ch.ergon.dope.resolvable.clause.model.DeleteClause import ch.ergon.dope.resolvable.clause.model.FromClause +import ch.ergon.dope.resolvable.clause.model.OrderByType import ch.ergon.dope.resolvable.clause.model.SelectClause import ch.ergon.dope.resolvable.clause.model.UpdateClause import ch.ergon.dope.resolvable.expression.AsteriskExpression @@ -67,6 +68,7 @@ fun someCMConverterBooleanList(name: String = "cmConverterBooleanList", path: St CMConverterList(name, path, DateBooleanConverterInstance) fun someSelect(expression: Expression = AsteriskExpression()) = SelectClause(expression) +fun someOrderBy(selectClause: SelectClause) = selectClause.orderBy(someNumberField(), OrderByType.ASC) fun someFrom(fromable: Fromable = someBucket(), selectClause: SelectClause = someSelect()) = FromClause(fromable, selectClause) fun someDelete(bucket: Bucket = someBucket()) = DeleteClause(bucket)