[Editor] Enable refreshing Queries

This commit is contained in:
2021-03-25 20:12:58 +01:00
parent 128620851f
commit d77d7d116f
7 changed files with 100 additions and 57 deletions

View File

@@ -0,0 +1,34 @@
package com.bartlomiejpluta.base.editor.database.controller
import com.bartlomiejpluta.base.editor.database.model.data.Query
import com.bartlomiejpluta.base.editor.database.service.DatabaseService
import org.springframework.stereotype.Component
import tornadofx.Controller
import tornadofx.error
import java.sql.Connection
import java.sql.SQLException
@Component
class DatabaseController : Controller() {
private val databaseService: DatabaseService by di()
fun execute(statement: String, name: String = ""): Query? = try {
databaseService.execute(statement, name)
} catch (e: SQLException) {
sqlErrorAlert(e)
null
}
fun execute(op: Connection.() -> Unit) {
databaseService.run<Unit> {
try {
op(this)
} catch (e: SQLException) {
sqlErrorAlert(e)
}
}
}
private fun sqlErrorAlert(e: SQLException) =
error("SQL Error ${e.sqlState}", e.joinToString("\n") { e.message ?: "" }, title = "SQL Error")
}

View File

@@ -3,7 +3,10 @@ package com.bartlomiejpluta.base.editor.database.model.data
import tornadofx.getValue import tornadofx.getValue
import tornadofx.toProperty import tornadofx.toProperty
class Query(name: String, val columns: List<String>, val data: List<DataRecord>) { class Query(name: String, query: String, val columns: List<String>, val data: List<DataRecord>) {
val nameProperty = name.toProperty() val nameProperty = name.toProperty()
val name by nameProperty val name by nameProperty
val queryProperty = query.toProperty()
val query by queryProperty
} }

View File

@@ -1,9 +1,13 @@
package com.bartlomiejpluta.base.editor.database.service package com.bartlomiejpluta.base.editor.database.service
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 java.sql.Connection import java.sql.Connection
interface DatabaseService { interface DatabaseService {
val database: SchemaDatabase val database: SchemaDatabase
fun run(op: Connection.() -> Unit)
fun <T> run(op: Connection.() -> T): T?
fun execute(statement: String, name: String = ""): Query?
} }

View File

@@ -1,5 +1,8 @@
package com.bartlomiejpluta.base.editor.database.service package com.bartlomiejpluta.base.editor.database.service
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.Query
import com.bartlomiejpluta.base.editor.database.model.schema.ColumnType import com.bartlomiejpluta.base.editor.database.model.schema.ColumnType
import com.bartlomiejpluta.base.editor.database.model.schema.SchemaDatabase import com.bartlomiejpluta.base.editor.database.model.schema.SchemaDatabase
import com.bartlomiejpluta.base.editor.project.context.ProjectContext import com.bartlomiejpluta.base.editor.project.context.ProjectContext
@@ -42,9 +45,38 @@ class H2DatabaseService : DatabaseService {
@Autowired @Autowired
private lateinit var projectContext: ProjectContext private lateinit var projectContext: ProjectContext
override fun run(op: Connection.() -> Unit) { override fun <T> run(op: Connection.() -> T): T? {
projectContext.project?.database?.connection?.use(op) return projectContext.project?.database?.connection?.use(op)
} }
private fun parseType(type: String) = ColumnType.valueOf(type.replace(" ", "_").substringBefore("(")) private fun parseType(type: String) = ColumnType.valueOf(type.replace(" ", "_").substringBefore("("))
override fun execute(statement: String, name: String): Query? = run {
val stmt = prepareStatement(statement).apply { execute() }
val results = stmt.resultSet
val metadata = stmt.metaData
if (results != null && metadata != null) {
val columns = mutableListOf<String>()
for (i in 1..metadata.columnCount) {
columns += metadata.getColumnLabel(i)
}
val data = mutableListOf<DataRecord>()
while (results.next()) {
val record = mutableMapOf<String, DataField>()
for (i in 1..metadata.columnCount) {
record[metadata.getColumnLabel(i)] = DataField(results.getObject(i).toString())
}
data += DataRecord(record)
}
return@run Query(name, statement, columns, data)
}
return@run null
}
} }

View File

