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 a8e6a0d3..38780740 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 @@ -39,7 +39,8 @@ abstract class IdTable>(name: String = ""): Table(name) { * @param columnName name for a primary key, "id" by default */ open class IntIdTable(name: String = "", columnName: String = "id") : IdTable(name) { - override val id: Column> = integer(columnName).autoIncrement().primaryKey().entityId() + override val id: Column> = integer(columnName).autoIncrement().entityId() + override val primaryKey = PrimaryKey(id) } /** @@ -49,7 +50,8 @@ open class IntIdTable(name: String = "", columnName: String = "id") : IdTable(name) { - override val id: Column> = long(columnName).autoIncrement().primaryKey().entityId() + override val id: Column> = long(columnName).autoIncrement().entityId() + override val primaryKey = PrimaryKey(id) } /** @@ -63,7 +65,8 @@ open class LongIdTable(name: String = "", columnName: String = "id") : IdTable(name) { - override val id: Column> = uuid(columnName).primaryKey() + override val id: Column> = uuid(columnName) .autoGenerate() .entityId() + override val primaryKey = PrimaryKey(id) } diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Column.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Column.kt index 4ebe52b9..9281ba57 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Column.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Column.kt @@ -37,9 +37,9 @@ class Column(val table: Table, val name: String, override val columnType: ICo override fun createStatement(): List { val alterTablePrefix = "ALTER TABLE ${TransactionManager.current().identity(table)} ADD" - val isLastColumnInPK = table.primaryKey.columns.lastOrNull() == this + val isLastColumnInPK = table.primaryKey?.columns?.last() == this val columnDefinition = when { - isOneColumnPK() && table.isCustomPKNameDefined && isLastColumnInPK && currentDialect !is H2Dialect -> descriptionDdl() + ", ADD ${table.primaryKeyConstraint()}" + isOneColumnPK() && table.isCustomPKNameDefined() && isLastColumnInPK && currentDialect !is H2Dialect -> descriptionDdl() + ", ADD ${table.primaryKeyConstraint()}" isOneColumnPK() && (currentDialect is H2Dialect || currentDialect is SQLiteDialect) -> descriptionDdl().removeSuffix(" PRIMARY KEY") !isOneColumnPK() && isLastColumnInPK && currentDialect !is H2Dialect -> descriptionDdl() + ", ADD ${table.primaryKeyConstraint()}" else -> descriptionDdl() @@ -55,19 +55,19 @@ class Column(val table: Table, val name: String, override val columnType: ICo override fun dropStatement() = listOf(TransactionManager.current().let {"ALTER TABLE ${it.identity(table)} DROP COLUMN ${it.identity(this)}" }) - internal fun isOneColumnPK() = table.primaryKey.columns.singleOrNull() == this + internal fun isOneColumnPK() = table.primaryKey?.columns?.singleOrNull() == this fun descriptionDdl(): String = buildString { val tr = TransactionManager.current() append(tr.identity(this@Column)) append(" ") - val isPKColumn = table.primaryKey.columns.contains(this@Column) + val isPKColumn = table.primaryKey?.columns?.contains(this@Column) == true val colType = columnType val isSQLiteAutoIncColumn = currentDialect is SQLiteDialect && colType.isAutoInc when { !isPKColumn && isSQLiteAutoIncColumn -> tr.throwUnsupportedException("Auto-increment could be applied only to primary key column") - isSQLiteAutoIncColumn && !isOneColumnPK() && table.primaryKey.columns.isNotEmpty() -> append(currentDialect.dataTypeProvider.integerType()) + isSQLiteAutoIncColumn && !isOneColumnPK() && table.primaryKey != null -> append(currentDialect.dataTypeProvider.integerType()) else -> append(colType.sqlType()) } @@ -92,7 +92,7 @@ class Column(val table: Table, val name: String, override val columnType: ICo append(" NOT NULL") } - if (!table.isCustomPKNameDefined && isOneColumnPK() && !isSQLiteAutoIncColumn) { + if (!table.isCustomPKNameDefined() && isOneColumnPK() && !isSQLiteAutoIncColumn) { append(" PRIMARY KEY") } } diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Table.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Table.kt index b61b27f5..694a7f47 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Table.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Table.kt @@ -236,37 +236,27 @@ open class Table(name: String = ""): ColumnSet(), DdlAware { return newColumn } - var isCustomPKNameDefined = false + internal fun isCustomPKNameDefined() : Boolean = primaryKey?.let { it.name != "pk_$tableName" } == true /** * The primary key class. - */ - inner class PrimaryKey { - val columns: List> - val name: String - - /** - * Define the columns in the primary key of the current table. You can also provide the name of primary key constraint - * by passing the "name" argument. Example : PrimaryKey(id1, id2, id3..., name = "CustomPKName") - * - * @param columns list of columns in the primary key - * @param name the primary key constraint name, by default it will be resolved from the table name with "pk_" prefix - */ - constructor(vararg columns: Column<*>, name: String = "") { - this.columns = columns.toList() + * Define the columns in the primary key of the current table. You can also provide the name of primary key constraint + * by passing the "name" argument. Example : PrimaryKey(id1, id2, id3..., name = "CustomPKName") + * + * @param columns list of columns in the primary key + * @param name the primary key constraint name, by default it will be resolved from the table name with "pk_" prefix + */ + inner class PrimaryKey( + vararg val columns: Column<*>, + val name: String = "pk_$tableName" + ) { + init { checkMultipleDeclaration() for (column in columns) { column.markPrimaryKey() } - - if (name.isEmpty()) { - this.name = "pk_${tableName}" - } else { - this.name = name - isCustomPKNameDefined = true - } } /** @@ -274,10 +264,7 @@ open class Table(name: String = ""): ColumnSet(), DdlAware { * * This constructor must be removed when [primaryKey] method is no longer supported. */ - internal constructor(columns: List>) { - this.columns = columns - this.name = "pk_${tableName}" - } + internal constructor(columns: List>) : this(*columns.toTypedArray()) /** * Mark @receiver column as an element of primary key. @@ -309,14 +296,17 @@ open class Table(name: String = ""): ColumnSet(), DdlAware { } /** - * Represents the primary key of the table. It is initialized with existing keys. + * Represents the primary key of the table if present. + * It is initialized with existing keys defined by [Column.primaryKey] function for a backward compatibility, + * but you have to define it explicitly by overriding that val instead. */ - open val primaryKey by lazy { PrimaryKey(getPrimaryKeyColumns()) } + open val primaryKey: PrimaryKey? by lazy { getPrimaryKeyColumns()?.let { PrimaryKey(it) } } /** - * Returns the list of columns in the primary key. + * Returns the list of columns in the primary key if present. */ - private fun getPrimaryKeyColumns(): List> = columns.filter { it.indexInPK != null }.sortedWith(compareBy({ !it.columnType.isAutoInc }, { it.indexInPK })) + private fun getPrimaryKeyColumns(): List>? + = columns.filter { it.indexInPK != null }.sortedWith(compareBy({ !it.columnType.isAutoInc }, { it.indexInPK })).takeIf { it.isNotEmpty() } /** * Mark @receiver column as primary key. @@ -329,7 +319,7 @@ open class Table(name: String = ""): ColumnSet(), DdlAware { */ @Deprecated("This function will be no longer supported. Please use the new declarations of primary key by " + "overriding the primaryKey property in the current table. " + - "Example : object TableName : Table() { override val primaryKey = PrimaryKey(columns, name = \"CustomPKConstraintName\") }") + "Example : object TableName : Table() { override val primaryKey = PrimaryKey(column1, column2, name = \"CustomPKConstraintName\") }") fun Column.primaryKey(indx: Int? = null): Column { if (indx != null && table.columns.any { it.indexInPK == indx } ) throw IllegalArgumentException("Table $tableName already contains PK at $indx") indexInPK = indx ?: table.columns.count { it.indexInPK != null } + 1 @@ -716,7 +706,7 @@ open class Table(name: String = ""): ColumnSet(), DdlAware { append(TransactionManager.current().identity(this@Table)) if (columns.any()) { append(columns.joinToString(prefix = " (") { it.descriptionDdl() }) - if (isCustomPKNameDefined || columns.none { it.isOneColumnPK() }) { + if (isCustomPKNameDefined() || columns.none { it.isOneColumnPK() }) { primaryKeyConstraint()?.let { append(", $it") } @@ -749,17 +739,14 @@ open class Table(name: String = ""): ColumnSet(), DdlAware { } internal fun primaryKeyConstraint(): String? { - val pkey = primaryKey.columns - - if (pkey.isNotEmpty()) { + return primaryKey?.let { primaryKey -> val tr = TransactionManager.current() val constraint = tr.db.identifierManager.cutIfNecessaryAndQuote(primaryKey.name) - return pkey.joinToString( + return primaryKey.columns.joinToString( prefix = "CONSTRAINT $constraint PRIMARY KEY (", postfix = ")") { tr.identity(it) } } - return null } override fun dropStatement() : List {