Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ open class Referrers<ParentID : Any, in Parent : Entity<ParentID>, ChildID : Any
val cache: Boolean,
references: Map<Column<*>, Column<*>>? = null
) : ReadOnlyProperty<Parent, SizedIterable<Child>> {
/** The list of columns and their [SortOrder] for ordering referred entities in one-to-many relationship. */
private val orderByExpressions: MutableList<Pair<Expression<*>, SortOrder>> = mutableListOf()
/** The set of columns and their [SortOrder] for ordering referred entities in one-to-many relationship. */
private val orderByExpressions = linkedSetOf<Pair<Expression<*>, SortOrder>>()

val allReferences = references ?: run {
reference.referee ?: error("Column $reference is not a reference")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package org.jetbrains.exposed.v1.tests.shared.entities

import org.jetbrains.exposed.v1.core.SortOrder.DESC
import org.jetbrains.exposed.v1.core.Transaction
import org.jetbrains.exposed.v1.core.dao.id.EntityID
import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
import org.jetbrains.exposed.v1.core.statements.StatementContext
import org.jetbrains.exposed.v1.core.statements.StatementInterceptor
import org.jetbrains.exposed.v1.dao.IntEntity
import org.jetbrains.exposed.v1.dao.IntEntityClass
import org.jetbrains.exposed.v1.dao.entityCache
import org.jetbrains.exposed.v1.jdbc.JdbcTransaction
import org.jetbrains.exposed.v1.jdbc.insert
import org.jetbrains.exposed.v1.jdbc.insertAndGetId
Expand All @@ -15,6 +19,8 @@ import org.jetbrains.exposed.v1.tests.shared.assertEquals
import org.jetbrains.exposed.v1.tests.shared.assertTrue
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertNotNull
import kotlin.math.max

@Tag(MISSING_R2DBC_TEST)
class OrderedReferenceTest : DatabaseTestsBase() {
Expand Down Expand Up @@ -65,6 +71,50 @@ class OrderedReferenceTest : DatabaseTestsBase() {
}
}

@Test
fun testNoDuplicatedOrderByPartsInQuery() {
// This interceptor counts duplicated ORDER BY parts in the sql sent to database.
// We want to be sure that DAO doesn't create duplicated parts.
val interceptor = object : StatementInterceptor {
var maxDuplicates = 0
override fun beforeExecution(transaction: Transaction, context: StatementContext) {
val duplicatedPartsAmount = context.statement.prepareSQL(transaction)
// Get all the parts from order by section
.lowercase()
.substringAfter("order by")
.split(",")
.map { it.trim() }
// Count the occurrences of each part and take maximum
.groupBy { it }
.mapValues { (_, list) -> list.size }
.maxByOrNull { it.value }
?.value ?: 0

maxDuplicates = max(maxDuplicates, duplicatedPartsAmount)
}
}

withOrderedReferenceTestTables {
registerInterceptor(interceptor)
// `orderBy` on references in DAO Entity classes could collect duplicated parts.
// That method is executed on every access to the field, so every query has
// one more duplicated part
// It's mentioned in the original issue
// 'EXPOSED-950 Order by clause is repeated hundredfold'
repeat(5) {
val user = UserDefaultOrder.all().first()
entityCache.clear()

// This sections needs only to force DAO fetch the data to execute SQL queries
user.ratings.forEach { rating ->
assertNotNull(rating.value)
}

assertEquals(1, interceptor.maxDuplicates)
}
}
}

class UserRatingMultiColumn(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<UserRatingMultiColumn>(UserRatings)

Expand Down
Loading