mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-20 00:17:44 +00:00
fix(mysql): show scheduled events in the sidebar
This commit is contained in:
@@ -2161,12 +2161,13 @@ async function handleQuickOpenSelect(item: any) {
|
||||
tableName: item.objectName || item.tableName,
|
||||
tableType: item.type === "view" ? "VIEW" : item.type === "materialized_view" ? "MATERIALIZED_VIEW" : "TABLE",
|
||||
});
|
||||
} else if (item.type === "procedure" || item.type === "function" || item.type === "trigger" || item.type === "sequence" || item.type === "package" || item.type === "package-body" || item.type === "type" || item.type === "type-body") {
|
||||
} else if (item.type === "procedure" || item.type === "function" || item.type === "trigger" || item.type === "event" || item.type === "sequence" || item.type === "package" || item.type === "package-body" || item.type === "type" || item.type === "type-body") {
|
||||
// Open the object source in a source tab
|
||||
const objectTypeMap: Record<string, ObjectSourceKind> = {
|
||||
procedure: "PROCEDURE",
|
||||
function: "FUNCTION",
|
||||
trigger: "TRIGGER",
|
||||
event: "EVENT",
|
||||
sequence: "SEQUENCE",
|
||||
package: "PACKAGE",
|
||||
"package-body": "PACKAGE_BODY",
|
||||
@@ -2193,7 +2194,7 @@ async function handleQuickOpenSelect(item: any) {
|
||||
});
|
||||
const tabId = queryStore.createTab(item.connectionId, item.database, `Source - ${objectName}`);
|
||||
queryStore.updateSql(tabId, editableSource);
|
||||
if (item.type !== "sequence" && item.type !== "trigger" && item.type !== "type" && item.type !== "type-body") {
|
||||
if (item.type !== "sequence" && item.type !== "trigger" && item.type !== "event" && item.type !== "type" && item.type !== "type-body") {
|
||||
queryStore.setObjectSource(tabId, {
|
||||
schema,
|
||||
name: objectName,
|
||||
|
||||
@@ -317,9 +317,9 @@ watch([deferredSearchQuery, regexMode], ([newQuery, isRegexMode], [oldQuery, was
|
||||
});
|
||||
});
|
||||
|
||||
const searchableObjectGroupTypes = new Set<TreeNodeType>(["group-tables", "group-dolt-system-tables", "group-views", "group-materialized-views", "group-procedures", "group-functions", "group-triggers", "group-sequences", "group-synonyms", "group-packages", "group-types"]);
|
||||
const searchableObjectGroupTypes = new Set<TreeNodeType>(["group-tables", "group-dolt-system-tables", "group-views", "group-materialized-views", "group-procedures", "group-functions", "group-triggers", "group-events", "group-sequences", "group-synonyms", "group-packages", "group-types"]);
|
||||
const simpleObjectParentTypes = new Set<TreeNodeType>(["database", "schema", "linked-server-schema"]);
|
||||
const simpleObjectChildTypes = new Set<TreeNodeType>(["table", "view", "materialized_view", "procedure", "function", "trigger", "sequence", "synonym", "package", "package-body", "type", "type-body", "load-more"]);
|
||||
const simpleObjectChildTypes = new Set<TreeNodeType>(["table", "view", "materialized_view", "procedure", "function", "trigger", "event", "sequence", "synonym", "package", "package-body", "type", "type-body", "load-more"]);
|
||||
|
||||
function isSimpleObjectSearchParent(node: TreeNode): boolean {
|
||||
return settingsStore.editorSettings.sidebarObjectDisplay === "simple" && simpleObjectParentTypes.has(node.type) && node.isExpanded === true && (!!node.children?.some((child) => simpleObjectChildTypes.has(child.type)) || !!store.sidebarTableSearchQueries[node.id]?.trim());
|
||||
|
||||
@@ -593,6 +593,7 @@ const groupTypes: Set<TreeNodeType> = new Set([
|
||||
"group-indexes",
|
||||
"group-fkeys",
|
||||
"group-triggers",
|
||||
"group-events",
|
||||
"group-constraints",
|
||||
"group-table-partitions",
|
||||
"group-table-subpartitions",
|
||||
@@ -5252,7 +5253,7 @@ function buildObjectSidebarMenu(context: SidebarMenuFactoryContext): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node.type === "sequence") {
|
||||
if (node.type === "sequence" || node.type === "event") {
|
||||
items.push({ label: t("contextMenu.viewSource"), action: () => openObjectSourceDialog(false), icon: Code2 });
|
||||
items.push({ label: t("contextMenu.copyName"), action: copyName, icon: Copy, shortcut: shortcutCopyName.value });
|
||||
items.push({ label: t("contextMenu.changeOpenMode"), action: () => emit("open-settings", "navigation"), icon: Settings2 });
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
Link,
|
||||
Link2,
|
||||
Zap,
|
||||
Clock,
|
||||
ListTree,
|
||||
FileCode,
|
||||
Network,
|
||||
@@ -252,6 +253,8 @@ function getIconInfo(node: TreeNode): { icon: any; colorClass: string } | null {
|
||||
return { icon: Link, colorClass: "text-blue-400" };
|
||||
case "group-triggers":
|
||||
return { icon: Zap, colorClass: "text-orange-400" };
|
||||
case "group-events":
|
||||
return { icon: Clock, colorClass: "text-orange-400" };
|
||||
case "group-constraints":
|
||||
return { icon: Key, colorClass: "text-amber-500" };
|
||||
case "group-table-partitions":
|
||||
@@ -279,6 +282,8 @@ function getIconInfo(node: TreeNode): { icon: any; colorClass: string } | null {
|
||||
return { icon: Link, colorClass: "text-blue-300" };
|
||||
case "trigger":
|
||||
return { icon: Zap, colorClass: "text-orange-300" };
|
||||
case "event":
|
||||
return { icon: Clock, colorClass: "text-orange-300" };
|
||||
case "redis-db":
|
||||
return { icon: Database, colorClass: "text-red-400" };
|
||||
case "mq-tenant":
|
||||
@@ -1418,6 +1423,7 @@ function onKeydown(event: KeyboardEvent) {
|
||||
node.type === 'group-procedures' ||
|
||||
node.type === 'group-functions' ||
|
||||
node.type === 'group-triggers' ||
|
||||
node.type === 'group-events' ||
|
||||
node.type === 'group-sequences' ||
|
||||
node.type === 'group-synonyms' ||
|
||||
node.type === 'group-packages' ||
|
||||
|
||||
+18
@@ -431,6 +431,24 @@ describe("TreeItem load-more activation", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("TreeItem object counts", () => {
|
||||
it("renders the event group count", async () => {
|
||||
const node: TreeNode = {
|
||||
id: "connection-1:app:__events",
|
||||
label: "tree.events",
|
||||
type: "group-events",
|
||||
connectionId: "connection-1",
|
||||
database: "app",
|
||||
objectCount: 17,
|
||||
children: [],
|
||||
};
|
||||
|
||||
const { row } = await mountTreeItem(node);
|
||||
|
||||
expect(row.textContent).toContain("17");
|
||||
});
|
||||
});
|
||||
|
||||
describe("TreeItem searched connection activation", () => {
|
||||
function searchedConnection(): TreeNode {
|
||||
const filtered = filterSidebarTree(
|
||||
|
||||
@@ -3027,6 +3027,7 @@ export default {
|
||||
indexes: "Indexes",
|
||||
foreignKeys: "Foreign Keys",
|
||||
triggers: "Triggers",
|
||||
events: "Events",
|
||||
constraints: "Constraints",
|
||||
tables: "Tables",
|
||||
doltSystemTables: "Dolt System Tables",
|
||||
|
||||
@@ -2956,6 +2956,7 @@ export default withEnglishFallback({
|
||||
indexes: "Índices",
|
||||
foreignKeys: "Claves foráneas",
|
||||
triggers: "Disparadores",
|
||||
events: "Eventos",
|
||||
constraints: "Restricciones",
|
||||
tables: "Tablas",
|
||||
tableNameFilterActive: "filtrado",
|
||||
|
||||
@@ -2954,6 +2954,7 @@ export default withEnglishFallback({
|
||||
indexes: "Indici",
|
||||
foreignKeys: "Chiavi Esterne",
|
||||
triggers: "Trigger",
|
||||
events: "Eventi",
|
||||
constraints: "Vincoli",
|
||||
tables: "Tabelle",
|
||||
tableNameFilterActive: "filtrato",
|
||||
|
||||
@@ -2980,6 +2980,7 @@ export default withEnglishFallback({
|
||||
indexes: "インデックス",
|
||||
foreignKeys: "外部キー",
|
||||
triggers: "トリガー",
|
||||
events: "イベント",
|
||||
constraints: "制約",
|
||||
tables: "テーブル",
|
||||
tableNameFilterActive: "フィルターあり",
|
||||
|
||||
@@ -2859,6 +2859,7 @@ export default withEnglishFallback({
|
||||
indexes: "인덱스",
|
||||
foreignKeys: "외래 키",
|
||||
triggers: "트리거",
|
||||
events: "이벤트",
|
||||
constraints: "제약 조건",
|
||||
tables: "테이블",
|
||||
tableNameFilterActive: "필터됨",
|
||||
|
||||
@@ -2957,6 +2957,7 @@ export default withEnglishFallback({
|
||||
indexes: "Índices",
|
||||
foreignKeys: "Chaves estrangeiras",
|
||||
triggers: "Triggers",
|
||||
events: "Eventos",
|
||||
constraints: "Restrições",
|
||||
tables: "Tabelas",
|
||||
tableNameFilterActive: "filtrado",
|
||||
|
||||
@@ -2951,6 +2951,7 @@ export default withEnglishFallback({
|
||||
indexes: "索引",
|
||||
foreignKeys: "外键",
|
||||
triggers: "触发器",
|
||||
events: "事件",
|
||||
constraints: "约束",
|
||||
tables: "表",
|
||||
doltSystemTables: "Dolt 系统表",
|
||||
|
||||
@@ -2956,6 +2956,7 @@ export default withEnglishFallback({
|
||||
indexes: "索引",
|
||||
foreignKeys: "外鍵",
|
||||
triggers: "觸發器",
|
||||
events: "事件",
|
||||
constraints: "約束",
|
||||
tables: "資料表",
|
||||
doltSystemTables: "Dolt 系統資料表",
|
||||
|
||||
@@ -39,8 +39,8 @@ describe("databaseObjectCapabilities", () => {
|
||||
});
|
||||
|
||||
it("exposes triggers only for native MySQL among MySQL-compatible paths", () => {
|
||||
expect(sidebarObjectKindsForDatabase("mysql")).toEqual(["TABLE", "VIEW", "PROCEDURE", "FUNCTION", "TRIGGER"]);
|
||||
expect(databaseObjectCapabilities("mysql").sourceReadable).toEqual(["VIEW", "PROCEDURE", "FUNCTION", "TRIGGER"]);
|
||||
expect(sidebarObjectKindsForDatabase("mysql")).toEqual(["TABLE", "VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "EVENT"]);
|
||||
expect(databaseObjectCapabilities("mysql").sourceReadable).toEqual(["VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "EVENT"]);
|
||||
|
||||
expect(sidebarObjectKindsForDatabase("doris")).toEqual(["TABLE", "VIEW"]);
|
||||
expect(sidebarObjectKindsForDatabase("starrocks")).toEqual(["TABLE", "VIEW", "MATERIALIZED_VIEW"]);
|
||||
|
||||
@@ -248,6 +248,16 @@ describe("programmable database objects", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("groups MySQL scheduled events under a dedicated Events group", () => {
|
||||
const objects: ObjectInfo[] = [{ name: "event_daily_middle_db_sync", object_type: "EVENT", schema: "shop" }];
|
||||
|
||||
const groups = buildGroupedObjectTreeNodes({ ...context, schema: "shop", objects, databaseType: "mysql" });
|
||||
const eventGroup = groups.find((node) => node.type === "group-events");
|
||||
|
||||
expect(eventGroup).toEqual(expect.objectContaining({ objectCount: 1, label: "tree.events" }));
|
||||
expect(eventGroup?.children).toEqual([expect.objectContaining({ type: "event", objectName: "event_daily_middle_db_sync" })]);
|
||||
});
|
||||
|
||||
it("keeps table-scoped Kingbase triggers distinct and source-addressable", () => {
|
||||
const objects: ObjectInfo[] = [
|
||||
{ name: "audit_before", object_type: "TRIGGER", schema: "public", parent_schema: "public", parent_name: "items" },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { DatabaseType } from "@/types/database";
|
||||
|
||||
export type SidebarObjectKind = "TABLE" | "VIEW" | "MATERIALIZED_VIEW" | "PROCEDURE" | "FUNCTION" | "TRIGGER" | "SEQUENCE" | "SYNONYM" | "PACKAGE" | "PACKAGE_BODY" | "TYPE" | "TYPE_BODY";
|
||||
export type SidebarObjectKind = "TABLE" | "VIEW" | "MATERIALIZED_VIEW" | "PROCEDURE" | "FUNCTION" | "TRIGGER" | "EVENT" | "SEQUENCE" | "SYNONYM" | "PACKAGE" | "PACKAGE_BODY" | "TYPE" | "TYPE_BODY";
|
||||
|
||||
export interface DatabaseObjectCapabilities {
|
||||
sidebarObjects: SidebarObjectKind[];
|
||||
@@ -12,7 +12,7 @@ const TABLE_VIEW_OBJECTS: SidebarObjectKind[] = ["TABLE", "VIEW"];
|
||||
const TABLE_VIEW_MV_OBJECTS: SidebarObjectKind[] = ["TABLE", "VIEW", "MATERIALIZED_VIEW"];
|
||||
|
||||
const ROUTINE_OBJECTS: SidebarObjectKind[] = ["TABLE", "VIEW", "PROCEDURE", "FUNCTION"];
|
||||
const MYSQL_OBJECTS: SidebarObjectKind[] = ["TABLE", "VIEW", "PROCEDURE", "FUNCTION", "TRIGGER"];
|
||||
const MYSQL_OBJECTS: SidebarObjectKind[] = ["TABLE", "VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "EVENT"];
|
||||
|
||||
// PostgreSQL-family databases with a verified pg_type listing path. TYPE only
|
||||
// covers user-created types (enum/domain/composite/range/multirange/base);
|
||||
@@ -157,6 +157,7 @@ export function normalizeSidebarObjectKind(type: string): SidebarObjectKind {
|
||||
if (normalized.includes("TYPE_BODY")) return "TYPE_BODY";
|
||||
if (normalized.includes("PACKAGE")) return "PACKAGE";
|
||||
if (normalized.includes("TRIGGER")) return "TRIGGER";
|
||||
if (normalized.includes("EVENT")) return "EVENT";
|
||||
if (normalized.includes("TYPE")) return "TYPE";
|
||||
if (normalized.includes("MATERIALIZED_VIEW")) return "MATERIALIZED_VIEW";
|
||||
if (value.includes("VIEW")) return "VIEW";
|
||||
|
||||
@@ -54,11 +54,11 @@ const objectBrowserNodeTypes = new Set<TreeNodeType>(["database", "schema", "obj
|
||||
export function shouldOpenObjectBrowserOnSingleClick(type: TreeNodeType, enabled: boolean): boolean {
|
||||
return enabled && objectBrowserNodeTypes.has(type);
|
||||
}
|
||||
const sourceNodeTypes = new Set<TreeNodeType>(["materialized_view", "procedure", "function", "trigger", "sequence", "synonym", "package", "package-body", "type", "type-body"]);
|
||||
const sourceNodeTypes = new Set<TreeNodeType>(["materialized_view", "procedure", "function", "trigger", "event", "sequence", "synonym", "package", "package-body", "type", "type-body"]);
|
||||
const savedSqlNodeTypes = new Set<TreeNodeType>(["saved-sql-file"]);
|
||||
const tableChildGroupNodeTypes = new Set<TreeNodeType>(["group-columns", "group-indexes", "group-fkeys", "group-triggers", "group-constraints", "group-partitions", "group-table-partitions", "group-table-subpartitions"]);
|
||||
const databaseChildGroupNodeTypes = new Set<TreeNodeType>(["group-tables", "group-dolt-system-tables", "group-views", "group-materialized-views", "group-procedures", "group-functions", "group-triggers", "group-sequences", "group-synonyms", "group-packages", "group-types"]);
|
||||
const displayPathObjectNodeTypes = new Set<TreeNodeType>(["table", "view", "materialized_view", "procedure", "function", "trigger"]);
|
||||
const databaseChildGroupNodeTypes = new Set<TreeNodeType>(["group-tables", "group-dolt-system-tables", "group-views", "group-materialized-views", "group-procedures", "group-functions", "group-triggers", "group-events", "group-sequences", "group-synonyms", "group-packages", "group-types"]);
|
||||
const displayPathObjectNodeTypes = new Set<TreeNodeType>(["table", "view", "materialized_view", "procedure", "function", "trigger", "event"]);
|
||||
|
||||
export function objectSourceKindForTreeNode(type: TreeNodeType): ObjectSourceKind | null {
|
||||
if (type === "view") return "VIEW";
|
||||
@@ -66,6 +66,7 @@ export function objectSourceKindForTreeNode(type: TreeNodeType): ObjectSourceKin
|
||||
if (type === "procedure") return "PROCEDURE";
|
||||
if (type === "function") return "FUNCTION";
|
||||
if (type === "trigger") return "TRIGGER";
|
||||
if (type === "event") return "EVENT";
|
||||
if (type === "sequence") return "SEQUENCE";
|
||||
if (type === "synonym") return "SYNONYM";
|
||||
if (type === "package") return "PACKAGE";
|
||||
|
||||
@@ -5,6 +5,7 @@ const treeGroupNodeTypes = new Set<TreeNodeType>([
|
||||
"group-indexes",
|
||||
"group-fkeys",
|
||||
"group-triggers",
|
||||
"group-events",
|
||||
"group-constraints",
|
||||
"group-table-partitions",
|
||||
"group-table-subpartitions",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Component } from "vue";
|
||||
import { Archive, Braces, Columns3, Database, Eye, FileCode, FolderClosed, FolderOpen, Gauge, Key, Link, Link2, ListTree, Network, Package, Plus, ScrollText, Server, ShieldCheck, Table, TableProperties, UsersRound, Zap } from "@lucide/vue";
|
||||
import { Archive, Braces, Clock, Columns3, Database, Eye, FileCode, FolderClosed, FolderOpen, Gauge, Key, Link, Link2, ListTree, Network, Package, Plus, ScrollText, Server, ShieldCheck, Table, TableProperties, UsersRound, Zap } from "@lucide/vue";
|
||||
import type { ColumnInfo, TreeNode } from "@/types/database";
|
||||
|
||||
export type TreeNodeIconInfo = {
|
||||
@@ -68,6 +68,10 @@ export function getTreeNodeIconInfo(node: TreeNode): TreeNodeIconInfo | null {
|
||||
return { icon: Zap, colorClass: "text-orange-400" };
|
||||
case "trigger":
|
||||
return { icon: Zap, colorClass: "text-orange-300" };
|
||||
case "group-events":
|
||||
return { icon: Clock, colorClass: "text-orange-400" };
|
||||
case "event":
|
||||
return { icon: Clock, colorClass: "text-orange-300" };
|
||||
case "group-constraints":
|
||||
case "constraint":
|
||||
return { icon: Key, colorClass: "text-amber-500" };
|
||||
|
||||
@@ -634,7 +634,7 @@ export function buildSimpleObjectTreeNodes({ nodeId, connectionId, database, sch
|
||||
|
||||
for (const obj of coalesceXuguPackageObjects(objects, databaseType)) {
|
||||
const objectType = normalizeObjectType(obj.object_type);
|
||||
if (!["TABLE", "VIEW", "MATERIALIZED_VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "SEQUENCE", "SYNONYM", "PACKAGE", "PACKAGE_BODY", "TYPE", "TYPE_BODY"].includes(objectType)) {
|
||||
if (!["TABLE", "VIEW", "MATERIALIZED_VIEW", "PROCEDURE", "FUNCTION", "TRIGGER", "EVENT", "SEQUENCE", "SYNONYM", "PACKAGE", "PACKAGE_BODY", "TYPE", "TYPE_BODY"].includes(objectType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -700,6 +700,7 @@ function simpleObjectNodeType(objectType: DatabaseObjectTreeKind): TreeNodeType
|
||||
if (objectType === "PROCEDURE") return "procedure";
|
||||
if (objectType === "FUNCTION") return "function";
|
||||
if (objectType === "TRIGGER") return "trigger";
|
||||
if (objectType === "EVENT") return "event";
|
||||
if (objectType === "SEQUENCE") return "sequence";
|
||||
if (objectType === "SYNONYM") return "synonym";
|
||||
if (objectType === "PACKAGE_BODY") return "package-body";
|
||||
@@ -752,6 +753,13 @@ const groupDefs: Array<{
|
||||
nodeType: "group-triggers",
|
||||
childType: "trigger",
|
||||
},
|
||||
{
|
||||
key: "__events",
|
||||
label: "tree.events",
|
||||
objectTypes: ["EVENT"],
|
||||
nodeType: "group-events",
|
||||
childType: "event",
|
||||
},
|
||||
{
|
||||
key: "__sequences",
|
||||
label: "tree.sequences",
|
||||
@@ -782,7 +790,7 @@ const groupDefs: Array<{
|
||||
},
|
||||
];
|
||||
|
||||
const objectGroupNodeTypes = new Set<TreeNodeType>(["group-tables", "group-dolt-system-tables", "group-views", "group-materialized-views", "group-procedures", "group-functions", "group-triggers", "group-sequences", "group-synonyms", "group-packages", "group-types"]);
|
||||
const objectGroupNodeTypes = new Set<TreeNodeType>(["group-tables", "group-dolt-system-tables", "group-views", "group-materialized-views", "group-procedures", "group-functions", "group-triggers", "group-events", "group-sequences", "group-synonyms", "group-packages", "group-types"]);
|
||||
|
||||
export function buildObjectGroupPlaceholderNodes({
|
||||
nodeId,
|
||||
|
||||
@@ -1303,7 +1303,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
// recurse into raw objects, its `meta` too), mirroring the markRaw() treatment
|
||||
// queryStore already applies to result rows. Containers stay reactive so their
|
||||
// children / isExpanded / isLoading mutations still drive the UI.
|
||||
const LEAF_TREE_NODE_TYPES = new Set<TreeNode["type"]>(["column", "index", "fkey", "trigger", "type-member"]);
|
||||
const LEAF_TREE_NODE_TYPES = new Set<TreeNode["type"]>(["column", "index", "fkey", "trigger", "event", "type-member"]);
|
||||
|
||||
function markRawLeafTreeNodes(nodes: TreeNode[]): TreeNode[] {
|
||||
for (const node of nodes) {
|
||||
|
||||
@@ -470,7 +470,7 @@ export interface ObjectStatistics {
|
||||
total_bytes?: number | null;
|
||||
}
|
||||
|
||||
export type ObjectSourceKind = "VIEW" | "MATERIALIZED_VIEW" | "PROCEDURE" | "FUNCTION" | "TRIGGER" | "SEQUENCE" | "SYNONYM" | "PACKAGE" | "PACKAGE_BODY" | "TYPE" | "TYPE_BODY";
|
||||
export type ObjectSourceKind = "VIEW" | "MATERIALIZED_VIEW" | "PROCEDURE" | "FUNCTION" | "TRIGGER" | "EVENT" | "SEQUENCE" | "SYNONYM" | "PACKAGE" | "PACKAGE_BODY" | "TYPE" | "TYPE_BODY";
|
||||
|
||||
export interface ObjectSource {
|
||||
name: string;
|
||||
@@ -911,6 +911,7 @@ export type TreeNodeType =
|
||||
| "group-indexes"
|
||||
| "group-fkeys"
|
||||
| "group-triggers"
|
||||
| "group-events"
|
||||
| "group-constraints"
|
||||
| "group-table-partitions"
|
||||
| "group-table-subpartitions"
|
||||
@@ -945,6 +946,7 @@ export type TreeNodeType =
|
||||
| "index"
|
||||
| "fkey"
|
||||
| "trigger"
|
||||
| "event"
|
||||
| "constraint"
|
||||
| "partition"
|
||||
| "subpartition"
|
||||
|
||||
@@ -347,6 +347,7 @@ fn object_type_keyword(object_type: &ObjectSourceKind) -> &'static str {
|
||||
ObjectSourceKind::Procedure => "PROCEDURE",
|
||||
ObjectSourceKind::Function => "FUNCTION",
|
||||
ObjectSourceKind::Trigger => "TRIGGER",
|
||||
ObjectSourceKind::Event => "EVENT",
|
||||
ObjectSourceKind::Sequence => "SEQUENCE",
|
||||
ObjectSourceKind::Synonym => "SYNONYM",
|
||||
ObjectSourceKind::Package => "PACKAGE",
|
||||
|
||||
@@ -2771,16 +2771,16 @@ mod tests {
|
||||
dameng_object_statistics_rows_only_sql, dameng_object_statistics_user_segments_sql, deduplicate_column_infos,
|
||||
ephemeral_agent_metadata_session_id, external_driver_uses_mysql_ddl, filter_mongodb_agent_collections,
|
||||
filter_mysql_system_databases_for_config, filter_object_infos, filter_table_infos, filter_visible_schema_names,
|
||||
gaussdb_m_view_object_source_sql, gbase8a_object_statistics_sql, is_agent_postgres_metadata_fallback_config,
|
||||
is_mysql_external_driver_config, is_retryable_metadata_error, metadata_error_action,
|
||||
metadata_name_or_comment_matches, mysql_database_list_timeout, mysql_external_driver_ddl_from_query_result,
|
||||
mysql_external_driver_ddl_sql, mysql_object_source_ddl_column_index, mysql_object_source_sql,
|
||||
mysql_table_list_source_for_config, mysql_table_metadata_catalog, normalize_information_schema_table_type,
|
||||
oracle_columns_from_query_result, oracle_columns_sql, oracle_object_statistics_dba_segments_sql,
|
||||
oracle_object_statistics_from_query_result, oracle_object_statistics_rows_only_sql,
|
||||
oracle_object_statistics_sql, oracle_object_statistics_user_segments_sql,
|
||||
oracle_table_comment_from_query_result, oracle_table_comment_sql, oracle_table_comments_sql,
|
||||
presto_like_columns_from_query_result, presto_like_information_schema_columns_sql,
|
||||
finalize_object_source, gaussdb_m_view_object_source_sql, gbase8a_object_statistics_sql,
|
||||
is_agent_postgres_metadata_fallback_config, is_mysql_external_driver_config, is_retryable_metadata_error,
|
||||
metadata_error_action, metadata_name_or_comment_matches, mysql_database_list_timeout,
|
||||
mysql_external_driver_ddl_from_query_result, mysql_external_driver_ddl_sql,
|
||||
mysql_object_source_ddl_column_index, mysql_object_source_sql, mysql_table_list_source_for_config,
|
||||
mysql_table_metadata_catalog, normalize_information_schema_table_type, oracle_columns_from_query_result,
|
||||
oracle_columns_sql, oracle_object_statistics_dba_segments_sql, oracle_object_statistics_from_query_result,
|
||||
oracle_object_statistics_rows_only_sql, oracle_object_statistics_sql,
|
||||
oracle_object_statistics_user_segments_sql, oracle_table_comment_from_query_result, oracle_table_comment_sql,
|
||||
oracle_table_comments_sql, presto_like_columns_from_query_result, presto_like_information_schema_columns_sql,
|
||||
presto_like_information_schema_tables_sql, presto_like_tables_from_query_result, replace_metadata_runtime,
|
||||
should_query_oracle_columns_via_sql_first, table_comments_from_query_result, table_name_filter_matches,
|
||||
tdengine_table_comment_like_pattern, tdengine_table_comment_sql, tdengine_table_comments_sql,
|
||||
@@ -3345,6 +3345,27 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mysql_object_source_sql_emits_show_create_event() {
|
||||
assert_eq!(
|
||||
mysql_object_source_sql("tenant_db", "event_daily_sync", &db::ObjectSourceKind::Event),
|
||||
"SHOW CREATE EVENT `tenant_db`.`event_daily_sync`"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mysql_event_object_source_is_read_only() {
|
||||
let source = finalize_object_source(db::ObjectSource {
|
||||
name: "event_daily_sync".to_string(),
|
||||
object_type: db::ObjectSourceKind::Event,
|
||||
schema: None,
|
||||
source: "CREATE EVENT event_daily_sync ON SCHEDULE EVERY 1 DAY DO SELECT 1".to_string(),
|
||||
editable: None,
|
||||
});
|
||||
|
||||
assert_eq!(source.editable, Some(false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mysql_object_source_sql_emits_show_create_materialized_view() {
|
||||
// Regression for the review comment: Doris / StarRocks ride on the MySQL
|
||||
@@ -3373,6 +3394,10 @@ mod tests {
|
||||
assert_eq!(mysql_object_source_ddl_column_index(&db::ObjectSourceKind::Procedure), 2);
|
||||
assert_eq!(mysql_object_source_ddl_column_index(&db::ObjectSourceKind::Function), 2);
|
||||
assert_eq!(mysql_object_source_ddl_column_index(&db::ObjectSourceKind::Trigger), 2);
|
||||
// SHOW CREATE EVENT returns (Event, sql_mode, time_zone, Create Event, …) —
|
||||
// one extra time_zone column before the DDL, verified against a real MySQL
|
||||
// 8.0 instance (`SHOW CREATE EVENT` for a live event).
|
||||
assert_eq!(mysql_object_source_ddl_column_index(&db::ObjectSourceKind::Event), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -7235,6 +7260,7 @@ fn sqlite_object_type(kind: &db::ObjectSourceKind) -> &'static str {
|
||||
db::ObjectSourceKind::Procedure
|
||||
| db::ObjectSourceKind::Function
|
||||
| db::ObjectSourceKind::Trigger
|
||||
| db::ObjectSourceKind::Event
|
||||
| db::ObjectSourceKind::Sequence
|
||||
| db::ObjectSourceKind::Synonym
|
||||
| db::ObjectSourceKind::Package
|
||||
@@ -7250,7 +7276,8 @@ fn sqlserver_object_type_filter(kind: &db::ObjectSourceKind) -> &'static str {
|
||||
db::ObjectSourceKind::Procedure => "'P'",
|
||||
db::ObjectSourceKind::Function => "'FN','IF','TF','FS','FT'",
|
||||
db::ObjectSourceKind::Trigger => "'TR'",
|
||||
db::ObjectSourceKind::Sequence
|
||||
db::ObjectSourceKind::Event
|
||||
| db::ObjectSourceKind::Sequence
|
||||
| db::ObjectSourceKind::Synonym
|
||||
| db::ObjectSourceKind::Package
|
||||
| db::ObjectSourceKind::PackageBody
|
||||
@@ -7488,6 +7515,7 @@ fn postgres_object_source_sql_inner(
|
||||
)
|
||||
}
|
||||
db::ObjectSourceKind::Trigger
|
||||
| db::ObjectSourceKind::Event
|
||||
| db::ObjectSourceKind::Synonym
|
||||
| db::ObjectSourceKind::Package
|
||||
| db::ObjectSourceKind::PackageBody
|
||||
@@ -7503,6 +7531,7 @@ pub fn oracle_object_source_sql(schema: &str, name: &str, kind: &db::ObjectSourc
|
||||
db::ObjectSourceKind::Procedure => "PROCEDURE",
|
||||
db::ObjectSourceKind::Function => "FUNCTION",
|
||||
db::ObjectSourceKind::Trigger => "TRIGGER",
|
||||
db::ObjectSourceKind::Event => "EVENT",
|
||||
db::ObjectSourceKind::Sequence => "SEQUENCE",
|
||||
db::ObjectSourceKind::Synonym => "SYNONYM",
|
||||
db::ObjectSourceKind::Package => "PACKAGE",
|
||||
@@ -7559,6 +7588,7 @@ pub fn mysql_object_source_sql(database: &str, name: &str, kind: &db::ObjectSour
|
||||
db::ObjectSourceKind::Procedure => format!("SHOW CREATE PROCEDURE {qualified_name}"),
|
||||
db::ObjectSourceKind::Function => format!("SHOW CREATE FUNCTION {qualified_name}"),
|
||||
db::ObjectSourceKind::Trigger => format!("SHOW CREATE TRIGGER {qualified_name}"),
|
||||
db::ObjectSourceKind::Event => format!("SHOW CREATE EVENT {qualified_name}"),
|
||||
db::ObjectSourceKind::Sequence
|
||||
| db::ObjectSourceKind::Synonym
|
||||
| db::ObjectSourceKind::Package
|
||||
@@ -7585,6 +7615,8 @@ pub fn mysql_object_source_sql(database: &str, name: &str, kind: &db::ObjectSour
|
||||
/// `(Name, DDL)` → DDL at index `1`.
|
||||
/// - `SHOW CREATE PROCEDURE`, `SHOW CREATE FUNCTION`, `SHOW CREATE TRIGGER` →
|
||||
/// `(Name, sql_mode, DDL, …)` → DDL at index `2`.
|
||||
/// - `SHOW CREATE EVENT` → `(Event, sql_mode, time_zone, Create Event, …)` →
|
||||
/// DDL at index `3` (it has an extra `time_zone` column before the DDL).
|
||||
///
|
||||
/// Encoded as a function so the index can be unit-tested without a live DB.
|
||||
pub(crate) fn mysql_object_source_ddl_column_index(kind: &db::ObjectSourceKind) -> usize {
|
||||
@@ -7599,6 +7631,7 @@ pub(crate) fn mysql_object_source_ddl_column_index(kind: &db::ObjectSourceKind)
|
||||
| db::ObjectSourceKind::PackageBody
|
||||
| db::ObjectSourceKind::Type
|
||||
| db::ObjectSourceKind::TypeBody => 2,
|
||||
db::ObjectSourceKind::Event => 3,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7804,7 +7837,7 @@ pub async fn get_object_source_core(
|
||||
signature: Option<&str>,
|
||||
relation_name: Option<&str>,
|
||||
) -> Result<db::ObjectSource, String> {
|
||||
let mut source = retry_metadata_connection(state, connection_id, Some(database), || {
|
||||
let source = retry_metadata_connection(state, connection_id, Some(database), || {
|
||||
get_object_source_once(
|
||||
state,
|
||||
connection_id,
|
||||
@@ -7817,10 +7850,17 @@ pub async fn get_object_source_core(
|
||||
)
|
||||
})
|
||||
.await?;
|
||||
Ok(finalize_object_source(source))
|
||||
}
|
||||
|
||||
fn finalize_object_source(mut source: db::ObjectSource) -> db::ObjectSource {
|
||||
if matches!(source.object_type, db::ObjectSourceKind::Procedure | db::ObjectSourceKind::Function) {
|
||||
source.source = normalize_routine_object_source(source.source);
|
||||
}
|
||||
Ok(source)
|
||||
if matches!(source.object_type, db::ObjectSourceKind::Event) {
|
||||
source.editable = Some(false);
|
||||
}
|
||||
source
|
||||
}
|
||||
|
||||
async fn get_object_source_once(
|
||||
|
||||
@@ -7468,9 +7468,10 @@ where
|
||||
| db::ObjectSourceKind::Synonym
|
||||
| db::ObjectSourceKind::Package
|
||||
| db::ObjectSourceKind::PackageBody => object.source.clone(),
|
||||
db::ObjectSourceKind::Trigger | db::ObjectSourceKind::Type | db::ObjectSourceKind::TypeBody => {
|
||||
object.source.clone()
|
||||
}
|
||||
db::ObjectSourceKind::Trigger
|
||||
| db::ObjectSourceKind::Event
|
||||
| db::ObjectSourceKind::Type
|
||||
| db::ObjectSourceKind::TypeBody => object.source.clone(),
|
||||
};
|
||||
let statements = build_executable_object_source_statements(EditableObjectSourceSqlInput {
|
||||
database_type: DatabaseType::Postgres,
|
||||
|
||||
@@ -122,6 +122,7 @@ pub enum ObjectSourceKind {
|
||||
Procedure,
|
||||
Function,
|
||||
Trigger,
|
||||
Event,
|
||||
Sequence,
|
||||
Synonym,
|
||||
Package,
|
||||
|
||||
Reference in New Issue
Block a user