From 37a358cccd99f9f68d0c0901ca5b92039b934ea6 Mon Sep 17 00:00:00 2001 From: Jan Sigrist Date: Wed, 22 May 2024 10:59:21 +0200 Subject: [PATCH 1/8] DOPE-201: added all extension functions for the select Clauses --- .../kotlin/ch/ergon/dope/CrystalMapAdapter.kt | 9 +++++ .../ch/ergon/dope/extension/clause/Select.kt | 40 ++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/CrystalMapAdapter.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/CrystalMapAdapter.kt index 26a34f0b..518f7616 100644 --- a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/CrystalMapAdapter.kt +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/CrystalMapAdapter.kt @@ -11,8 +11,17 @@ import ch.ergon.dope.validtype.ValidType import com.schwarz.crystalapi.schema.CMField import com.schwarz.crystalapi.schema.CMList import com.schwarz.crystalapi.schema.CMObjectList +import com.schwarz.crystalapi.schema.CMType import com.schwarz.crystalapi.schema.Schema +fun CMType.asField(reference: String = path): Field = Field( + when (this) { + is CMField<*> -> this.name + is CMList<*> -> this.name + is CMObjectList<*> -> this.name + else -> "" + }, reference) + @JvmName("asNumberField") fun CMField.asField(reference: String = path): Field = Field(name, reference) diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt index 890fd3f3..3dcc7445 100644 --- a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt @@ -1,20 +1,58 @@ package ch.ergon.dope.extension.clause +import ch.ergon.dope.QueryBuilder +import ch.ergon.dope.asArrayField import ch.ergon.dope.asField +import ch.ergon.dope.resolvable.clause.ISelectFromClause import ch.ergon.dope.resolvable.clause.ISelectGroupByClause +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.ISelectWhereClause +import ch.ergon.dope.resolvable.clause.model.GroupByClause import ch.ergon.dope.resolvable.clause.model.OrderByType +import ch.ergon.dope.resolvable.clause.model.SelectClause +import ch.ergon.dope.resolvable.clause.model.SelectDistinctClause 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.SelectRawClause +import ch.ergon.dope.resolvable.fromable.Bucket import com.schwarz.crystalapi.schema.CMField +import com.schwarz.crystalapi.schema.CMList +import com.schwarz.crystalapi.schema.CMType fun ISelectLimitClause.offset(numberField: CMField): SelectOffsetClause = offset(numberField.asField()) fun ISelectOrderByClause.limit(numberField: CMField): SelectLimitClause = limit(numberField.asField()) +fun ISelectGroupByClause.orderBy(stringField: CMField): SelectOrderByClause = orderBy(stringField.asField()) + fun ISelectGroupByClause.orderBy(stringField: CMField, orderByType: OrderByType): SelectOrderByClause = orderBy(stringField.asField(), orderByType) -fun ISelectGroupByClause.orderBy(stringField: CMField): SelectOrderByClause = orderBy(stringField.asField()) +fun ISelectWhereClause.groupBy(field: CMType, vararg fields: CMType): GroupByClause = + groupBy(field.asField(), *fields.map { it.asField() }.toTypedArray()) + +fun ISelectFromClause.where(whereExpression: CMField) = where(whereExpression.asField()) + +fun ISelectJoinClause.join(bucket: Bucket, onKeys: CMField) = join(bucket, onKeys.asField()) + +fun ISelectJoinClause.innerJoin(bucket: Bucket, onKeys: CMField) = innerJoin(bucket, onKeys.asField()) + +fun ISelectJoinClause.leftJoin(bucket: Bucket, onKeys: CMField) = leftJoin(bucket, onKeys.asField()) + +fun ISelectJoinClause.rightJoin(bucket: Bucket, onKeys: CMField) = rightJoin(bucket, onKeys.asField()) +fun ISelectUnnestClause.unnest(arrayField: CMList) = unnest(arrayField.asArrayField()) +fun ISelectUnnestClause.unnest(arrayField: CMList) = unnest(arrayField.asArrayField()) + +fun ISelectUnnestClause.unnest(arrayField: CMList) = unnest(arrayField.asArrayField()) + +fun QueryBuilder.select(expression: CMType, vararg expressions: CMType): SelectClause = + select(expression.asField(), *expressions.map { it.asField() }.toTypedArray()) + +fun QueryBuilder.selectDistinct(expression: CMType, vararg expressions: CMType): SelectDistinctClause = + selectDistinct(expression.asField(), *expressions.map { it.asField() }.toTypedArray()) + +fun QueryBuilder.selectRaw(expression: CMType): SelectRawClause = selectRaw(expression.asField()) From 4dd3575e33951967cd4e236d21d001a3f1247a0e Mon Sep 17 00:00:00 2001 From: Jan Sigrist Date: Wed, 22 May 2024 11:04:25 +0200 Subject: [PATCH 2/8] DOPE-201: added extensions for the delete Clauses --- .../kotlin/ch/ergon/dope/CrystalMapAdapter.kt | 4 +++- .../ch/ergon/dope/extension/clause/Delete.kt | 18 ++++++++++++++++++ .../ch/ergon/dope/extension/clause/Select.kt | 5 +++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Delete.kt diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/CrystalMapAdapter.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/CrystalMapAdapter.kt index 518f7616..bf4cf47b 100644 --- a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/CrystalMapAdapter.kt +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/CrystalMapAdapter.kt @@ -20,7 +20,9 @@ fun CMType.asField(reference: String = path): Field = Field( is CMList<*> -> this.name is CMObjectList<*> -> this.name else -> "" - }, reference) + }, + reference, +) @JvmName("asNumberField") fun CMField.asField(reference: String = path): Field = Field(name, reference) diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Delete.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Delete.kt new file mode 100644 index 00000000..e51049b3 --- /dev/null +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Delete.kt @@ -0,0 +1,18 @@ +package ch.ergon.dope.extension.clause + +import ch.ergon.dope.asField +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.IDeleteWhereClause +import com.schwarz.crystalapi.schema.CMField +import com.schwarz.crystalapi.schema.CMType + +fun IDeleteOffsetClause.returning(field: CMType, vararg fields: CMType) = + returning(field.asField(), *fields.map { it.asField() }.toTypedArray()) + +fun IDeleteLimitClause.offset(numberExpression: CMField) = offset(numberExpression.asField()) + +fun IDeleteWhereClause.limit(numberExpression: CMField) = limit(numberExpression.asField()) + +fun IDeleteClause.where(booleanExpression: CMField) = where(booleanExpression.asField()) diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt index 3dcc7445..fad1813f 100644 --- a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt @@ -44,9 +44,14 @@ fun ISelectJoinClause.innerJoin(bucket: Bucket, onKeys: CMField) = innerJoi fun ISelectJoinClause.leftJoin(bucket: Bucket, onKeys: CMField) = leftJoin(bucket, onKeys.asField()) fun ISelectJoinClause.rightJoin(bucket: Bucket, onKeys: CMField) = rightJoin(bucket, onKeys.asField()) + +@JvmName("unnestString") fun ISelectUnnestClause.unnest(arrayField: CMList) = unnest(arrayField.asArrayField()) + +@JvmName("unnestNumber") fun ISelectUnnestClause.unnest(arrayField: CMList) = unnest(arrayField.asArrayField()) +@JvmName("unnestBoolean") fun ISelectUnnestClause.unnest(arrayField: CMList) = unnest(arrayField.asArrayField()) fun QueryBuilder.select(expression: CMType, vararg expressions: CMType): SelectClause = From 94ead5cea7b99e979583b5a50bea4502e30cb17b Mon Sep 17 00:00:00 2001 From: Jan Sigrist Date: Fri, 24 May 2024 09:00:49 +0200 Subject: [PATCH 3/8] DOPE-201: added tests for some extensions --- .../ch/ergon/dope/extension/clause/Select.kt | 8 +- .../dope/extensions/aggregator/CountTest.kt | 55 ++++++ .../dope/extensions/aggregator/MinTest.kt | 55 ++++++ .../dope/extensions/clause/DeleteTest.kt | 41 +++++ .../dope/extensions/clause/SelectTest.kt | 163 ++++++++++++++++++ .../kotlin/ch/ergon/dope/helper/Builder.kt | 27 +++ 6 files changed, 345 insertions(+), 4 deletions(-) create mode 100644 crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/aggregator/CountTest.kt create mode 100644 crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/aggregator/MinTest.kt create mode 100644 crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteTest.kt create mode 100644 crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectTest.kt create mode 100644 crystal-map-connector/src/test/kotlin/ch/ergon/dope/helper/Builder.kt diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt index fad1813f..13e01409 100644 --- a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt @@ -37,13 +37,13 @@ fun ISelectWhereClause.groupBy(field: CMType, vararg fields: CMType): GroupByCla fun ISelectFromClause.where(whereExpression: CMField) = where(whereExpression.asField()) -fun ISelectJoinClause.join(bucket: Bucket, onKeys: CMField) = join(bucket, onKeys.asField()) +fun ISelectJoinClause.join(bucket: Bucket, onKeys: CMField) = join(bucket, onKeys.asField()) -fun ISelectJoinClause.innerJoin(bucket: Bucket, onKeys: CMField) = innerJoin(bucket, onKeys.asField()) +fun ISelectJoinClause.innerJoin(bucket: Bucket, onKeys: CMField) = innerJoin(bucket, onKeys.asField()) -fun ISelectJoinClause.leftJoin(bucket: Bucket, onKeys: CMField) = leftJoin(bucket, onKeys.asField()) +fun ISelectJoinClause.leftJoin(bucket: Bucket, onKeys: CMField) = leftJoin(bucket, onKeys.asField()) -fun ISelectJoinClause.rightJoin(bucket: Bucket, onKeys: CMField) = rightJoin(bucket, onKeys.asField()) +fun ISelectJoinClause.rightJoin(bucket: Bucket, onKeys: CMField) = rightJoin(bucket, onKeys.asField()) @JvmName("unnestString") fun ISelectUnnestClause.unnest(arrayField: CMList) = unnest(arrayField.asArrayField()) diff --git a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/aggregator/CountTest.kt b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/aggregator/CountTest.kt new file mode 100644 index 00000000..3cccda39 --- /dev/null +++ b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/aggregator/CountTest.kt @@ -0,0 +1,55 @@ +package ch.ergon.dope.extensions.aggregator + +import ch.ergon.dope.extension.aggregator.count +import ch.ergon.dope.helper.someCMBooleanField +import ch.ergon.dope.helper.someCMBooleanList +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 org.junit.jupiter.api.Assertions.assertEquals +import kotlin.test.Test + +class CountTest { + @Test + fun `should support count with CMField Number`() { + val actual: String = count(someCMNumberField()).toDopeQuery().queryString + + assertEquals("COUNT(someNumberField)", actual) + } + + @Test + fun `should support count with CMField String`() { + val actual: String = count(someCMStringField()).toDopeQuery().queryString + + assertEquals("COUNT(someStringField)", actual) + } + + @Test + fun `should support count with CMField Boolean`() { + val actual: String = count(someCMBooleanField()).toDopeQuery().queryString + + assertEquals("COUNT(someBooleanField)", actual) + } + + @Test + fun `should support count with CMList Number`() { + val actual: String = count(someCMNumberList()).toDopeQuery().queryString + + assertEquals("COUNT(someNumberList)", actual) + } + + @Test + fun `should support count with CMList String`() { + val actual: String = count(someCMStringList()).toDopeQuery().queryString + + assertEquals("COUNT(someStringList)", actual) + } + + @Test + fun `should support count with CMList Boolean`() { + val actual: String = count(someCMBooleanList()).toDopeQuery().queryString + + assertEquals("COUNT(someBooleanList)", actual) + } +} diff --git a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/aggregator/MinTest.kt b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/aggregator/MinTest.kt new file mode 100644 index 00000000..f4a07de4 --- /dev/null +++ b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/aggregator/MinTest.kt @@ -0,0 +1,55 @@ +package ch.ergon.dope.extensions.aggregator + +import ch.ergon.dope.extension.aggregator.min +import ch.ergon.dope.helper.someCMBooleanField +import ch.ergon.dope.helper.someCMBooleanList +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 org.junit.jupiter.api.Assertions.assertEquals +import kotlin.test.Test + +class MinTest { + @Test + fun `should support min with CMField Number`() { + val actual: String = min(someCMNumberField()).toDopeQuery().queryString + + assertEquals("MIN(someNumberField)", actual) + } + + @Test + fun `should support min with CMField String`() { + val actual: String = min(someCMStringField()).toDopeQuery().queryString + + assertEquals("MIN(someStringField)", actual) + } + + @Test + fun `should support min with CMField Boolean`() { + val actual: String = min(someCMBooleanField()).toDopeQuery().queryString + + assertEquals("MIN(someBooleanField)", actual) + } + + @Test + fun `should support min with CMList Number`() { + val actual: String = min(someCMNumberList()).toDopeQuery().queryString + + assertEquals("MIN(someNumberList)", actual) + } + + @Test + fun `should support min with CMList String`() { + val actual: String = min(someCMStringList()).toDopeQuery().queryString + + assertEquals("MIN(someStringList)", actual) + } + + @Test + fun `should support min with CMList Boolean`() { + val actual: String = min(someCMBooleanList()).toDopeQuery().queryString + + assertEquals("MIN(someBooleanList)", actual) + } +} diff --git a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteTest.kt b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteTest.kt new file mode 100644 index 00000000..17558c86 --- /dev/null +++ b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteTest.kt @@ -0,0 +1,41 @@ +package ch.ergon.dope.extensions.clause + +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.where +import ch.ergon.dope.helper.someCMBooleanField +import ch.ergon.dope.helper.someCMNumberField +import ch.ergon.dope.helper.someDelete +import org.junit.jupiter.api.Assertions.assertEquals +import kotlin.test.Test + +class DeleteTest { + @Test + fun `should support delete where with CM`() { + val actual: String = someDelete().where(someCMBooleanField()).toDopeQuery().queryString + + assertEquals("DELETE FROM someBucket WHERE someBooleanField", actual) + } + + @Test + fun `should support delete limit with CM`() { + val actual: String = someDelete().limit(someCMNumberField()).toDopeQuery().queryString + + assertEquals("DELETE FROM someBucket LIMIT someNumberField", actual) + } + + @Test + fun `should support delete offset with CM`() { + val actual: String = someDelete().offset(someCMNumberField()).toDopeQuery().queryString + + assertEquals("DELETE FROM someBucket OFFSET someNumberField", actual) + } + + @Test + fun `should support delete returning with CM`() { + val actual: String = someDelete().returning(someCMNumberField()).toDopeQuery().queryString + + assertEquals("DELETE FROM someBucket RETURNING someNumberField", actual) + } +} diff --git a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectTest.kt b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectTest.kt new file mode 100644 index 00000000..3f0a4688 --- /dev/null +++ b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectTest.kt @@ -0,0 +1,163 @@ +package ch.ergon.dope.extensions.clause + +import ch.ergon.dope.QueryBuilder +import ch.ergon.dope.extension.clause.groupBy +import ch.ergon.dope.extension.clause.innerJoin +import ch.ergon.dope.extension.clause.join +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.rightJoin +import ch.ergon.dope.extension.clause.select +import ch.ergon.dope.extension.clause.selectDistinct +import ch.ergon.dope.extension.clause.selectRaw +import ch.ergon.dope.extension.clause.unnest +import ch.ergon.dope.extension.clause.where +import ch.ergon.dope.helper.someBucket +import ch.ergon.dope.helper.someCMBooleanField +import ch.ergon.dope.helper.someCMBooleanList +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.someFrom +import ch.ergon.dope.helper.someSelect +import ch.ergon.dope.resolvable.clause.model.OrderByType +import org.junit.jupiter.api.Assertions.assertEquals +import kotlin.test.Test + +class SelectTest { + @Test + fun `should support select with CM`() { + val actual: String = QueryBuilder().select(someCMNumberField()).toDopeQuery().queryString + + assertEquals("SELECT someNumberField", actual) + } + + @Test + fun `should support select with multiple CM`() { + val actual: String = QueryBuilder().select(someCMBooleanField(), someCMStringList()).toDopeQuery().queryString + + assertEquals("SELECT someBooleanField, someStringList", actual) + } + + @Test + fun `should support select distinct with CM`() { + val actual: String = QueryBuilder().selectDistinct(someCMNumberField()).toDopeQuery().queryString + + assertEquals("SELECT DISTINCT someNumberField", actual) + } + + @Test + fun `should support select distinct with multiple CM`() { + val actual: String = QueryBuilder().selectDistinct(someCMBooleanField(), someCMStringList()).toDopeQuery().queryString + + assertEquals("SELECT DISTINCT someBooleanField, someStringList", actual) + } + + @Test + fun `should support select raw with CM`() { + val actual: String = QueryBuilder().selectRaw(someCMNumberField()).toDopeQuery().queryString + + assertEquals("SELECT RAW someNumberField", actual) + } + + @Test + fun `should support select where with CM`() { + val actual: String = someSelect().where(someCMBooleanField()).toDopeQuery().queryString + + assertEquals("SELECT * WHERE someBooleanField", actual) + } + + @Test + fun `should support select unnest with CM Number`() { + val actual: String = someFrom().unnest(someCMNumberList()).toDopeQuery().queryString + + assertEquals("SELECT * FROM someBucket UNNEST someNumberList", actual) + } + + @Test + fun `should support select unnest with CM String`() { + val actual: String = someFrom().unnest(someCMStringList()).toDopeQuery().queryString + + assertEquals("SELECT * FROM someBucket UNNEST someStringList", actual) + } + + @Test + fun `should support select unnest with CM Boolean`() { + val actual: String = someFrom().unnest(someCMBooleanList()).toDopeQuery().queryString + + assertEquals("SELECT * FROM someBucket UNNEST someBooleanList", actual) + } + + @Test + fun `should support select join with CM`() { + val actual: String = someFrom().join(someBucket("other"), onKeys = someCMNumberField()).toDopeQuery().queryString + + assertEquals("SELECT * FROM someBucket JOIN other ON KEYS someNumberField", actual) + } + + @Test + fun `should support select inner join with CM`() { + val actual: String = someFrom().innerJoin(someBucket("other"), onKeys = someCMNumberField()).toDopeQuery().queryString + + assertEquals("SELECT * FROM someBucket INNER JOIN other ON KEYS someNumberField", actual) + } + + @Test + fun `should support select left join with CM`() { + val actual: String = someFrom().leftJoin(someBucket("other"), onKeys = someCMNumberField()).toDopeQuery().queryString + + assertEquals("SELECT * FROM someBucket LEFT JOIN other ON KEYS someNumberField", actual) + } + + @Test + fun `should support select right join with CM`() { + val actual: String = someFrom().rightJoin(someBucket("other"), onKeys = someCMNumberField()).toDopeQuery().queryString + + assertEquals("SELECT * FROM someBucket RIGHT JOIN other ON KEYS someNumberField", actual) + } + + @Test + fun `should support select group by with multiple CM`() { + val actual: String = someSelect().groupBy(someCMStringField(), someCMNumberList()).toDopeQuery().queryString + + assertEquals("SELECT * GROUP BY someStringField, someNumberList", actual) + } + + @Test + fun `should support select group by with CM`() { + val actual: String = someSelect().groupBy(someCMStringField()).toDopeQuery().queryString + + assertEquals("SELECT * GROUP BY someStringField", actual) + } + + @Test + fun `should support select order by with CM and type`() { + val actual: String = someSelect().orderBy(someCMStringField(), OrderByType.ASC).toDopeQuery().queryString + + assertEquals("SELECT * ORDER BY someStringField ASC", actual) + } + + @Test + fun `should support select order by with CM`() { + val actual: String = someSelect().orderBy(someCMStringField()).toDopeQuery().queryString + + assertEquals("SELECT * ORDER BY someStringField", actual) + } + + @Test + fun `should support select limit with CM`() { + val actual: String = someSelect().limit(someCMNumberField()).toDopeQuery().queryString + + assertEquals("SELECT * LIMIT someNumberField", actual) + } + + @Test + fun `should support select offset with CM`() { + val actual: String = someSelect().offset(someCMNumberField()).toDopeQuery().queryString + + assertEquals("SELECT * OFFSET someNumberField", actual) + } +} 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 new file mode 100644 index 00000000..5b829c50 --- /dev/null +++ b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/helper/Builder.kt @@ -0,0 +1,27 @@ +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.SelectClause +import ch.ergon.dope.resolvable.expression.AsteriskExpression +import ch.ergon.dope.resolvable.expression.Expression +import ch.ergon.dope.resolvable.fromable.Bucket +import ch.ergon.dope.resolvable.fromable.Fromable +import ch.ergon.dope.resolvable.fromable.UnaliasedBucket +import com.schwarz.crystalapi.schema.CMField +import com.schwarz.crystalapi.schema.CMList + +fun someBucket(name: String = "someBucket") = UnaliasedBucket(name) + +fun someCMNumberField(name: String = "someNumberField", path: String = "") = CMField(name, path) +fun someCMStringField(name: String = "someStringField", path: String = "") = CMField(name, path) +fun someCMBooleanField(name: String = "someBooleanField", path: String = "") = CMField(name, path) + +fun someCMNumberList(name: String = "someNumberList", path: String = "") = CMList(name, path) +fun someCMStringList(name: String = "someStringList", path: String = "") = CMList(name, path) +fun someCMBooleanList(name: String = "someBooleanList", path: String = "") = CMList(name, path) + +fun someSelect(exception: Expression = AsteriskExpression()) = SelectClause(exception) +fun someFrom(fromable: Fromable = someBucket(), selectClause: SelectClause = someSelect()) = FromClause(fromable, selectClause) + +fun someDelete(bucket: Bucket = someBucket()) = DeleteClause(bucket) From b98f3be77f5c2a427bf26e5c844ae9726c93d3c5 Mon Sep 17 00:00:00 2001 From: Jan Sigrist Date: Fri, 24 May 2024 13:21:50 +0200 Subject: [PATCH 4/8] DOPE-201: renamed test files --- .../extensions/clause/{DeleteTest.kt => DeleteClauseTest.kt} | 3 ++- .../extensions/clause/{SelectTest.kt => SelectClauseTest.kt} | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) rename crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/{DeleteTest.kt => DeleteClauseTest.kt} (95%) rename crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/{SelectTest.kt => SelectClauseTest.kt} (99%) diff --git a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteTest.kt b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteClauseTest.kt similarity index 95% rename from crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteTest.kt rename to crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteClauseTest.kt index 17558c86..105be6b4 100644 --- a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteTest.kt +++ b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/DeleteClauseTest.kt @@ -6,11 +6,12 @@ import ch.ergon.dope.extension.clause.returning import ch.ergon.dope.extension.clause.where import ch.ergon.dope.helper.someCMBooleanField import ch.ergon.dope.helper.someCMNumberField +import ch.ergon.dope.helper.someCMStringList import ch.ergon.dope.helper.someDelete import org.junit.jupiter.api.Assertions.assertEquals import kotlin.test.Test -class DeleteTest { +class DeleteClauseTest { @Test fun `should support delete where with CM`() { val actual: String = someDelete().where(someCMBooleanField()).toDopeQuery().queryString diff --git a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectTest.kt b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectClauseTest.kt similarity index 99% rename from crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectTest.kt rename to crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectClauseTest.kt index 3f0a4688..0df82ce1 100644 --- a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectTest.kt +++ b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/clause/SelectClauseTest.kt @@ -27,7 +27,7 @@ import ch.ergon.dope.resolvable.clause.model.OrderByType import org.junit.jupiter.api.Assertions.assertEquals import kotlin.test.Test -class SelectTest { +class SelectClauseTest { @Test fun `should support select with CM`() { val actual: String = QueryBuilder().select(someCMNumberField()).toDopeQuery().queryString From 63a809e46fe2eb5758e7ec7daf6df69b0c9602c0 Mon Sep 17 00:00:00 2001 From: Jan Sigrist Date: Fri, 24 May 2024 13:22:38 +0200 Subject: [PATCH 5/8] DOPE-201: added test about delete returning multiple CMTypes --- .../ch/ergon/dope/extensions/clause/DeleteClauseTest.kt | 7 +++++++ 1 file changed, 7 insertions(+) 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 105be6b4..e1947b93 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 @@ -39,4 +39,11 @@ class DeleteClauseTest { assertEquals("DELETE FROM someBucket RETURNING someNumberField", actual) } + + @Test + fun `should support delete returning with multiple CM`() { + val actual: String = someDelete().returning(someCMNumberField(), someCMStringList(), someCMBooleanField()).toDopeQuery().queryString + + assertEquals("DELETE FROM someBucket RETURNING someNumberField, someStringList, someBooleanField", actual) + } } From ae557849cfc75a2a8a51ad9f5a57c1a12b576f37 Mon Sep 17 00:00:00 2001 From: Jan Sigrist Date: Fri, 24 May 2024 13:23:33 +0200 Subject: [PATCH 6/8] DOPE-201: added ticket number and also illegalArgumentException, when it reaches else --- .../src/main/kotlin/ch/ergon/dope/CrystalMapAdapter.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/CrystalMapAdapter.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/CrystalMapAdapter.kt index bf4cf47b..5767e4f6 100644 --- a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/CrystalMapAdapter.kt +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/CrystalMapAdapter.kt @@ -10,6 +10,7 @@ import ch.ergon.dope.validtype.StringType import ch.ergon.dope.validtype.ValidType import com.schwarz.crystalapi.schema.CMField import com.schwarz.crystalapi.schema.CMList +import com.schwarz.crystalapi.schema.CMObject import com.schwarz.crystalapi.schema.CMObjectList import com.schwarz.crystalapi.schema.CMType import com.schwarz.crystalapi.schema.Schema @@ -19,7 +20,8 @@ fun CMType.asField(reference: String = path): Field = Field( is CMField<*> -> this.name is CMList<*> -> this.name is CMObjectList<*> -> this.name - else -> "" + is CMObject<*> -> TODO("DOPE-216") + else -> throw IllegalArgumentException("Unsupported type $this") }, reference, ) From ecf2f02a7202eeb0cf50e8e547bce36e161431b1 Mon Sep 17 00:00:00 2001 From: Jan Sigrist Date: Fri, 24 May 2024 13:54:38 +0200 Subject: [PATCH 7/8] DOPE-201: moved tests into correct file --- .../ch/ergon/dope/extension/QueryBuilder.kt | 16 +++++++ .../ch/ergon/dope/extension/clause/Select.kt | 12 ----- .../ergon/dope/extensions/QueryBuilderTest.kt | 48 +++++++++++++++++++ .../extensions/clause/SelectClauseTest.kt | 39 --------------- 4 files changed, 64 insertions(+), 51 deletions(-) create mode 100644 crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/QueryBuilder.kt create mode 100644 crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/QueryBuilderTest.kt diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/QueryBuilder.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/QueryBuilder.kt new file mode 100644 index 00000000..b3356fb4 --- /dev/null +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/QueryBuilder.kt @@ -0,0 +1,16 @@ +package ch.ergon.dope.extension + +import ch.ergon.dope.QueryBuilder +import ch.ergon.dope.asField +import ch.ergon.dope.resolvable.clause.model.SelectClause +import ch.ergon.dope.resolvable.clause.model.SelectDistinctClause +import ch.ergon.dope.resolvable.clause.model.SelectRawClause +import com.schwarz.crystalapi.schema.CMType + +fun QueryBuilder.select(expression: CMType, vararg expressions: CMType): SelectClause = + select(expression.asField(), *expressions.map { it.asField() }.toTypedArray()) + +fun QueryBuilder.selectDistinct(expression: CMType, vararg expressions: CMType): SelectDistinctClause = + selectDistinct(expression.asField(), *expressions.map { it.asField() }.toTypedArray()) + +fun QueryBuilder.selectRaw(expression: CMType): SelectRawClause = selectRaw(expression.asField()) diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt index 13e01409..1b423b1f 100644 --- a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt +++ b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt @@ -1,6 +1,5 @@ package ch.ergon.dope.extension.clause -import ch.ergon.dope.QueryBuilder import ch.ergon.dope.asArrayField import ch.ergon.dope.asField import ch.ergon.dope.resolvable.clause.ISelectFromClause @@ -12,12 +11,9 @@ import ch.ergon.dope.resolvable.clause.ISelectUnnestClause import ch.ergon.dope.resolvable.clause.ISelectWhereClause import ch.ergon.dope.resolvable.clause.model.GroupByClause import ch.ergon.dope.resolvable.clause.model.OrderByType -import ch.ergon.dope.resolvable.clause.model.SelectClause -import ch.ergon.dope.resolvable.clause.model.SelectDistinctClause 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.SelectRawClause import ch.ergon.dope.resolvable.fromable.Bucket import com.schwarz.crystalapi.schema.CMField import com.schwarz.crystalapi.schema.CMList @@ -53,11 +49,3 @@ fun ISelectUnnestClause.unnest(arrayField: CMList) = unnest(arrayField.a @JvmName("unnestBoolean") fun ISelectUnnestClause.unnest(arrayField: CMList) = unnest(arrayField.asArrayField()) - -fun QueryBuilder.select(expression: CMType, vararg expressions: CMType): SelectClause = - select(expression.asField(), *expressions.map { it.asField() }.toTypedArray()) - -fun QueryBuilder.selectDistinct(expression: CMType, vararg expressions: CMType): SelectDistinctClause = - selectDistinct(expression.asField(), *expressions.map { it.asField() }.toTypedArray()) - -fun QueryBuilder.selectRaw(expression: CMType): SelectRawClause = selectRaw(expression.asField()) diff --git a/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/QueryBuilderTest.kt b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/QueryBuilderTest.kt new file mode 100644 index 00000000..ea78ef30 --- /dev/null +++ b/crystal-map-connector/src/test/kotlin/ch/ergon/dope/extensions/QueryBuilderTest.kt @@ -0,0 +1,48 @@ +package ch.ergon.dope.extensions + +import ch.ergon.dope.QueryBuilder +import ch.ergon.dope.extension.select +import ch.ergon.dope.extension.selectDistinct +import ch.ergon.dope.extension.selectRaw +import ch.ergon.dope.helper.someCMBooleanField +import ch.ergon.dope.helper.someCMNumberField +import ch.ergon.dope.helper.someCMStringList +import org.junit.jupiter.api.Assertions.assertEquals +import kotlin.test.Test + +class QueryBuilderTest { + @Test + fun `should support select with CM`() { + val actual: String = QueryBuilder().select(someCMNumberField()).toDopeQuery().queryString + + assertEquals("SELECT someNumberField", actual) + } + + @Test + fun `should support select with multiple CM`() { + val actual: String = QueryBuilder().select(someCMBooleanField(), someCMStringList()).toDopeQuery().queryString + + assertEquals("SELECT someBooleanField, someStringList", actual) + } + + @Test + fun `should support select distinct with CM`() { + val actual: String = QueryBuilder().selectDistinct(someCMNumberField()).toDopeQuery().queryString + + assertEquals("SELECT DISTINCT someNumberField", actual) + } + + @Test + fun `should support select distinct with multiple CM`() { + val actual: String = QueryBuilder().selectDistinct(someCMBooleanField(), someCMStringList()).toDopeQuery().queryString + + assertEquals("SELECT DISTINCT someBooleanField, someStringList", actual) + } + + @Test + fun `should support select raw with CM`() { + val actual: String = QueryBuilder().selectRaw(someCMNumberField()).toDopeQuery().queryString + + assertEquals("SELECT RAW someNumberField", actual) + } +} 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 0df82ce1..5a329f67 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 @@ -1,6 +1,5 @@ package ch.ergon.dope.extensions.clause -import ch.ergon.dope.QueryBuilder import ch.ergon.dope.extension.clause.groupBy import ch.ergon.dope.extension.clause.innerJoin import ch.ergon.dope.extension.clause.join @@ -9,9 +8,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.rightJoin -import ch.ergon.dope.extension.clause.select -import ch.ergon.dope.extension.clause.selectDistinct -import ch.ergon.dope.extension.clause.selectRaw import ch.ergon.dope.extension.clause.unnest import ch.ergon.dope.extension.clause.where import ch.ergon.dope.helper.someBucket @@ -28,41 +24,6 @@ import org.junit.jupiter.api.Assertions.assertEquals import kotlin.test.Test class SelectClauseTest { - @Test - fun `should support select with CM`() { - val actual: String = QueryBuilder().select(someCMNumberField()).toDopeQuery().queryString - - assertEquals("SELECT someNumberField", actual) - } - - @Test - fun `should support select with multiple CM`() { - val actual: String = QueryBuilder().select(someCMBooleanField(), someCMStringList()).toDopeQuery().queryString - - assertEquals("SELECT someBooleanField, someStringList", actual) - } - - @Test - fun `should support select distinct with CM`() { - val actual: String = QueryBuilder().selectDistinct(someCMNumberField()).toDopeQuery().queryString - - assertEquals("SELECT DISTINCT someNumberField", actual) - } - - @Test - fun `should support select distinct with multiple CM`() { - val actual: String = QueryBuilder().selectDistinct(someCMBooleanField(), someCMStringList()).toDopeQuery().queryString - - assertEquals("SELECT DISTINCT someBooleanField, someStringList", actual) - } - - @Test - fun `should support select raw with CM`() { - val actual: String = QueryBuilder().selectRaw(someCMNumberField()).toDopeQuery().queryString - - assertEquals("SELECT RAW someNumberField", actual) - } - @Test fun `should support select where with CM`() { val actual: String = someSelect().where(someCMBooleanField()).toDopeQuery().queryString From 3820d091f567c12885b3c7c02eac11cd4b1892fb Mon Sep 17 00:00:00 2001 From: Jan Sigrist Date: Fri, 24 May 2024 13:56:16 +0200 Subject: [PATCH 8/8] DOPE-201: renaming --- .../ch/ergon/dope/extension/clause/{Delete.kt => DeleteClause.kt} | 0 .../ch/ergon/dope/extension/clause/{Select.kt => SelectClause.kt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/{Delete.kt => DeleteClause.kt} (100%) rename crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/{Select.kt => SelectClause.kt} (100%) diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Delete.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/DeleteClause.kt similarity index 100% rename from crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Delete.kt rename to crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/DeleteClause.kt diff --git a/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt b/crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/SelectClause.kt similarity index 100% rename from crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/Select.kt rename to crystal-map-connector/src/main/kotlin/ch/ergon/dope/extension/clause/SelectClause.kt