mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 04:47:00 +00:00
fix(mysql): allow create database without selection
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { requiresDatabaseSelection } from "../useSqlExecution";
|
||||
import type { ConnectionConfig, QueryTab } from "@/types/database";
|
||||
|
||||
function connection(dbType: ConnectionConfig["db_type"]): ConnectionConfig {
|
||||
return {
|
||||
id: "conn-1",
|
||||
name: "Local",
|
||||
db_type: dbType,
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
username: "root",
|
||||
password: "",
|
||||
};
|
||||
}
|
||||
|
||||
function queryTab(database = ""): QueryTab {
|
||||
return {
|
||||
id: "tab-1",
|
||||
connectionId: "conn-1",
|
||||
database,
|
||||
schema: undefined,
|
||||
title: "SQL",
|
||||
sql: "",
|
||||
mode: "query",
|
||||
isDirty: false,
|
||||
isExecuting: false,
|
||||
isCancelling: false,
|
||||
isExplaining: false,
|
||||
};
|
||||
}
|
||||
|
||||
describe("requiresDatabaseSelection", () => {
|
||||
it("allows MySQL CREATE DATABASE to run without a selected database", () => {
|
||||
expect(requiresDatabaseSelection(queryTab(), connection("mysql"), "CREATE DATABASE app_db")).toBe(false);
|
||||
});
|
||||
|
||||
it("allows MySQL CREATE SCHEMA with options to run without a selected database", () => {
|
||||
expect(requiresDatabaseSelection(queryTab(), connection("mysql"), "CREATE SCHEMA `app-db` DEFAULT CHARACTER SET utf8mb4")).toBe(false);
|
||||
});
|
||||
|
||||
it("requires a database when a MySQL batch includes non-creation statements", () => {
|
||||
expect(requiresDatabaseSelection(queryTab(), connection("mysql"), "CREATE DATABASE app_db; SELECT * FROM users")).toBe(true);
|
||||
});
|
||||
|
||||
it("still requires a database for ordinary MySQL queries", () => {
|
||||
expect(requiresDatabaseSelection(queryTab(), connection("mysql"), "SELECT * FROM users")).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -14,6 +14,7 @@ import { extractSqlParameters } from "@/lib/sqlParameters";
|
||||
import type { ConnectionConfig, QueryTab } from "@/types/database";
|
||||
|
||||
const DANGER_RE = /^\s*(DROP|DELETE|TRUNCATE|ALTER|UPDATE|MERGE|REPLACE)\b/i;
|
||||
const CONNECTION_LEVEL_CREATE_DATABASE_RE = /^\s*CREATE\s+(?:DATABASE|SCHEMA)\s+(?:IF\s+NOT\s+EXISTS\s+)?[`"[\]\w$.-]+/i;
|
||||
|
||||
export function stripSqlComments(sql: string): string {
|
||||
return sql
|
||||
@@ -72,7 +73,7 @@ export function useSqlExecution(deps: {
|
||||
const tab = deps.activeTab.value;
|
||||
const sql = await resolvedExecutableSql(sqlOverride);
|
||||
if (!tab || !sql.trim()) return;
|
||||
if (requiresDatabaseSelection(tab, deps.activeConnection.value)) {
|
||||
if (requiresDatabaseSelection(tab, deps.activeConnection.value, sql)) {
|
||||
deps.onMissingDatabase?.();
|
||||
return;
|
||||
}
|
||||
@@ -118,7 +119,7 @@ export function useSqlExecution(deps: {
|
||||
sql ??= await resolvedExecutableSql();
|
||||
const tab = deps.activeTab.value;
|
||||
if (!tab || !sql.trim()) return;
|
||||
if (requiresDatabaseSelection(tab, deps.activeConnection.value)) {
|
||||
if (requiresDatabaseSelection(tab, deps.activeConnection.value, sql)) {
|
||||
deps.onMissingDatabase?.();
|
||||
return;
|
||||
}
|
||||
@@ -226,9 +227,21 @@ function supportsSqlTemplateParameters(connection: ConnectionConfig | undefined)
|
||||
return connection.db_type !== "redis" && connection.db_type !== "mongodb";
|
||||
}
|
||||
|
||||
function requiresDatabaseSelection(tab: QueryTab, connection: ConnectionConfig | undefined): boolean {
|
||||
function canExecuteWithoutSelectedDatabase(connection: ConnectionConfig, sql: string): boolean {
|
||||
if (connection.db_type !== "mysql") return false;
|
||||
const statements = stripSqlComments(sql)
|
||||
.split(";")
|
||||
.map((stmt) => stmt.trim())
|
||||
.filter(Boolean);
|
||||
// Only connection-level database creation may bypass the selected-database guard.
|
||||
if (statements.length !== 1) return false;
|
||||
return CONNECTION_LEVEL_CREATE_DATABASE_RE.test(statements[0]);
|
||||
}
|
||||
|
||||
export function requiresDatabaseSelection(tab: QueryTab, connection: ConnectionConfig | undefined, sql = ""): boolean {
|
||||
if (tab.mode !== "query") return false;
|
||||
if (!connection || tab.database) return false;
|
||||
if (isSingleDatabase(connection.db_type)) return false;
|
||||
if (canExecuteWithoutSelectedDatabase(connection, sql)) return false;
|
||||
return !["elasticsearch", "qdrant", "milvus", "weaviate", "chromadb", "zookeeper"].includes(connection.db_type);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user