Skip to content

Commit

Permalink
docs: Add missing KDocs for exposed-core vendors API (#1892)
Browse files Browse the repository at this point in the history
* docs: Add missing KDocs for public exposed-core vendors API

Add KDocs to InListOps and vendor package files.
  • Loading branch information
bog-walk authored Nov 24, 2023
1 parent e32506d commit 84723ce
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ abstract class InListOrNotInListBaseOp<V> (
val expr: Any,
/** Returns the query to check against. */
val list: Iterable<V>,
/** Returns `true` if the check is inverted, `false` otherwise. */
/** Returns `false` if the check is inverted, `true` otherwise. */
val isInList: Boolean = true
) : Op<Boolean>(), ComplexExpression {

Expand Down Expand Up @@ -74,6 +74,11 @@ abstract class InListOrNotInListBaseOp<V> (
}
}

/**
* Represents an SQL operator that checks if a single-value [expr] is equal to any element from [list].
*
* To inverse the operator and check if [expr] is **not** in [list], set [isInList] to `false`.
*/
class SingleValueInListOp<T>(
expr: ExpressionWithColumnType<out T>,
list: Iterable<T>,
Expand All @@ -84,6 +89,11 @@ class SingleValueInListOp<T>(
override fun extractValues(value: T): List<Any?> = listOf(value)
}

/**
* Represents an SQL operator that checks if both values of a `Pair` [expr] match any element from [list].
*
* To inverse the operator and check if the `Pair` is **not** in [list], set [isInList] to `false`.
*/
class PairInListOp<T1, T2>(
expr: Pair<ExpressionWithColumnType<T1>, ExpressionWithColumnType<T2>>,
list: Iterable<Pair<T1, T2>>,
Expand All @@ -94,6 +104,11 @@ class PairInListOp<T1, T2>(
override fun extractValues(value: Pair<T1, T2>): List<Any?> = listOf(value.first, value.second)
}

/**
* Represents an SQL operator that checks if all values of a `Triple` [expr] match any element from [list].
*
* To inverse the operator and check if the `Triple` is **not** in [list], set [isInList] to `false`.
*/
class TripleInListOp<T1, T2, T3>(
expr: Triple<ExpressionWithColumnType<T1>, ExpressionWithColumnType<T2>, ExpressionWithColumnType<T3>>,
list: Iterable<Triple<T1, T2, T3>>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ abstract class DataTypeProvider {
/** Binary type for storing [UUID]. */
open fun uuidType(): String = "BINARY(16)"

/** Returns a database-compatible object from the specified UUID [value]. */
@Suppress("MagicNumber")
open fun uuidToDB(value: UUID): Any =
ByteBuffer.allocate(16).putLong(value.mostSignificantBits).putLong(value.leastSignificantBits).array()
Expand Down Expand Up @@ -144,6 +145,7 @@ abstract class DataTypeProvider {
else -> "($e)"
}

/** Returns the SQL representation of the specified [expression], to be used in an ORDER BY clause. */
open fun precessOrderByClause(queryBuilder: QueryBuilder, expression: Expression<*>, sortOrder: SortOrder) {
queryBuilder.append((expression as? ExpressionAlias<*>)?.alias ?: expression, " ", sortOrder.code)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ interface DatabaseDialect {

/** Returns`true` if the dialect supports returning generated keys obtained from a sequence. */
val supportsSequenceAsGeneratedKeys: Boolean get() = supportsCreateSequence

/** Returns `true` if the dialect supports only returning generated keys that are identity columns. */
val supportsOnlyIdentifiersInGeneratedKeys: Boolean get() = false

/** Returns `true` if the dialect supports an upsert operation returning an affected-row value of 0, 1, or 2. */
Expand All @@ -49,22 +51,28 @@ interface DatabaseDialect {
/** Returns `true` if the dialect supports subqueries within a UNION/EXCEPT/INTERSECT statement */
val supportsSubqueryUnions: Boolean get() = false

/** Returns `true` if the dialect provides a special dummy DUAL table, accessible by all users. */
val supportsDualTableConcept: Boolean get() = false

/** Returns `true` if the dialect provides options to configure how nulls are sorted compared to non-null values. */
val supportsOrderByNullsFirstLast: Boolean get() = false

/** Returns `true` if the dialect supports window function definitions with GROUPS mode in frame clause */
val supportsWindowFrameGroupsMode: Boolean get() = false

/** Returns `true` if the dialect supports using the ON UPDATE clause with a foreign key constraint. */
val supportsOnUpdate: Boolean get() = true

/** Returns `true` if the dialect supports the SET DEFAULT action as part of a foreign key constraint clause. */
val supportsSetDefaultReferenceOption: Boolean get() = true

/** Returns `true` if the dialect supports the RESTRICT action as part of a foreign key constraint clause. */
val supportsRestrictReferenceOption: Boolean get() = true

/** Returns a mapping of dialect-specific characters to be escaped when used alongside the LIKE operator. */
val likePatternSpecialChars: Map<Char, Char?> get() = defaultLikePatternSpecialChars

/** Returns true if autoCommit should be enabled to create/drop database */
/** Returns true if autoCommit should be enabled to create/drop a database. */
val requiresAutoCommitOnCreateDrop: Boolean get() = false

/** Returns the name of the current database. */
Expand Down Expand Up @@ -112,32 +120,38 @@ interface DatabaseDialect {

// Specific SQL statements

/** Returns the SQL command that creates the specified [index]. */
/** Returns the SQL statement that creates the specified [index]. */
fun createIndex(index: Index): String

/** Returns the SQL command that drops the specified [indexName] from the specified [tableName]. */
/** Returns the SQL statement that drops the specified [indexName] from the specified [tableName]. */
fun dropIndex(tableName: String, indexName: String, isUnique: Boolean, isPartialOrFunctional: Boolean): String

/** Returns the SQL command that modifies the specified [column]. */
/** Returns the SQL statement that modifies the specified [column]. */
fun modifyColumn(column: Column<*>, columnDiff: ColumnDiff): List<String>

/** Returns the SQL command that adds a primary key specified [pkName] to an existing [table]. */
/** Returns the SQL statement that adds a primary key specified [pkName] to an existing [table]. */
fun addPrimaryKey(table: Table, pkName: String?, vararg pkColumns: Column<*>): String

/** Returns the SQL statement that creates a database with the specified [name]. */
fun createDatabase(name: String) = "CREATE DATABASE IF NOT EXISTS ${name.inProperCase()}"

/** Returns the SQL query that retrieves a set of existing databases. */
fun listDatabases(): String = "SHOW DATABASES"

/** Returns the SQL statement that drops the database with the specified [name]. */
fun dropDatabase(name: String) = "DROP DATABASE IF EXISTS ${name.inProperCase()}"

/** Returns the SQL statement that sets the current schema to the specified [schema]. */
fun setSchema(schema: Schema): String = "SET SCHEMA ${schema.identifier}"

/** Returns the SQL statement that creates the specified [schema]. */
fun createSchema(schema: Schema): String = buildString {
append("CREATE SCHEMA IF NOT EXISTS ")
append(schema.identifier)
appendIfNotNull(" AUTHORIZATION ", schema.authorization)
}

/** Returns the SQL statement that drops the specified [schema], as well as all its objects if [cascade] is `true`. */
fun dropSchema(schema: Schema, cascade: Boolean): String = buildString {
append("DROP SCHEMA IF EXISTS ", schema.identifier)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,45 @@ package org.jetbrains.exposed.sql.vendors

import org.jetbrains.exposed.sql.Table

/**
* Clauses that perform a locking read at row-level for SELECT statements.
*
* @sample org.jetbrains.exposed.sql.tests.postgresql.PostgresqlTests.testForUpdateOptionsSyntax
*/
sealed class ForUpdateOption(open val querySuffix: String) {

internal object NoForUpdateOption : ForUpdateOption("") {
override val querySuffix: String get() = error("querySuffix should not be called for NoForUpdateOption object")
}

/** Common clause that locks the rows retrieved by a SELECT statement against concurrent updates. */
object ForUpdate : ForUpdateOption("FOR UPDATE")

// https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html for clarification
object MySQL {
/** MySQL clause that acquires a shared lock for each row retrieved. */
object ForShare : ForUpdateOption("FOR SHARE")

/** This MySQL clause is equivalent to [ForShare] but exists for backward compatibility. */
object LockInShareMode : ForUpdateOption("LOCK IN SHARE MODE")
}

// https://mariadb.com/kb/en/select/#lock-in-share-modefor-update
object MariaDB {
/** MariaDB clause that acquires a shared lock for each row retrieved. */
object LockInShareMode : ForUpdateOption("LOCK IN SHARE MODE")
}

// https://www.postgresql.org/docs/current/sql-select.html
// https://www.postgresql.org/docs/12/explicit-locking.html#LOCKING-ROWS for clarification
object PostgreSQL {
/** Optional modes that determine what should happen if the retrieved rows are not immediately available. */
enum class MODE(val statement: String) {
NO_WAIT("NOWAIT"), SKIP_LOCKED("SKIP LOCKED")
/** Indicates that an error should be reported. */
NO_WAIT("NOWAIT"),

/** Indicates that the unavailable rows should be skipped. */
SKIP_LOCKED("SKIP LOCKED")
}

abstract class ForUpdateBase(
Expand All @@ -47,25 +61,29 @@ sealed class ForUpdateOption(open val querySuffix: String) {
final override val querySuffix: String = preparedQuerySuffix
}

/** PostgreSQL clause that locks the rows retrieved as though for update. */
class ForUpdate(
mode: MODE? = null,
vararg ofTables: Table
) : ForUpdateBase("FOR UPDATE", mode, ofTables = ofTables)

/** PostgreSQL clause that locks the rows retrieved, but at a weaker strength than [ForUpdate]. */
open class ForNoKeyUpdate(
mode: MODE? = null,
vararg ofTables: Table
) : ForUpdateBase("FOR NO KEY UPDATE", mode, ofTables = ofTables) {
companion object : ForNoKeyUpdate()
}

/** PostgreSQL clause that acquires a shared lock for each row retrieved. */
open class ForShare(
mode: MODE? = null,
vararg ofTables: Table
) : ForUpdateBase("FOR SHARE", mode, ofTables = ofTables) {
companion object : ForShare()
}

/** PostgreSQL clause that acquires a shared lock for each row, but at a weaker strength than [ForShare]. */
open class ForKeyShare(
mode: MODE? = null,
vararg ofTables: Table
Expand All @@ -76,8 +94,10 @@ sealed class ForUpdateOption(open val querySuffix: String) {

// https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_10002.htm#i2066346
object Oracle {
/** Oracle clause that never waits to acquire a row lock. */
object ForUpdateNoWait : ForUpdateOption("FOR UPDATE NOWAIT")

/** Oracle clause that waits for the provided timeout until the row becomes available. */
class ForUpdateWait(timeout: Int) : ForUpdateOption("FOR UPDATE WAIT $timeout")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ abstract class FunctionProvider {
*
* @param ignore Whether to ignore errors or not.
* @param table Table to delete rows from.
* @param where Condition that decides the rows to update.
* @param where Condition that decides the rows to delete.
* @param limit Maximum number of rows to delete.
* @param transaction Transaction where the operation is executed.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,17 @@ open class H2Dialect : VendorDialect(dialectName, H2DataTypeProvider, H2Function
}
}

/** Indicates whether the H2 Database Engine version is greater than or equal to 2.0. */
val isSecondVersion get() = majorVersion == H2MajorVersion.Two

private fun exactH2Version(transaction: Transaction): String = transaction.db.metadata { databaseProductVersion.substringBefore(" (") }

/** H2 database compatibility modes that emulate the behavior of other specific databases. */
enum class H2CompatibilityMode {
MySQL, MariaDB, SQLServer, Oracle, PostgreSQL
}

/** The specific database name that an H2 compatibility mode delegates to. */
val delegatedDialectNameProvider: DialectNameProvider? by lazy {
when (h2Mode) {
H2CompatibilityMode.MySQL -> MysqlDialect
Expand All @@ -170,18 +173,21 @@ open class H2Dialect : VendorDialect(dialectName, H2DataTypeProvider, H2Function
}
}

/** The regular H2 mode implementation of [FunctionProvider] instead of a delegated mode implementation. */
val originalFunctionProvider: FunctionProvider = H2FunctionProvider

override val functionProvider: FunctionProvider by lazy {
resolveDelegatedDialect()?.takeIf { it !is MysqlDialect }?.functionProvider ?: originalFunctionProvider
}

/** The regular H2 mode implementation of [DataTypeProvider] instead of a delegated mode implementation. */
val originalDataTypeProvider: DataTypeProvider = H2DataTypeProvider

override val dataTypeProvider: DataTypeProvider by lazy {
resolveDelegatedDialect()?.takeIf { it !is MysqlDialect }?.dataTypeProvider ?: originalDataTypeProvider
}

/** The H2 database compatibility mode retrieved from metadata. */
val h2Mode: H2CompatibilityMode? by lazy {
val (settingNameField, settingValueField) = when (majorVersion) {
H2MajorVersion.One -> "NAME" to "VALUE"
Expand Down Expand Up @@ -272,4 +278,5 @@ open class H2Dialect : VendorDialect(dialectName, H2DataTypeProvider, H2Function
companion object : DialectNameProvider("H2")
}

/** The current H2 database compatibility mode or `null` if the current database is not H2. */
val DatabaseDialect.h2Mode: H2Dialect.H2CompatibilityMode? get() = (this as? H2Dialect)?.h2Mode
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,10 @@ open class MysqlDialect : VendorDialect(dialectName, MysqlDataTypeProvider, Mysq

override val supportsSetDefaultReferenceOption: Boolean = false

/** Returns `true` if the MySQL JDBC connector version is greater than or equal to 5.6. */
fun isFractionDateTimeSupported(): Boolean = TransactionManager.current().db.isVersionCovers(BigDecimal("5.6"))

// Available from MySQL 8.0.19
/** Returns `true` if a MySQL JDBC connector is being used and its version is greater than or equal to 8.0. */
fun isTimeZoneOffsetSupported(): Boolean = (currentDialect !is MariaDBDialect) && isMysql8

override fun isAllowedAsColumnDefault(e: Expression<*>): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class PostgresqlTests : DatabaseTestsBase() {
}

@Test
fun `test for update options syntax`() {
fun testForUpdateOptionsSyntax() {
val id = 1

fun Query.city() = map { it[table.name] }.single()
Expand Down

0 comments on commit 84723ce

Please sign in to comment.