FEAT: Multi query support!
Queries will be split by the ';' and ran at the same time! They will each have their own table display and info.
This commit is contained in:
parent
da3ad813be
commit
3382a1537b
BIN
bin/web_server
BIN
bin/web_server
Binary file not shown.
@ -4,6 +4,7 @@ import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Azpect3120/Web-Database-Viewer/internal/templates"
|
||||
"github.com/gin-contrib/sessions"
|
||||
@ -16,13 +17,19 @@ func QueryCurrent(c *gin.Context) {
|
||||
query := c.PostForm("sql")
|
||||
conn := getConnection(c)
|
||||
|
||||
queries := strings.Split(query, ";")
|
||||
var results []string
|
||||
for _, query := range queries {
|
||||
cols, data, err := queryConnection(query, conn)
|
||||
if err != nil {
|
||||
c.String(200, templates.ErrorQueryResults(err))
|
||||
return
|
||||
}
|
||||
|
||||
c.String(200, templates.QueryResults(cols, data))
|
||||
results = append(results, templates.QueryResult(cols, data))
|
||||
}
|
||||
|
||||
c.String(200, templates.ConcatResults(results))
|
||||
}
|
||||
|
||||
func queryConnection(query, url string) ([]string, []map[string]interface{}, error) {
|
||||
|
||||
@ -13,7 +13,7 @@ const MANUAL_QUERY string = `
|
||||
<label for="auto-toggle" class="text-sm font-medium text-gray-700">Auto-Run</label>
|
||||
<input type="checkbox" name="toggle" class="toggle-checkbox">
|
||||
</form>
|
||||
<button hx-post="/v1/api/query" hx-trigger="click" hx-swap="outerHTML" hx-target="#query-result" hx-indicator="#spinner" hx-include="#sql" class="bg-blue-500 text-white py-2 px-3 rounded-md text-xs md:text-sm">Run Query</button>
|
||||
<button hx-post="/v1/api/query" hx-trigger="click" hx-swap="outerHTML" hx-target="#query-results" hx-indicator="#spinner" hx-include="#sql" class="bg-blue-500 text-white py-2 px-3 rounded-md text-xs md:text-sm">Run Query</button>
|
||||
</div>
|
||||
</div>
|
||||
<textarea id="sql" name="sql" rows="4" class="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm"></textarea>
|
||||
@ -34,7 +34,7 @@ const AUTO_QUERY string = `
|
||||
<button class="bg-blue-500 text-white py-2 px-3 rounded-md text-xs md:text-sm opacity-60 cursor-default" title="Disable Auto-Run to use manual queries." disabled>Run Query</button>
|
||||
</div>
|
||||
</div>
|
||||
<textarea id="sql" name="sql" rows="4" class="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm" hx-post="/v1/api/query" hx-trigger="input delay:500ms" hx-swap="outerHTML" hx-target="#query-result" hx-indicator="#spinner"></textarea>
|
||||
<textarea id="sql" name="sql" rows="4" class="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm" hx-post="/v1/api/query" hx-trigger="input delay:500ms" hx-swap="outerHTML" hx-target="#query-results" hx-indicator="#spinner"></textarea>
|
||||
<p id="spinner" class="text-gray-700 text-sm px-1 py-2 htmx-indicator hidden"> Query running... </p>
|
||||
<p id="query-error" hx-swap-oob="outerHTML" class="text-red-500 py-2 text-sm hidden"></p>
|
||||
</div>
|
||||
|
||||
@ -4,8 +4,19 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Result list definition
|
||||
const result_list_open string = `<ul id="query-results">`
|
||||
const result_list_close string = `</ul>`
|
||||
|
||||
// Result item definition
|
||||
const result_item string = `
|
||||
<li class="overflow-x-auto overflow-y-hidden bg-white rounded-lg shadow-md mb-8">
|
||||
%s
|
||||
</li>
|
||||
`
|
||||
|
||||
// Table wrapper definitions
|
||||
const table_open string = `<table id="query-result" class="min-w-full divide-y divide-gray-200">`
|
||||
const table_open string = `<table class="min-w-full divide-y divide-gray-200">`
|
||||
const table_close string = `</table>`
|
||||
|
||||
// Header definitions
|
||||
@ -23,10 +34,20 @@ const query_error_message string = `<p id="query-error" hx-swap-oob="outerHTML"
|
||||
const query_error_message_blank string = `<p id="query-error" hx-swap-oob="outerHTML" class="text-red-500 py-2 text-sm hidden"></p>`
|
||||
|
||||
func ErrorQueryResults(e error) string {
|
||||
return table_open + table_close + fmt.Sprintf(query_error_message, e.Error())
|
||||
return result_list_open + result_list_close + fmt.Sprintf(query_error_message, e.Error())
|
||||
}
|
||||
|
||||
func QueryResults(cols []string, rows []map[string]interface{}) string {
|
||||
func ConcatResults(items []string) string {
|
||||
var html string = result_list_open
|
||||
|
||||
for _, h := range items {
|
||||
html += h
|
||||
}
|
||||
|
||||
return html + result_list_close
|
||||
}
|
||||
|
||||
func QueryResult(cols []string, rows []map[string]interface{}) string {
|
||||
head := generateHead(cols)
|
||||
|
||||
body := table_body_open
|
||||
@ -36,7 +57,7 @@ func QueryResults(cols []string, rows []map[string]interface{}) string {
|
||||
|
||||
body += table_body_close
|
||||
|
||||
return table_open + head + body + table_close + query_error_message_blank
|
||||
return fmt.Sprintf(result_item, table_open+head+body+table_close+query_error_message_blank)
|
||||
}
|
||||
|
||||
// Generate the tables head row
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -80,17 +80,13 @@
|
||||
<div class="flex items-center justify-between">
|
||||
<label for="sql" class="block text-sm font-medium text-gray-700">SQL Query</label>
|
||||
<div class="flex items-center space-x-6">
|
||||
<form class="flex items-center space-x-2" hx-get="/v1/web/query/auto" hx-swap="outerHTML"
|
||||
hx-target="#query-main" hx-trigger="input">
|
||||
<form class="flex items-center space-x-2" hx-get="/v1/web/query/auto" hx-swap="outerHTML" hx-target="#query-main" hx-trigger="input">
|
||||
<label for="auto-toggle" class="text-sm font-medium text-gray-700">Auto-Run</label>
|
||||
<input type="checkbox" name="toggle" class="toggle-checkbox"
|
||||
title="Toggle auto-query functionality. Note: This will send whatever query is in the input and clear the box.">
|
||||
<input type="checkbox" name="toggle" class="toggle-checkbox" title="Toggle auto-query functionality. Note: This will send whatever query is in the input and clear the box.">
|
||||
</form>
|
||||
|
||||
<!-- Manual Query Button -->
|
||||
<button hx-post="/v1/api/query" hx-trigger="click" hx-swap="outerHTML" hx-target="#query-result"
|
||||
hx-indicator="#spinner" hx-include="#sql"
|
||||
class="bg-blue-500 text-white py-2 px-3 rounded-md text-xs md:text-sm">Run Query</button>
|
||||
<button hx-post="/v1/api/query" hx-trigger="click" hx-swap="outerHTML" hx-target="#query-results" hx-indicator="#spinner" hx-include="#sql" class="bg-blue-500 text-white py-2 px-3 rounded-md text-xs md:text-sm">Run Query</button>
|
||||
|
||||
<!-- Auto Query Button -->
|
||||
<!-- <button class="bg-blue-500 text-white py-2 px-3 rounded-md text-xs md:text-sm opacity-60 cursor-default" title="Disable Auto-Run to use manual queries." disabled>Run Query</button> -->
|
||||
@ -98,20 +94,56 @@
|
||||
</div>
|
||||
|
||||
<!-- Manual Query Input -->
|
||||
<textarea id="sql" name="sql" rows="4"
|
||||
class="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm"></textarea>
|
||||
<textarea id="sql" name="sql" rows="4" class="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm"></textarea>
|
||||
|
||||
<!-- Auto Query Input -->
|
||||
<!-- <textarea id="sql" name="sql" rows="4" class="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm" hx-post="/v1/api/query" hx-trigger="input delay:500ms" hx-swap="outerHTML" hx-target="#query-result" hx-indicator="#spinner"></textarea> -->
|
||||
<!-- <textarea id="sql" name="sql" rows="4" class="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm" hx-post="/v1/api/query" hx-trigger="input delay:500ms" hx-swap="outerHTML" hx-target="#query-results" hx-indicator="#spinner"></textarea> -->
|
||||
|
||||
<p id="spinner" class="text-gray-700 text-sm px-1 py-2 htmx-indicator hidden"> Query running... </p>
|
||||
<p id="query-error" hx-swap-oob="outerHTML" class="text-red-500 py-2 text-sm hidden"></p>
|
||||
</div>
|
||||
|
||||
<!-- Query Results -->
|
||||
<div class="overflow-x-auto overflow-y-hidden bg-white shadow-md rounded-lg">
|
||||
<table id="query-result" class="min-w-full divide-y divide-gray-200"></table>
|
||||
</div>
|
||||
<ul id="query-results">
|
||||
<!-- <li class="overflow-x-auto overflow-y-hidden bg-white rounded-lg shadow-md"> -->
|
||||
<!-- <table class="min-w-full divide-y divide-gray-200"> -->
|
||||
<!-- <thead class="bg-gray-50"> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">id</th> -->
|
||||
<!-- <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">username</th> -->
|
||||
<!-- <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">password</th> -->
|
||||
<!-- <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">secret</th> -->
|
||||
<!-- <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">permission</th> -->
|
||||
<!-- </tr> -->
|
||||
<!-- </thead> -->
|
||||
<!-- <tbody class="bg-white divide-y divide-gray-200"> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap">513fbe25-ff69-4386-87c2-90ff6b691169</td> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap">ConnieH</td> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap">d1d15c321c523cbcfe2c18f92168cb5b:</td> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap"><nil></td> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap">Admin</td> -->
|
||||
<!-- </tr> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap">5e02c767-f035-40da-867a-1c067c1678e2</td> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap">AustinH</td> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap">588b2205579a4ee48f9014f2742fd1b0:</td> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap"><nil></td> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap">User</td> -->
|
||||
<!-- </tr> -->
|
||||
<!-- <tr> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap">1d007e19-d84b-4cc6-9e6b-1c51122aa3e5</td> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap">Azpect</td> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap">a8778398e9afed7f00a88b13ffc14a95:</td> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap"><nil></td> -->
|
||||
<!-- <td class="px-6 py-4 whitespace-nowrap">Dev</td> -->
|
||||
<!-- </tr> -->
|
||||
<!-- </tbody> -->
|
||||
<!-- </table> -->
|
||||
<!-- <p id="query-error" hx-swap-oob="outerHTML" class="text-red-500 py-2 text-sm hidden"></p> -->
|
||||
<!-- </li> -->
|
||||
</ul>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@ -230,7 +262,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Manage Connections Modal -->
|
||||
<div id="manager-modal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden opacity-0"></div>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user