mirror of
https://github.com/jlengrand/Exposed.git
synced 2026-03-10 08:11:20 +00:00
New Query features: slice/columnSet/where adjustments, fields visibility; Minor fixes
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
||||
.gradle
|
||||
build
|
||||
classes
|
||||
out/test/resources
|
||||
|
||||
@@ -125,8 +125,8 @@ allprojects {
|
||||
testCompile 'org.slf4j:slf4j-log4j12:1.7.25'
|
||||
testCompile 'log4j:log4j:1.2.17'
|
||||
testCompile 'junit:junit:4.12'
|
||||
testCompile 'org.hamcrest:hamcrest-library:1.3'
|
||||
testCompile 'com.h2database:h2:1.4.194'
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
group=org.jetbrains.exposed
|
||||
version=0.9-SNAPSHOT
|
||||
kotlin_version=1.1.2-3
|
||||
version=0.8.1-SNAPSHOT
|
||||
kotlin_version=1.1.3
|
||||
|
||||
@@ -75,15 +75,48 @@ class ResultRow(size: Int, private val fieldIndex: Map<Expression<*>, Int>) {
|
||||
}
|
||||
}
|
||||
|
||||
open class Query(val transaction: Transaction, val set: FieldSet, val where: Op<Boolean>?): SizedIterable<ResultRow>, Statement<ResultSet>(StatementType.SELECT, set.source.targetTables()) {
|
||||
private val groupedByColumns = ArrayList<Expression<*>>()
|
||||
private val orderByColumns = ArrayList<Pair<Expression<*>, Boolean>>()
|
||||
private var having: Op<Boolean>? = null
|
||||
private var limit: Int? = null
|
||||
private var offset: Int = 0
|
||||
private var distinct: Boolean = false
|
||||
private var count: Boolean = false
|
||||
open class Query(val transaction: Transaction, set: FieldSet, where: Op<Boolean>?): SizedIterable<ResultRow>, Statement<ResultSet>(StatementType.SELECT, set.source.targetTables()) {
|
||||
var groupedByColumns: List<Expression<*>> = mutableListOf()
|
||||
private set
|
||||
var orderByColumns: List<Pair<Expression<*>, Boolean>> = mutableListOf()
|
||||
private set
|
||||
var having: Op<Boolean>? = null
|
||||
private set
|
||||
var distinct: Boolean = false
|
||||
private set
|
||||
private var forUpdate: Boolean? = null
|
||||
var set: FieldSet = set
|
||||
private set
|
||||
var where: Op<Boolean>? = where
|
||||
private set
|
||||
var limit: Int? = null
|
||||
private set
|
||||
var offset: Int = 0
|
||||
private set
|
||||
|
||||
/**
|
||||
* Changes [set.fields] field of a Query, [set.source] will be preserved
|
||||
* @param body builder for new column set, current [set.source] used as a receiver, you are expected to slice it
|
||||
* @sample org.jetbrains.exposed.sql.tests.shared.DMLTests.testAdjustQuerySlice
|
||||
*/
|
||||
fun adjustSlice(body: ColumnSet.() -> FieldSet): Query = apply { set = set.source.body() }
|
||||
|
||||
/**
|
||||
* Changes [set.source] field of a Query, [set.fields] will be preserved
|
||||
* @param body builder for new column set, previous value used as a receiver
|
||||
* @sample org.jetbrains.exposed.sql.tests.shared.DMLTests.testAdjustQueryColumnSet
|
||||
*/
|
||||
fun adjustColumnSet(body: ColumnSet.() -> ColumnSet): Query {
|
||||
val oldSlice = set.fields
|
||||
return adjustSlice { body().slice(oldSlice) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes [where] field of a Query.
|
||||
* @param body new WHERE condition builder, previous value used as a receiver
|
||||
* @sample org.jetbrains.exposed.sql.tests.shared.DMLTests.testAdjustQueryWhere
|
||||
*/
|
||||
fun adjustWhere(body: Op<Boolean>?.() -> Op<Boolean>): Query = apply { where = where.body() }
|
||||
|
||||
fun hasCustomForUpdateState() = forUpdate != null
|
||||
fun isForUpdate() = (forUpdate ?: transaction.selectsForUpdate) && transaction.db.dialect.supportsSelectForUpdate()
|
||||
@@ -112,9 +145,9 @@ open class Query(val transaction: Transaction, val set: FieldSet, val where: Op<
|
||||
append(" FROM ")
|
||||
append(set.source.describe(transaction))
|
||||
|
||||
if (where != null) {
|
||||
where?.let {
|
||||
append(" WHERE ")
|
||||
append(where.toSQL(builder))
|
||||
append(it.toSQL(builder))
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
@@ -156,14 +189,14 @@ open class Query(val transaction: Transaction, val set: FieldSet, val where: Op<
|
||||
return this
|
||||
}
|
||||
|
||||
fun withDistinct() : Query {
|
||||
distinct = true
|
||||
fun withDistinct(value: Boolean = true) : Query {
|
||||
distinct = value
|
||||
return this
|
||||
}
|
||||
|
||||
fun groupBy(vararg columns: Expression<*>): Query {
|
||||
for (column in columns) {
|
||||
groupedByColumns.add(column)
|
||||
(groupedByColumns as MutableList).add(column)
|
||||
}
|
||||
return this
|
||||
}
|
||||
@@ -179,13 +212,13 @@ open class Query(val transaction: Transaction, val set: FieldSet, val where: Op<
|
||||
}
|
||||
|
||||
fun orderBy (column: Expression<*>, isAsc: Boolean = true) : Query {
|
||||
orderByColumns.add(column to isAsc)
|
||||
(orderByColumns as MutableList).add(column to isAsc)
|
||||
return this
|
||||
}
|
||||
|
||||
fun orderBy (vararg columns: Pair<Column<*>,Boolean>) : Query {
|
||||
for (pair in columns) {
|
||||
orderByColumns.add(pair)
|
||||
(orderByColumns as MutableList).add(pair)
|
||||
}
|
||||
return this
|
||||
}
|
||||
@@ -231,6 +264,7 @@ open class Query(val transaction: Transaction, val set: FieldSet, val where: Op<
|
||||
return ResultIterator(transaction.exec(this)!!)
|
||||
}
|
||||
|
||||
private var count: Boolean = false
|
||||
override fun count(): Int {
|
||||
flushEntities()
|
||||
|
||||
|
||||
@@ -158,9 +158,12 @@ object SchemaUtils {
|
||||
}
|
||||
|
||||
fun drop(vararg tables: Table) {
|
||||
EntityCache.sortTablesByReferences(tables.toList()).reversed().filter { it in tables}.flatMap { it.dropStatement() }.forEach {
|
||||
TransactionManager.current().exec(it)
|
||||
}
|
||||
EntityCache.sortTablesByReferences(tables.toList()).reversed()
|
||||
.filter { it in tables && it.exists() }
|
||||
.flatMap { it.dropStatement() }
|
||||
.forEach {
|
||||
TransactionManager.current().exec(it)
|
||||
}
|
||||
currentDialect.resetCaches()
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,8 @@ interface FieldSet {
|
||||
abstract class ColumnSet : FieldSet {
|
||||
abstract val columns: List<Column<*>>
|
||||
override val fields: List<Expression<*>> get() = columns
|
||||
override val source get() = this
|
||||
override val source
|
||||
get() = this
|
||||
|
||||
abstract fun describe(s: Transaction): String
|
||||
|
||||
@@ -220,7 +221,7 @@ open class Table(name: String = ""): ColumnSet(), DdlAware {
|
||||
|
||||
fun blob(name: String): Column<Blob> = registerColumn(name, BlobColumnType())
|
||||
|
||||
fun text(name: String): Column<String> = registerColumn(name, StringColumnType())
|
||||
fun text(name: String): Column<String> = registerColumn(name, StringColumnType(length = 65535))
|
||||
|
||||
fun binary(name: String, length: Int): Column<ByteArray> = registerColumn(name, BinaryColumnType(length))
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.sql.ResultSet
|
||||
import java.util.*
|
||||
|
||||
|
||||
class BatchInsertStatement(table: Table, ignore: Boolean = false): InsertStatement<List<Map<Column<*>, Any>>>(table, ignore) {
|
||||
open class BatchInsertStatement(table: Table, ignore: Boolean = false): InsertStatement<List<Map<Column<*>, Any>>>(table, ignore) {
|
||||
|
||||
override val flushCache: Boolean = false
|
||||
// REVIEW
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package org.jetbrains.exposed.sql.tests.shared
|
||||
|
||||
import org.hamcrest.Matchers.*
|
||||
import org.jetbrains.exposed.dao.IntIdTable
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.tests.DatabaseTestsBase
|
||||
import org.jetbrains.exposed.sql.tests.TestDB
|
||||
import org.joda.time.DateTime
|
||||
import org.junit.Assert.assertThat
|
||||
import org.junit.Test
|
||||
import java.math.BigDecimal
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.*
|
||||
|
||||
object DMLTestsData {
|
||||
object Cities : Table() {
|
||||
@@ -1026,6 +1025,78 @@ class DMLTests : DatabaseTestsBase() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertQueryResultValid(query: Query): Unit {
|
||||
val users = DMLTestsData.Users
|
||||
val cities = DMLTestsData.Cities
|
||||
query.forEach { row ->
|
||||
val userName = row[users.name]
|
||||
val cityName = row[cities.name]
|
||||
when (userName) {
|
||||
"Andrey" -> assertEquals("St. Petersburg", cityName)
|
||||
"Sergey" -> assertEquals("Munich", cityName)
|
||||
else -> error("Unexpected user $userName")
|
||||
}
|
||||
}
|
||||
}
|
||||
private val predicate = Op.build {
|
||||
val nameCheck = (DMLTestsData.Users.id eq "andrey") or (DMLTestsData.Users.name eq "Sergey")
|
||||
val cityCheck = DMLTestsData.Users.cityId eq DMLTestsData.Cities.id
|
||||
nameCheck and cityCheck
|
||||
}
|
||||
|
||||
@Test fun testAdjustQuerySlice() {
|
||||
withCitiesAndUsers { cities, users, _ ->
|
||||
val queryAdjusted = (users innerJoin cities)
|
||||
.slice(users.name)
|
||||
.select(predicate)
|
||||
|
||||
fun Query.sliceIt(): FieldSet = this.set.source.slice(users.name, cities.name)
|
||||
val oldSlice = queryAdjusted.set.fields
|
||||
val expectedSlice = queryAdjusted.sliceIt().fields
|
||||
queryAdjusted.adjustSlice { slice(users.name, cities.name) }
|
||||
val actualSlice = queryAdjusted.set.fields
|
||||
fun containsInAnyOrder(list: List<*>) = containsInAnyOrder(*list.toTypedArray())
|
||||
|
||||
assertThat(oldSlice, not(containsInAnyOrder(actualSlice)))
|
||||
assertThat(actualSlice, containsInAnyOrder(expectedSlice))
|
||||
assertQueryResultValid(queryAdjusted)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun testAdjustQueryColumnSet() {
|
||||
withCitiesAndUsers { cities, users, _ ->
|
||||
val queryAdjusted = users
|
||||
.slice(users.name, cities.name)
|
||||
.select(predicate)
|
||||
val oldColumnSet = queryAdjusted.set.source
|
||||
val expectedColumnSet = users innerJoin cities
|
||||
queryAdjusted.adjustColumnSet { innerJoin(cities) }
|
||||
val actualColumnSet = queryAdjusted.set.source
|
||||
fun ColumnSet.repr(): String = this.describe(queryAdjusted.transaction)
|
||||
|
||||
assertNotEquals(oldColumnSet.repr(), actualColumnSet.repr())
|
||||
assertEquals(expectedColumnSet.repr(), actualColumnSet.repr())
|
||||
assertQueryResultValid(queryAdjusted)
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun testAdjustQueryWhere() {
|
||||
withCitiesAndUsers { cities, users, _ ->
|
||||
val queryAdjusted = (users innerJoin cities)
|
||||
.slice(users.name, cities.name)
|
||||
.selectAll()
|
||||
queryAdjusted.adjustWhere {
|
||||
assertNull(this)
|
||||
predicate
|
||||
}
|
||||
val actualWhere = queryAdjusted.where
|
||||
fun Op<Boolean>.repr(): String = this.toSQL(QueryBuilder(false))
|
||||
|
||||
assertEquals(predicate.repr(), actualWhere!!.repr())
|
||||
assertQueryResultValid(queryAdjusted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val today: DateTime = DateTime.now().withTimeAtStartOfDay()
|
||||
|
||||
Reference in New Issue
Block a user