Breaking Changes
0.56.0
If the
distinctparameter ofgroupConcat()is set totrue, when using Oracle or SQL Server, this will now fail early with anUnsupportedByDialectException. Previously, the setting would be ignored and SQL function generation would not include aDISTINCTclause.In Oracle and H2 Oracle, the
ubyte()column now maps to data typeNUMBER(3)instead ofNUMBER(4).In Oracle and H2 Oracle, the
ushort()column now maps to data typeNUMBER(5)instead ofNUMBER(6).In Oracle and H2 Oracle, the
uinteger()column now maps to data typeNUMBER(10)instead ofNUMBER(13).In Oracle and H2 Oracle, the
integer()column now maps to data typeNUMBER(10)andINTEGERrespectively, instead ofNUMBER(12). In Oracle and SQLite, using the integer column in a table now also creates a CHECK constraint to ensure that no out-of-range values are inserted.ArrayColumnTypenow supports multidimensional arrays and includes an additional generic parameter. If it was previously used for one-dimensional arrays with the parameterTlikeArrayColumnType<T>, it should now be defined asArrayColumnType<T, List<T>>. For instance,ArrayColumnType<Int>should now beArrayColumnType<Int, List<Int>>.EntityIDandCompositeIDno longer implementComparablethemselves, to allow their wrapped identity values to be of a type that is not necessarilyComparable, likekotlin.uuid.Uuid.Any use of an entity's
idwith Kotlin comparison operators orcompareTo()will now require that the wrapped value be used directly:entity1.id < entity2.idwill need to becomeentity1.id.value < entity2.id.value. Any use of an entity'sidwith an Exposed function that is also type restricted toComparable(for example,avg()) will also require defining a new function. In this event, please also leave a comment on YouTrack with a use case so the original function signature can be potentially reassessed.
0.55.0
The
DeleteStatementpropertytableis now deprecated in favor oftargetsSet, which holds aColumnSetthat may be aTableorJoin. This enables the use of the newJoin.delete()function, which performs a delete operation on a specific table from the join relation. The original statement class constructor has also been deprecated in favor of the constructor that acceptstargetsSet, as well as another additional parametertargetTables(for specifying which table from the join relation, if applicable, to delete from).The
DeleteStatementpropertyoffsetwas not being used and is now deprecated, as are the extension functions that have anoffsetparameter.deleteWhere()anddeleteIgnoreWhere(), as well as the original statement class constructor, no longer accept an argument foroffset.SizedIterable.limit(n, offset)is now deprecated in favor of 2 independent methods,limit()andoffset(). In supporting databases, this allows the generation of an OFFSET clause in the SELECT statement without any LIMIT clause. Any custom implementations of theSizedIterableinterface with alimit()override will now show a warning that the declaration overrides a deprecated member. This override should be split into an implementation of the 2 new members instead.The original
FunctionProvider.queryLimit()is also being deprecated in favor ofqueryLimitAndOffset(), which takes a nullablesizeparameter to allow exclusion of the LIMIT clause. This latter deprecation only affects extensions of theFunctionProviderclass when creating a customVendorDialectclass.In Oracle, the
shortcolumn now maps to data typeNUMBER(5)instead ofSMALLINTbecauseSMALLINTis stored asNUMBER(38)in the database and takes up unnecessary storage. In Oracle and SQLite, using theshortcolumn in a table now also creates a check constraint to ensure that no out-of-range values are inserted.In Oracle, the
bytecolumn now maps to data typeNUMBER(3)instead ofSMALLINTbecauseSMALLINTis stored asNUMBER(38)in the database and takes up unnecessary storage. In SQL Server, thebytecolumn now maps to data typeSMALLINTinstead ofTINYINTbecauseTINYINTallows values from 0 to 255. In SQL Server, SQLite, Oracle, PostgreSQL, and H2 PostgreSQL, using thebytecolumn in a table now also creates a check constraint to ensure that no out-of-range values are inserted.The transformation of a nullable column (
Column<Unwrapped?>.transform()) requires handling null values. This enables conversions fromnullto a non-nullable value, and vice versa.In H2 the definition of json column with default value changed from
myColumn JSON DEFAULT '{"key": "value"}'tomyColumn JSON DEFAULT JSON '{"key": "value"}'
0.54.0
All objects that are part of the sealed class
ForUpdateOptionare now converted todata object.The
onUpdateparameter inupsert(),upsertReturning(), andbatchUpsert()will no longer accept a list of column-value pairs as an argument. The parameter now takes a lambda block with anUpdateStatementas its argument, so that column-value assignments for the UPDATE clause can be set in a similar way toupdate(). This enables the use ofinsertValue(column)in expressions to specify that the same value to be inserted into a column should be used when updating.
The function
statementsRequiredForDatabaseMigrationhas been moved fromSchemaUtilstoMigrationUtilsin theexposed-migrationmodule.A nested transaction (with
useNestedTransactions = true) that throws any exception will now rollback any commits since the last savepoint. This ensures that the nested transaction is properly configured to act in the exact same way as a top-level transaction orinTopLevelTransaction().An inner transaction (with
useNestedTransactions = false) that throws any exception will also rollback any commits since the last savepoint. This ensures that any exception propagated from the inner transaction to the outer transaction will not be swallowed if caught by some exception handler wrapping the inner transaction, and any inner commits will not be saved. In version 0.55.0, this change will be reduced so that only inner transactions that throw anSQLExceptionfrom the database will trigger such a rollback.
0.53.0
DAO Entity Transformation Changes
Parameter Renaming:
transform()andmemoizedTransform()now usewrapandunwrapinstead oftoColumnandtoReal.// Old: var name by EmployeeTable.name.transform(toColumn = { it.uppercase() }, toReal = { it.lowercase() }) // New: var name by EmployeeTable.name.transform(wrap = { it.uppercase() }, unwrap = { it.lowercase() })Class Renaming:
ColumnWithTransformis nowEntityFieldWithTransform, consolidating properties into a singletransformer.EntityFieldWithTransform(column, object : ColumnTransformer<String, Int> { override fun unwrap(value: Int): String = value.toString() override fun wrap(value: String): Int = value.toInt() })Entity transformation via DAO is deprecated and should be replaced with DSL transformation.
val tester = object : Table() { val value = integer("value") .transform(wrap = { ... }, unwrap = { ... }) }
0.51.0
The
exposed-spring-boot-startermodule no longer provides the entire spring-boot-starter-data-jdbc module. It now provides just the spring-boot-starter-jdbc. If there was a reliance on this transitive dependency, please directly include a dependency on Spring Data JDBC in your build files.ulongcolumn type is now NUMERIC(20) instead of BIGINT for H2 (excluding H2_PSQL), SQLite, and SQL Server to allow storing the full range ofULong, includingULong.MAX_VALUE.
0.50.0
The
Transactionclass propertyrepetitionAttemptsis being deprecated in favor ofmaxAttempts. Additionally, the propertyminRepetitionDelayshould be replaced withminRetryDelay, andmaxRepetitionDelaywithmaxRetryDelay. These changes also affect the default variants of these properties inDatabaseConfig.The property
maxAttemptsrepresents the maximum amount of attempts to perform a transaction block. Setting it, or the now deprecatedrepetitionAttempts, to a value less than 1 now throws anIllegalArgumentException.IColumnTypeandColumnTypenow expect a type argument.IColumnType.valueFromDB()also no longer has a default implementation, so an override for this method must be provided in any custom column type implementation. Check this pull request for details regarding this change.
0.49.0
For SQLite database, Exposed now requires bumping the SQLite JDBC driver version to a minimum of 3.45.0.0.
0.48.0
In
nonNullValueToStringforKotlinInstantColumnTypeandJavaDateColumnType, the formatted String for MySQL did not match the format received from the metadata whenisFractionDateTimeSupportedis true, so a new formatter specific to that is now used.In
nonNullValueToStringforKotlinLocalDateTimeColumnType, the formatted String for MySQL did not match the format received from the metadata whenisFractionDateTimeSupportedis true, so a new formatter specific to MySQL is now used.In
nonNullValueToStringforDateColumnType,JavaLocalDateTimeColumnType,JavaLocalTimeColumnType,JavaInstantColumnType,KotlinLocalDateTimeColumnType,KotlinLocalTimeColumnType, andKotlinInstantColumnType, the correct formatter for MySQL is used when the version (below 5.6) does not support fractional seconds.In
nonNullValueToStringforDateColumnTypeandDateTimeWithTimeZoneColumnType, the formatters used are changed to reflect the fact that Joda-Time stores date/time values only down to the millisecond (up to SSS and not SSSSSS).Functions
anyFrom(array)andallFrom(array)now useArrayColumnTypeto process the provided array argument when query building.ArrayColumnTyperequires a base column type to process contents correctly, and Exposed attempts to resolve the best match internally based on the array content type. A specific column type argument should be provided to the function parameterdelegateTypeif the content requires either an unsupported or custom column type, or a column type not defined in theexposed-coremodule.exposed-cryptmodule now uses Spring Security Crypto 6.+, which requires Java 17 as a minimum version.
0.47.0
The function
SchemaUtils.checkExcessiveIndicesis used to check both excessive indices and excessive foreign key constraints. It now has a different behavior and deals with excessive indices only. Also, its return type is nowList<Index>instead ofUnit. A new function,SchemaUtils.checkExcessiveForeignKeyConstraints, deals with excessive foreign key constraints and has a return typeList<ForeignKeyConstraint>.
0.46.0
When an Exposed table object is created with a keyword identifier (a table or column name) it now retains the exact case used before being automatically quoted in generated SQL. This primarily affects H2 and Oracle, both of which support folding identifiers to uppercase, and PostgresSQL, which folds identifiers to a lower case.
If
preserveKeywordCasing = truehad been previously set inDatabaseConfigto remove logged warnings about any keyword identifiers, this can now be removed as the property istrueby default.To temporarily opt out of this behavior and to not keep the defined casing of keyword identifiers, please set
preserveKeywordCasing = falseinDatabaseConfig:
0.44.0
SpringTransactionManagerno longer extendsDataSourceTransactionManager; instead, it directly extendsAbstractPlatformTransactionManagerwhile retaining the previous basic functionality. The class also no longer implements the Exposed interfaceTransactionManager, as transaction operations are instead delegated to Spring. These changes ensure that Exposed's underlying transaction management no longer interferes with the expected behavior of Spring's transaction management, for example, when using nested transactions or with@Transactionalelements likepropagationorisolation.If integration still requires a
DataSourceTransactionManager, please add two bean declarations to the configuration: one forSpringTransactionManagerand one forDataSourceTransactionManager. Then define a composite transaction manager that combines these two managers.If
TransactionManagerfunctions were being invoked by aSpringTransactionManagerinstance, please replace these calls with the appropriate Spring annotation or, if necessary, by using the companion object ofTransactionManagerdirectly (for example,TransactionManager.currentOrNull()).spring-transactionandexposed-spring-boot-startermodules now use Spring Framework 6.0 and Spring Boot 3.0, which require Java 17 as a minimum version.A table that is created with a keyword identifier (a table or column name) now logs a warning that the identifier's case may be lost when it is automatically quoted in generated SQL. This primarily affects H2 and Oracle, both of which support folding identifiers to uppercase, and PostgreSQL, which folds identifiers to a lower case.
To remove these warnings and to ensure that the keyword identifier sent to the database matches the exact case used in the Exposed table object, please set
preserveKeywordCasing = trueinDatabaseConfig:
0.43.0
In all databases except MySQL, MariaDB, and SQL Server, the
ubyte()column now maps to data typeSMALLINTinstead ofTINYINT, which allows the full range ofUBytevalues to be inserted without any overflow. Registering the column on a table also creates a check constraint that restricts inserted data to the range between 0 andUByte.MAX_VALUE. If a column that only uses 1 byte of storage is needed, but without allowing any non-negative values to be inserted, please use a signedbyte()column instead with a manually created check constraint:
In all databases except MySQL and MariaDB, the
uint()column now maps to data typeBIGINTinstead ofINT, which allows the full range ofUIntvalues to be inserted without any overflow. Registering the column on a table also creates a check constraint that restricts inserted data to the range between 0 andUInt.MAX_VALUE. If a column that only uses 4 bytes of storage is needed, but without allowing any non-negative values to be inserted, please use a signedinteger()column instead with a manually created check constraint:
0.42.0
SQLite The table column created using
date()now uses TEXT datatype instead of DATE (which the database mapped internally to NUMERIC type). This applies to the specificDateColumnTypein all 3 date/time modules and meansLocalDatecomparisons can now be done directly without conversions.H2, PostgreSQL Using
replace()now throws an exception as the REPLACE command is not supported by these databases. Ifreplace()was being used to perform an insert or update operation, all usages should instead be switched toupsert(). See documentation for UPSERT detailsOperator classes
existsandnotExistshave been renamed toExistsandNotExists. The functionsexists()andnotExists()have been introduced to return an instance of their respectively-named classes and to avoid unresolved reference issues. Any usages of these classes should be renamed to their capitalized forms.customEnumeration()now registers aCustomEnumerationColumnTypeto allow referencing by another column. The signature ofcustomEnumeration()has not changed and table columns initialized using it are still of typeColumn<DataClass>.Transaction.suspendedTransaction()has been renamed toTransaction.withSuspendTransaction(). Please runEdit -> Find -> Replace in files...twice withsuspendedTransaction(andsuspendedTransactionas the search options, to ensure that both variants are replaced without affectingsuspendedTransactionAsync()(if used in code).The
repetitionAttemptsparameter intransaction()has been removed and replaced with a mutable property in theTransactionclass. Please remove any arguments for this parameter and assign values to the property directly:
In all databases except MySQL and MariaDB, the
ushort()column now maps to data typeINTinstead ofSMALLINT, which allows the full range ofUShortvalues to be inserted without any overflow. Registering the column on a table also creates a check constraint that restricts inserted data to the range between 0 andUShort.MAX_VALUE. If a column that only uses 2 bytes of storage is needed, but without allowing any non-negative values to be inserted, please use a signedshort()column instead with a manually created check constraint: