diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Op.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Op.kt index 88bb8feb..28fab504 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Op.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Op.kt @@ -218,21 +218,10 @@ class notExists(val query: Query) : Op() { } } -class PlusOp(val expr1: Expression, val expr2: Expression, override val columnType: IColumnType): ExpressionWithColumnType() { - override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { append(expr1, '+', expr2) } -} - -class MinusOp(val expr1: Expression, val expr2: Expression, override val columnType: IColumnType): ExpressionWithColumnType() { - override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { append(expr1, '-', expr2) } -} - -class TimesOp(val expr1: Expression, val expr2: Expression, override val columnType: IColumnType): ExpressionWithColumnType() { - override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { append(expr1, '*', expr2) } -} - -class DivideOp(val expr1: Expression, val expr2: Expression, override val columnType: IColumnType): ExpressionWithColumnType() { - override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { append('(', expr1, " / ", expr2, ')') } -} +class PlusOp(expr1: Expression, expr2: Expression, override val columnType: IColumnType): CustomOperator("+", columnType, expr1, expr2) +class MinusOp(expr1: Expression, expr2: Expression, override val columnType: IColumnType): CustomOperator("-", columnType, expr1, expr2) +class TimesOp(expr1: Expression, expr2: Expression, override val columnType: IColumnType): CustomOperator("*", columnType, expr1, expr2) +class DivideOp(expr1: Expression, expr2: Expression, override val columnType: IColumnType): CustomOperator("/", columnType, expr1, expr2) class ModOp(val expr1: Expression, val expr2: Expression, override val columnType: IColumnType): ExpressionWithColumnType() { override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SQLExpressionBuilder.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SQLExpressionBuilder.kt index 73fb628e..29b5bb54 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SQLExpressionBuilder.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SQLExpressionBuilder.kt @@ -16,6 +16,10 @@ fun, S:T?> ExpressionWithColumnType.min() : ExpressionWit fun, S:T?> ExpressionWithColumnType.max() : ExpressionWithColumnType = Max(this, this.columnType) +/** + * Calculates the average value. Typed to BigDecimal because some DBMS return floating point values for AVG, even if column an integral type + * See examples [here](https://www.w3resource.com/sql/aggregate-functions/avg-function.php) + */ fun, S:T?> ExpressionWithColumnType.avg(scale: Int = 2) : ExpressionWithColumnType = Avg(this, scale) fun ExpressionWithColumnType.stdDevPop(scale: Int = 2) = StdDevPop(this, scale) diff --git a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/ArithmeticTests.kt b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/ArithmeticTests.kt new file mode 100644 index 00000000..d2c2532b --- /dev/null +++ b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/ArithmeticTests.kt @@ -0,0 +1,29 @@ +package org.jetbrains.exposed.sql.tests.shared.dml + +import org.jetbrains.exposed.sql.Op +import org.jetbrains.exposed.sql.SqlExpressionBuilder.div +import org.jetbrains.exposed.sql.SqlExpressionBuilder.minus +import org.jetbrains.exposed.sql.SqlExpressionBuilder.times +import org.jetbrains.exposed.sql.select +import org.jetbrains.exposed.sql.selectAll +import org.jetbrains.exposed.sql.tests.DatabaseTestsBase +import org.jetbrains.exposed.sql.tests.shared.assertEquals +import org.junit.Test + +class ArithmeticTests : DatabaseTestsBase() { + @Test + fun `test operator precedence of minus() plus() div() times()`() { + withCitiesAndUsers { _, _, userData -> + val calculatedColumn = ((DMLTestsData.UserData.value - 5) * 2) / 2 + userData + .slice(DMLTestsData.UserData.value, calculatedColumn) + .selectAll() + .forEach { + val value = it[DMLTestsData.UserData.value] + val actualResult = it[calculatedColumn] + val expectedResult = ((value - 5) * 2) / 2 + assertEquals(expectedResult, actualResult) + } + } + } +} \ No newline at end of file