@@ -1,10 +1,8 @@
package com.bartlomiejpluta.base.editor.database.view.list package com.bartlomiejpluta.base.editor.database.view.list
import com.bartlomiejpluta.base.editor.database.component.SQLElementCell import com.bartlomiejpluta.base.editor.database.component.SQLElementCell
import com.bartlomiejpluta.base.editor.database.controller.DatabaseController
import com.bartlomiejpluta.base.editor.database.model.* import com.bartlomiejpluta.base.editor.database.model.*
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.Query
import com.bartlomiejpluta.base.editor.database.model.schema.Schema import com.bartlomiejpluta.base.editor.database.model.schema.Schema
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.database.model.schema.SchemaTable
@@ -15,13 +13,12 @@ import com.bartlomiejpluta.base.editor.project.context.ProjectContext
import javafx.scene.control.TreeItem import javafx.scene.control.TreeItem
import org.kordamp.ikonli.javafx.FontIcon import org.kordamp.ikonli.javafx.FontIcon
import tornadofx.* import tornadofx.*
import java.sql.Connection
import java.sql.SQLException
class TablesListView : View() { class TablesListView : View() {
private val mainController: MainController by di() private val mainController: MainController by di()
private val projectContext: ProjectContext by di() private val projectContext: ProjectContext by di()
private val databaseService: DatabaseService by di() private val databaseService: DatabaseService by di()
private val databaseController: DatabaseController by di()
private var database: SchemaDatabase? = null private var database: SchemaDatabase? = null
@@ -37,9 +34,9 @@ class TablesListView : View() {
setOnMouseClicked { event -> setOnMouseClicked { event ->
val selected = selectionModel?.selectedItem?.value val selected = selectionModel?.selectedItem?.value
if (event.clickCount == 2 && selected is SchemaTable) { if (event.clickCount == 2 && selected is SchemaTable) {
onConnection { databaseController
executeScript(selected.name, "SELECT * FROM ${selected.name}", this) .execute("SELECT * FROM ${selected.name}", selected.name)
} ?.let(mainController::openQuery)
} }
} }
} }
@@ -57,7 +54,10 @@ class TablesListView : View() {
val name = "Script ${++index}" val name = "Script ${++index}"
mainController.openScript( mainController.openScript(
fsNode = InMemoryStringFileNode(name, "sql", ""), fsNode = InMemoryStringFileNode(name, "sql", ""),
execute = { code -> onConnection { executeScript(name, code, this) } }, execute = { code ->
databaseController.execute(code, name)?.let(mainController::openQuery)
refresh()
},
saveable = false saveable = false
) )
} }
@@ -84,51 +84,12 @@ class TablesListView : View() {
treeView.root.expandTo(1) treeView.root.expandTo(1)
} }
private fun onConnection(op: Connection.() -> Unit) {
databaseService.run {
try {
op(this)
} catch (e: SQLException) {
error("SQL Error ${e.sqlState}", e.joinToString("\n") { e.message ?: "" }, title = "SQL Error")
}
}
}
private fun executeScript(name: String, sql: String, conn: Connection) {
val stmt = conn.prepareStatement(sql).apply { execute() }
val results = stmt.resultSet
val metadata = stmt.metaData
if (results != null && metadata != null) {
val columns = mutableListOf<String>()
for (i in 1..metadata.columnCount) {
columns += metadata.getColumnLabel(i)
}
val data = mutableListOf<DataRecord>()
while (results.next()) {
val record = mutableMapOf<String, DataField>()
for (i in 1..metadata.columnCount) {
record[metadata.getColumnLabel(i)] = DataField(results.getObject(i).toString())
}
data += DataRecord(record)
}
mainController.openQuery(Query(name, columns, data))
}
refresh()
}
private fun renameElement(element: Schema, newName: String): Schema { private fun renameElement(element: Schema, newName: String): Schema {
onConnection { element.rename(this, newName) } databaseController.execute { element.rename(this, newName) }
return element return element
} }
private fun deleteElement(element: Schema) { private fun deleteElement(element: Schema) {
onConnection(element::delete) databaseController.execute(element::delete)
} }
} }

View File

@@ -1,17 +1,19 @@
package com.bartlomiejpluta.base.editor.database.view.query package com.bartlomiejpluta.base.editor.database.view.query
import com.bartlomiejpluta.base.editor.database.component.QueryFieldCell import com.bartlomiejpluta.base.editor.database.component.QueryFieldCell
import com.bartlomiejpluta.base.editor.database.controller.DatabaseController
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.viewmodel.QueryVM import com.bartlomiejpluta.base.editor.database.viewmodel.QueryVM
import javafx.scene.control.TableColumn import javafx.scene.control.TableColumn
import org.kordamp.ikonli.javafx.FontIcon
import tornadofx.* import tornadofx.*
class QueryResultView : View() { class QueryResultView : View() {
private val databaseController: DatabaseController by di()
private val queryVM = find<QueryVM>() private val queryVM = find<QueryVM>()
private val table = tableview<DataRecord> { private val table = tableview<DataRecord>()
}
init { init {
queryVM.itemProperty.addListener { _, _, _ -> refreshData() } queryVM.itemProperty.addListener { _, _, _ -> refreshData() }
@@ -38,7 +40,11 @@ class QueryResultView : View() {
override val root = borderpane { override val root = borderpane {
top = toolbar { top = toolbar {
button(graphic = FontIcon("fa-refresh")) {
action {
databaseController.execute(queryVM.query, queryVM.name)?.let { queryVM.item = it }
}
}
} }
center = table center = table

View File

@@ -7,4 +7,7 @@ import tornadofx.getValue
class QueryVM(query: Query) : ItemViewModel<Query>(query) { class QueryVM(query: Query) : ItemViewModel<Query>(query) {
val nameProperty = bind(Query::nameProperty) val nameProperty = bind(Query::nameProperty)
val name by nameProperty val name by nameProperty
val queryProperty = bind(Query::queryProperty)
val query by queryProperty
} }