Skip to content

Commit d6c23b8

Browse files
refactor bulkInsert
1 parent 72c24ed commit d6c23b8

File tree

2 files changed

+56
-59
lines changed

2 files changed

+56
-59
lines changed

ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/BulkInsertOrUpdate.kt renamed to ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/BulkInsert.kt

Lines changed: 27 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,22 @@ import org.ktorm.expression.ColumnExpression
2525
import org.ktorm.expression.SqlExpression
2626
import org.ktorm.expression.TableExpression
2727
import org.ktorm.schema.BaseTable
28-
import org.ktorm.schema.Column
2928

3029
/**
3130
* Bulk insert expression, represents a bulk insert statement in PostgreSQL.
3231
*
33-
* For example: `insert into table (column1, column2) values (?, ?), (?, ?), (?, ?)... ON
34-
* CONFLICT (...) DO NOTHING/UPDATE SET ...`.
32+
* For example:
33+
* `insert into table (column1, column2) values (?, ?), (?, ?), (?, ?)... on conflict (...) do update set ...`.
3534
*
3635
* @property table the table to be inserted.
3736
* @property assignments column assignments of the bulk insert statement.
38-
* @property conflictTarget the index columns on which the conflict may happens.
37+
* @property conflictColumns the index columns on which the conflict may happens.
3938
* @property updateAssignments the updated column assignments while key conflict exists.
4039
*/
4140
public data class BulkInsertExpression(
4241
val table: TableExpression,
4342
val assignments: List<List<ColumnAssignmentExpression<*>>>,
44-
val conflictTarget: List<ColumnExpression<*>>,
43+
val conflictColumns: List<ColumnExpression<*>> = emptyList(),
4544
val updateAssignments: List<ColumnAssignmentExpression<*>> = emptyList(),
4645
override val isLeafNode: Boolean = false,
4746
override val extraProperties: Map<String, Any> = emptyMap()
@@ -55,55 +54,42 @@ public data class BulkInsertExpression(
5554
* special SQL using PostgreSQL's bulk insert syntax, instead of based on JDBC batch operations.
5655
* For this reason, its performance is much better than [batchInsert].
5756
*
58-
* The generated SQL is like: `insert into table (column1, column2) values (?, ?), (?, ?), (?, ?)... ON
59-
* CONFLICT (...) DO NOTHING/UPDATE SET ...`.
57+
* The generated SQL is like: `insert into table (column1, column2) values (?, ?), (?, ?), (?, ?)...`.
6058
*
6159
* Usage:
6260
*
6361
* ```kotlin
64-
* database.bulkInsert(Employees) {
65-
* item {
66-
* set(it.id, 1)
67-
* set(it.name, "vince")
68-
* set(it.job, "engineer")
69-
* set(it.salary, 1000)
70-
* set(it.hireDate, LocalDate.now())
71-
* set(it.departmentId, 1)
72-
* }
73-
* item {
74-
* set(it.id, 5)
75-
* set(it.name, "vince")
76-
* set(it.job, "engineer")
77-
* set(it.salary, 1000)
78-
* set(it.hireDate, LocalDate.now())
79-
* set(it.departmentId, 1)
80-
* }
81-
*
82-
* onDuplicateKey(Employees.id) {
83-
* // Or leave this empty to simply ignore without updating (do nothing)
84-
* set(it.salary, it.salary + 900)
85-
* }
86-
* }
62+
* database.bulkInsert(Employees) {
63+
* item {
64+
* set(it.id, 1)
65+
* set(it.name, "vince")
66+
* set(it.job, "engineer")
67+
* set(it.salary, 1000)
68+
* set(it.hireDate, LocalDate.now())
69+
* set(it.departmentId, 1)
70+
* }
71+
* item {
72+
* set(it.id, 5)
73+
* set(it.name, "vince")
74+
* set(it.job, "engineer")
75+
* set(it.salary, 1000)
76+
* set(it.hireDate, LocalDate.now())
77+
* set(it.departmentId, 1)
78+
* }
79+
* }
8780
* ```
8881
*
8982
* @since 3.3.0
9083
* @param table the table to be inserted.
91-
* @param block the DSL block, extension function of [BulkInsertStatementBuilder],
92-
* used to construct the expression.
84+
* @param block the DSL block, extension function of [BulkInsertStatementBuilder], used to construct the expression.
9385
* @return the effected row count.
9486
* @see batchInsert
9587
*/
96-
public fun <T : BaseTable<*>> Database.bulkInsert(
97-
table: T,
98-
block: BulkInsertStatementBuilder<T>.() -> Unit
99-
): Int {
88+
public fun <T : BaseTable<*>> Database.bulkInsert(table: T, block: BulkInsertStatementBuilder<T>.() -> Unit): Int {
10089
val builder = BulkInsertStatementBuilder(table).apply(block)
10190

102-
val expression = BulkInsertExpression(
103-
table = table.asExpression(),
104-
assignments = builder.assignments,
105-
conflictTarget = builder.conflictColumns.map { it.asExpression() },
106-
updateAssignments = builder.updateAssignments
91+
val expression = AliasRemover.visit(
92+
BulkInsertExpression(table.asExpression(), builder.assignments)
10793
)
10894

10995
return executeUpdate(expression)
@@ -115,8 +101,6 @@ public fun <T : BaseTable<*>> Database.bulkInsert(
115101
@KtormDsl
116102
public class BulkInsertStatementBuilder<T : BaseTable<*>>(internal val table: T) {
117103
internal val assignments = ArrayList<List<ColumnAssignmentExpression<*>>>()
118-
internal val conflictColumns = ArrayList<Column<*>>()
119-
internal val updateAssignments = ArrayList<ColumnAssignmentExpression<*>>()
120104

121105
/**
122106
* Add the assignments of a new row to the bulk insert.
@@ -133,15 +117,4 @@ public class BulkInsertStatementBuilder<T : BaseTable<*>>(internal val table: T)
133117
throw IllegalArgumentException("Every item in a batch operation must be the same.")
134118
}
135119
}
136-
137-
/**
138-
* Specify the update assignments while any key conflict exists.
139-
*/
140-
public fun onDuplicateKey(vararg columns: Column<*>, block: AssignmentsBuilder.(T) -> Unit) {
141-
val builder = PostgreSqlAssignmentsBuilder()
142-
builder.block(table)
143-
144-
updateAssignments += builder.assignments
145-
conflictColumns += columns
146-
}
147120
}

ktorm-support-postgresql/src/main/kotlin/org/ktorm/support/postgresql/InsertOrUpdate.kt

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,13 @@ public fun <T : BaseTable<*>> Database.insertOrUpdate(
9090
throw IllegalStateException(msg)
9191
}
9292

93-
val expression = InsertOrUpdateExpression(
94-
table = table.asExpression(),
95-
assignments = builder.assignments,
96-
conflictTarget = builder.conflictColumns.ifEmpty { primaryKeys }.map { it.asExpression() },
97-
updateAssignments = builder.updateAssignments
93+
val expression = AliasRemover.visit(
94+
InsertOrUpdateExpression(
95+
table = table.asExpression(),
96+
assignments = builder.assignments,
97+
conflictTarget = builder.conflictColumns.ifEmpty { primaryKeys }.map { it.asExpression() },
98+
updateAssignments = builder.updateAssignments
99+
)
98100
)
99101

100102
return executeUpdate(expression)
@@ -129,3 +131,25 @@ public class InsertOrUpdateStatementBuilder : PostgreSqlAssignmentsBuilder() {
129131
conflictColumns += columns
130132
}
131133
}
134+
135+
/**
136+
* [PostgreSqlExpressionVisitor] implementation used to removed table aliases, used by Ktorm internal.
137+
*/
138+
internal object AliasRemover : PostgreSqlExpressionVisitor() {
139+
140+
override fun visitTable(expr: TableExpression): TableExpression {
141+
if (expr.tableAlias == null) {
142+
return expr
143+
} else {
144+
return expr.copy(tableAlias = null)
145+
}
146+
}
147+
148+
override fun <T : Any> visitColumn(expr: ColumnExpression<T>): ColumnExpression<T> {
149+
if (expr.table == null) {
150+
return expr
151+
} else {
152+
return expr.copy(table = null)
153+
}
154+
}
155+
}

0 commit comments

Comments
 (0)