feat(cli): extend Repl with printNames and tableNames
This commit is contained in:
1 parent
9387689ade
commit
aedd88ca70
2 files changed
+102
-15
No files matched your search
@@ -319,12 +319,34 @@ class Repl(
|
|||||||
}
|
}
|
||||||
is CreateTableResult -> output.appendLine("Table ${result.tableName} created")
|
is CreateTableResult -> output.appendLine("Table ${result.tableName} created")
|
||||||
is DropTableResult -> output.appendLine("Table ${result.tableName} dropped")
|
is DropTableResult -> output.appendLine("Table ${result.tableName} dropped")
|
||||||
|
is TruncateTableResult -> output.appendLine("Table(s) ${result.tableNames.joinToString(", ")} truncated")
|
||||||
|
is MergeResult -> {
|
||||||
|
output.appendLine(
|
||||||
|
"${rowsWord(result.insertedCount)} inserted, ${rowsWord(result.updatedCount)} updated, " +
|
||||||
|
"${rowsWord(result.deletedCount)} deleted"
|
||||||
|
)
|
||||||
|
result.returning?.let { output.appendLine(TableRenderer.render(it)) }
|
||||||
|
}
|
||||||
|
is AlterTableResult -> output.appendLine("Table ${result.tableName} altered")
|
||||||
is CreateIndexResult -> output.appendLine("Index ${result.indexName} created")
|
is CreateIndexResult -> output.appendLine("Index ${result.indexName} created")
|
||||||
is DropIndexResult -> output.appendLine("Index ${result.indexName} dropped")
|
is DropIndexResult -> output.appendLine("Index ${result.indexName} dropped")
|
||||||
|
is CreateViewResult -> output.appendLine("View ${result.viewName} created")
|
||||||
|
is DropViewResult -> output.appendLine("View ${result.viewName} dropped")
|
||||||
|
is CreateTriggerResult -> output.appendLine("Trigger ${result.triggerName} created")
|
||||||
|
is DropTriggerResult -> output.appendLine("Trigger ${result.triggerName} dropped")
|
||||||
|
is CreateSequenceResult -> output.appendLine("Sequence ${result.sequenceName} created")
|
||||||
|
is DropSequenceResult -> output.appendLine("Sequence ${result.sequenceName} dropped")
|
||||||
|
is AlterSequenceResult -> output.appendLine("Sequence ${result.sequenceName} altered")
|
||||||
is ExplainResult -> result.plan.forEach { output.appendLine(it) }
|
is ExplainResult -> result.plan.forEach { output.appendLine(it) }
|
||||||
BeginResult -> output.appendLine("Transaction started")
|
BeginResult -> output.appendLine("Transaction started")
|
||||||
CommitResult -> output.appendLine("Transaction committed")
|
CommitResult -> output.appendLine("Transaction committed")
|
||||||
RollbackResult -> output.appendLine("Transaction rolled back")
|
RollbackResult -> output.appendLine("Transaction rolled back")
|
||||||
|
is SavepointResult -> output.appendLine("Savepoint ${result.name} created")
|
||||||
|
is ReleaseSavepointResult -> output.appendLine("Savepoint ${result.name} released")
|
||||||
|
is RollbackToSavepointResult -> output.appendLine("Rolled back to savepoint ${result.name}")
|
||||||
|
is PrepareResult -> output.appendLine("Prepared statement ${result.name} created")
|
||||||
|
is DeallocateResult ->
|
||||||
|
output.appendLine(if (result.all) "All prepared statements deallocated" else "Prepared statement ${result.name} deallocated")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,14 +354,15 @@ class Repl(
|
|||||||
val parts = command.split(Regex("\\s+"), limit = 2)
|
val parts = command.split(Regex("\\s+"), limit = 2)
|
||||||
when (parts[0]) {
|
when (parts[0]) {
|
||||||
".exit", ".quit" -> return true
|
".exit", ".quit" -> return true
|
||||||
".tables" -> {
|
".tables" -> printNames(tableNames(), "(no tables)")
|
||||||
val names = catalog.tableNames
|
".indexes" -> printNames(indexNames(), "(no indexes)")
|
||||||
if (names.isEmpty()) output.appendLine("(no tables)") else names.forEach { output.appendLine(it) }
|
".views" -> printNames(viewNames(), "(no views)")
|
||||||
}
|
".triggers" -> printNames(triggerNames(), "(no triggers)")
|
||||||
".indexes" -> {
|
".sequences" -> printNames(sequenceNames(), "(no sequences)")
|
||||||
val names = catalog.indexNames
|
".prepared" -> printNames(
|
||||||
if (names.isEmpty()) output.appendLine("(no indexes)") else names.forEach { output.appendLine(it) }
|
diskExecutor?.preparedStatementNames ?: executor.preparedStatementNames,
|
||||||
}
|
"(no prepared statements)"
|
||||||
|
)
|
||||||
".schema" -> {
|
".schema" -> {
|
||||||
if (parts.size < 2 || parts[1].isBlank()) {
|
if (parts.size < 2 || parts[1].isBlank()) {
|
||||||
printError("usage: .schema <table>")
|
printError("usage: .schema <table>")
|
||||||
@@ -352,25 +375,87 @@ class Repl(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun printNames(names: List<String>, emptyMessage: String) {
|
||||||
|
if (names.isEmpty()) output.appendLine(emptyMessage) else names.forEach { output.appendLine(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tableNames(): List<String> = diskCatalog?.tableNames ?: catalog.tableNames
|
||||||
|
private fun viewNames(): List<String> = diskCatalog?.viewNames ?: catalog.viewNames
|
||||||
|
private fun triggerNames(): List<String> = diskCatalog?.triggerNames ?: catalog.triggerNames
|
||||||
|
private fun sequenceNames(): List<String> = diskCatalog?.sequenceNames ?: catalog.sequenceNames
|
||||||
|
|
||||||
|
private fun indexNames(): List<String> {
|
||||||
|
val disk = diskCatalog ?: return catalog.indexNames
|
||||||
|
return disk.tableNames.flatMap { disk.table(it).secondaryIndexes.map { index -> index.name } }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Every `CREATE [UNIQUE] INDEX ...;` line for [tableName], one engine or the other - never both. */
|
||||||
|
private fun indexLines(tableName: String): List<String> {
|
||||||
|
val disk = diskCatalog
|
||||||
|
if (disk != null) {
|
||||||
|
val table = disk.tableOrNull(tableName) ?: return emptyList()
|
||||||
|
return table.secondaryIndexes.map { index ->
|
||||||
|
val uniqueKeyword = if (index.unique) "UNIQUE " else ""
|
||||||
|
"CREATE ${uniqueKeyword}INDEX ${index.name} ON $tableName (${index.columnNames.joinToString(", ")});"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return catalog.indexDefinitions()
|
||||||
|
.filter { it.tableName.equals(tableName, ignoreCase = true) }
|
||||||
|
.map { index ->
|
||||||
|
val uniqueKeyword = if (index.unique) "UNIQUE " else ""
|
||||||
|
"CREATE ${uniqueKeyword}INDEX ${index.name} ON $tableName (${index.columnDisplayName});"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Every `CREATE TRIGGER ...` block for [tableName], one engine or the other - never both. */
|
||||||
|
private fun triggerLines(tableName: String): List<String> {
|
||||||
|
val definitions = diskCatalog?.triggerDefinitions() ?: catalog.triggerDefinitions()
|
||||||
|
return definitions
|
||||||
|
.filter { it.tableName.equals(tableName, ignoreCase = true) }
|
||||||
|
.map { SqlWriter.triggerText(it) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun printSchema(tableName: String) {
|
private fun printSchema(tableName: String) {
|
||||||
val table = catalog.tableOrNull(tableName)
|
val schema = diskCatalog?.tableOrNull(tableName)?.schema
|
||||||
if (table == null) {
|
?: diskCatalog?.temporaryTableOrNull(tableName)?.schema
|
||||||
|
?: catalog.tableOrNull(tableName)?.schema
|
||||||
|
if (schema == null) {
|
||||||
printError("no such table: $tableName")
|
printError("no such table: $tableName")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val schema = table.schema
|
|
||||||
val builder = StringBuilder()
|
val builder = StringBuilder()
|
||||||
builder.appendLine("CREATE TABLE ${schema.name} (")
|
builder.appendLine("CREATE TABLE ${schema.name} (")
|
||||||
schema.columns.forEachIndexed { index, column ->
|
val lines = mutableListOf<String>()
|
||||||
|
schema.columns.forEach { column ->
|
||||||
val constraints = buildString {
|
val constraints = buildString {
|
||||||
if (column.primaryKey) append(" PRIMARY KEY")
|
if (column.primaryKey) append(" PRIMARY KEY")
|
||||||
if (column.notNull && !column.primaryKey) append(" NOT NULL")
|
if (column.notNull && !column.primaryKey) append(" NOT NULL")
|
||||||
|
column.default?.let { append(" DEFAULT ${SqlWriter.expressionText(it)}") }
|
||||||
}
|
}
|
||||||
val comma = if (index < schema.columns.size - 1) "," else ""
|
lines.add(" ${column.name} ${column.type.displayWith(column.precision, column.scale)}$constraints")
|
||||||
builder.appendLine(" ${column.name} ${column.type.displayName}$constraints$comma")
|
|
||||||
}
|
}
|
||||||
builder.append(");")
|
if (schema.compositePrimaryKey.isNotEmpty()) {
|
||||||
|
lines.add(" PRIMARY KEY (${schema.compositePrimaryKey.joinToString(", ")})")
|
||||||
|
}
|
||||||
|
schema.foreignKeys.forEach { fk ->
|
||||||
|
val onDelete = if (fk.onDelete != ForeignKeyAction.NoAction) " ON DELETE ${fk.onDelete.sqlKeyword}" else ""
|
||||||
|
val onUpdate = if (fk.onUpdate != ForeignKeyAction.NoAction) " ON UPDATE ${fk.onUpdate.sqlKeyword}" else ""
|
||||||
|
lines.add(
|
||||||
|
" FOREIGN KEY (${fk.columns.joinToString(", ")}) REFERENCES ${fk.referencedTable} " +
|
||||||
|
"(${fk.referencedColumns.joinToString(", ")})$onDelete$onUpdate"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
schema.checks.forEach { check ->
|
||||||
|
lines.add(" CHECK (${SqlWriter.expressionText(check.expression)})")
|
||||||
|
}
|
||||||
|
schema.uniqueConstraints.forEach { unique ->
|
||||||
|
lines.add(" UNIQUE (${unique.columns.joinToString(", ")})")
|
||||||
|
}
|
||||||
|
builder.append(lines.joinToString(",\n"))
|
||||||
|
builder.append("\n);")
|
||||||
output.appendLine(builder.toString())
|
output.appendLine(builder.toString())
|
||||||
|
indexLines(schema.name).forEach { output.appendLine(it) }
|
||||||
|
triggerLines(schema.name).forEach { output.appendLine(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun printError(message: String?) {
|
private fun printError(message: String?) {
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ object TableRenderer {
|
|||||||
is Value.RealValue -> value.value.toString()
|
is Value.RealValue -> value.value.toString()
|
||||||
is Value.TextValue -> value.value
|
is Value.TextValue -> value.value
|
||||||
is Value.BooleanValue -> value.value.toString()
|
is Value.BooleanValue -> value.value.toString()
|
||||||
|
is Value.DecimalValue -> value.value.toPlainString()
|
||||||
|
is Value.DateValue -> value.value.toString()
|
||||||
is Value.NullValue -> "NULL"
|
is Value.NullValue -> "NULL"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user