diff --git a/src/components/editor/QueryToolbar.tsx b/src/components/editor/QueryToolbar.tsx
index 7f95848..faa5880 100644
--- a/src/components/editor/QueryToolbar.tsx
+++ b/src/components/editor/QueryToolbar.tsx
@@ -16,7 +16,7 @@ import {
import { useEffect, useRef, useState } from "react";
import { format } from "sql-formatter";
import { useQueryExecution } from "../../hooks/useQueryExecution";
-import { useSchemaCache } from "../../hooks/useSchemaCache";
+import { useSchemaCacheStore } from "../../stores/schemaCacheStore";
import { postProcessSQL } from "../../lib/sql-post-process";
import { useAiStore } from "../../stores/aiStore";
import { useConnectionStore } from "../../stores/connectionStore";
@@ -46,8 +46,8 @@ export function QueryToolbar() {
(s) => s.selectedConnectionId,
);
const activeConnections = useConnectionStore((s) => s.activeConnections);
- const refreshSchema = useSchemaCache((s) => s.refreshSchema);
- const schemaLoading = useSchemaCache((s) => s.loading);
+ const refreshSchema = useSchemaCacheStore((s) => s.refreshSchema);
+ const schemaLoading = useSchemaCacheStore((s) => s.loading);
const {
executeQuery,
diff --git a/src/components/editor/SQLEditor.tsx b/src/components/editor/SQLEditor.tsx
index e8b8dd2..bd9ee39 100644
--- a/src/components/editor/SQLEditor.tsx
+++ b/src/components/editor/SQLEditor.tsx
@@ -2,7 +2,7 @@ import Editor, { type OnMount, useMonaco } from "@monaco-editor/react";
import type { editor, IDisposable } from "monaco-editor";
import { useCallback, useEffect, useRef } from "react";
import { format } from "sql-formatter";
-import { useSchemaCache } from "../../hooks/useSchemaCache";
+import { useSchemaCacheStore } from "../../stores/schemaCacheStore";
import { createCompletionProvider } from "../../lib/schema-completion-provider";
import { postProcessSQL } from "../../lib/sql-post-process";
import { getStatementAtCursor } from "../../lib/statement-at-cursor";
@@ -47,7 +47,7 @@ export function SQLEditor() {
const selectedConnectionId = useConnectionStore(
(s) => s.selectedConnectionId,
);
- const schemaCache = useSchemaCache();
+ const schemaCache = useSchemaCacheStore();
// Sync schema cache with active connection
useEffect(() => {
@@ -274,7 +274,7 @@ export function SQLEditor() {
64,
],
run: async () => {
- await useSchemaCache.getState().refreshSchema();
+ await useSchemaCacheStore.getState().refreshSchema();
},
});
diff --git a/src/components/editor/__tests__/QueryToolbar.test.tsx b/src/components/editor/__tests__/QueryToolbar.test.tsx
index fdb4d87..54f369a 100644
--- a/src/components/editor/__tests__/QueryToolbar.test.tsx
+++ b/src/components/editor/__tests__/QueryToolbar.test.tsx
@@ -45,8 +45,8 @@ vi.mock("../../../hooks/useQueryExecution", () => ({
const mockRefreshSchema = vi.fn().mockResolvedValue(undefined);
let mockSchemaLoading = false;
-vi.mock("../../../hooks/useSchemaCache", () => ({
- useSchemaCache: vi.fn(() => ({
+vi.mock("../../../stores/schemaCacheStore", () => ({
+ useSchemaCacheStore: vi.fn(() => ({
refreshSchema: mockRefreshSchema,
loading: mockSchemaLoading,
connectionId: "conn-1",
diff --git a/src/components/editor/__tests__/SQLEditor.browser.test.tsx b/src/components/editor/__tests__/SQLEditor.browser.test.tsx
index ffe0306..ddc5f66 100644
--- a/src/components/editor/__tests__/SQLEditor.browser.test.tsx
+++ b/src/components/editor/__tests__/SQLEditor.browser.test.tsx
@@ -156,8 +156,8 @@ vi.mock("../../stores/resultStore", () => ({
),
}));
-vi.mock("../../hooks/useSchemaCache", () => ({
- useSchemaCache: vi.fn(() => ({
+vi.mock("../../stores/schemaCacheStore", () => ({
+ useSchemaCacheStore: vi.fn(() => ({
connectionId: "conn-1",
databases: [],
tables: [],
@@ -214,8 +214,8 @@ vi.mock("../../stores/themeStore", () => ({
}),
}));
-vi.mock("../../hooks/useSchemaCache", () => ({
- useSchemaCache: vi.fn((selector?: (s: object) => unknown) => {
+vi.mock("../../stores/schemaCacheStore", () => ({
+ useSchemaCacheStore: vi.fn((selector?: (s: object) => unknown) => {
const state = {
connectionId: null,
databases: [],
@@ -308,7 +308,7 @@ describe("SQLEditor (browser)", () => {
expect(m.mockExecuteExplainAnalyze).toHaveBeenCalledWith("conn-1", "SELECT 1", undefined);
});
- it("refresh-schema.run calls useSchemaCache.refreshSchema", async () => {
+ it("refresh-schema.run calls useSchemaCacheStore.refreshSchema", async () => {
render();
await waitFor(() => {
expect(m.capturedActions.some((a) => a.id === "refresh-schema")).toBe(true);
diff --git a/src/components/editor/__tests__/SQLEditor.test.tsx b/src/components/editor/__tests__/SQLEditor.test.tsx
index 45adf1c..03e9633 100644
--- a/src/components/editor/__tests__/SQLEditor.test.tsx
+++ b/src/components/editor/__tests__/SQLEditor.test.tsx
@@ -132,8 +132,8 @@ vi.mock("../../../stores/settingsStore", () => ({
}));
// Mock schema cache store
-vi.mock("../../../hooks/useSchemaCache", () => ({
- useSchemaCache: vi.fn((selector?: (s: any) => any) => {
+vi.mock("../../../stores/schemaCacheStore", () => ({
+ useSchemaCacheStore: vi.fn((selector?: (s: any) => any) => {
const state = {
connectionId: null,
databases: [],
diff --git a/src/components/layout/AppLayout.tsx b/src/components/layout/AppLayout.tsx
index f936d53..56970f7 100644
--- a/src/components/layout/AppLayout.tsx
+++ b/src/components/layout/AppLayout.tsx
@@ -3,7 +3,7 @@ import { getCurrentWindow } from "@tauri-apps/api/window";
import { useCallback, useEffect, useState } from "react";
import { Group, Panel, Separator } from "react-resizable-panels";
import { useKeyboardShortcuts } from "../../hooks/useKeyboardShortcuts";
-import { useSchemaCache } from "../../hooks/useSchemaCache";
+import { useSchemaCacheStore } from "../../stores/schemaCacheStore";
import { useTheme } from "../../hooks/useTheme";
import { useAiStore } from "../../stores/aiStore";
import { useConnectionStore } from "../../stores/connectionStore";
@@ -140,7 +140,7 @@ export function AppLayout() {
if (selectedConnectionId) disconnect(selectedConnectionId);
break;
case "refresh-schema":
- useSchemaCache.getState().refreshSchema();
+ useSchemaCacheStore.getState().refreshSchema();
break;
case "compare-schemas":
addCompareTab();
diff --git a/src/components/layout/__tests__/AppLayout.browser.test.tsx b/src/components/layout/__tests__/AppLayout.browser.test.tsx
index d71f87e..1f6f01c 100644
--- a/src/components/layout/__tests__/AppLayout.browser.test.tsx
+++ b/src/components/layout/__tests__/AppLayout.browser.test.tsx
@@ -127,8 +127,8 @@ vi.mock("../../../hooks/useKeyboardShortcuts", () => ({
vi.mock("../../../hooks/useTheme", () => ({
useTheme: vi.fn(),
}));
-vi.mock("../../../hooks/useSchemaCache", () => ({
- useSchemaCache: {
+vi.mock("../../../stores/schemaCacheStore", () => ({
+ useSchemaCacheStore: {
getState: vi.fn(() => ({ refreshSchema: vi.fn() })),
},
}));
@@ -652,8 +652,8 @@ describe("AppLayout (browser)", () => {
// ─── Menu action: refresh-schema ───
it("handles refresh-schema menu action", async () => {
const refreshSpy = vi.fn();
- const schemaCacheModule = await import("../../../hooks/useSchemaCache");
- vi.mocked(schemaCacheModule.useSchemaCache.getState).mockReturnValue({ refreshSchema: refreshSpy } as any);
+ const schemaCacheModule = await import("../../../stores/schemaCacheStore");
+ vi.mocked(schemaCacheModule.useSchemaCacheStore.getState).mockReturnValue({ refreshSchema: refreshSpy } as any);
await renderApp();
await act(async () => {
window.dispatchEvent(new CustomEvent("menu-action", { detail: "refresh-schema" }));
diff --git a/src/components/layout/__tests__/AppLayout.test.tsx b/src/components/layout/__tests__/AppLayout.test.tsx
index 9729508..0485fe7 100644
--- a/src/components/layout/__tests__/AppLayout.test.tsx
+++ b/src/components/layout/__tests__/AppLayout.test.tsx
@@ -134,8 +134,8 @@ vi.mock("../../../hooks/useKeyboardShortcuts", () => ({
vi.mock("../../../hooks/useTheme", () => ({
useTheme: vi.fn(),
}));
-vi.mock("../../../hooks/useSchemaCache", () => ({
- useSchemaCache: {
+vi.mock("../../../stores/schemaCacheStore", () => ({
+ useSchemaCacheStore: {
getState: vi.fn(() => ({ refreshSchema: vi.fn() })),
},
}));
diff --git a/src/hooks/__tests__/useSchemaCache.test.ts b/src/stores/__tests__/schemaCacheStore.test.ts
similarity index 76%
rename from src/hooks/__tests__/useSchemaCache.test.ts
rename to src/stores/__tests__/schemaCacheStore.test.ts
index 2468b5b..1082b17 100644
--- a/src/hooks/__tests__/useSchemaCache.test.ts
+++ b/src/stores/__tests__/schemaCacheStore.test.ts
@@ -1,5 +1,5 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
-import { useSchemaCache } from "../useSchemaCache";
+import { useSchemaCacheStore } from "../schemaCacheStore";
vi.mock("../../lib/tauri-api", () => ({
api: {
@@ -23,7 +23,7 @@ const mockGetTriggers = api.getTriggers as ReturnType;
const mockGetColumns = api.getColumns as ReturnType;
function doReset() {
- useSchemaCache.setState({
+ useSchemaCacheStore.setState({
connectionId: null,
databases: [],
tables: new Map(),
@@ -43,17 +43,17 @@ beforeEach(() => {
doReset();
});
-describe("useSchemaCache", () => {
+describe("useSchemaCacheStore", () => {
describe("setConnection", () => {
it("clears all caches when setting a new connection", () => {
- useSchemaCache.setState({
+ useSchemaCacheStore.setState({
databases: ["db1"],
tables: new Map([["db1", ["table1"]]]),
});
- useSchemaCache.getState().setConnection("conn-2");
+ useSchemaCacheStore.getState().setConnection("conn-2");
- const state = useSchemaCache.getState();
+ const state = useSchemaCacheStore.getState();
expect(state.connectionId).toBe("conn-2");
expect(state.databases).toEqual([]);
expect(state.tables.size).toBe(0);
@@ -64,14 +64,14 @@ describe("useSchemaCache", () => {
});
it("does nothing when setting the same connection", () => {
- useSchemaCache.setState({
+ useSchemaCacheStore.setState({
connectionId: "conn-1",
databases: ["db1", "db2"],
});
- useSchemaCache.getState().setConnection("conn-1");
+ useSchemaCacheStore.getState().setConnection("conn-1");
- const state = useSchemaCache.getState();
+ const state = useSchemaCacheStore.getState();
expect(state.databases).toEqual(["db1", "db2"]);
});
@@ -82,27 +82,27 @@ describe("useSchemaCache", () => {
]);
mockGetTables.mockResolvedValue([{ name: "users" }]);
- useSchemaCache.getState().setConnection("conn-1");
+ useSchemaCacheStore.getState().setConnection("conn-1");
await flushPromises();
expect(mockGetDatabases).toHaveBeenCalledWith("conn-1");
- expect(useSchemaCache.getState().databases).toEqual([
+ expect(useSchemaCacheStore.getState().databases).toEqual([
"mydb",
"testdb",
]);
});
it("clears caches when connection is set to null", () => {
- useSchemaCache.setState({
+ useSchemaCacheStore.setState({
connectionId: "conn-1",
databases: ["db1"],
tables: new Map([["db1", ["t1"]]]),
});
- useSchemaCache.getState().setConnection(null);
+ useSchemaCacheStore.getState().setConnection(null);
- const state = useSchemaCache.getState();
+ const state = useSchemaCacheStore.getState();
expect(state.connectionId).toBeNull();
expect(state.databases).toEqual([]);
expect(state.tables.size).toBe(0);
@@ -111,12 +111,12 @@ describe("useSchemaCache", () => {
describe("fetchDatabases", () => {
it("returns cached databases if available and connectionId matches", async () => {
- useSchemaCache.setState({
+ useSchemaCacheStore.setState({
connectionId: "conn-1",
databases: ["cached_db"],
});
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchDatabases("conn-1");
@@ -131,15 +131,15 @@ describe("useSchemaCache", () => {
]);
mockGetTables.mockResolvedValue([]);
- useSchemaCache.setState({ connectionId: "conn-1" });
+ useSchemaCacheStore.setState({ connectionId: "conn-1" });
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchDatabases("conn-1");
expect(mockGetDatabases).toHaveBeenCalledWith("conn-1");
expect(result).toEqual(["db1", "db2"]);
- expect(useSchemaCache.getState().databases).toEqual([
+ expect(useSchemaCacheStore.getState().databases).toEqual([
"db1",
"db2",
]);
@@ -149,13 +149,13 @@ describe("useSchemaCache", () => {
mockGetDatabases.mockResolvedValue([{ name: "db1" }]);
mockGetTables.mockResolvedValue([]);
- useSchemaCache.setState({ connectionId: "conn-1" });
+ useSchemaCacheStore.setState({ connectionId: "conn-1" });
- const promise = useSchemaCache.getState().fetchDatabases("conn-1");
- expect(useSchemaCache.getState().loading).toBe(true);
+ const promise = useSchemaCacheStore.getState().fetchDatabases("conn-1");
+ expect(useSchemaCacheStore.getState().loading).toBe(true);
await promise;
- expect(useSchemaCache.getState().loading).toBe(false);
+ expect(useSchemaCacheStore.getState().loading).toBe(false);
});
it("pre-fetches tables for all databases", async () => {
@@ -165,9 +165,9 @@ describe("useSchemaCache", () => {
]);
mockGetTables.mockResolvedValue([{ name: "users" }]);
- useSchemaCache.setState({ connectionId: "conn-1" });
+ useSchemaCacheStore.setState({ connectionId: "conn-1" });
- await useSchemaCache.getState().fetchDatabases("conn-1");
+ await useSchemaCacheStore.getState().fetchDatabases("conn-1");
expect(mockGetTables).toHaveBeenCalledWith("conn-1", "db1");
expect(mockGetTables).toHaveBeenCalledWith("conn-1", "db2");
@@ -176,24 +176,24 @@ describe("useSchemaCache", () => {
it("returns empty array and sets loading false on error", async () => {
mockGetDatabases.mockRejectedValue(new Error("Network error"));
- useSchemaCache.setState({ connectionId: "conn-1" });
+ useSchemaCacheStore.setState({ connectionId: "conn-1" });
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchDatabases("conn-1");
expect(result).toEqual([]);
- expect(useSchemaCache.getState().loading).toBe(false);
+ expect(useSchemaCacheStore.getState().loading).toBe(false);
});
});
describe("fetchTables", () => {
it("returns cached tables if available", async () => {
- useSchemaCache.setState({
+ useSchemaCacheStore.setState({
tables: new Map([["mydb", ["users", "orders"]]]),
});
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchTables("conn-1", "mydb");
@@ -207,13 +207,13 @@ describe("useSchemaCache", () => {
{ name: "orders" },
]);
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchTables("conn-1", "mydb");
expect(mockGetTables).toHaveBeenCalledWith("conn-1", "mydb");
expect(result).toEqual(["users", "orders"]);
- expect(useSchemaCache.getState().tables.get("mydb")).toEqual([
+ expect(useSchemaCacheStore.getState().tables.get("mydb")).toEqual([
"users",
"orders",
]);
@@ -222,22 +222,22 @@ describe("useSchemaCache", () => {
it("returns empty array on error", async () => {
mockGetTables.mockRejectedValue(new Error("DB error"));
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchTables("conn-1", "mydb");
expect(result).toEqual([]);
- expect(useSchemaCache.getState().loading).toBe(false);
+ expect(useSchemaCacheStore.getState().loading).toBe(false);
});
});
describe("fetchViews", () => {
it("returns cached views if available", async () => {
- useSchemaCache.setState({
+ useSchemaCacheStore.setState({
views: new Map([["mydb", ["user_view"]]]),
});
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchViews("conn-1", "mydb");
@@ -248,13 +248,13 @@ describe("useSchemaCache", () => {
it("fetches from API when not cached", async () => {
mockGetViews.mockResolvedValue([{ name: "v1" }, { name: "v2" }]);
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchViews("conn-1", "mydb");
expect(mockGetViews).toHaveBeenCalledWith("conn-1", "mydb");
expect(result).toEqual(["v1", "v2"]);
- expect(useSchemaCache.getState().views.get("mydb")).toEqual([
+ expect(useSchemaCacheStore.getState().views.get("mydb")).toEqual([
"v1",
"v2",
]);
@@ -263,7 +263,7 @@ describe("useSchemaCache", () => {
it("returns empty array on error", async () => {
mockGetViews.mockRejectedValue(new Error("DB error"));
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchViews("conn-1", "mydb");
@@ -273,11 +273,11 @@ describe("useSchemaCache", () => {
describe("fetchRoutines", () => {
it("returns cached routines if available", async () => {
- useSchemaCache.setState({
+ useSchemaCacheStore.setState({
routines: new Map([["mydb", ["proc1", "func1"]]]),
});
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchRoutines("conn-1", "mydb");
@@ -291,21 +291,21 @@ describe("useSchemaCache", () => {
{ name: "my_func" },
]);
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchRoutines("conn-1", "mydb");
expect(mockGetRoutines).toHaveBeenCalledWith("conn-1", "mydb");
expect(result).toEqual(["my_proc", "my_func"]);
expect(
- useSchemaCache.getState().routines.get("mydb"),
+ useSchemaCacheStore.getState().routines.get("mydb"),
).toEqual(["my_proc", "my_func"]);
});
it("returns empty array on error", async () => {
mockGetRoutines.mockRejectedValue(new Error("DB error"));
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchRoutines("conn-1", "mydb");
@@ -315,11 +315,11 @@ describe("useSchemaCache", () => {
describe("fetchTriggers", () => {
it("returns cached triggers if available", async () => {
- useSchemaCache.setState({
+ useSchemaCacheStore.setState({
triggers: new Map([["mydb", ["trg1"]]]),
});
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchTriggers("conn-1", "mydb");
@@ -332,21 +332,21 @@ describe("useSchemaCache", () => {
{ name: "trg_before_insert" },
]);
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchTriggers("conn-1", "mydb");
expect(mockGetTriggers).toHaveBeenCalledWith("conn-1", "mydb");
expect(result).toEqual(["trg_before_insert"]);
expect(
- useSchemaCache.getState().triggers.get("mydb"),
+ useSchemaCacheStore.getState().triggers.get("mydb"),
).toEqual(["trg_before_insert"]);
});
it("returns empty array on error", async () => {
mockGetTriggers.mockRejectedValue(new Error("DB error"));
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchTriggers("conn-1", "mydb");
@@ -359,11 +359,11 @@ describe("useSchemaCache", () => {
const colInfo = [
{ name: "id", dataType: "int", nullable: false },
] as ColumnInfo[];
- useSchemaCache.setState({
+ useSchemaCacheStore.setState({
columns: new Map([["mydb.users", colInfo]]),
});
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchColumns("conn-1", "mydb", "users");
@@ -377,21 +377,21 @@ describe("useSchemaCache", () => {
] as ColumnInfo[];
mockGetColumns.mockResolvedValue(colInfo);
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchColumns("conn-1", "mydb", "users");
expect(mockGetColumns).toHaveBeenCalledWith("conn-1", "mydb", "users");
expect(result).toEqual(colInfo);
expect(
- useSchemaCache.getState().columns.get("mydb.users"),
+ useSchemaCacheStore.getState().columns.get("mydb.users"),
).toEqual(colInfo);
});
it("returns empty array on error", async () => {
mockGetColumns.mockRejectedValue(new Error("DB error"));
- const result = await useSchemaCache
+ const result = await useSchemaCacheStore
.getState()
.fetchColumns("conn-1", "mydb", "users");
@@ -406,7 +406,7 @@ describe("useSchemaCache", () => {
]);
mockGetTables.mockResolvedValue([]);
- useSchemaCache.setState({
+ useSchemaCacheStore.setState({
connectionId: "conn-1",
databases: ["old_db"],
tables: new Map([["old_db", ["old_table"]]]),
@@ -416,9 +416,9 @@ describe("useSchemaCache", () => {
columns: new Map([["old_db.old_table", []]]),
});
- await useSchemaCache.getState().refreshSchema();
+ await useSchemaCacheStore.getState().refreshSchema();
- const state = useSchemaCache.getState();
+ const state = useSchemaCacheStore.getState();
expect(state.databases).toEqual(["new_db"]);
// After refresh, fetchDatabases eagerly fetches tables for all new databases,
// so tables Map has an entry for "new_db" (even if empty result).
@@ -431,9 +431,9 @@ describe("useSchemaCache", () => {
});
it("does nothing when connectionId is null", async () => {
- useSchemaCache.setState({ connectionId: null });
+ useSchemaCacheStore.setState({ connectionId: null });
- await useSchemaCache.getState().refreshSchema();
+ await useSchemaCacheStore.getState().refreshSchema();
expect(mockGetDatabases).not.toHaveBeenCalled();
});
diff --git a/src/hooks/useSchemaCache.ts b/src/stores/schemaCacheStore.ts
similarity index 98%
rename from src/hooks/useSchemaCache.ts
rename to src/stores/schemaCacheStore.ts
index f000cad..5e54249 100644
--- a/src/hooks/useSchemaCache.ts
+++ b/src/stores/schemaCacheStore.ts
@@ -26,7 +26,7 @@ interface SchemaCache {
refreshSchema: () => Promise;
}
-export const useSchemaCache = create((set, get) => ({
+export const useSchemaCacheStore = create((set, get) => ({
connectionId: null,
databases: [],
tables: new Map(),