fix(completion): resolve ob-oracle schema for alias column completion
This commit is contained in:
5 files changed
+112
-8
No files matched your search
@@ -8,8 +8,11 @@ const contentAreaSource = readFileSync(new URL("../../../components/layout/Conte
|
||||
describe("Oracle session-scoped completion", () => {
|
||||
it("uses the tab session only for unqualified references without a selected schema", () => {
|
||||
expect(usesOracleSessionCompletionColumns({ databaseType: "oracle", clientSessionId: "tab-a" })).toBe(true);
|
||||
expect(usesOracleSessionCompletionColumns({ databaseType: "oceanbase-oracle", clientSessionId: "tab-a" })).toBe(true);
|
||||
expect(usesOracleSessionCompletionColumns({ databaseType: "oracle", clientSessionId: "tab-a", referenceSchema: "REPORTING" })).toBe(false);
|
||||
expect(usesOracleSessionCompletionColumns({ databaseType: "oceanbase-oracle", clientSessionId: "tab-a", referenceSchema: "REPORTING" })).toBe(false);
|
||||
expect(usesOracleSessionCompletionColumns({ databaseType: "oracle", clientSessionId: "tab-a", selectedSchema: "REPORTING" })).toBe(false);
|
||||
expect(usesOracleSessionCompletionColumns({ databaseType: "oceanbase-oracle", clientSessionId: "tab-a", selectedSchema: "REPORTING" })).toBe(false);
|
||||
expect(usesOracleSessionCompletionColumns({ databaseType: "postgres", clientSessionId: "tab-a" })).toBe(false);
|
||||
expect(usesOracleSessionCompletionColumns({ databaseType: "oracle" })).toBe(false);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import type { DatabaseType } from "@/types/database";
|
||||
|
||||
export function usesOracleCurrentSchemaCompletion(databaseType?: DatabaseType, schema?: string | null): boolean {
|
||||
return (databaseType === "oracle" || databaseType === "oceanbase-oracle") && !schema;
|
||||
}
|
||||
|
||||
export function usesOracleSessionCompletionColumns(options: { databaseType?: DatabaseType; selectedSchema?: string; referenceSchema?: string | null; clientSessionId?: string }): boolean {
|
||||
return options.databaseType === "oracle" && !options.selectedSchema && !options.referenceSchema && !!options.clientSessionId;
|
||||
return usesOracleCurrentSchemaCompletion(options.databaseType, options.referenceSchema || options.selectedSchema) && !!options.clientSessionId;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createPinia, setActivePinia } from "pinia";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { getSqlCompletionContext } from "@/lib/sql/sqlCompletion";
|
||||
import type { ConnectionConfig } from "@/types/database";
|
||||
|
||||
function installLocalStorage() {
|
||||
@@ -715,6 +716,40 @@ describe("connectionStore completion assistant", () => {
|
||||
expect(upper).toEqual(lower);
|
||||
});
|
||||
|
||||
it("uses the OceanBase Oracle session schema for an unqualified aliased table", async () => {
|
||||
const completionAssistantSearch = vi.fn();
|
||||
const getColumns = vi.fn().mockResolvedValue([{ name: "PARAM_VALUE", data_type: "VARCHAR2(100)", is_nullable: true, column_default: null, is_primary_key: false, extra: null, comment: null }]);
|
||||
|
||||
vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
|
||||
vi.doMock("@/lib/backend/api", () => ({
|
||||
checkConnectionHealth: vi.fn().mockResolvedValue(undefined),
|
||||
completionAssistantSearch,
|
||||
getColumns,
|
||||
}));
|
||||
|
||||
const sql = "select a. from tbparam a";
|
||||
const completion = getSqlCompletionContext(sql, sql.indexOf("a.") + 2, { databaseType: "oceanbase-oracle" });
|
||||
const reference = completion.referencedTables[0];
|
||||
expect(reference).toEqual(expect.objectContaining({ name: "tbparam", alias: "a", schema: undefined, nameQuoted: false }));
|
||||
|
||||
const { useConnectionStore } = await import("@/stores/connectionStore");
|
||||
const store = useConnectionStore();
|
||||
store.connections = [oceanBaseOracleConnection()];
|
||||
store.connectedIds.add("oceanbase-oracle-1");
|
||||
|
||||
const columns = await store.listCompletionColumns("oceanbase-oracle-1", "OBORCL", reference!.name, reference!.schema, {
|
||||
clientSessionId: "tab-a",
|
||||
version: 0,
|
||||
tableQuoted: reference!.nameQuoted,
|
||||
schemaQuoted: reference!.schemaQuoted,
|
||||
});
|
||||
|
||||
expect(completionAssistantSearch).not.toHaveBeenCalled();
|
||||
expect(getColumns).toHaveBeenCalledWith("oceanbase-oracle-1", "OBORCL", "", "TBPARAM", undefined, "tab-a");
|
||||
expect(columns).toEqual([expect.objectContaining({ name: "PARAM_VALUE", table: "TBPARAM", schema: undefined, dataType: "VARCHAR2(100)" })]);
|
||||
expect(store.lookupLocalCompletionColumns("oceanbase-oracle-1", "OBORCL", "TBPARAM")).toEqual([]);
|
||||
});
|
||||
|
||||
it("keeps quoted OceanBase Oracle identifiers exact and isolated from unquoted cache entries", async () => {
|
||||
const completionAssistantSearch = vi.fn(async (request: { parent_name?: string | null; parent_schema?: string | null }) => ({
|
||||
candidates: [
|
||||
|
||||
@@ -74,6 +74,7 @@ import {
|
||||
type ConnectionExportProtection,
|
||||
} from "@/lib/connection/connectionConfigTransfer";
|
||||
import type { SqlCompletionColumn, SqlCompletionForeignKey, SqlCompletionObject, SqlCompletionTable } from "@/lib/sql/sqlCompletion";
|
||||
import { usesOracleCurrentSchemaCompletion } from "@/lib/sql/oracleCompletionSession";
|
||||
import { mergeSqlObjectNavigationType, sqlObjectNavigationTypeFromTableType } from "@/lib/sql/sqlNavigation";
|
||||
import * as api from "@/lib/backend/api";
|
||||
import { isTauriRuntime } from "@/lib/backend/tauriRuntime";
|
||||
@@ -7807,11 +7808,11 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
const completionTable = uppercaseUnquotedIdentifier && context?.tableQuoted === false ? table.toUpperCase() : table;
|
||||
const rawCompletionSchema = schema?.trim() || (config?.db_type === "dameng" ? config.username?.trim() || undefined : undefined);
|
||||
const completionSchema = uppercaseUnquotedIdentifier && rawCompletionSchema && context?.schemaQuoted === false ? rawCompletionSchema.toUpperCase() : rawCompletionSchema;
|
||||
const usesOracleCurrentSchema = config?.db_type === "oracle" && !completionSchema;
|
||||
if (isSchemaAwareDatabase(connectionId) && !connectionUsesDatabaseObjectTreeMode(config) && !completionSchema && !usesOracleCurrentSchema) {
|
||||
const usesCurrentSchema = usesOracleCurrentSchemaCompletion(config?.db_type, completionSchema);
|
||||
if (isSchemaAwareDatabase(connectionId) && !connectionUsesDatabaseObjectTreeMode(config) && !completionSchema && !usesCurrentSchema) {
|
||||
return [];
|
||||
}
|
||||
const sessionCacheScope = usesOracleCurrentSchema && context?.clientSessionId ? `:${context.clientSessionId}:${context.version ?? 0}` : "";
|
||||
const sessionCacheScope = usesCurrentSchema && context?.clientSessionId ? `:${context.clientSessionId}:${context.version ?? 0}` : "";
|
||||
const cacheKey = `${completionColumnsKey(connectionId, database, completionTable, completionSchema, catalog, context)}${sessionCacheScope}`;
|
||||
if (!completionColumnsCache.value[cacheKey]) {
|
||||
const requestRevision = completionCacheRevision(connectionId, database);
|
||||
@@ -7820,7 +7821,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
async () => {
|
||||
await ensureConnected(connectionId);
|
||||
// Use assistant metadata opportunistically, then fall back to canonical metadata.
|
||||
if (!usesOracleCurrentSchema && !catalog) {
|
||||
if (!usesCurrentSchema && !catalog) {
|
||||
try {
|
||||
const assistantColumns = await listCompletionAssistantColumns(connectionId, database, completionTable, completionSchema, context, requestRevision);
|
||||
if (assistantColumns.length > 0) {
|
||||
@@ -7845,8 +7846,8 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
// Fall back to the existing metadata path below.
|
||||
}
|
||||
}
|
||||
const querySchema = usesOracleCurrentSchema ? "" : metadataQuerySchema(connectionId, database, completionSchema);
|
||||
const columns = await api.getColumns(connectionId, database, querySchema, completionTable, catalog, usesOracleCurrentSchema ? context?.clientSessionId : undefined);
|
||||
const querySchema = usesCurrentSchema ? "" : metadataQuerySchema(connectionId, database, completionSchema);
|
||||
const columns = await api.getColumns(connectionId, database, querySchema, completionTable, catalog, usesCurrentSchema ? context?.clientSessionId : undefined);
|
||||
if (requestRevision !== completionCacheRevision(connectionId, database)) return;
|
||||
completionColumnsCache.value[cacheKey] = columns;
|
||||
evictOldestCacheEntries(completionColumnsCache.value, COMPLETION_CACHE_MAX);
|
||||
@@ -7867,7 +7868,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
isNullable: column.is_nullable,
|
||||
comment: column.comment,
|
||||
}));
|
||||
if (!usesOracleCurrentSchema) indexCompletionColumns(connectionId, database, completionTable, completionSchema, columns, catalog, context);
|
||||
if (!usesCurrentSchema) indexCompletionColumns(connectionId, database, completionTable, completionSchema, columns, catalog, context);
|
||||
return columns;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user