Skip to content

Instantly share code, notes, and snippets.

@tomix26
Created February 27, 2023 19:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomix26/9e1ea63353707ef3b5cf4869fc50eec2 to your computer and use it in GitHub Desktop.
Save tomix26/9e1ea63353707ef3b5cf4869fc50eec2 to your computer and use it in GitHub Desktop.
Plugin that watches for the occurrence of connection strings in the log and updates the database settings in IntelliJ IDEA accordingly
import com.intellij.database.psi.DbPsiFacade
import com.intellij.database.util.DbImplUtil
import com.intellij.execution.filters.ConsoleInputFilterProvider
import com.intellij.execution.filters.InputFilter
import com.intellij.execution.ui.ConsoleViewContentType as ContentType
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Pair
import java.util.regex.Matcher
import java.util.regex.Pattern
import static com.intellij.execution.filters.ConsoleInputFilterProvider.INPUT_FILTER_PROVIDERS
import static com.intellij.openapi.util.text.StringUtil.newBombedCharSequence
import static liveplugin.PluginUtil.changeGlobalVar
import static liveplugin.PluginUtil.show
// depends-on-plugin com.intellij.database
if (isIdeStartup) return
// =====================================================================================
// Customizable mappings of application's data sources to IntelliJ IDEA's database names
// =====================================================================================
def dataSourceMapping = [
[ds: "dataSource", db: 'embedded-postgres', driver: 'postgresql'],
[ds: "dataSource", db: 'embedded-sqlserver', driver: 'sqlserver'],
[ds: "dataSource", db: 'embedded-mariadb', driver: 'mariadb'],
[ds: "dataSource", db: 'embedded-mysql', driver: 'mysql'],
[ds: "dataSource", db: 'embedded-h2', driver: 'h2']
]
Pattern pattern = Pattern.compile(".*JDBC URL to connect to '([^']+)': url='(jdbc:([^:]+):[^']+)'.*")
static CharSequence limitAndCutNewline(String text, int maxLength, milliseconds) {
int endIndex = text.length()
if (text.endsWith("\n")) {
--endIndex
}
if (maxLength >= 0) {
endIndex = Math.min(endIndex, maxLength)
}
def substring = text.substring(0, endIndex)
if (milliseconds > 0) {
return newBombedCharSequence(substring, milliseconds)
}
return substring
}
static def updateDatabase(Project project, String dbName, String jdbcUrl) {
DbPsiFacade.getInstance(project).getDataSources()
.collect { DbImplUtil.getMaybeLocalDataSource(it) }
.findAll { it != null }
.findAll { it.name == dbName }
.findAll { it.url != jdbcUrl }
.forEach { ds ->
ds.url = jdbcUrl
show("Database '" + ds.name + "' has been updated to '" + jdbcUrl + "'")
}
}
static def databaseUpdater(Project project, Pattern pattern, List<Map<String, String>> mappings) {
new InputFilter() {
List<Pair<String, ContentType>> applyFilter(String consoleText, ContentType contentType) {
if (!consoleText.contains("EmbeddedDatabaseReporter")) {
return null
}
try {
CharSequence textForMatching = limitAndCutNewline(consoleText, 500, 1000)
Matcher matcher = pattern.matcher(textForMatching)
if (matcher.matches()) {
def dsName = matcher.group(1)
def jdbcUrl = matcher.group(2)
def driver = matcher.group(3)
def mapping = mappings.find { it.get("ds") == dsName && it.get("driver") == driver }
if (mapping) {
updateDatabase(project, mapping.get("db"), jdbcUrl)
}
}
} catch (ProcessCanceledException ex) {
show("Processing took too long for: " + consoleText)
}
return null
}
}
}
def extensionPoint = Extensions.rootArea.getExtensionPoint(INPUT_FILTER_PROVIDERS)
def inputFilterProvider = changeGlobalVar("EmbeddedDatabaseUpdater") { prevInputFilterProvider ->
if (prevInputFilterProvider != null && extensionPoint.hasExtension(prevInputFilterProvider)) {
extensionPoint.unregisterExtension(prevInputFilterProvider)
}
new ConsoleInputFilterProvider() {
InputFilter[] getDefaultFilters(Project project) {
[databaseUpdater(project, pattern, dataSourceMapping)]
}
}
}
extensionPoint.registerExtension(inputFilterProvider)
@tomix26
Copy link
Author

tomix26 commented Feb 27, 2023

How to use it:

  1. Install the LivePlugin plugin
  2. In LivePlugin, create a new Groovy plugin and copy the snippet above into the newly created plugin.groovy file
  3. In IntelliJ IDEA, create a new data source with the corresponding name and driver (embedded-postgres, embedded-sqlserver, etc. - names and types are configurable at the beginning of the script)
  4. Run the plugin and from that moment the database settings will be synchronized according to the connection strings produced by the embedded-database-spring-test library

@spyro2000
Copy link

spyro2000 commented Sep 4, 2023

Hi there,

loving this plugin, worked like a charm the first time. But after the plugin (correctly!) replaces port and db-name in the data source, IntelliJ still displays the old db only:

image

Even after refreshing and/or reconnecting, it's not possible to connect to the current DB (I refresh the DB after each test):

image

Maybe it would be better to (re)create the date source instead of editing it?

Update: Seems like IntelliJ insists of using the first found "default database".
Maybe this could be updated and refreshed (sorry, don't know the internals)...?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment