diff --git a/exposed-core/api/exposed-core.api b/exposed-core/api/exposed-core.api index 70f64567c1..470a86d324 100644 --- a/exposed-core/api/exposed-core.api +++ b/exposed-core/api/exposed-core.api @@ -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 ()V + public fun (Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (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 ()V public fun (Ljava/lang/String;Ljava/lang/String;)V diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/dao/id/IdTable.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/dao/id/IdTable.kt index ea32c70065..1daa3550dc 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/dao/id/IdTable.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/dao/id/IdTable.kt @@ -60,6 +60,18 @@ open class LongIdTable(name: String = "", columnName: String = "id") : IdTable(name) { + /** The identity column of this [ULongIdTable], for storing 8-byte unsigned integers wrapped as [EntityID] instances. */ + final override val id: Column> = ulong(columnName).autoIncrement().entityId() + final override val primaryKey = PrimaryKey(id) +} + /** * Identity table with a primary key consisting of an auto-generating [UUID] value. * diff --git a/exposed-dao/api/exposed-dao.api b/exposed-dao/api/exposed-dao.api index e72896f451..25f7a7514d 100644 --- a/exposed-dao/api/exposed-dao.api +++ b/exposed-dao/api/exposed-dao.api @@ -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 (Lorg/jetbrains/exposed/dao/id/EntityID;)V +} + +public abstract class org/jetbrains/exposed/dao/ULongEntityClass : org/jetbrains/exposed/dao/EntityClass { + public fun (Lorg/jetbrains/exposed/dao/id/IdTable;Ljava/lang/Class;Lkotlin/jvm/functions/Function1;)V + public synthetic fun (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 (Lorg/jetbrains/exposed/dao/id/EntityID;)V } diff --git a/exposed-dao/src/main/kotlin/org/jetbrains/exposed/dao/ULongEntity.kt b/exposed-dao/src/main/kotlin/org/jetbrains/exposed/dao/ULongEntity.kt new file mode 100644 index 0000000000..7341e74443 --- /dev/null +++ b/exposed-dao/src/main/kotlin/org/jetbrains/exposed/dao/ULongEntity.kt @@ -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) : Entity(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( + table: IdTable, + entityType: Class? = null, + entityCtor: ((EntityID) -> E)? = null +) : EntityClass(table, entityType, entityCtor) diff --git a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/entities/ULongIdTableEntityTest.kt b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/entities/ULongIdTableEntityTest.kt new file mode 100644 index 0000000000..cdd9fb1c1a --- /dev/null +++ b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/entities/ULongIdTableEntityTest.kt @@ -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("Mumbai")) + assertEquals(true, allCities.contains("Pune")) + assertEquals(false, allCities.contains("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("Mumbai")) + assertEquals(false, allCities.contains("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) : ULongEntity(id) { + companion object : ULongEntityClass(Cities) + + var name by Cities.name + } + + object People : ULongIdTable() { + val name = varchar("name", 80) + val cityId = reference("city_id", Cities) + } + + class Person(id: EntityID) : ULongEntity(id) { + companion object : ULongEntityClass(People) + + var name by People.name + var city by City referencedOn People.cityId + } +}