Skip to content

Commit

Permalink
feat: EXPOSED-310 Add support for ULongIdTable and ULongEntity (#2025)
Browse files Browse the repository at this point in the history
  • Loading branch information
joc-a committed Mar 13, 2024
1 parent 4d17f56 commit c8c7d26
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 0 deletions.
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/ULongIdTable : 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/UUIDTable : 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 @@ -60,6 +60,18 @@ open class LongIdTable(name: String = "", columnName: String = "id") : IdTable<L
final override val primaryKey = PrimaryKey(id)
}

/**
* Identity table with a primary key consisting of an auto-incrementing `ULong` 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 ULongIdTable(name: String = "", columnName: String = "id") : IdTable<ULong>(name) {
/** The identity column of this [ULongIdTable], for storing 8-byte unsigned integers wrapped as [EntityID] instances. */
final override val id: Column<EntityID<ULong>> = ulong(columnName).autoIncrement().entityId()
final override val primaryKey = PrimaryKey(id)
}

/**
* Identity table with a primary key consisting of an auto-generating [UUID] 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/ULongEntity : org/jetbrains/exposed/dao/Entity {
public fun <init> (Lorg/jetbrains/exposed/dao/id/EntityID;)V
}

public abstract class org/jetbrains/exposed/dao/ULongEntityClass : 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/UUIDEntity : 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 `ULong` value. */
abstract class ULongEntity(id: EntityID<ULong>) : Entity<ULong>(id)

/**
* Base class representing the [EntityClass] that manages [ULongEntity] 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 [ULongEntity] type. This can be left `null` if it is the class of type
* argument [E] provided to this [ULongEntityClass] instance. If this `ULongEntityClass` is defined as a companion
* object of a custom `ULongEntity` 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 a [ULongEntity] 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 `ULongEntityClass`
* is defined as a companion object of a custom `ULongEntity` 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 ULongEntityClass<out E : ULongEntity>(
table: IdTable<ULong>,
entityType: Class<E>? = null,
entityCtor: ((EntityID<ULong>) -> E)? = null
) : EntityClass<ULong, 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.ULongEntity
import org.jetbrains.exposed.dao.ULongEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.ULongIdTable
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 ULongIdTableEntityTest : DatabaseTestsBase() {

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

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

val allCities = ULongIdTables.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 = ULongIdTables.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(ULongIdTables.Cities, ULongIdTables.People) {
val mumbai = ULongIdTables.City.new { name = "Mumbai" }
val pune = ULongIdTables.City.new { name = "Pune" }
ULongIdTables.Person.new {
name = "David D'souza"
city = mumbai
}
ULongIdTables.Person.new {
name = "Tushar Mumbaikar"
city = mumbai
}
val tanu = ULongIdTables.Person.new {
name = "Tanu Arora"
city = pune
}

tanu.delete()
pune.delete()

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

val allPeople = ULongIdTables.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 ULongIdTables {
object Cities : ULongIdTable() {
val name = varchar("name", 50)
}

class City(id: EntityID<ULong>) : ULongEntity(id) {
companion object : ULongEntityClass<City>(Cities)

var name by Cities.name
}

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

class Person(id: EntityID<ULong>) : ULongEntity(id) {
companion object : ULongEntityClass<Person>(People)

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

0 comments on commit c8c7d26

Please sign in to comment.