[Editor] Add support deleting data with Query Result view

This commit is contained in:
2021-03-26 14:17:50 +01:00
parent 3b0e117541
commit 97ad8e49ac
8 changed files with 61 additions and 34 deletions

View File

@@ -2,19 +2,21 @@ package com.bartlomiejpluta.base.editor.database.controller
import com.bartlomiejpluta.base.editor.database.model.data.DataRecord import com.bartlomiejpluta.base.editor.database.model.data.DataRecord
import com.bartlomiejpluta.base.editor.database.model.data.Query import com.bartlomiejpluta.base.editor.database.model.data.Query
import com.bartlomiejpluta.base.editor.database.model.schema.SchemaTable
import com.bartlomiejpluta.base.editor.database.service.DatabaseService import com.bartlomiejpluta.base.editor.database.service.DatabaseService
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
import tornadofx.Controller import tornadofx.Controller
import tornadofx.error import tornadofx.error
import java.sql.Connection import java.sql.Connection
import java.sql.PreparedStatement
import java.sql.SQLException import java.sql.SQLException
@Component @Component
class DatabaseController : Controller() { class DatabaseController : Controller() {
private val databaseService: DatabaseService by di() private val databaseService: DatabaseService by di()
fun execute(statement: String, name: String, table: String? = null): Query? = try { fun execute(statement: String, name: String, schema: SchemaTable? = null): Query? = try {
databaseService.execute(statement, name, table) databaseService.execute(statement, name, schema)
} catch (e: SQLException) { } catch (e: SQLException) {
sqlErrorAlert(e) sqlErrorAlert(e)
null null
@@ -30,15 +32,12 @@ class DatabaseController : Controller() {
} }
} ?: false } ?: false
fun submitBatch(table: String, records: List<DataRecord>) = execute { fun submitBatch(records: List<DataRecord>) = execute {
autoCommit = false autoCommit = false
records.forEach {
it.prepareStatement(table)?.let { sql -> records
val statement = prepareStatement(sql) .mapNotNull { it.prepareStatement(this) }
it.fields.values.forEachIndexed { index, field -> statement.setObject(index + 1, field.value) } .forEach(PreparedStatement::execute)
statement.execute()
}
}
commit() commit()
} }

View File

@@ -1,12 +1,18 @@
package com.bartlomiejpluta.base.editor.database.model.data package com.bartlomiejpluta.base.editor.database.model.data
import com.bartlomiejpluta.base.editor.database.model.schema.SchemaTable
import tornadofx.getValue import tornadofx.getValue
import tornadofx.setValue import tornadofx.setValue
import tornadofx.toProperty import tornadofx.toProperty
import java.sql.Connection
import kotlin.collections.component1 import kotlin.collections.component1
import kotlin.collections.component2 import kotlin.collections.component2
class DataRecord(val fields: Map<String, DataField>, operation: Operation = Operation.DO_NOTHING) { class DataRecord(
val fields: Map<String, DataField>,
operation: Operation = Operation.DO_NOTHING,
private val schema: SchemaTable?
) {
val operationProperty = operation.toProperty() val operationProperty = operation.toProperty()
var operation by operationProperty var operation by operationProperty
@@ -14,10 +20,28 @@ class DataRecord(val fields: Map<String, DataField>, operation: Operation = Oper
fields.forEach { (_, field) -> field.record = this } fields.forEach { (_, field) -> field.record = this }
} }
fun prepareStatement(table: String) = when (operation) { fun prepareStatement(connection: Connection) = schema?.let { schema ->
Operation.INSERT -> "INSERT INTO `$table` SET $parameters;" when (operation) {
else -> null Operation.INSERT -> {
} val parametersClause = fields.map { (column, _) -> "`$column` = ?" }.joinToString(", ")
val sql = "INSERT INTO `${schema.name}` SET $parametersClause"
val statement = connection.prepareStatement(sql)
fields.values.forEachIndexed { index, field -> statement.setObject(index + 1, field.value) }
private val parameters = fields.map { (column, _) -> "`$column` = ?" }.joinToString(", ") statement
}
Operation.DELETE -> {
val pk = schema.columns.filtered { it.primary }
val filterClause = pk.joinToString(" AND ") { "`${it.name}` = ?" }
val sql = "DELETE FROM `${schema.name}` WHERE $filterClause"
val statement = connection.prepareStatement(sql)
pk.forEachIndexed { index, column -> statement.setObject(index + 1, fields[column.name]!!.value) }
statement
}
else -> null
}
}
} }

