Skip to content

Commit

Permalink
feat!: Change all entity type paramaters from Comparable to Any
Browse files Browse the repository at this point in the history
- EntityID still implements Comparable interface itself
  • Loading branch information
bog-walk committed Oct 16, 2024
1 parent b0a7aed commit 85a6013
Show file tree
Hide file tree
Showing 23 changed files with 171 additions and 164 deletions.
50 changes: 25 additions & 25 deletions exposed-core/api/exposed-core.api

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import org.jetbrains.exposed.sql.Column

/** Class representing a mapping of each composite primary key column to its stored identity value. */
class CompositeID private constructor() : Comparable<CompositeID> {
internal val values: MutableMap<Column<*>, Comparable<*>?> = HashMap()
internal val values: MutableMap<Column<*>, Any?> = HashMap()

@Suppress("UNCHECKED_CAST")
@JvmName("setWithEntityIdValue")
operator fun <T : Comparable<T>, ID : EntityID<T>> set(column: Column<ID>, value: T) {
operator fun <T : Any, ID : EntityID<T>> set(column: Column<ID>, value: T) {
require(values.isEmpty() || values.keys.first().table == column.table) {
"CompositeID key columns must all come from the same IdTable ${values.keys.first().table.tableName}"
}
Expand All @@ -17,23 +17,23 @@ class CompositeID private constructor() : Comparable<CompositeID> {

@Suppress("UNCHECKED_CAST")
@JvmName("setWithNullableEntityIdValue")
operator fun <T : Comparable<T>, ID : EntityID<T>> set(column: Column<ID?>, value: T?) {
operator fun <T : Any, ID : EntityID<T>> set(column: Column<ID?>, value: T?) {
require(column.columnType.nullable || value != null) {
"Trying to set null to not nullable column $column"
}
values[column] = value?.let { EntityID(value, column.table as IdTable<T>) }
}

@JvmName("setWithEntityID")
operator fun <T : Comparable<T>, ID : EntityID<T>> set(column: Column<ID>, value: ID) {
operator fun <T : Any, ID : EntityID<T>> set(column: Column<ID>, value: ID) {
require(values.isEmpty() || values.keys.first().table == column.table) {
"CompositeID key columns must all come from the same IdTable ${values.keys.first().table.tableName}"
}
values[column] = value
}

@Suppress("UNCHECKED_CAST")
operator fun <T : Comparable<T>> get(column: Column<T>): T = values[column] as T
operator fun <T : Any> get(column: Column<T>): T = values[column] as T

operator fun contains(column: Column<*>): Boolean = values.contains(column)

Expand All @@ -56,7 +56,10 @@ class CompositeID private constructor() : Comparable<CompositeID> {

values.entries.forEach { (column, idValue) ->
if (!other.values.containsKey(column)) return -1
compareValues(idValue, other.values[column]).let {
require(idValue is Comparable<*>) { "This stored identity value must implement Comparable" }
val otherValue = other.values[column]
require(otherValue is Comparable<*>) { "This stored identity value must implement Comparable" }
compareValues(idValue, otherValue).let {
if (it != 0) return it
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ package org.jetbrains.exposed.dao.id
* @sample org.jetbrains.exposed.sql.tests.shared.entities.EntityTestsData.YTable
* @sample org.jetbrains.exposed.sql.tests.shared.dml.InsertTests.testInsertWithPredefinedId
*/
open class EntityID<T : Comparable<T>> protected constructor(val table: IdTable<T>, id: T?) : Comparable<EntityID<T>> {
open class EntityID<T : Any> protected constructor(val table: IdTable<T>, id: T?) : Comparable<EntityID<T>> {
constructor(id: T, table: IdTable<T>) : this(table, id)

@Suppress("VariableNaming")
Expand Down Expand Up @@ -42,5 +42,9 @@ open class EntityID<T : Comparable<T>> protected constructor(val table: IdTable<
return other._value == _value && other.table == table
}

override fun compareTo(other: EntityID<T>): Int = value.compareTo(other.value)
override fun compareTo(other: EntityID<T>): Int {
require(value is Comparable<*>) { "This stored identity value must implement Comparable" }
require(other.value is Comparable<*>) { "The other stored identity value must implement Comparable" }
return (value as Comparable<T>).compareTo(other.value)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import java.util.*
/** Base class representing a producer of [EntityID] instances. */
interface EntityIDFactory {
/** Returns a new [EntityID] that holds a [value] of type [T], for the specified [table]. */
fun <T : Comparable<T>> createEntityID(value: T, table: IdTable<T>): EntityID<T>
fun <T : Any> createEntityID(value: T, table: IdTable<T>): EntityID<T>
}

/** Class responsible for locating and providing the appropriate functions to produce [EntityID] instances. */
Expand All @@ -16,37 +16,37 @@ object EntityIDFunctionProvider {
init {
factory = ServiceLoader.load(EntityIDFactory::class.java, EntityIDFactory::class.java.classLoader).firstOrNull()
?: object : EntityIDFactory {
override fun <T : Comparable<T>> createEntityID(value: T, table: IdTable<T>): EntityID<T> {
override fun <T : Any> createEntityID(value: T, table: IdTable<T>): EntityID<T> {
return EntityID(value, table)
}
}
}

/** Returns a new [EntityID] that holds a [value] of type [T], for the specified [table]. */
fun <T : Comparable<T>> createEntityID(value: T, table: IdTable<T>) = factory.createEntityID(value, table)
fun <T : Any> createEntityID(value: T, table: IdTable<T>) = factory.createEntityID(value, table)
}

/**
* Base class for an identity table, which could be referenced from other tables.
*
* @param name Table name. By default, this will be resolved from any class name with a "Table" suffix removed (if present).
*/
abstract class IdTable<T : Comparable<T>>(name: String = "") : Table(name) {
abstract class IdTable<T : Any>(name: String = "") : Table(name) {
/** The identity column of this [IdTable], for storing values of type [T] wrapped as [EntityID] instances. */
abstract val id: Column<EntityID<T>>

private val _idColumns = HashSet<Column<out Comparable<*>>>()
private val _idColumns = HashSet<Column<out Any>>()

/** All base columns that make up this [IdTable]'s identifier column. */
val idColumns: Set<Column<out Comparable<*>>>
val idColumns: Set<Column<out Any>>
get() = _idColumns.ifEmpty {
val message = "Table definition must include id columns. Please use Column.entityId() or IdTable.addIdColumn()."
exposedLogger.error(message)
error(message)
}

/** Adds a column to [idColumns] so that it can be used as a component of the [id] property. */
protected fun <S : Comparable<S>> addIdColumn(newColumn: Column<EntityID<S>>) {
protected fun <S : Any> addIdColumn(newColumn: Column<EntityID<S>>) {
if (_idColumns.isNotEmpty() && this !is CompositeIdTable) {
val message = "CompositeIdTable should be used if multiple EntityID key columns are required"
exposedLogger.error(message)
Expand All @@ -55,7 +55,7 @@ abstract class IdTable<T : Comparable<T>>(name: String = "") : Table(name) {
_idColumns.add(newColumn)
}

internal fun <S : Comparable<S>> addIdColumnInternal(newColumn: Column<EntityID<S>>) { addIdColumn(newColumn) }
internal fun <S : Any> addIdColumnInternal(newColumn: Column<EntityID<S>>) { addIdColumn(newColumn) }
}

/**
Expand Down Expand Up @@ -152,7 +152,7 @@ open class CompositeIdTable(name: String = "") : IdTable<CompositeID>(name) {
(toCompare as? EntityID<CompositeID>) ?: error("toCompare must be an EntityID<CompositeID> value")
return idColumns.map { column ->
val otherValue = if (column in toCompare.value.values) {
toCompare.value[column as Column<EntityID<Comparable<Any>>>]
toCompare.value[column as Column<EntityID<Any>>]
} else {
error("Comparison CompositeID is missing a key mapping for ${column.name}")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class Alias<out T : Table>(val delegate: T, val alias: String) : Table() {
delegateIdColumns.map { column ->
val delegateColumn = originalColumn(column)
val otherValue = if (delegateColumn in toCompare.value.values) {
toCompare.value[delegateColumn as Column<EntityID<Comparable<Any>>>]
toCompare.value[delegateColumn as Column<EntityID<Any>>]
} else {
error("Comparison CompositeID is missing a key mapping for ${delegateColumn?.name}")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ internal fun Column<*>.isEntityIdentifier(): Boolean {
/**
* Identity column type for storing unique [EntityID] values.
*/
class EntityIDColumnType<T : Comparable<T>>(
class EntityIDColumnType<T : Any>(
/** The underlying wrapped column storing the identity values. */
val idColumn: Column<T>
) : ColumnType<EntityID<T>>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ class QueryParameter<T>(
}

/** Returns the specified [value] as a query parameter with the same type as [column]. */
fun <T : Comparable<T>> idParam(value: EntityID<T>, column: Column<EntityID<T>>): Expression<EntityID<T>> =
fun <T : Any> idParam(value: EntityID<T>, column: Column<EntityID<T>>): Expression<EntityID<T>> =
QueryParameter(value, column.columnType)

/** Returns the specified [value] as a boolean query parameter. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ fun <T : Table> T.insert(body: T.(InsertStatement<Number>) -> Unit): InsertState
* @return The generated ID for the new row.
* @sample org.jetbrains.exposed.sql.tests.shared.dml.InsertTests.testGeneratedKey04
*/
fun <Key : Comparable<Key>, T : IdTable<Key>> T.insertAndGetId(body: T.(InsertStatement<EntityID<Key>>) -> Unit): EntityID<Key> =
fun <Key : Any, T : IdTable<Key>> T.insertAndGetId(body: T.(InsertStatement<EntityID<Key>>) -> Unit): EntityID<Key> =
InsertStatement<EntityID<Key>>(this, false).run {
body(this)
execute(TransactionManager.current())
Expand Down Expand Up @@ -381,7 +381,7 @@ fun <T : Table> T.insertIgnore(body: T.(UpdateBuilder<*>) -> Unit): InsertStatem
* @return The generated ID for the new row, or `null` if none was retrieved after statement execution.
* @sample org.jetbrains.exposed.sql.tests.shared.dml.InsertTests.testInsertIgnoreAndGetId01
*/
fun <Key : Comparable<Key>, T : IdTable<Key>> T.insertIgnoreAndGetId(body: T.(UpdateBuilder<*>) -> Unit): EntityID<Key>? =
fun <Key : Any, T : IdTable<Key>> T.insertIgnoreAndGetId(body: T.(UpdateBuilder<*>) -> Unit): EntityID<Key>? =
InsertStatement<EntityID<Key>>(this, isIgnore = true).run {
body(this)
when (execute(TransactionManager.current())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class ResultRow(
column?.isEntityIdentifier() == true && column.table is CompositeIdTable -> {
val resultID = CompositeID {
column.table.idColumns.forEach { column ->
it[column as Column<EntityID<Comparable<Any>>>] = getInternal(column, checkNullability = true).value
it[column as Column<EntityID<Any>>] = getInternal(column, checkNullability = true).value
}
}
EntityID(resultID, column.table) as T
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,8 @@ interface ISqlExpressionBuilder {
}

/** Checks if this [EntityID] expression is equal to some [t] value. */
infix fun <T : Comparable<T>, E : EntityID<T>?, V : T?> ExpressionWithColumnType<E>.eq(t: V): Op<Boolean> {
@JvmName("eqEntityIDValue")
infix fun <T : Any, E : EntityID<T>?, V : T?> ExpressionWithColumnType<E>.eq(t: V): Op<Boolean> {
if (t == null) return isNull()

@Suppress("UNCHECKED_CAST")
Expand All @@ -346,15 +347,15 @@ interface ISqlExpressionBuilder {
}

/** Checks if this [EntityID] expression is equal to some [other] expression. */
infix fun <T : Comparable<T>, E : EntityID<T>?, V : T?> ExpressionWithColumnType<E>.eq(
infix fun <T : Any, E : EntityID<T>?, V : T?> ExpressionWithColumnType<E>.eq(
other: Expression<V>
): Op<Boolean> = when (other as Expression<*>) {
is Op.NULL -> isNull()
else -> EqOp(this, other)
}

/** Checks if this expression is equal to some [other] [EntityID] expression. */
infix fun <T : Comparable<T>, V : T?, E : EntityID<T>?> Expression<V>.eq(
infix fun <T : Any, V : T?, E : EntityID<T>?> Expression<V>.eq(
other: ExpressionWithColumnType<E>
): Op<Boolean> = other eq this

Expand All @@ -376,7 +377,8 @@ interface ISqlExpressionBuilder {
}

/** Checks if this [EntityID] expression is not equal to some [t] value. */
infix fun <T : Comparable<T>, E : EntityID<T>?, V : T?> ExpressionWithColumnType<E>.neq(t: V): Op<Boolean> {
@JvmName("neqEntityIDValue")
infix fun <T : Any, E : EntityID<T>?, V : T?> ExpressionWithColumnType<E>.neq(t: V): Op<Boolean> {
if (t == null) return isNotNull()
@Suppress("UNCHECKED_CAST")
val table = (columnType as EntityIDColumnType<*>).idColumn.table as IdTable<T>
Expand All @@ -389,15 +391,15 @@ interface ISqlExpressionBuilder {
}

/** Checks if this [EntityID] expression is not equal to some [other] expression. */
infix fun <T : Comparable<T>, E : EntityID<T>?, V : T?> ExpressionWithColumnType<E>.neq(
infix fun <T : Any, E : EntityID<T>?, V : T?> ExpressionWithColumnType<E>.neq(
other: Expression<V>
): Op<Boolean> = when (other as Expression<*>) {
is Op.NULL -> isNotNull()
else -> NeqOp(this, other)
}

/** Checks if this expression is not equal to some [other] [EntityID] expression. */
infix fun <T : Comparable<T>, V : T?, E : EntityID<T>?> Expression<V>.neq(
infix fun <T : Any, V : T?, E : EntityID<T>?> Expression<V>.neq(
other: ExpressionWithColumnType<E>
): Op<Boolean> = other neq this

Expand Down Expand Up @@ -503,7 +505,7 @@ interface ISqlExpressionBuilder {
fun <T, S : T?> ExpressionWithColumnType<in S>.between(from: T, to: T): Between = Between(this, wrap(from), wrap(to))

/** Returns `true` if this [EntityID] expression is between the values [from] and [to], `false` otherwise. */
fun <T : Comparable<T>, E : EntityID<T>?> Column<E>.between(from: T, to: T): Between =
fun <T : Any, E : EntityID<T>?> Column<E>.between(from: T, to: T): Between =
Between(this, wrap(EntityID(from, this.idTable())), wrap(EntityID(to, this.idTable())))

/** Returns `true` if this expression is null, `false` otherwise. */
Expand Down Expand Up @@ -538,16 +540,16 @@ interface ISqlExpressionBuilder {

/** Checks if this expression is equal to some [t] value, with `null` treated as a comparable value */
@JvmName("isNotDistinctFromEntityID")
infix fun <T : Comparable<T>> Column<EntityID<T>>.isNotDistinctFrom(t: T): IsNotDistinctFromOp =
infix fun <T : Any> Column<EntityID<T>>.isNotDistinctFrom(t: T): IsNotDistinctFromOp =
IsNotDistinctFromOp(this, wrap(EntityID(t, this.idTable())))

/** Checks if this [EntityID] expression is equal to some [other] expression */
infix fun <T : Comparable<T>, E : EntityID<T>?, V : T?> ExpressionWithColumnType<E>.isNotDistinctFrom(
infix fun <T : Any, E : EntityID<T>?, V : T?> ExpressionWithColumnType<E>.isNotDistinctFrom(
other: Expression<in V>
): IsNotDistinctFromOp = IsNotDistinctFromOp(this, other)

/** Checks if this expression is equal to some [other] [EntityID] expression. */
infix fun <T : Comparable<T>, V : T?, E : EntityID<T>?> Expression<V>.isNotDistinctFrom(
infix fun <T : Any, V : T?, E : EntityID<T>?> Expression<V>.isNotDistinctFrom(
other: ExpressionWithColumnType<E>
): IsNotDistinctFromOp = IsNotDistinctFromOp(this, other)

Expand All @@ -560,16 +562,16 @@ interface ISqlExpressionBuilder {

/** Checks if this expression is not equal to some [t] value, with `null` treated as a comparable value */
@JvmName("isDistinctFromEntityID")
infix fun <T : Comparable<T>> Column<EntityID<T>>.isDistinctFrom(t: T): IsDistinctFromOp =
infix fun <T : Any> Column<EntityID<T>>.isDistinctFrom(t: T): IsDistinctFromOp =
IsDistinctFromOp(this, wrap(EntityID(t, this.idTable())))

/** Checks if this [EntityID] expression is not equal to some [other] expression */
infix fun <T : Comparable<T>, E : EntityID<T>?, V : T?> ExpressionWithColumnType<E>.isDistinctFrom(
infix fun <T : Any, E : EntityID<T>?, V : T?> ExpressionWithColumnType<E>.isDistinctFrom(
other: Expression<in V>
): IsDistinctFromOp = IsDistinctFromOp(this, other)

/** Checks if this expression is not equal to some [other] [EntityID] expression. */
infix fun <T : Comparable<T>, V : T?, E : EntityID<T>?> Expression<in V>.isDistinctFrom(
infix fun <T : Any, V : T?, E : EntityID<T>?> Expression<in V>.isDistinctFrom(
other: ExpressionWithColumnType<E>
): IsDistinctFromOp = IsDistinctFromOp(this, other)

Expand Down Expand Up @@ -923,7 +925,7 @@ interface ISqlExpressionBuilder {
infix fun List<Column<*>>.inList(list: Iterable<CompositeID>): InListOrNotInListBaseOp<List<*>> {
val componentList = list.map { id ->
List(this.size) { i ->
val component = id[this[i] as Column<Comparable<Any>>]
val component = id[this[i] as Column<Any>]
component.takeIf { this[i].columnType is EntityIDColumnType<*> } ?: (component as EntityID<*>).value
}
}
Expand All @@ -937,7 +939,7 @@ interface ISqlExpressionBuilder {
*/
@Suppress("UNCHECKED_CAST")
@JvmName("inListIds")
infix fun <T : Comparable<T>, ID : EntityID<T>?> Column<ID>.inList(list: Iterable<T>): InListOrNotInListBaseOp<EntityID<T>?> {
infix fun <T : Any, ID : EntityID<T>?> Column<ID>.inList(list: Iterable<T>): InListOrNotInListBaseOp<EntityID<T>?> {
val idTable = (columnType as EntityIDColumnType<T>).idColumn.table as IdTable<T>
return SingleValueInListOp(this, list.map { EntityIDFunctionProvider.createEntityID(it, idTable) }, isInList = true)
}
Expand Down Expand Up @@ -1003,7 +1005,7 @@ interface ISqlExpressionBuilder {
infix fun List<Column<*>>.notInList(list: Iterable<CompositeID>): InListOrNotInListBaseOp<List<*>> {
val componentList = list.map { id ->
List(this.size) { i ->
val component = id[this[i] as Column<Comparable<Any>>]
val component = id[this[i] as Column<Any>]
component.takeIf { this[i].columnType is EntityIDColumnType<*> } ?: (component as EntityID<*>).value
}
}
Expand All @@ -1017,7 +1019,7 @@ interface ISqlExpressionBuilder {
*/
@Suppress("UNCHECKED_CAST")
@JvmName("notInListIds")
infix fun <T : Comparable<T>, ID : EntityID<T>?> Column<ID>.notInList(list: Iterable<T>): InListOrNotInListBaseOp<EntityID<T>?> {
infix fun <T : Any, ID : EntityID<T>?> Column<ID>.notInList(list: Iterable<T>): InListOrNotInListBaseOp<EntityID<T>?> {
val idTable = (columnType as EntityIDColumnType<T>).idColumn.table as IdTable<T>
return SingleValueInListOp(this, list.map { EntityIDFunctionProvider.createEntityID(it, idTable) }, isInList = false)
}
Expand Down Expand Up @@ -1069,7 +1071,7 @@ interface ISqlExpressionBuilder {
fun ExpressionWithColumnType<Int>.intToDecimal(): NoOpConversion<Int, BigDecimal> =
NoOpConversion(this, DecimalColumnType(precision = 15, scale = 0))

private fun <T : Comparable<T>, E : EntityID<T>> Column<out E?>.idTable(): IdTable<T> =
private fun <T : Any, E : EntityID<T>> Column<out E?>.idTable(): IdTable<T> =
when (val table = this.foreignKey?.targetTable ?: this.table) {
is Alias<*> -> table.delegate
else -> table
Expand Down
Loading

0 comments on commit 85a6013

Please sign in to comment.