Skip to content

Commit 0d2e6ce

Browse files
committed
feat(database): add SQL generation functionality #80
This commit adds functionality to generate SQL scripts based on selected tables. It introduces new classes and methods to handle the SQL generation process. The `GenSqlScriptBySelection` class now includes a `generateSqlWorkflow` method that runs the SQL generation process in the background. It also introduces the `GenSqlFlow` class, which handles the step-by-step process of generating SQL scripts. The `clarify` method prompts the user to clarify the requirements, while the `generate` method generates the SQL script based on the clarified requirements and selected tables. This new functionality enhances the database migration capabilities of the application.
1 parent 26227ba commit 0d2e6ce

File tree

3 files changed

+109
-14
lines changed

3 files changed

+109
-14
lines changed

exts/database/src/main/kotlin/cc/unitmesh/database/actions/GenSqlScriptBySelection.kt

Lines changed: 104 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,32 @@
11
package cc.unitmesh.database.actions
22

33
import cc.unitmesh.devti.AutoDevBundle
4-
import cc.unitmesh.devti.gui.sendToChatWindow
4+
import cc.unitmesh.devti.gui.chat.ChatCodingPanel
5+
import cc.unitmesh.devti.gui.sendToChatPanel
56
import cc.unitmesh.devti.intentions.action.base.AbstractChatIntention
6-
import cc.unitmesh.devti.provider.ContextPrompter
7+
import cc.unitmesh.devti.llms.LLMProvider
8+
import cc.unitmesh.devti.llms.LlmFactory
79
import cc.unitmesh.devti.template.TemplateRender
810
import com.intellij.database.model.DasTable
911
import com.intellij.database.model.ObjectKind
1012
import com.intellij.database.psi.DbPsiFacade
1113
import com.intellij.database.util.DasUtil
14+
import com.intellij.openapi.application.ApplicationManager
15+
import com.intellij.openapi.application.ReadAction
1216
import com.intellij.openapi.diagnostic.logger
1317
import com.intellij.openapi.editor.Editor
18+
import com.intellij.openapi.progress.ProgressIndicator
19+
import com.intellij.openapi.progress.ProgressManager
20+
import com.intellij.openapi.progress.Task
1421
import com.intellij.openapi.project.Project
1522
import com.intellij.psi.PsiFile
23+
import kotlinx.coroutines.runBlocking
1624

1725

