From 518c02396eff3c8e86d9bca371b097e0c7e6da3b Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Sat, 25 Jan 2025 19:22:29 +0100 Subject: feat(server): More SQL refactoring --- .../moe/nea/ledger/database/sql/ClauseBuilder.kt | 5 +++++ .../moe/nea/ledger/database/sql/ColumnOperand.kt | 2 +- .../moe/nea/ledger/database/sql/ListClause.kt | 8 ++++++++ .../moe/nea/ledger/database/sql/ListExpression.kt | 22 ++++++++++++++++++++++ .../nea/ledger/database/sql/SQLQueryComponent.kt | 19 +++++++++++++++++++ .../moe/nea/ledger/database/sql/TypedOperand.kt | 4 ++-- 6 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 database/core/src/main/kotlin/moe/nea/ledger/database/sql/ListClause.kt create mode 100644 database/core/src/main/kotlin/moe/nea/ledger/database/sql/ListExpression.kt (limited to 'database/core/src/main') diff --git a/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ClauseBuilder.kt b/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ClauseBuilder.kt index aae8456..cb0ddfc 100644 --- a/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ClauseBuilder.kt +++ b/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ClauseBuilder.kt @@ -4,6 +4,7 @@ import moe.nea.ledger.database.Column import moe.nea.ledger.database.DBType class ClauseBuilder { + // TODO: should we match on T AND R? maybe allow explicit upcasting fun column(column: Column): ColumnOperand = ColumnOperand(column) fun string(string: String): StringOperand = StringOperand(string) fun value(dbType: DBType, value: T): Operand = ValuedOperand(dbType, value) @@ -15,6 +16,10 @@ class ClauseBuilder { infix fun Operand<*, T>.le(op: Operand<*, T>): BooleanExpression = LessThanEqualsExpression(this, op) infix fun Operand<*, T>.gt(op: Operand<*, T>): BooleanExpression = op lt this infix fun Operand<*, T>.ge(op: Operand<*, T>): BooleanExpression = op le this + infix fun Operand<*, T>.inList(list: ListExpression<*, T>): Clause = ListClause(this, list) + infix fun TypedOperand.inList(list: List): Clause = this inList list(dbType, list) + fun list(dbType: DBType, vararg values: T): ListExpression = list(dbType, values.toList()) + fun list(dbType: DBType, values: List): ListExpression = ListExpression(values, dbType) infix fun BooleanExpression.and(clause: BooleanExpression): BooleanExpression = ANDExpression(listOf(this, clause)) infix fun BooleanExpression.or(clause: BooleanExpression): BooleanExpression = ORExpression(listOf(this, clause)) } \ No newline at end of file diff --git a/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ColumnOperand.kt b/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ColumnOperand.kt index 710c577..430d592 100644 --- a/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ColumnOperand.kt +++ b/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ColumnOperand.kt @@ -4,7 +4,7 @@ import moe.nea.ledger.database.Column import moe.nea.ledger.database.DBType import java.sql.PreparedStatement -data class ColumnOperand(val column: Column) : TypedOperand() { +data class ColumnOperand(val column: Column) : TypedOperand { override val dbType: DBType get() = column.type diff --git a/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ListClause.kt b/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ListClause.kt new file mode 100644 index 0000000..d240472 --- /dev/null +++ b/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ListClause.kt @@ -0,0 +1,8 @@ +package moe.nea.ledger.database.sql + +class ListClause( + val lhs: Operand<*, R>, + val list: ListExpression<*, R>, +) : Clause, SQLQueryComponent by SQLQueryComponent.composite( + lhs, SQLQueryComponent.standalone("IN"), list +) \ No newline at end of file diff --git a/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ListExpression.kt b/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ListExpression.kt new file mode 100644 index 0000000..e1522d0 --- /dev/null +++ b/database/core/src/main/kotlin/moe/nea/ledger/database/sql/ListExpression.kt @@ -0,0 +1,22 @@ +package moe.nea.ledger.database.sql + +import moe.nea.ledger.database.DBType +import java.sql.PreparedStatement + +data class ListExpression( + val elements: List, + val dbType: DBType +) : Operand, List> { + override fun asSql(): String { + return elements.joinToString(prefix = "(", postfix = ")") { "?" } + } + + override fun appendToStatement(stmt: PreparedStatement, startIndex: Int): Int { + var index = startIndex + for (element in elements) { + dbType.set(stmt, index, element) + index++ + } + return index + } +} diff --git a/database/core/src/main/kotlin/moe/nea/ledger/database/sql/SQLQueryComponent.kt b/database/core/src/main/kotlin/moe/nea/ledger/database/sql/SQLQueryComponent.kt index 10b2be6..77d63d3 100644 --- a/database/core/src/main/kotlin/moe/nea/ledger/database/sql/SQLQueryComponent.kt +++ b/database/core/src/main/kotlin/moe/nea/ledger/database/sql/SQLQueryComponent.kt @@ -11,6 +11,25 @@ interface SQLQueryComponent { fun appendToStatement(stmt: PreparedStatement, startIndex: Int): Int companion object { + fun composite(vararg elements: SQLQueryComponent): SQLQueryComponent { + return object : SQLQueryComponent { + override fun asSql(): String { + return elements.joinToString(" ") { it.asSql() } + } + + override fun appendToStatement(stmt: PreparedStatement, startIndex: Int): Int { + var index = startIndex + for (element in elements) { + val lastIndex = index + index = element.appendToStatement(stmt, index) + require(lastIndex <= index) { "$element just tried to go back in time $index < $lastIndex" } + } + return index + + } + } + } + fun standalone(sql: String): SQLQueryComponent { return object : SQLQueryComponent { override fun asSql(): String { diff --git a/database/core/src/main/kotlin/moe/nea/ledger/database/sql/TypedOperand.kt b/database/core/src/main/kotlin/moe/nea/ledger/database/sql/TypedOperand.kt index 57efe58..8a1f723 100644 --- a/database/core/src/main/kotlin/moe/nea/ledger/database/sql/TypedOperand.kt +++ b/database/core/src/main/kotlin/moe/nea/ledger/database/sql/TypedOperand.kt @@ -2,6 +2,6 @@ package moe.nea.ledger.database.sql import moe.nea.ledger.database.DBType -abstract class TypedOperand : Operand { - abstract val dbType: DBType +interface TypedOperand : Operand { + val dbType: DBType } -- cgit