This library add named parameter, data object handling to Java's JDBC and other quality of life features. Support bean-style and all-args-style creation for DTO. Written to be easy to use for both Java and Kotlin users.
Add the latest maven dependency:
<dependency> <groupId>com.qualifiedcactus</groupId> <artifactId>sqlObjectMapper</artifactId> <version>4.1.3</version> </dependency>val sql = "select count(*) from table_1 where column_1 = :param_1" val count = connection.prepareStmt(sql).use {stmt-> stmt.setParametersByDto(ParamDto(1)) .executeThen() .processScalarResult(Long::class).firstOnly()!! } This library assumes that the column names is case-insensitive and the column names taken from java.sql.ResultSetMetaData.getColumnLabel() is always in UPPERCASE (which is the behaviour HSQL and Oracle JDBC's drivers).
Since this assumption might be wrong for other JDBC drivers which you might use, please use uppercase column names or use avoid using case-sensitive columns names when that happens.
val connection: Connection = dataSource.connection val sql = """ select column_1, column_2 from table_1 where column_1 = :param_1 and column_2 in :param_2[3] """ val stmt = connection.prepareStmt(sql) Note that the prepareStmt extension function belongs to the companion object of NpStatement. The sql string above will be translated to:
select column_1, column_2 from table_1 where column_1 = ? and column_2 in (?,?,?) :param_1 (simple parameter) is replaced with ? and :param_2[3] (expanded parameter) is replaced with (?,?,?). A named parameter can appear at multiple places. Using unnamed parameter (?) in a named-parameter SQL string is also possible, but it is not recommended to do so.
Use setParameter or setParametersByDto. An expanded parameter (which param_2 is) requires value to be castable to Collection<Any?> and the collection's size must be less or equal to the integer specified inside the square brackets.
You can set parameters directly:
stmt.setParameter("param_1", 1) stmt.setParameter("param_2", listOf(1,2,3))Or you can set parameters using a data object. Names of DTO's properties are automatically converted to snake-cased name. You can use annotations SqlParam, NestedParams or IgnoreParam from the package com.qualifiedcactus.sqlObjectMapper.toParam to customize your DTO.
data class Dto( val param1: Int, @NestedParams val nested: NestedDto, ) data class NestedDto( val param2: List<Int>, ) stmt.setParametersByDto(Dto( 1, NestedDto( listOf(1,2,3) ) ))Use NpStatement.processDtoResult for DTO and NpStatement.processScalarResult for scalar (first column's value). Both methods return a ResultSetProcessor<T>, which have these methods for getting the data:
toListandtoSetreturn a list and a set of data, respectively.firstOnlyreturns first row's data or null if there is no row.toStreamreturns a CLOSABLE stream of data, which is useful if your database driver supports setting fetch size.
data class ResultSetDto( val column1: Int, val column2: Int, ) val dtoList: List<ResultSetDto> = stmt.executeThen() .processDtoResult(ResultSetDto::class).toList()val scalarList: List<Int> = stmt.executeThen() .processScalarResult(Int::class).toList()You can feature specify your DTO using annotations RsColumn, RsNested, RsToMany (parent table left join child table query), RsRecursive (recursive common table expression query) and RsIgnore from the package com.qualifiedcactus.sqlObjectMapper.fromRs (see Javadocs for more details).
Create a statement with the extension function prepareStmtWithGeneratedKeys in NpStatement to tell JDBC to retrieve the generated key(s). Both single-columns and multi-columns key are supported by the classes SingleAutoGenKey and CompositeAutoGenKey in the package com.qualifiedcactus.sqlObjectMapper.fromRs.autoGenKeys.
Creating single-column generated key declaration:
val keyDeclaration = SingleAutoGenKey("column_1", Int::class)Creating multi-columns generated key declaration:
data class GenerateKeyDto( val column1: Int, val column2: Int, ) val keyDeclaration = CompositeAutoGenKey(GenerateKeyDto::class)Creating a statement with generated key:
val stmt = connection.prepareStmtWithGeneratedKeys(sqlString, keyDeclaration)Retrieve the key after statement's execution:
val resultSetProcessor = stmt.processAutoGenKeys()