View File

@@ -1,7 +1,8 @@
package com.bartlomiejpluta.base.editor.database.model.data package com.bartlomiejpluta.base.editor.database.model.data
import com.bartlomiejpluta.base.editor.database.model.schema.SchemaTable
import javafx.beans.property.SimpleListProperty import javafx.beans.property.SimpleListProperty
import javafx.beans.property.SimpleStringProperty import javafx.beans.property.SimpleObjectProperty
import javafx.collections.ObservableList import javafx.collections.ObservableList
import tornadofx.getValue import tornadofx.getValue
import tornadofx.toProperty import tornadofx.toProperty
@@ -11,10 +12,10 @@ class Query(
query: String, query: String,
columns: ObservableList<String>, columns: ObservableList<String>,
data: ObservableList<DataRecord>, data: ObservableList<DataRecord>,
table: String? = null schema: SchemaTable? = null
) { ) {
val tableProperty = SimpleStringProperty(table) val schemaProperty = SimpleObjectProperty<SchemaTable>(schema)
val table by tableProperty val schema by schemaProperty
val nameProperty = name.toProperty() val nameProperty = name.toProperty()
val name by nameProperty val name by nameProperty
@@ -30,6 +31,6 @@ class Query(
fun addEmptyRecord() { fun addEmptyRecord() {
val fields = columns.map { it to DataField(null) }.toMap() val fields = columns.map { it to DataField(null) }.toMap()
data += DataRecord(fields, Operation.INSERT) data += DataRecord(fields, Operation.INSERT, schema)
} }
} }

View File

@@ -2,6 +2,7 @@ package com.bartlomiejpluta.base.editor.database.service
import com.bartlomiejpluta.base.editor.database.model.data.Query import com.bartlomiejpluta.base.editor.database.model.data.Query
import com.bartlomiejpluta.base.editor.database.model.schema.SchemaDatabase import com.bartlomiejpluta.base.editor.database.model.schema.SchemaDatabase
import com.bartlomiejpluta.base.editor.database.model.schema.SchemaTable
import java.sql.Connection import java.sql.Connection
interface DatabaseService { interface DatabaseService {
@@ -9,5 +10,5 @@ interface DatabaseService {
fun <T> run(op: Connection.() -> T): T? fun <T> run(op: Connection.() -> T): T?
fun execute(statement: String, name: String, table: String? = null): Query? fun execute(statement: String, name: String, schema: SchemaTable? = null): Query?
} }

View File

@@ -2,8 +2,10 @@ package com.bartlomiejpluta.base.editor.database.service
import com.bartlomiejpluta.base.editor.database.model.data.DataField import com.bartlomiejpluta.base.editor.database.model.data.DataField
import com.bartlomiejpluta.base.editor.database.model.data.DataRecord import com.bartlomiejpluta.base.editor.database.model.data.DataRecord
import com.bartlomiejpluta.base.editor.database.model.data.Operation
import com.bartlomiejpluta.base.editor.database.model.data.Query import com.bartlomiejpluta.base.editor.database.model.data.Query
import com.bartlomiejpluta.base.editor.database.model.schema.SchemaDatabase import com.bartlomiejpluta.base.editor.database.model.schema.SchemaDatabase
import com.bartlomiejpluta.base.editor.database.model.schema.SchemaTable
import com.bartlomiejpluta.base.editor.project.context.ProjectContext import com.bartlomiejpluta.base.editor.project.context.ProjectContext
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@@ -49,7 +51,7 @@ class H2DatabaseService : DatabaseService {
return projectContext.project?.database?.connection?.use(op) return projectContext.project?.database?.connection?.use(op)
} }
override fun execute(statement: String, name: String, table: String?): Query? = run { override fun execute(statement: String, name: String, schema: SchemaTable?): Query? = run {
val stmt = prepareStatement(statement).apply { execute() } val stmt = prepareStatement(statement).apply { execute() }
val results = stmt.resultSet val results = stmt.resultSet
val metadata = stmt.metaData val metadata = stmt.metaData
@@ -70,10 +72,10 @@ class H2DatabaseService : DatabaseService {
record[metadata.getColumnLabel(i)] = field record[metadata.getColumnLabel(i)] = field
} }
data += DataRecord(record) data += DataRecord(record, Operation.DO_NOTHING, schema)
} }
return@run Query(name, statement, columns, data, table) return@run Query(name, statement, columns, data, schema)
} }
return@run null return@run null

View File

@@ -35,7 +35,7 @@ class TablesListView : View() {
val selected = selectionModel?.selectedItem?.value val selected = selectionModel?.selectedItem?.value
if (event.clickCount == 2 && selected is SchemaTable) { if (event.clickCount == 2 && selected is SchemaTable) {
databaseController databaseController
.execute("SELECT * FROM ${selected.name}", selected.name, selected.name) .execute("SELECT * FROM ${selected.name}", selected.name, selected)
?.let(mainController::openQuery) ?.let(mainController::openQuery)
} }
} }

View File

@@ -17,7 +17,7 @@ class QueryResultView : View() {
private val queryVM = find<QueryVM>() private val queryVM = find<QueryVM>()
private val table = tableview(queryVM.dataProperty) { private val table = tableview(queryVM.dataProperty) {
editableProperty().bind(queryVM.tableProperty.isNotNull) editableProperty().bind(queryVM.schemaProperty.isNotNull)
setRowFactory { DataRecordRow() } setRowFactory { DataRecordRow() }
} }
@@ -55,7 +55,7 @@ class QueryResultView : View() {
} }
button(graphic = FontIcon("fa-plus")) { button(graphic = FontIcon("fa-plus")) {
enableWhen(queryVM.tableProperty.isNotNull) enableWhen(queryVM.schemaProperty.isNotNull)
action { action {
queryVM.item?.addEmptyRecord() queryVM.item?.addEmptyRecord()
@@ -63,7 +63,7 @@ class QueryResultView : View() {
} }
button(graphic = FontIcon("fa-minus")) { button(graphic = FontIcon("fa-minus")) {
enableWhen(queryVM.tableProperty.isNotNull) enableWhen(queryVM.schemaProperty.isNotNull)
action { action {
val selected = table.selectionModel.selectedItem val selected = table.selectionModel.selectedItem
@@ -75,10 +75,10 @@ class QueryResultView : View() {
} }
button(graphic = FontIcon("fa-check")) { button(graphic = FontIcon("fa-check")) {
enableWhen(queryVM.tableProperty.isNotNull) enableWhen(queryVM.schemaProperty.isNotNull)
action { action {
val success = databaseController.submitBatch(queryVM.name, queryVM.data) val success = databaseController.submitBatch(queryVM.data)
if (success) { if (success) {
refresh() refresh()
} }
@@ -90,7 +90,7 @@ class QueryResultView : View() {
} }
private fun refresh() { private fun refresh() {
databaseController.execute(queryVM.query, queryVM.name, queryVM.table)?.let { databaseController.execute(queryVM.query, queryVM.name, queryVM.schema)?.let {
queryVM.item = it queryVM.item = it
} }
} }

View File

@@ -5,8 +5,8 @@ import tornadofx.ItemViewModel
import tornadofx.getValue import tornadofx.getValue
class QueryVM(query: Query) : ItemViewModel<Query>(query) { class QueryVM(query: Query) : ItemViewModel<Query>(query) {
val tableProperty = bind(Query::tableProperty) val schemaProperty = bind(Query::schemaProperty)
val table by tableProperty val schema by schemaProperty
val nameProperty = bind(Query::nameProperty) val nameProperty = bind(Query::nameProperty)
val name by nameProperty val name by nameProperty