mirror of
https://github.com/jlengrand/Exposed.git
synced 2026-03-10 08:11:20 +00:00
Correct precedence for arithmetic operators (#788)
* Add parentheses for arithmetic operators in sql builders * Added unit test * Re-use CustomOperator for arithmetic
This commit is contained in:
committed by
GitHub
parent
cdbc588494
commit
d512d18776
@@ -218,21 +218,10 @@ class notExists(val query: Query) : Op<Boolean>() {
|
||||
}
|
||||
}
|
||||
|
||||
class PlusOp<T, S: T>(val expr1: Expression<T>, val expr2: Expression<S>, override val columnType: IColumnType): ExpressionWithColumnType<T>() {
|
||||
override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { append(expr1, '+', expr2) }
|
||||
}
|
||||
|
||||
class MinusOp<T, S: T>(val expr1: Expression<T>, val expr2: Expression<S>, override val columnType: IColumnType): ExpressionWithColumnType<T>() {
|
||||
override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { append(expr1, '-', expr2) }
|
||||
}
|
||||
|
||||
class TimesOp<T, S: T>(val expr1: Expression<T>, val expr2: Expression<S>, override val columnType: IColumnType): ExpressionWithColumnType<T>() {
|
||||
override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { append(expr1, '*', expr2) }
|
||||
}
|
||||
|
||||
class DivideOp<T, S: T>(val expr1: Expression<T>, val expr2: Expression<S>, override val columnType: IColumnType): ExpressionWithColumnType<T>() {
|
||||
override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { append('(', expr1, " / ", expr2, ')') }
|
||||
}
|
||||
class PlusOp<T, S: T>(expr1: Expression<T>, expr2: Expression<S>, override val columnType: IColumnType): CustomOperator<T>("+", columnType, expr1, expr2)
|
||||
class MinusOp<T, S: T>(expr1: Expression<T>, expr2: Expression<S>, override val columnType: IColumnType): CustomOperator<T>("-", columnType, expr1, expr2)
|
||||
class TimesOp<T, S: T>(expr1: Expression<T>, expr2: Expression<S>, override val columnType: IColumnType): CustomOperator<T>("*", columnType, expr1, expr2)
|
||||
class DivideOp<T, S: T>(expr1: Expression<T>, expr2: Expression<S>, override val columnType: IColumnType): CustomOperator<T>("/", columnType, expr1, expr2)
|
||||
|
||||
class ModOp<T:Number?, S: Number?>(val expr1: Expression<T>, val expr2: Expression<S>, override val columnType: IColumnType): ExpressionWithColumnType<T>() {
|
||||
override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder {
|
||||
|
||||
@@ -16,6 +16,10 @@ fun<T:Comparable<T>, S:T?> ExpressionWithColumnType<in S>.min() : ExpressionWit
|
||||
|
||||
fun<T:Comparable<T>, S:T?> ExpressionWithColumnType<in S>.max() : ExpressionWithColumnType<T?> = Max<T, S>(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<T:Comparable<T>, S:T?> ExpressionWithColumnType<in S>.avg(scale: Int = 2) : ExpressionWithColumnType<BigDecimal?> = Avg<T, S>(this, scale)
|
||||
|
||||
fun<T:Any?> ExpressionWithColumnType<T>.stdDevPop(scale: Int = 2) = StdDevPop(this, scale)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user