Skip to content

Commit

Permalink
GH-7 Sort columns alphabetically so that it works properly (Fix #6)
Browse files Browse the repository at this point in the history
* fix(sql): Sort columns alphabetically so that it works properly (thanks, Exposed)

* test: Add test case for sorting columns

* test: Fix test for update order, add lastUpdated field to StatisticsTable
  • Loading branch information
tecc authored Mar 30, 2023
1 parent 629cd3d commit c4ea2ad
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 18 deletions.
21 changes: 6 additions & 15 deletions src/main/kotlin/net/dzikoysk/exposed/upsert/UpsertStatement.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ internal class UpsertStatement<Key : Any>(
return result
}

@Suppress("UNCHECKED_CAST")
// @Suppress("UNCHECKED_CAST")
override fun prepareSQL(transaction: Transaction) = buildString {
append(super.prepareSQL(transaction))

Expand Down Expand Up @@ -88,26 +88,17 @@ internal class UpsertStatement<Key : Any>(

private fun doUpdateSet(transaction: Transaction, updateValues: Map<Column<*>, Any?>): String = buildString {
append(" DO UPDATE SET ")

updateValues.entries
.filter { it.key !in indexColumns }
.joinTo(this) { (column, value) ->
when (value) {
is Expression<*> -> {
val queryBuilder = QueryBuilder(true)
value.toQueryBuilder(queryBuilder)
"${transaction.identity(column)}=${queryBuilder}"
}
else -> "${transaction.identity(column)}=?"
}
}
append(appendUpdateSet(transaction, updateValues))
}

private fun onDuplicateKeyUpdate(transaction: Transaction, updateValues: Map<Column<*>, Any?>): String = buildString {
append(" ON DUPLICATE KEY UPDATE ")

append(appendUpdateSet(transaction, updateValues))
}
private fun appendUpdateSet(transaction: Transaction, updateValues: Map<Column<*>, Any?>): String = buildString {
updateValues.entries
.filter { it.key !in indexColumns }
.sortedBy { it.key }
.joinTo(this) { (column, value) ->
when (value) {
is Expression<*> -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ internal class StatisticsRepository {
val httpMethod: Column<String> = varchar("http_method", 32)
val uri: Column<String> = varchar("uri", 512)
val count: Column<Long> = long("count")
val lastUpdated: Column<Long> = long("last_updated") // you would probably use DateTime for this but this is easier

val typeIndex = withIndex("index_type", columns = arrayOf(httpMethod))
val uniqueTypeValue = withUnique("unique_http_method_to_uri", httpMethod, uri)
Expand All @@ -68,7 +69,8 @@ internal class StatisticsRepository {
override val id: Int = UNINITIALIZED_ENTITY_ID,
val httpMethod: String,
val uri: String,
val count: Long
val count: Long,
val lastUpdated: Long = 0
) : IdentifiableEntity {

override fun toString() = "$id | $httpMethod | $uri | $count"
Expand All @@ -91,6 +93,7 @@ internal class StatisticsRepository {
it[this.httpMethod] = record.httpMethod
it[this.uri] = record.uri
it[this.count] = record.count
it[this.lastUpdated] = record.lastUpdated
},
updateBody = {
with(SqlExpressionBuilder) {
Expand Down Expand Up @@ -119,7 +122,8 @@ internal class StatisticsRepository {
id = row[StatisticsTable.id].value,
httpMethod = row[StatisticsTable.httpMethod],
uri = row[StatisticsTable.uri],
count = row[StatisticsTable.count]
count = row[StatisticsTable.count],
lastUpdated = row[StatisticsTable.lastUpdated]
)

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ package net.dzikoysk.exposed.upsert.spec

import net.dzikoysk.exposed.shared.UNINITIALIZED_ENTITY_ID
import net.dzikoysk.exposed.upsert.spec.StatisticsRepository.Record
import net.dzikoysk.exposed.upsert.spec.StatisticsRepository.StatisticsTable
import net.dzikoysk.exposed.upsert.upsert
import org.jetbrains.exposed.sql.transactions.transaction
import kotlin.test.assertEquals

internal open class UpsertSpecification {
Expand Down Expand Up @@ -76,6 +79,32 @@ internal open class UpsertSpecification {
assertEquals(400, statisticsRepository.upsertRecord(Record(3, "POST", "/xyz/xyz", 0)).count)

statisticsRepository.findAll().forEach { println(it) }
}

// should reset count and change URI
val records = statisticsRepository.findAll()
if (!records.isEmpty()) {
for (record in records) {
val value = transaction {
StatisticsTable.upsert(conflictIndex = StatisticsTable.uniqueTypeValue,
insertBody = {
// this is technically irrelevant
// it[this.id] = record.id
it[this.httpMethod] = record.httpMethod
it[this.uri] = record.uri
it[this.count] = record.count
it[this.lastUpdated] = record.lastUpdated
},
updateBody = {
// intentionally ordered in reverse
it[this.lastUpdated] = record.lastUpdated + 100 // something predictable
it[this.count] = 1
}
)
statisticsRepository.findByTypeAndValue(record.httpMethod, record.uri)
}
assertEquals(record.lastUpdated + 100, value.lastUpdated)
assertEquals(1, value.count)
}
}
}
}

0 comments on commit c4ea2ad

Please sign in to comment.