1826
class GenSqlScriptBySelection : AbstractChatIntention() {
1927
override fun priority(): Int = 1001
20-
2128
override fun startInWriteAction(): Boolean = false
22-
2329
override fun getFamilyName(): String = AutoDevBundle.message("migration.database.plsql")
24-
2530
override fun getText(): String = AutoDevBundle.message("migration.database.sql.generate")
2631

2732
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean {
@@ -32,10 +37,12 @@ class GenSqlScriptBySelection : AbstractChatIntention() {
3237
private val logger = logger<GenSqlScriptBySelection>()
3338

3439
override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
40+
if (editor == null || file == null) return
41+
3542
val dbPsiFacade = DbPsiFacade.getInstance(project)
3643
val dataSource = dbPsiFacade.dataSources.firstOrNull() ?: return
3744

38-
val selectedText = editor?.selectionModel?.selectedText
45+
val selectedText = editor.selectionModel.selectedText
3946

4047
val rawDataSource = dbPsiFacade.getDataSourceManager(dataSource).dataSources.firstOrNull() ?: return
4148
val databaseVersion = rawDataSource.databaseVersion
@@ -55,16 +62,80 @@ class GenSqlScriptBySelection : AbstractChatIntention() {
5562
)
5663

5764
val actions = DbContextActionProvider(dasTables)
58-
val prompter = generateStepOnePrompt(dbContext, actions)
5965

60-
sendToChatWindow(project, getActionType()) { panel, service ->
61-
service.handlePromptAndResponse(panel, object : ContextPrompter() {
62-
override fun displayPrompt(): String = prompter
63-
override fun requestPrompt(): String = prompter
64-
}, null, false)
66+
sendToChatPanel(project) { contentPanel, _ ->
67+
val llmProvider = LlmFactory().create(project)
68+
val prompter = GenSqlFlow(dbContext, actions, contentPanel, llmProvider)
69+
ApplicationManager.getApplication().invokeLater {
70+
71+
ProgressManager.getInstance()
72+
.run(generateSqlWorkflow(project, contentPanel, prompter))
73+
}
6574
}
6675
}
6776

77+
private fun generateSqlWorkflow(
78+
project: Project,
79+
ui: ChatCodingPanel,
80+
flow: GenSqlFlow,
81+
) =
82+
object : Task.Backgroundable(project, "Loading retained test failure", true) {
83+
override fun run(indicator: ProgressIndicator) {
84+
indicator.fraction = 0.2
85+
86+
87+
indicator.text = AutoDevBundle.message("migration.database.sql.generate.clarify")
88+
val tables = ReadAction.compute<String, Throwable> {
89+
flow.clarify()
90+
}
91+
92+
// tables will be list in string format, like: `[table1, table2]`, we need to parse to Lists
93+
val tableNames = tables.substringAfter("[").substringBefore("]")
94+
.split(", ").map { it.trim() }
95+
96+
indicator.fraction = 0.6
97+
val sqlScript = flow.generate(tableNames)
98+
99+
logger.info("SQL Script: $sqlScript")
100+
101+
indicator.fraction = 1.0
102+
}
103+
}
104+
}
105+
106+
class GenSqlFlow(
107+
val dbContext: DbContext,
108+
val actions: DbContextActionProvider,
109+
val ui: ChatCodingPanel,
110+
val llm: LLMProvider
111+
) {
112+
private val logger = logger<GenSqlFlow>()
113+
114+
fun clarify(): String {
115+
val stepOnePrompt = generateStepOnePrompt(dbContext, actions)
116+
ui.addMessage(stepOnePrompt, true, stepOnePrompt)
117+
// for answer
118+
ui.addMessage(AutoDevBundle.message("autodev.loading"))
119+
120+
return runBlocking {
121+
val prompt = llm.stream(stepOnePrompt, "")
122+
return@runBlocking ui.updateMessage(prompt)
123+
}
124+
}
125+
126+
fun generate(tableNames: List<String>): String {
127+
val stepTwoPrompt = generateStepTwoPrompt(dbContext, actions, tableNames)
128+
ui.addMessage(stepTwoPrompt, true, stepTwoPrompt)
129+
// for answer
130+
ui.addMessage(AutoDevBundle.message("autodev.loading"))
131+
132+
return runBlocking {
133+
val prompt = llm.stream(stepTwoPrompt, "")
134+
return@runBlocking ui.updateMessage(prompt)
135+
}
136+
}
137+
138+
68139
private fun generateStepOnePrompt(context: DbContext, actions: DbContextActionProvider): String {
69140
val templateRender = TemplateRender("genius/sql")
70141
val template = templateRender.getTemplate("sql-gen-clarify.vm")
@@ -77,15 +148,35 @@ class GenSqlScriptBySelection : AbstractChatIntention() {
77148
logger.info("Prompt: $prompter")
78149
return prompter
79150
}
151+
152+
private fun generateStepTwoPrompt(
153+
dbContext: DbContext,
154+
actions: DbContextActionProvider,
155+
tableInfos: List<String>
156+
): String {
157+
val templateRender = TemplateRender("genius/sql")
158+
val template = templateRender.getTemplate("sql-gen-generate.vm")
159+
160+
dbContext.tableInfos = actions.getTableColumns(tableInfos)
161+
162+
templateRender.context = dbContext
163+
templateRender.actions = actions
164+
165+
val prompter = templateRender.renderTemplate(template)
166+
167+
logger.info("Prompt: $prompter")
168+
return prompter
169+
}
80170
}
81171

172+
82173
data class DbContext(
83174
val requirement: String,
84175
val databaseVersion: String,
85176
val schemaName: String,
86177
val tableNames: List<String>,
87178
// for step 2
88-
val tableInfos: List<String> = emptyList(),
179+
var tableInfos: List<String> = emptyList(),
89180
)
90181

91182
data class DbContextActionProvider(val dasTables: List<DasTable>) {

src/main/kotlin/com/intellij/temporary/gui/block/CodeBlockView.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@ class CodeBlockView(
105105
document: Document,
106106
disposable: Disposable
107107
): EditorEx {
108-
val editor: Editor = EditorFactory.getInstance().createViewer(document, project, EditorKind.PREVIEW)
108+
val editor: Editor = EditorFactory.getInstance()
109+
.createViewer(document, project, EditorKind.PREVIEW)
110+
109111
disposable.whenDisposed(disposable) {
110112
EditorFactory.getInstance().releaseEditor(editor)
111113
}

src/main/resources/messages/AutoDevBundle.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,5 @@ migration.database.plsql.generate.entity=Generate Entity
120120
migration.database.plsql.visual=Visualize PL/SQL
121121
migration.database.plsql.modular.design=Modular Code
122122
migration.database.sql.generate=Generate SQL (by selection)
123+
migration.database.sql.generate.clarify=Clarify Requiements
124+
migration.database.sql.generate.generate=Generate SQL

0 commit comments

Comments
 (0)