From 56863e01961ea0eb0cb44c928b73ffecec5ed861 Mon Sep 17 00:00:00 2001 From: Ryan Brewster Date: Mon, 15 Jun 2020 04:38:26 -0700 Subject: [PATCH] Allow setting index_type (e.g., 'HASH' or 'BTREE') (#949) * Allow setting index_type (e.g., 'HASH' or 'BTREE') * review feedback * fix test compilation --- .../org/jetbrains/exposed/sql/Constraints.kt | 4 +- .../kotlin/org/jetbrains/exposed/sql/Table.kt | 5 +- .../jetbrains/exposed/sql/vendors/Default.kt | 5 ++ .../org/jetbrains/exposed/sql/vendors/H2.kt | 4 ++ .../exposed/sql/vendors/MariaDBDialect.kt | 5 +- .../exposed/sql/vendors/PostgreSQL.kt | 4 ++ .../exposed/sql/vendors/SQLiteDialect.kt | 4 ++ .../sql/tests/shared/ddl/CreateIndexTests.kt | 46 +++++++++++++++++++ 8 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/ddl/CreateIndexTests.kt diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Constraints.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Constraints.kt index 0102de1105..9353773b69 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Constraints.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Constraints.kt @@ -163,7 +163,9 @@ data class Index( /** Whether the index in unique or not. */ val unique: Boolean, /** Optional custom name for the index. */ - val customName: String? = null + val customName: String? = null, + /** Optional custom index type (e.g, BTREE or HASH) */ + val indexType: String? = null ) : DdlAware { /** Table where the index is defined. */ val table: Table 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 061043061a..17afa540f0 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 @@ -917,9 +917,10 @@ open class Table(name: String = "") : ColumnSet(), DdlAware { * @param customIndexName Name of the index. * @param columns Columns that compose the index. * @param isUnique Whether the index is unique or not. + * @param indexType A custom index type (e.g., "BTREE" or "HASH"). */ - fun index(customIndexName: String? = null, isUnique: Boolean = false, vararg columns: Column<*>) { - _indices.add(Index(columns.toList(), isUnique, customIndexName)) + fun index(customIndexName: String? = null, isUnique: Boolean = false, vararg columns: Column<*>, indexType: String? = null) { + _indices.add(Index(columns.toList(), isUnique, customIndexName, indexType = indexType)) } /** diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/Default.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/Default.kt index 0e7f3c0eae..9ae57c8677 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/Default.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/Default.kt @@ -708,10 +708,15 @@ abstract class VendorDialect( val columnsList = index.columns.joinToString(prefix = "(", postfix = ")") { t.identity(it) } return if (index.unique) { "ALTER TABLE $quotedTableName ADD CONSTRAINT $quotedIndexName UNIQUE $columnsList" + } else if (index.indexType != null) { + return createIndexWithType(name = quotedIndexName, table = quotedTableName, columns = columnsList, type = index.indexType) } else { "CREATE INDEX $quotedIndexName ON $quotedTableName $columnsList" } + } + protected open fun createIndexWithType(name: String, table: String, columns: String, type: String): String { + return "CREATE INDEX $name ON $table $columns USING $type" } override fun dropIndex(tableName: String, indexName: String): String { diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/H2.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/H2.kt index 80acda08f1..c05ebe08b5 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/H2.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/H2.kt @@ -146,6 +146,10 @@ open class H2Dialect : VendorDialect(dialectName, H2DataTypeProvider, H2Function exposedLogger.warn("Index on ${index.table.tableName} for ${index.columns.joinToString { it.name }} can't be created in H2") return "" } + if (index.indexType != null) { + exposedLogger.warn("Index of type ${index.indexType} on ${index.table.tableName} for ${index.columns.joinToString { it.name }} can't be created in H2") + return "" + } return super.createIndex(index) } diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/MariaDBDialect.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/MariaDBDialect.kt index a3d809ba5a..0b411d39f5 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/MariaDBDialect.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/MariaDBDialect.kt @@ -1,9 +1,6 @@ package org.jetbrains.exposed.sql.vendors -import org.jetbrains.exposed.sql.Expression -import org.jetbrains.exposed.sql.QueryBuilder -import org.jetbrains.exposed.sql.Sequence -import org.jetbrains.exposed.sql.append +import org.jetbrains.exposed.sql.* internal object MariaDBFunctionProvider : MysqlFunctionProvider() { override fun nextVal(seq: Sequence, builder: QueryBuilder) = builder { diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/PostgreSQL.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/PostgreSQL.kt index 9aaf6d8e99..16ba16661b 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/PostgreSQL.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/PostgreSQL.kt @@ -224,6 +224,10 @@ open class PostgreSQLDialect : VendorDialect(dialectName, PostgreSQLDataTypeProv override fun setSchema(schema: Schema): String = "SET search_path TO ${schema.identifier}" + override fun createIndexWithType(name: String, table: String, columns: String, type: String): String { + return "CREATE INDEX $name ON $table USING $type $columns" + } + companion object { /** PostgreSQL dialect name */ const val dialectName: String = "postgresql" diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/SQLiteDialect.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/SQLiteDialect.kt index e8016c7dac..a4bb1aeac0 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/SQLiteDialect.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/SQLiteDialect.kt @@ -137,6 +137,10 @@ open class SQLiteDialect : VendorDialect(dialectName, SQLiteDataTypeProvider, SQ override fun isAllowedAsColumnDefault(e: Expression<*>): Boolean = true override fun createIndex(index: Index): String { + if (index.indexType != null) { + exposedLogger.warn("Index of type ${index.indexType} on ${index.table.tableName} for ${index.columns.joinToString { it.name }} can't be created in SQLite") + return "" + } val originalCreateIndex = super.createIndex(index.copy(unique = false)) return if (index.unique) { originalCreateIndex.replace("CREATE INDEX", "CREATE UNIQUE INDEX") diff --git a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/ddl/CreateIndexTests.kt b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/ddl/CreateIndexTests.kt new file mode 100644 index 0000000000..b0ca0786f3 --- /dev/null +++ b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/ddl/CreateIndexTests.kt @@ -0,0 +1,46 @@ +package org.jetbrains.exposed.sql.tests.shared.ddl + +import org.jetbrains.exposed.sql.SchemaUtils +import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.sql.exists +import org.jetbrains.exposed.sql.tests.DatabaseTestsBase +import org.jetbrains.exposed.sql.tests.TestDB +import org.jetbrains.exposed.sql.tests.shared.assertTrue +import org.junit.Test + +class CreateIndexTests : DatabaseTestsBase() { + + @Test + fun createStandardIndex() { + val TestTable = object : Table("test_table") { + val id = integer("id") + val name = varchar("name", length = 42) + + override val primaryKey = PrimaryKey(id) + val byName = index("test_table_by_name", false, name) + } + + withTables(excludeSettings = listOf(TestDB.H2_MYSQL), tables = *arrayOf(TestTable)) { + SchemaUtils.createMissingTablesAndColumns(TestTable) + assertTrue(TestTable.exists()) + SchemaUtils.drop(TestTable) + } + } + + @Test + fun createHashIndex() { + val TestTable = object : Table("test_table") { + val id = integer("id") + val name = varchar("name", length = 42) + + override val primaryKey = PrimaryKey(id) + val byNameHash = index("test_table_by_name", /* isUnique = */ false, name, indexType = "HASH") + } + + withTables(excludeSettings = listOf(TestDB.H2_MYSQL), tables = *arrayOf(TestTable)) { + SchemaUtils.createMissingTablesAndColumns(TestTable) + assertTrue(TestTable.exists()) + SchemaUtils.drop(TestTable) + } + } +}