From 5b6d8607a66e6fdcd5838537995e7613778a15b3 Mon Sep 17 00:00:00 2001 From: Miha_x64 Date: Sat, 9 Dec 2017 18:52:13 +0300 Subject: [PATCH 01/12] Added Dialect.escapeColumnName(String): String function --- .../kotlin/com/github/andrewoma/kwery/core/dialect/Dialect.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/Dialect.kt b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/Dialect.kt index 273e89f..f947c7b 100644 --- a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/Dialect.kt +++ b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/Dialect.kt @@ -55,6 +55,8 @@ interface Dialect { .joinToString(" ") return sql + "\n" + limitAndOffset } + + fun escapeColumnName(columnName: String): String = columnName } internal fun String.truncate(limit: Int): String { From 30c43deac278949379fcc0832e4742a55172b6df Mon Sep 17 00:00:00 2001 From: Miha_x64 Date: Sat, 9 Dec 2017 18:52:35 +0300 Subject: [PATCH 02/12] implement escapeColumnName in PostgresDialect --- .../github/andrewoma/kwery/core/dialect/PostgresDialect.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/PostgresDialect.kt b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/PostgresDialect.kt index cf911c8..c2003e0 100644 --- a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/PostgresDialect.kt +++ b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/PostgresDialect.kt @@ -49,4 +49,8 @@ open class PostgresDialect : Dialect { "select nextval('$sequence') as $columnName from generate_series(1, $count)" override val supportsFetchingGeneratedKeysByName = true + + override fun escapeColumnName(columnName: String): String = + '"' + columnName.replace("\"", "\"\"") + '"' + } From 6b080e90c9a454c79dc1c88c7ed69a3fd866e8e4 Mon Sep 17 00:00:00 2001 From: Miha_x64 Date: Sat, 9 Dec 2017 19:11:49 +0300 Subject: [PATCH 03/12] implement escapeColumnName in MysqlDialect --- .../com/github/andrewoma/kwery/core/dialect/MysqlDialect.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/MysqlDialect.kt b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/MysqlDialect.kt index 54f68d5..3238be6 100644 --- a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/MysqlDialect.kt +++ b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/MysqlDialect.kt @@ -47,4 +47,8 @@ open class MysqlDialect : Dialect { override fun allocateIds(count: Int, sequence: String, columnName: String) = throw UnsupportedOperationException() override val supportsFetchingGeneratedKeysByName = false + + override fun escapeColumnName(columnName: String): String = + '`' + columnName.replace("`", "``") + '`' + } From c85b758e8975a8b1dcf004b624cd664e555e14ac Mon Sep 17 00:00:00 2001 From: Miha_x64 Date: Sat, 9 Dec 2017 19:12:04 +0300 Subject: [PATCH 04/12] using escapeColumnName in AbstractDao --- .../kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt index 4d63339..19f24d9 100644 --- a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt +++ b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt @@ -76,11 +76,11 @@ abstract class AbstractDao( } protected fun Iterable>.join(separator: String = ", ", f: (Column) -> String = nf): String { - return this.map { f(it) }.joinToString(separator) + return this.map { session.dialect.escapeColumnName(f(it)) }.joinToString(separator) } protected fun Iterable>.equate(separator: String = ", ", f: (Column) -> String = nf): String { - return this.map { "${f(it)} = :${f(it)}" }.joinToString(separator) + return this.map { "${session.dialect.escapeColumnName(f(it))} = :${f(it)}" }.joinToString(separator) } protected fun Collection.copyToSqlArray(): java.sql.Array { From 5ad8135c5de69d05307cedee0260c6060521b99c Mon Sep 17 00:00:00 2001 From: Miha_x64 Date: Sat, 23 Dec 2017 00:16:32 +0300 Subject: [PATCH 05/12] renamed escapeColumnName to escapeName, using it to escape table names too --- .../andrewoma/kwery/core/dialect/Dialect.kt | 2 +- .../kwery/core/dialect/MysqlDialect.kt | 2 +- .../kwery/core/dialect/PostgresDialect.kt | 2 +- .../andrewoma/kwery/mapper/AbstractDao.kt | 38 +++++++++++-------- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/Dialect.kt b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/Dialect.kt index f947c7b..c7c4d41 100644 --- a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/Dialect.kt +++ b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/Dialect.kt @@ -56,7 +56,7 @@ interface Dialect { return sql + "\n" + limitAndOffset } - fun escapeColumnName(columnName: String): String = columnName + fun escapeName(columnName: String): String = columnName } internal fun String.truncate(limit: Int): String { diff --git a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/MysqlDialect.kt b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/MysqlDialect.kt index 3238be6..b79a1a2 100644 --- a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/MysqlDialect.kt +++ b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/MysqlDialect.kt @@ -48,7 +48,7 @@ open class MysqlDialect : Dialect { override val supportsFetchingGeneratedKeysByName = false - override fun escapeColumnName(columnName: String): String = + override fun escapeName(columnName: String): String = '`' + columnName.replace("`", "``") + '`' } diff --git a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/PostgresDialect.kt b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/PostgresDialect.kt index c2003e0..0f28201 100644 --- a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/PostgresDialect.kt +++ b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/PostgresDialect.kt @@ -50,7 +50,7 @@ open class PostgresDialect : Dialect { override val supportsFetchingGeneratedKeysByName = true - override fun escapeColumnName(columnName: String): String = + override fun escapeName(columnName: String): String = '"' + columnName.replace("\"", "\"\"") + '"' } diff --git a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt index 19f24d9..f59065f 100644 --- a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt +++ b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt @@ -76,11 +76,11 @@ abstract class AbstractDao( } protected fun Iterable>.join(separator: String = ", ", f: (Column) -> String = nf): String { - return this.map { session.dialect.escapeColumnName(f(it)) }.joinToString(separator) + return this.joinToString(separator) { session.dialect.escapeName(f(it)) } } protected fun Iterable>.equate(separator: String = ", ", f: (Column) -> String = nf): String { - return this.map { "${session.dialect.escapeColumnName(f(it))} = :${f(it)}" }.joinToString(separator) + return this.joinToString(separator) { "${session.dialect.escapeName(f(it))} = :${f(it)}" } } protected fun Collection.copyToSqlArray(): java.sql.Array { @@ -103,7 +103,7 @@ abstract class AbstractDao( override fun findById(id: ID, columns: Set>): T? = withTransaction { val name = "findById" val sql = sql(name to columns) { - "select ${columns.join()} \nfrom ${table.name} \nwhere ${table.idColumns.equate(" and ")}" + "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${table.idColumns.equate(" and ")}" } session.select(sql, table.idMap(session, id, nf), options(name), table.rowMapper(columns)).firstOrNull() } @@ -111,14 +111,14 @@ abstract class AbstractDao( override fun findByIdForUpdate(id: ID, columns: Set>): T? = withTransaction { val name = "findByIdForUpdate" val sql = sql(name to columns) { - "select ${columns.join()} \nfrom ${table.name} \nwhere ${table.idColumns.equate(" and ")}\nfor update" + "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${table.idColumns.equate(" and ")}\nfor update" } session.select(sql, table.idMap(session, id, nf), options(name), table.rowMapper(columns)).firstOrNull() } override fun findAll(columns: Set>): List = withTransaction { val name = "findAll" - val sql = sql(name to columns) { "select ${columns.join()} \nfrom ${table.name}" } + val sql = sql(name to columns) { "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)}" } session.select(sql, mapOf(), options(name), table.rowMapper(columns)) } @@ -130,7 +130,7 @@ abstract class AbstractDao( val exampleMap = table.objectMap(session, example, exampleColumns, nf) val sql = sql(Triple(name, exampleColumns, columns)) { - "select ${columns.join()} \nfrom ${table.name}\nwhere ${exampleColumns.equate(" and ")}" + "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)}\nwhere ${exampleColumns.equate(" and ")}" } session.select(sql, exampleMap, options(name), table.rowMapper(columns)) } @@ -165,8 +165,10 @@ abstract class AbstractDao( fun delta(): Pair> { val differences = difference(oldMap, newMap) val sql = sql(name to differences) { - val columns = differences.keys.map { "$it = :$it" }.joinToString(", ") - "update ${table.name}\nset $columns \nwhere ${table.idColumns.equate(" and ")} and $versionCol = :$oldVersionParam" + val columns = differences.keys.joinToString(", ") { "$it = :$it" } + "update ${session.dialect.escapeName(table.name)} \n" + + "set $columns \n" + + "where ${table.idColumns.equate(" and ")} and $versionCol = :$oldVersionParam" } val parameters = hashMapOfExpectedSize(differences.size + table.idColumns.size + 1) parameters.putAll(differences) @@ -177,7 +179,9 @@ abstract class AbstractDao( fun full(): Pair> { val sql = sql(name) { - "update ${table.name}\nset ${table.dataColumns.equate()} \nwhere ${table.idColumns.equate(" and ")} and $versionCol = :$oldVersionParam" + "update ${session.dialect.escapeName(table.name)} \n" + + "set ${table.dataColumns.equate()} \n" + + "where ${table.idColumns.equate(" and ")} and $versionCol = :$oldVersionParam" } val parameters = hashMapOfExpectedSize(newMap.size + table.idColumns.size + 1) parameters.putAll(newMap) @@ -208,7 +212,7 @@ abstract class AbstractDao( override fun delete(id: ID): Int = withTransaction { val name = "delete" - val sql = sql(name) { "delete from ${table.name} where ${table.idColumns.equate(" and ")}" } + val sql = sql(name) { "delete from ${session.dialect.escapeName(table.name)} where ${table.idColumns.equate(" and ")}" } val count = session.update(sql, table.idMap(session, id, nf), options(name)) fireEvent { DeleteEvent(table, id, null) } @@ -247,7 +251,8 @@ abstract class AbstractDao( } val columns = if (generateKeys) table.dataColumns else table.allColumns - val sql = sql(name) { "insert into ${table.name}(${columns.join()}) \nvalues (${columns.join { ":${it.name}" }})" } + val sql = sql(name) { "insert into ${session.dialect.escapeName(table.name)} (${columns.join()}) \n" + + "values (${columns.join { ":${it.name}" }})" } val inserted = if (generateKeys) { val list = session.batchInsert(sql, new.map { table.objectMap(session, it, columns, nf) }, options(name), @@ -281,7 +286,8 @@ abstract class AbstractDao( val generateKeys = isGeneratedKey(new, idStrategy) val columns = if (generateKeys) table.dataColumns else table.allColumns - val sql = sql(name to columns) { "insert into ${table.name}(${columns.join()}) \nvalues (${columns.join { ":${it.name}" }})" } + val sql = sql(name to columns) { "insert into ${session.dialect.escapeName(table.name)} (${columns.join()}) \n" + + "values (${columns.join { ":${it.name}" }})" } val parameters = table.objectMap(session, new, columns, nf) val (count, inserted) = if (generateKeys) { @@ -314,7 +320,7 @@ abstract class AbstractDao( val values = if (session.dialect.supportsArrayBasedIn) { val sql = sql(name to columns) { - "select ${columns.join()} \nfrom ${table.name} \nwhere ${table.idColumns.first().name} " + + "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${session.dialect.escapeName(table.idColumns.first().name)} " + session.dialect.arrayBasedIn("ids") } val array = ids.copyToSqlArray() @@ -325,7 +331,7 @@ abstract class AbstractDao( } } else { val sql = sql(name to columns) { - "select ${columns.join()} \nfrom ${table.name} \nwhere ${table.idColumns.first().name} in (:ids)" + "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${session.dialect.escapeName(table.idColumns.first().name)} in (:ids)" } session.select(sql, mapOf("ids" to ids), options(name), table.rowMapper(columns)) } @@ -353,7 +359,7 @@ abstract class AbstractDao( val updates = new.map { table.objectMap(session, it, table.allColumns) } val sql = sql(name) { - "update ${table.name}\nset ${table.dataColumns.equate()} \nwhere ${table.idColumns.equate(" and ")}" + "update ${session.dialect.escapeName(table.name)}\nset ${table.dataColumns.equate()} \nwhere ${table.idColumns.equate(" and ")}" } val counts = session.batchUpdate(sql, updates, options(name)) @@ -402,7 +408,7 @@ abstract class AbstractDao( } val sql = sql(name) { - "update ${table.name}\nset ${table.dataColumns.equate()} \nwhere ${table.idColumns.equate(" and ")} and $versionCol = :$oldVersionParam" + "update ${session.dialect.escapeName(table.name)}\nset ${table.dataColumns.equate()} \nwhere ${table.idColumns.equate(" and ")} and $versionCol = :$oldVersionParam" } val counts = session.batchUpdate(sql, updates.map { it.first }, options(name)) From e6a992b0eab12b139ceccc280cbf61adbe61b0cd Mon Sep 17 00:00:00 2001 From: Miha_x64 Date: Sat, 23 Dec 2017 00:17:38 +0300 Subject: [PATCH 06/12] SqliteDialect.escapeName implementation --- .../com/github/andrewoma/kwery/core/dialect/SqliteDialect.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/SqliteDialect.kt b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/SqliteDialect.kt index 5b788d5..742ef5d 100644 --- a/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/SqliteDialect.kt +++ b/core/src/main/kotlin/com/github/andrewoma/kwery/core/dialect/SqliteDialect.kt @@ -47,4 +47,8 @@ open class SqliteDialect : Dialect { override fun allocateIds(count: Int, sequence: String, columnName: String) = throw UnsupportedOperationException() override val supportsFetchingGeneratedKeysByName = false + + override fun escapeName(columnName: String): String = + '"' + columnName.replace("\"", "\"\"") + '"' + } From a3eebeb9290e9a8e922d3687c07cf701a277d691 Mon Sep 17 00:00:00 2001 From: Miha_x64 Date: Mon, 25 Dec 2017 18:09:14 +0300 Subject: [PATCH 07/12] supporting default and custom order for findAll queries --- .../andrewoma/kwery/mapper/AbstractDao.kt | 17 ++++++++++++----- .../com/github/andrewoma/kwery/mapper/Dao.kt | 9 +++++++-- .../andrewoma/kwery/mapper/OrderByDirection.kt | 5 +++++ 3 files changed, 24 insertions(+), 7 deletions(-) create mode 100644 mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/OrderByDirection.kt diff --git a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt index f59065f..d9fca9c 100644 --- a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt +++ b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt @@ -116,21 +116,25 @@ abstract class AbstractDao( session.select(sql, table.idMap(session, id, nf), options(name), table.rowMapper(columns)).firstOrNull() } - override fun findAll(columns: Set>): List = withTransaction { + override fun findAll(columns: Set>, order: Map, OrderByDirection>): List = withTransaction { val name = "findAll" - val sql = sql(name to columns) { "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)}" } + val sql = sql(Triple(name, columns, order)) { "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)}${order.toOrderByClause()}" } session.select(sql, mapOf(), options(name), table.rowMapper(columns)) } - override fun findByExample(example: T, exampleColumns: Set>, columns: Set>): List = + override fun findByExample( + example: T, exampleColumns: Set>, + columns: Set>, + order: Map, OrderByDirection> + ): List = if (exampleColumns.isEmpty()) { findAll(columns) } else withTransaction { val name = "findByExample" val exampleMap = table.objectMap(session, example, exampleColumns, nf) - val sql = sql(Triple(name, exampleColumns, columns)) { - "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)}\nwhere ${exampleColumns.equate(" and ")}" + val sql = sql(Triple(name, exampleColumns to columns, order)) { // wow, that's ugly + "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)}\nwhere ${exampleColumns.equate(" and ")}${order.toOrderByClause()}" } session.select(sql, exampleMap, options(name), table.rowMapper(columns)) } @@ -438,6 +442,9 @@ abstract class AbstractDao( id(table.rowMapper(table.idColumns, nf)(row)) } } + + private fun Map, OrderByDirection>.toOrderByClause() = if (isEmpty()) "" else + entries.joinToString(prefix = " ORDER BY ") { session.dialect.escapeName(it.key.name) + ' ' + it.value.name } } enum class IdStrategy { diff --git a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/Dao.kt b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/Dao.kt index 00c67d6..66313b0 100644 --- a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/Dao.kt +++ b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/Dao.kt @@ -26,6 +26,8 @@ package com.github.andrewoma.kwery.mapper interface Dao { val defaultColumns: Set> val defaultIdStrategy: IdStrategy + val defaultOrder: Map, OrderByDirection> + get() = emptyMap() fun findById(id: ID, columns: Set> = defaultColumns): T? @@ -42,9 +44,12 @@ interface Dao { fun findByIds(ids: Collection, columns: Set> = defaultColumns): Map - fun findAll(columns: Set> = defaultColumns): List + fun findAll(columns: Set> = defaultColumns, order: Map, OrderByDirection> = defaultOrder): List - fun findByExample(example: T, exampleColumns: Set>, columns: Set> = defaultColumns): List + fun findByExample( + example: T, exampleColumns: Set>, + columns: Set> = defaultColumns, order: Map, OrderByDirection> = defaultOrder + ): List fun update(oldValue: T, newValue: T, deltaOnly: Boolean = false): T diff --git a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/OrderByDirection.kt b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/OrderByDirection.kt new file mode 100644 index 0000000..8a9093d --- /dev/null +++ b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/OrderByDirection.kt @@ -0,0 +1,5 @@ +package com.github.andrewoma.kwery.mapper + +enum class OrderByDirection { + ASC, DESC +} From 8531fab3e257107febc65d8f059b5b744596fa20 Mon Sep 17 00:00:00 2001 From: Miha_x64 Date: Mon, 25 Dec 2017 18:37:21 +0300 Subject: [PATCH 08/12] binary compatibility --- .../main/kotlin/com/github/andrewoma/kwery/mapper/Dao.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/Dao.kt b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/Dao.kt index 66313b0..bdc22c2 100644 --- a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/Dao.kt +++ b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/Dao.kt @@ -46,11 +46,20 @@ interface Dao { fun findAll(columns: Set> = defaultColumns, order: Map, OrderByDirection> = defaultOrder): List + @Deprecated(message = "Only for binary compatibility.", level = DeprecationLevel.HIDDEN) + fun findAll(columns: Set> = defaultColumns): List = findAll(columns, defaultOrder) + fun findByExample( example: T, exampleColumns: Set>, columns: Set> = defaultColumns, order: Map, OrderByDirection> = defaultOrder ): List + @Deprecated(message = "Only for binary compatibility.", level = DeprecationLevel.HIDDEN) + fun findByExample( + example: T, exampleColumns: Set>, + columns: Set> = defaultColumns + ): List = findByExample(example, exampleColumns, columns, defaultOrder) + fun update(oldValue: T, newValue: T, deltaOnly: Boolean = false): T fun delete(id: ID): Int From 723076b2d5f8b351c2ffce40644784b0ffe8b8ea Mon Sep 17 00:00:00 2001 From: Miha_x64 Date: Wed, 27 Dec 2017 21:08:46 +0300 Subject: [PATCH 09/12] separate joinNames (with escaping) and joinStrings (without escaping) instead of join --- .../andrewoma/kwery/mapper/AbstractDao.kt | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt index f59065f..086c69d 100644 --- a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt +++ b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt @@ -43,7 +43,7 @@ abstract class AbstractDao( override val defaultColumns = table.defaultColumns - protected val columns = table.defaultColumns.join() + protected val columns = table.defaultColumns.joinNames() private val listeners = linkedSetOf() @@ -75,7 +75,11 @@ abstract class AbstractDao( return this.groupBy { it.first }.map { apply(it.key, it.value.map { it.second }) } } - protected fun Iterable>.join(separator: String = ", ", f: (Column) -> String = nf): String { + protected fun Iterable>.joinNames(separator: String = ", ", f: (Column) -> String = nf): String { + return this.joinToString(separator) { session.dialect.escapeName(f(it)) } + } + + protected fun Iterable>.joinStrings(separator: String = ", ", f: (Column) -> String = nf): String { return this.joinToString(separator) { session.dialect.escapeName(f(it)) } } @@ -103,7 +107,7 @@ abstract class AbstractDao( override fun findById(id: ID, columns: Set>): T? = withTransaction { val name = "findById" val sql = sql(name to columns) { - "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${table.idColumns.equate(" and ")}" + "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${table.idColumns.equate(" and ")}" } session.select(sql, table.idMap(session, id, nf), options(name), table.rowMapper(columns)).firstOrNull() } @@ -111,14 +115,14 @@ abstract class AbstractDao( override fun findByIdForUpdate(id: ID, columns: Set>): T? = withTransaction { val name = "findByIdForUpdate" val sql = sql(name to columns) { - "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${table.idColumns.equate(" and ")}\nfor update" + "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${table.idColumns.equate(" and ")}\nfor update" } session.select(sql, table.idMap(session, id, nf), options(name), table.rowMapper(columns)).firstOrNull() } override fun findAll(columns: Set>): List = withTransaction { val name = "findAll" - val sql = sql(name to columns) { "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)}" } + val sql = sql(name to columns) { "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)}" } session.select(sql, mapOf(), options(name), table.rowMapper(columns)) } @@ -130,7 +134,7 @@ abstract class AbstractDao( val exampleMap = table.objectMap(session, example, exampleColumns, nf) val sql = sql(Triple(name, exampleColumns, columns)) { - "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)}\nwhere ${exampleColumns.equate(" and ")}" + "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)}\nwhere ${exampleColumns.equate(" and ")}" } session.select(sql, exampleMap, options(name), table.rowMapper(columns)) } @@ -251,8 +255,8 @@ abstract class AbstractDao( } val columns = if (generateKeys) table.dataColumns else table.allColumns - val sql = sql(name) { "insert into ${session.dialect.escapeName(table.name)} (${columns.join()}) \n" + - "values (${columns.join { ":${it.name}" }})" } + val sql = sql(name) { "insert into ${session.dialect.escapeName(table.name)} (${columns.joinNames()}) \n" + + "values (${columns.joinStrings { ":${it.name}" }})" } val inserted = if (generateKeys) { val list = session.batchInsert(sql, new.map { table.objectMap(session, it, columns, nf) }, options(name), @@ -286,8 +290,8 @@ abstract class AbstractDao( val generateKeys = isGeneratedKey(new, idStrategy) val columns = if (generateKeys) table.dataColumns else table.allColumns - val sql = sql(name to columns) { "insert into ${session.dialect.escapeName(table.name)} (${columns.join()}) \n" + - "values (${columns.join { ":${it.name}" }})" } + val sql = sql(name to columns) { "insert into ${session.dialect.escapeName(table.name)} (${columns.joinNames()}) \n" + + "values (${columns.joinStrings { ":${it.name}" }})" } val parameters = table.objectMap(session, new, columns, nf) val (count, inserted) = if (generateKeys) { @@ -320,7 +324,7 @@ abstract class AbstractDao( val values = if (session.dialect.supportsArrayBasedIn) { val sql = sql(name to columns) { - "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${session.dialect.escapeName(table.idColumns.first().name)} " + + "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${session.dialect.escapeName(table.idColumns.first().name)} " + session.dialect.arrayBasedIn("ids") } val array = ids.copyToSqlArray() @@ -331,7 +335,7 @@ abstract class AbstractDao( } } else { val sql = sql(name to columns) { - "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${session.dialect.escapeName(table.idColumns.first().name)} in (:ids)" + "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${session.dialect.escapeName(table.idColumns.first().name)} in (:ids)" } session.select(sql, mapOf("ids" to ids), options(name), table.rowMapper(columns)) } From 9a72d91f92b040cb5e7bcffdfea766e8cfd62bb0 Mon Sep 17 00:00:00 2001 From: Miha_x64 Date: Wed, 27 Dec 2017 21:11:14 +0300 Subject: [PATCH 10/12] up-to-date with escaping --- .../com/github/andrewoma/kwery/mapper/AbstractDao.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt index 40e9057..d208a9c 100644 --- a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt +++ b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt @@ -122,8 +122,7 @@ abstract class AbstractDao( override fun findAll(columns: Set>, order: Map, OrderByDirection>): List = withTransaction { val name = "findAll" - val sql = sql(Triple(name, columns, order)) { "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)}${order.toOrderByClause()}" } - val sql = sql(name to columns) { "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)}" } + val sql = sql(Triple(name, columns, order)) { "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)}${order.toOrderByClause()}" } session.select(sql, mapOf(), options(name), table.rowMapper(columns)) } @@ -139,9 +138,7 @@ abstract class AbstractDao( val exampleMap = table.objectMap(session, example, exampleColumns, nf) val sql = sql(Triple(name, exampleColumns to columns, order)) { // wow, that's ugly - "select ${columns.join()} \nfrom ${session.dialect.escapeName(table.name)}\nwhere ${exampleColumns.equate(" and ")}${order.toOrderByClause()}" - val sql = sql(Triple(name, exampleColumns, columns)) { - "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)}\nwhere ${exampleColumns.equate(" and ")}" + "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)}\nwhere ${exampleColumns.equate(" and ")}${order.toOrderByClause()}" } session.select(sql, exampleMap, options(name), table.rowMapper(columns)) } From 2d12b9e7bec2df9a6cc1a230efe938d50dd79e96 Mon Sep 17 00:00:00 2001 From: Miha_x64 Date: Wed, 27 Dec 2017 21:18:47 +0300 Subject: [PATCH 11/12] adequate joinStrings implementation --- .../kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt index 086c69d..4e4d4e7 100644 --- a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt +++ b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt @@ -80,7 +80,7 @@ abstract class AbstractDao( } protected fun Iterable>.joinStrings(separator: String = ", ", f: (Column) -> String = nf): String { - return this.joinToString(separator) { session.dialect.escapeName(f(it)) } + return this.joinToString(separator) { f(it) } } protected fun Iterable>.equate(separator: String = ", ", f: (Column) -> String = nf): String { From c18a8a1b53fd88e24992318c5ff09dfd7fd4bae7 Mon Sep 17 00:00:00 2001 From: Miha_x64 Date: Wed, 27 Dec 2017 21:42:25 +0300 Subject: [PATCH 12/12] escaped table name in unsafeUpdate, moved escaped table name to a property --- .../andrewoma/kwery/mapper/AbstractDao.kt | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt index 4e4d4e7..b4dce41 100644 --- a/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt +++ b/mapper/src/main/kotlin/com/github/andrewoma/kwery/mapper/AbstractDao.kt @@ -47,6 +47,8 @@ abstract class AbstractDao( private val listeners = linkedSetOf() + private val escapedTableName = session.dialect.escapeName(table.name) + fun addListener(listener: Listener) { listeners.add(listener) } @@ -107,7 +109,7 @@ abstract class AbstractDao( override fun findById(id: ID, columns: Set>): T? = withTransaction { val name = "findById" val sql = sql(name to columns) { - "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${table.idColumns.equate(" and ")}" + "select ${columns.joinNames()} \nfrom $escapedTableName \nwhere ${table.idColumns.equate(" and ")}" } session.select(sql, table.idMap(session, id, nf), options(name), table.rowMapper(columns)).firstOrNull() } @@ -115,14 +117,14 @@ abstract class AbstractDao( override fun findByIdForUpdate(id: ID, columns: Set>): T? = withTransaction { val name = "findByIdForUpdate" val sql = sql(name to columns) { - "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${table.idColumns.equate(" and ")}\nfor update" + "select ${columns.joinNames()} \nfrom $escapedTableName \nwhere ${table.idColumns.equate(" and ")}\nfor update" } session.select(sql, table.idMap(session, id, nf), options(name), table.rowMapper(columns)).firstOrNull() } override fun findAll(columns: Set>): List = withTransaction { val name = "findAll" - val sql = sql(name to columns) { "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)}" } + val sql = sql(name to columns) { "select ${columns.joinNames()} \nfrom $escapedTableName" } session.select(sql, mapOf(), options(name), table.rowMapper(columns)) } @@ -134,7 +136,7 @@ abstract class AbstractDao( val exampleMap = table.objectMap(session, example, exampleColumns, nf) val sql = sql(Triple(name, exampleColumns, columns)) { - "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)}\nwhere ${exampleColumns.equate(" and ")}" + "select ${columns.joinNames()} \nfrom $escapedTableName\nwhere ${exampleColumns.equate(" and ")}" } session.select(sql, exampleMap, options(name), table.rowMapper(columns)) } @@ -170,7 +172,7 @@ abstract class AbstractDao( val differences = difference(oldMap, newMap) val sql = sql(name to differences) { val columns = differences.keys.joinToString(", ") { "$it = :$it" } - "update ${session.dialect.escapeName(table.name)} \n" + + "update $escapedTableName \n" + "set $columns \n" + "where ${table.idColumns.equate(" and ")} and $versionCol = :$oldVersionParam" } @@ -183,7 +185,7 @@ abstract class AbstractDao( fun full(): Pair> { val sql = sql(name) { - "update ${session.dialect.escapeName(table.name)} \n" + + "update $escapedTableName \n" + "set ${table.dataColumns.equate()} \n" + "where ${table.idColumns.equate(" and ")} and $versionCol = :$oldVersionParam" } @@ -216,7 +218,7 @@ abstract class AbstractDao( override fun delete(id: ID): Int = withTransaction { val name = "delete" - val sql = sql(name) { "delete from ${session.dialect.escapeName(table.name)} where ${table.idColumns.equate(" and ")}" } + val sql = sql(name) { "delete from $escapedTableName where ${table.idColumns.equate(" and ")}" } val count = session.update(sql, table.idMap(session, id, nf), options(name)) fireEvent { DeleteEvent(table, id, null) } @@ -229,7 +231,7 @@ abstract class AbstractDao( val new = fireTransformingEvent(newValue) { PreUpdateEvent(table, id(newValue), newValue, null) } val sql = sql(name) { - "update ${table.name}\nset ${table.dataColumns.equate()} \nwhere ${table.idColumns.equate(" and ")}" + "update $escapedTableName\nset ${table.dataColumns.equate()} \nwhere ${table.idColumns.equate(" and ")}" } val newMap = table.objectMap(session, new, table.allColumns) @@ -255,7 +257,7 @@ abstract class AbstractDao( } val columns = if (generateKeys) table.dataColumns else table.allColumns - val sql = sql(name) { "insert into ${session.dialect.escapeName(table.name)} (${columns.joinNames()}) \n" + + val sql = sql(name) { "insert into $escapedTableName (${columns.joinNames()}) \n" + "values (${columns.joinStrings { ":${it.name}" }})" } val inserted = if (generateKeys) { @@ -290,7 +292,7 @@ abstract class AbstractDao( val generateKeys = isGeneratedKey(new, idStrategy) val columns = if (generateKeys) table.dataColumns else table.allColumns - val sql = sql(name to columns) { "insert into ${session.dialect.escapeName(table.name)} (${columns.joinNames()}) \n" + + val sql = sql(name to columns) { "insert into $escapedTableName (${columns.joinNames()}) \n" + "values (${columns.joinStrings { ":${it.name}" }})" } val parameters = table.objectMap(session, new, columns, nf) @@ -324,7 +326,7 @@ abstract class AbstractDao( val values = if (session.dialect.supportsArrayBasedIn) { val sql = sql(name to columns) { - "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${session.dialect.escapeName(table.idColumns.first().name)} " + + "select ${columns.joinNames()} \nfrom $escapedTableName \nwhere ${session.dialect.escapeName(table.idColumns.first().name)} " + session.dialect.arrayBasedIn("ids") } val array = ids.copyToSqlArray() @@ -335,7 +337,7 @@ abstract class AbstractDao( } } else { val sql = sql(name to columns) { - "select ${columns.joinNames()} \nfrom ${session.dialect.escapeName(table.name)} \nwhere ${session.dialect.escapeName(table.idColumns.first().name)} in (:ids)" + "select ${columns.joinNames()} \nfrom $escapedTableName \nwhere ${session.dialect.escapeName(table.idColumns.first().name)} in (:ids)" } session.select(sql, mapOf("ids" to ids), options(name), table.rowMapper(columns)) } @@ -363,7 +365,7 @@ abstract class AbstractDao( val updates = new.map { table.objectMap(session, it, table.allColumns) } val sql = sql(name) { - "update ${session.dialect.escapeName(table.name)}\nset ${table.dataColumns.equate()} \nwhere ${table.idColumns.equate(" and ")}" + "update $escapedTableName\nset ${table.dataColumns.equate()} \nwhere ${table.idColumns.equate(" and ")}" } val counts = session.batchUpdate(sql, updates, options(name)) @@ -412,7 +414,7 @@ abstract class AbstractDao( } val sql = sql(name) { - "update ${session.dialect.escapeName(table.name)}\nset ${table.dataColumns.equate()} \nwhere ${table.idColumns.equate(" and ")} and $versionCol = :$oldVersionParam" + "update $escapedTableName\nset ${table.dataColumns.equate()} \nwhere ${table.idColumns.equate(" and ")} and $versionCol = :$oldVersionParam" } val counts = session.batchUpdate(sql, updates.map { it.first }, options(name))