Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: EXPOSED-316 Add support for UIntIdTable and UIntEntity #2026

Merged
merged 1 commit into from
Mar 15, 2024
Merged
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
8 changes: 8 additions & 0 deletions exposed-core/api/exposed-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ public class org/jetbrains/exposed/dao/id/LongIdTable : org/jetbrains/exposed/da
public final fun getPrimaryKey ()Lorg/jetbrains/exposed/sql/Table$PrimaryKey;
}

public class org/jetbrains/exposed/dao/id/UIntIdTable : org/jetbrains/exposed/dao/id/IdTable {
public fun <init> ()V
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getId ()Lorg/jetbrains/exposed/sql/Column;
public final fun getPrimaryKey ()Lorg/jetbrains/exposed/sql/Table$PrimaryKey;
}

public class org/jetbrains/exposed/dao/id/ULongIdTable : org/jetbrains/exposed/dao/id/IdTable {
public fun <init> ()V
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ open class IntIdTable(name: String = "", columnName: String = "id") : IdTable<In
final override val primaryKey = PrimaryKey(id)
}

/**
* Identity table with a primary key consisting of an auto-incrementing `UInt` value.
*
* @param name Table name. By default, this will be resolved from any class name with a "Table" suffix removed (if present).
* @param columnName Name for the primary key column. By default, "id" is used.
*/
open class UIntIdTable(name: String = "", columnName: String = "id") : IdTable<UInt>(name) {
/** The identity column of this [IntIdTable], for storing 4-byte unsigned integers wrapped as [EntityID] instances. */
final override val id: Column<EntityID<UInt>> = uinteger(columnName).autoIncrement().entityId()
final override val primaryKey = PrimaryKey(id)
}

/**
* Identity table with a primary key consisting of an auto-incrementing `Long` value.
*
Expand Down
9 changes: 9 additions & 0 deletions exposed-dao/api/exposed-dao.api
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,15 @@ public final class org/jetbrains/exposed/dao/Referrers : kotlin/properties/ReadO
public fun getValue (Lorg/jetbrains/exposed/dao/Entity;Lkotlin/reflect/KProperty;)Lorg/jetbrains/exposed/sql/SizedIterable;
}

public abstract class org/jetbrains/exposed/dao/UIntEntity : org/jetbrains/exposed/dao/Entity {
public fun <init> (Lorg/jetbrains/exposed/dao/id/EntityID;)V
}

public abstract class org/jetbrains/exposed/dao/UIntEntityClass : org/jetbrains/exposed/dao/EntityClass {
public fun <init> (Lorg/jetbrains/exposed/dao/id/IdTable;Ljava/lang/Class;Lkotlin/jvm/functions/Function1;)V
public synthetic fun <init> (Lorg/jetbrains/exposed/dao/id/IdTable;Ljava/lang/Class;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public abstract class org/jetbrains/exposed/dao/ULongEntity : org/jetbrains/exposed/dao/Entity {
public fun <init> (Lorg/jetbrains/exposed/dao/id/EntityID;)V
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.jetbrains.exposed.dao

import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IdTable

/** Base class for an [Entity] instance identified by an [id] comprised of a wrapped `UInt` value. */
abstract class UIntEntity(id: EntityID<UInt>) : Entity<UInt>(id)

/**
* Base class representing the [EntityClass] that manages [UIntEntity] instances and
* maintains their relation to the provided [table].
*
* @param [table] The [IdTable] object that stores rows mapped to entities of this class.
* @param [entityType] The expected [UIntEntity] type. This can be left `null` if it is the class of type
* argument [E] provided to this [UIntEntityClass] instance. If this `UIntEntityClass` is defined as a companion
* object of a custom `UIntEntity` class, the parameter will be set to this immediately enclosing class by default.
* @sample org.jetbrains.exposed.sql.tests.shared.DDLTests.testDropTableFlushesCache
* @param [entityCtor] The function invoked to instantiate an [UIntEntity] using a provided [EntityID] value.
* If a reference to a specific constructor or a custom function is not passed as an argument, reflection will
* be used to determine the primary constructor of the associated entity class on first access. If this `UIntEntityClass`
* is defined as a companion object of a custom `UIntEntity` class, the constructor will be set to that of the
* immediately enclosing class by default.
* @sample org.jetbrains.exposed.sql.tests.shared.entities.EntityTests.testExplicitEntityConstructor
*/
abstract class UIntEntityClass<out E : UIntEntity>(
table: IdTable<UInt>,
entityType: Class<E>? = null,
entityCtor: ((EntityID<UInt>) -> E)? = null
) : EntityClass<UInt, E>(table, entityType, entityCtor)
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package org.jetbrains.exposed.sql.tests.shared.entities

