[Editor] Add support deleting data with Query Result view
This commit is contained in:
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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?
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user