Skip to content

Commit

Permalink
EVA-JOOQ enum constraint (#121)
Browse files Browse the repository at this point in the history
* EVA-JOOQ enum constraint

* regroup persistence exceptions

* regroup persistence exceptions
  • Loading branch information
Rattenkrieg committed Feb 14, 2024
1 parent dc82f3f commit 1ce61d2
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 44 deletions.
4 changes: 2 additions & 2 deletions buildSrc/src/main/kotlin/CI.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import java.lang.Boolean.parseBoolean

object Ci {

private const val SNAPSHOT_BASE = "0.6.0"
private const val RELEASE_VERSION = "0.5.8"
private const val SNAPSHOT_BASE = "0.7.0"
private const val RELEASE_VERSION = "0.6.0"
private val githubSha = System.getenv("GITHUB_SHA") ?: "latest"

val publishRelease = System.getProperty("release", "true").let(::parseBoolean)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class JdbcQueryExecutor(
.toTypedArray()
).coerce(table).fetch()

override fun getConstraintName(e: DataAccessException): String? {
return e.getCause(PSQLException::class.java)?.serverErrorMessage?.constraint
override fun getConstraintName(ex: DataAccessException): String? {
return ex.getCause(PSQLException::class.java)?.serverErrorMessage?.constraint
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,5 @@ class VertxQueryExecutor(
return record.into(table)
}

override fun getConstraintName(e: DataAccessException): String? = null
override fun getConstraintName(ex: DataAccessException): String? = null
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,28 @@ import java.util.UUID

sealed class PersistenceException(message: String) : RuntimeException(message) {

class UniqueModelRecordViolationException(
val modelId: ModelId<*>,
tableName: String,
sealed interface ConstraintViolation {
val constraintName: String?
) : PersistenceException(
}

open class UniqueModelRecordViolationException(
val modelId: ModelId<*>,
val tableName: String,
override val constraintName: String?
) : ConstraintViolation, PersistenceException(
"Uniqueness of [$tableName]:[${modelId.stringValue()}]" +
" violated ${constraintName?.let { ": [$it]" }}"
)

open class ModelRecordConstraintViolationException(
val modelId: ModelId<*>,
val tableName: String,
override val constraintName: String?
) : ConstraintViolation, PersistenceException(
"Constraint for [$tableName]:[${modelId.stringValue()}]" +
" violated ${constraintName?.let { ": [$it]" }}"
)

class UniqueUowEventRecordViolationException(
val uowId: UUID,
val uowName: String,
Expand All @@ -25,15 +38,6 @@ sealed class PersistenceException(message: String) : RuntimeException(message) {
" violated ${constraintName?.let { ": [$it]" }}"
)

class ModelRecordConstraintViolationException(
val modelId: ModelId<*>,
tableName: String,
val constraintName: String?
) : PersistenceException(
"Constraint for [$tableName]:[${modelId.stringValue()}]" +
" violated ${constraintName?.let { ": [$it]" }}"
)

class StaleRecordException(
val modelIds: Set<ModelId<*>>
) : PersistenceException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ interface QueryExecutor {
jooqQuery: DMLQuery<R>,
): Int

fun getConstraintName(e: DataAccessException): String?
fun getConstraintName(ex: DataAccessException): String?
}
Original file line number Diff line number Diff line change
Expand Up @@ -387,32 +387,52 @@ abstract class JooqBaseModelRepository<ID, MID, M, ME, R>(

private inline fun <R : Record, ME : M> wrapException(model: ME, block: () -> List<R>) = try {
block()
} catch (e: DataAccessException) {
} catch (ex: DataAccessException) {
when {
e.sqlState() == PgHelpers.PG_UNIQUE_VIOLATION -> {
val constraintName = PgHelpers.extractUniqueConstraintName(queryExecutor, table, e)
throw PersistenceException.UniqueModelRecordViolationException(model.id(), table.name, constraintName)
ex.sqlState() == PgHelpers.PG_UNIQUE_VIOLATION -> {
val constraintName = PgHelpers.extractUniqueConstraintName(queryExecutor, table, ex)
val uex = PersistenceException.UniqueModelRecordViolationException(
model.id(),
table.name,
constraintName,
)
throw mapConstraintViolation(uex) ?: uex
}
e.sqlStateClass() == SQLStateClass.C23_INTEGRITY_CONSTRAINT_VIOLATION -> {
val constraintName = PgHelpers.extractConstraintName(queryExecutor, e)
throw PersistenceException.ModelRecordConstraintViolationException(
ex.sqlStateClass() == SQLStateClass.C23_INTEGRITY_CONSTRAINT_VIOLATION -> {
val constraintName = PgHelpers.extractConstraintName(queryExecutor, ex)
val cex = PersistenceException.ModelRecordConstraintViolationException(
model.id(),
table.name,
constraintName
constraintName,
)
throw mapConstraintViolation(cex) ?: cex
}
else -> throw PersistenceException.ModelPersistingGenericException(model.id(), e)
else -> throw PersistenceException.ModelPersistingGenericException(model.id(), ex)
}
} catch (e: PgException) {
} catch (ex: PgException) {
when {
e.sqlState == PgHelpers.PG_UNIQUE_VIOLATION ->
throw PersistenceException.UniqueModelRecordViolationException(model.id(), table.name, e.constraint)
SQLStateClass.fromCode(e.sqlState) == SQLStateClass.C23_INTEGRITY_CONSTRAINT_VIOLATION ->
throw PersistenceException.ModelRecordConstraintViolationException(model.id(), table.name, e.constraint)
else -> throw PersistenceException.ModelPersistingGenericException(model.id(), e)
ex.sqlState == PgHelpers.PG_UNIQUE_VIOLATION -> {
val uex = PersistenceException.UniqueModelRecordViolationException(
model.id(),
table.name,
ex.constraint,
)
throw mapConstraintViolation(uex) ?: uex
}
SQLStateClass.fromCode(ex.sqlState) == SQLStateClass.C23_INTEGRITY_CONSTRAINT_VIOLATION -> {
val cex = PersistenceException.ModelRecordConstraintViolationException(
model.id(),
table.name,
ex.constraint,
)
throw mapConstraintViolation(cex) ?: cex
}
else -> throw PersistenceException.ModelPersistingGenericException(model.id(), ex)
}
}

protected open fun mapConstraintViolation(ex: PersistenceException.ConstraintViolation): Exception? = null

private companion object {
private const val MAX_RETURNED_RECORDS = 1000

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ class JooqEventRepository(
setRecord(toUERecord(uowEvent))
},
)
} catch (e: Exception) {
} catch (ex: Exception) {
val constraintName = when {
e is DataAccessException && e.sqlState() == PG_UNIQUE_VIOLATION ->
extractUniqueConstraintName(queryExecutor, UOW_EVENTS, e)
e is PgException && e.sqlState == PG_UNIQUE_VIOLATION -> e.constraint
else -> throw e
ex is DataAccessException && ex.sqlState() == PG_UNIQUE_VIOLATION ->
extractUniqueConstraintName(queryExecutor, UOW_EVENTS, ex)
ex is PgException && ex.sqlState == PG_UNIQUE_VIOLATION -> ex.constraint
else -> throw ex
}
throw UniqueUowEventRecordViolationException(
uowEvent.id.uuidValue(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ import org.jooq.exception.DataAccessException
object PgHelpers {
const val PG_UNIQUE_VIOLATION = "23505"

fun extractUniqueConstraintName(queryExecutor: QueryExecutor, table: Table<*>, e: DataAccessException): String? {
val constraintName = queryExecutor.getConstraintName(e)
fun extractUniqueConstraintName(queryExecutor: QueryExecutor, table: Table<*>, ex: DataAccessException): String? {
val constraintName = queryExecutor.getConstraintName(ex)
return if (table.comment == "PARTITIONED") {
constraintName
} else {
table.indexes.firstOrNull { it.unique && it.name == constraintName }?.name
}
}

fun extractConstraintName(queryExecutor: QueryExecutor, e: DataAccessException): String? {
return queryExecutor.getConstraintName(e)
fun extractConstraintName(queryExecutor: QueryExecutor, ex: DataAccessException): String? {
return queryExecutor.getConstraintName(ex)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,5 @@ class FakeMemorizingQueryExecutor(
}
}

override fun getConstraintName(e: DataAccessException): String? = null
override fun getConstraintName(ex: DataAccessException): String? = null
}

0 comments on commit 1ce61d2

Please sign in to comment.