import org.jetbrains.exposed.dao.UIntEntity
import org.jetbrains.exposed.dao.UIntEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.UIntIdTable
import org.jetbrains.exposed.sql.exists
import org.jetbrains.exposed.sql.tests.DatabaseTestsBase
import org.jetbrains.exposed.sql.tests.shared.assertEquals
import org.junit.Test

class UIntIdTableEntityTest : DatabaseTestsBase() {

@Test
fun `create tables`() {
withTables(UIntIdTables.Cities, UIntIdTables.People) {
assertEquals(true, UIntIdTables.Cities.exists())
assertEquals(true, UIntIdTables.People.exists())
}
}

@Test
fun `create records`() {
withTables(UIntIdTables.Cities, UIntIdTables.People) {
val mumbai = UIntIdTables.City.new { name = "Mumbai" }
val pune = UIntIdTables.City.new { name = "Pune" }
UIntIdTables.Person.new {
name = "David D'souza"
city = mumbai
}
UIntIdTables.Person.new {
name = "Tushar Mumbaikar"
city = mumbai
}
UIntIdTables.Person.new {
name = "Tanu Arora"
city = pune
}

val allCities = UIntIdTables.City.all().map { it.name }
assertEquals(true, allCities.contains<String>("Mumbai"))
assertEquals(true, allCities.contains<String>("Pune"))
assertEquals(false, allCities.contains<String>("Chennai"))

val allPeople = UIntIdTables.Person.all().map { Pair(it.name, it.city.name) }
assertEquals(true, allPeople.contains(Pair("David D'souza", "Mumbai")))
assertEquals(false, allPeople.contains(Pair("David D'souza", "Pune")))
}
}

@Test
fun `update and delete records`() {
withTables(UIntIdTables.Cities, UIntIdTables.People) {
val mumbai = UIntIdTables.City.new { name = "Mumbai" }
val pune = UIntIdTables.City.new { name = "Pune" }
UIntIdTables.Person.new {
name = "David D'souza"
city = mumbai
}
UIntIdTables.Person.new {
name = "Tushar Mumbaikar"
city = mumbai
}
val tanu = UIntIdTables.Person.new {
name = "Tanu Arora"
city = pune
}

tanu.delete()
pune.delete()

val allCities = UIntIdTables.City.all().map { it.name }
assertEquals(true, allCities.contains<String>("Mumbai"))
assertEquals(false, allCities.contains<String>("Pune"))

val allPeople = UIntIdTables.Person.all().map { Pair(it.name, it.city.name) }
assertEquals(true, allPeople.contains(Pair("David D'souza", "Mumbai")))
assertEquals(false, allPeople.contains(Pair("Tanu Arora", "Pune")))
}
}
}

object UIntIdTables {
object Cities : UIntIdTable() {
val name = varchar("name", 50)
}

class City(id: EntityID<UInt>) : UIntEntity(id) {
companion object : UIntEntityClass<City>(Cities)

var name by Cities.name
}

object People : UIntIdTable() {
val name = varchar("name", 80)
val cityId = reference("city_id", Cities)
}

class Person(id: EntityID<UInt>) : UIntEntity(id) {
companion object : UIntEntityClass<Person>(People)

var name by People.name
var city by City referencedOn People.cityId
}
}
Loading