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

Add support for check constraints. #270

Merged
merged 6 commits into from
Mar 28, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 3 additions & 3 deletions src/main/kotlin/org/jetbrains/exposed/sql/Constraints.kt
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,17 @@ data class CheckConstraint(val tableName: String, val checkName: String, val che
}

override fun createStatement(): List<String> {
if (currentDialect is MysqlDialect) throw UnsupportedOperationException("Check constraints are not currently supported by MySQL")
if (currentDialect is MysqlDialect) exposedLogger.warn("CHECK constraints are not currently supported by MySQL")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more "idea": why not to return an empty list in a case when the database doesn't support constraints? With warn logging ofc.
Here and in dropStatements(). And you can remove any checks in modifyStatements().

return listOf("ALTER TABLE $tableName ADD$checkPart")
}

override fun dropStatement(): List<String> {
if (currentDialect is MysqlDialect) throw UnsupportedOperationException("Check constraints are not currently supported by MySQL")
if (currentDialect is MysqlDialect) throw UnsupportedOperationException("CHECK constraints are not currently supported by MySQL")
return listOf("ALTER TABLE $tableName DROP CONSTRAINT $checkName")
}

override fun modifyStatement(): List<String> {
if (currentDialect is MysqlDialect) throw UnsupportedOperationException("Check constraints are not currently supported by MySQL")
if (currentDialect is MysqlDialect) throw UnsupportedOperationException("CHECK constraints are not currently supported by MySQL")
return dropStatement() + createStatement()
}
}
Expand Down
20 changes: 12 additions & 8 deletions src/main/kotlin/org/jetbrains/exposed/sql/Table.kt
Original file line number Diff line number Diff line change
Expand Up @@ -404,21 +404,25 @@ open class Table(name: String = ""): ColumnSet(), DdlAware {
}

/**
* Creates a check constraint in this column
* @param name The name to identify the constraint, optional.
* @param op The expression that the value of this column must satisfy
* Creates a check constraint in this column.
* @param name The name to identify the constraint, optional. Must be **unique** (case-insensitive) to this table, otherwise, the constraint will
* not be created. All names are [trimmed][String.trim], blank names are ignored and the database engine decides the default name.
* @param op The expression against which the newly inserted values will be compared.
*/
fun <T> Column<T>.check(name: String = "", op: SqlExpressionBuilder.(Column<T>) -> Op<Boolean>) = apply {
table.checkConstraints.add(name to SqlExpressionBuilder.op(this))
table.checkConstraints.takeIf { name.isEmpty() || it.none { it.first.equals(name, true) } }?.add(name to SqlExpressionBuilder.op(this))
?: exposedLogger.warn("A CHECK constraint with name '$name' was ignored because there is already one with that name")
}

/**
* Creates a check constraint in this table
* @param name The name to identify the constraint, optional.
* @param op The expression that the values in certain columns must satisfy
* Creates a check constraint in this table.
* @param name The name to identify the constraint, optional. Must be **unique** (case-insensitive) to this table, otherwise, the constraint will
* not be created. All names are [trimmed][String.trim], blank names are ignored and the database engine decides the default name.
* @param op The expression against which the newly inserted values will be compared.
*/
fun check(name: String = "", op: SqlExpressionBuilder.() -> Op<Boolean>) {
checkConstraints.add(name to SqlExpressionBuilder.op())
checkConstraints.takeIf { name.isEmpty() || it.none { it.first.equals(name, true) } }?.add(name to SqlExpressionBuilder.op())
?: exposedLogger.warn("A CHECK constraint with name '$name' was ignored because there is already one with that name")
}

val ddl: List<String>
Expand Down
30 changes: 22 additions & 8 deletions src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/DDLTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ class DDLTests : DatabaseTestsBase() {
else -> "NULL"
}


withTables(TestTable) {
val dtType = currentDialect.dataTypeProvider.dateTimeType()
assertEquals("CREATE TABLE " + if (currentDialect.supportsIfNotExists) { "IF NOT EXISTS " } else { "" } +
Expand Down Expand Up @@ -384,11 +384,11 @@ class DDLTests : DatabaseTestsBase() {
}
}


private abstract class EntityTable(name: String = "") : IdTable<String>(name) {
override val id: Column<EntityID<String>> = varchar("id", 64).clientDefault { UUID.randomUUID().toString() }.primaryKey().entityId()
}

@Test fun complexTest01() {
val User = object : EntityTable() {
val name = varchar("name", 255)
Expand Down Expand Up @@ -482,10 +482,17 @@ class DDLTests : DatabaseTestsBase() {

assertEquals(1, checkTable.selectAll().count())

assertFailAndRollback("Check constraint") {
assertFailAndRollback("Check constraint 1") {
checkTable.insert {
it[positive] = -472
it[negative] = 354
it[negative] = -354
}
}

assertFailAndRollback("Check constraint 2") {
checkTable.insert {
it[positive] = 538
it[negative] = 915
}
}
}
Expand All @@ -509,10 +516,17 @@ class DDLTests : DatabaseTestsBase() {

assertEquals(1, checkTable.selectAll().count())

assertFailAndRollback("Check constraint") {
assertFailAndRollback("Check constraint 1") {
checkTable.insert {
it[positive] = -47
it[negative] = -35
}
}

assertFailAndRollback("Check constraint 2") {
checkTable.insert {
it[positive] = -14
it[negative] = 42
it[positive] = 53
it[negative] = 91
}
}
}
Expand Down