From f2e13922a26290a57b8f05de60b2a320490de5f2 Mon Sep 17 00:00:00 2001 From: jearhe <0verme7753@gmail.com> Date: Fri, 21 Aug 2026 10:18:56 +0800 Subject: [PATCH] fix(phoenix): preserve schema in all table references --- apps/desktop/src/App.vue | 1 + .../sidebar/SidebarTreeRuntimeHost.vue | 6 ++- .../src/components/sidebar/TreeItem.vue | 7 ++++ .../useSidebarDataOpenRuntime.spec.ts | 25 ++++++++++++ .../__tests__/database/jdbcDialect.spec.ts | 11 ++++++ .../editor/queryEditorTableDrop.spec.ts | 14 +++++++ .../lib/__tests__/sql/newQueryContext.spec.ts | 18 +++++++++ .../__tests__/table/tableSelectSql.spec.ts | 14 +++++++ apps/desktop/src/lib/database/jdbcDialect.ts | 10 ++++- .../src/lib/editor/queryEditorTableDrop.ts | 7 +++- apps/desktop/src/lib/sql/newQueryContext.ts | 7 ++-- apps/desktop/src/lib/table/tableSelectSql.ts | 10 +++++ .../src/lib/table/tableSqlTemplates.ts | 2 + crates/dbx-core/src/data_grid_sql.rs | 13 +++++++ .../dbx-core/src/sql_dialect/table_select.rs | 4 ++ crates/dbx-core/src/sql_dialect/tests.rs | 38 +++++++++++++++++++ packages/app-tests/jdbcDialect.test.ts | 6 +-- packages/app-tests/tableSqlTemplates.test.ts | 16 ++++++++ 18 files changed, 200 insertions(+), 9 deletions(-) diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue index 3a53e558dd..5a59e457f9 100644 --- a/apps/desktop/src/App.vue +++ b/apps/desktop/src/App.vue @@ -1686,6 +1686,7 @@ async function newQuery() { targetConnectionId: target.connectionId, targetDatabase: target.database, databaseType: effectiveDatabaseTypeForConnection(conn), + driverProfile: conn.driver_profile, identifierQuote: connectionStore.connectionIdentifierQuote?.(target.connectionId), }); const tabId = queryStore.createTab(conn.id, target.database, undefined, "query", target.schema, initialSql, target.catalog); diff --git a/apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue b/apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue index 9bfdbfab2e..67297827fb 100644 --- a/apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue +++ b/apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue @@ -1719,7 +1719,7 @@ async function loadTemplateContext(allowView = false) { } const identifierQuote = connectionStore.connectionIdentifierQuote(node.connectionId); - return { node, dbType, identifierQuote, tableSchema, columns, tableType }; + return { node, dbType, driverProfile: config?.driver_profile, identifierQuote, tableSchema, columns, tableType }; } function openSqlTemplateTab(connectionId: string, database: string, schema: string | undefined, catalog: string | undefined, sql: string, title?: string) { @@ -1733,6 +1733,7 @@ async function newSelectTemplate() { if (!context) return; const sql = buildTableSelectTemplate({ databaseType: context.dbType, + driverProfile: context.driverProfile, identifierQuote: context.identifierQuote, catalog: context.node.catalog, database: context.node.database, @@ -1752,6 +1753,7 @@ async function newInsertTemplate() { if (!context) return; const sql = buildTableInsertTemplate({ databaseType: context.dbType, + driverProfile: context.driverProfile, identifierQuote: context.identifierQuote, catalog: context.node.catalog, database: context.node.database, @@ -1772,6 +1774,7 @@ async function newUpdateTemplate() { if (!context) return; const sql = buildTableUpdateTemplate({ databaseType: context.dbType, + driverProfile: context.driverProfile, identifierQuote: context.identifierQuote, catalog: context.node.catalog, database: context.node.database, @@ -1791,6 +1794,7 @@ async function newDeleteTemplate() { if (!context) return; const sql = buildTableDeleteTemplate({ databaseType: context.dbType, + driverProfile: context.driverProfile, identifierQuote: context.identifierQuote, catalog: context.node.catalog, database: context.node.database, diff --git a/apps/desktop/src/components/sidebar/TreeItem.vue b/apps/desktop/src/components/sidebar/TreeItem.vue index 36ee7243be..6428ccd756 100644 --- a/apps/desktop/src/components/sidebar/TreeItem.vue +++ b/apps/desktop/src/components/sidebar/TreeItem.vue @@ -208,6 +208,10 @@ function currentDatabaseType(): DatabaseType | undefined { return activeNode.value.connectionId ? effectiveDatabaseTypeForConnection(connectionStore.getConfig(activeNode.value.connectionId)) : undefined; } +function currentDriverProfile(): string | undefined { + return activeNode.value.connectionId ? connectionStore.getConfig(activeNode.value.connectionId)?.driver_profile : undefined; +} + function getIconInfo(node: TreeNode): { icon: any; colorClass: string } | null { switch (node.type) { case "connection": @@ -1116,6 +1120,7 @@ function tableReferenceDragPayload(): QueryEditorTableReferencePayload | null { database: activeNode.value.database, referenceType: "database", databaseType: currentDatabaseType(), + driverProfile: currentDriverProfile(), }); } if (activeNode.value.type === "column") { @@ -1128,6 +1133,7 @@ function tableReferenceDragPayload(): QueryEditorTableReferencePayload | null { tableName: activeNode.value.tableName, columnName, databaseType: currentDatabaseType(), + driverProfile: currentDriverProfile(), }); } const payload = createTableReferencePayload({ @@ -1136,6 +1142,7 @@ function tableReferenceDragPayload(): QueryEditorTableReferencePayload | null { schema: activeNode.value.schema, tableName: activeNode.value.label, databaseType: currentDatabaseType(), + driverProfile: currentDriverProfile(), }); return payload; } diff --git a/apps/desktop/src/composables/__tests__/useSidebarDataOpenRuntime.spec.ts b/apps/desktop/src/composables/__tests__/useSidebarDataOpenRuntime.spec.ts index d802872ef8..a39f5889cf 100644 --- a/apps/desktop/src/composables/__tests__/useSidebarDataOpenRuntime.spec.ts +++ b/apps/desktop/src/composables/__tests__/useSidebarDataOpenRuntime.spec.ts @@ -359,6 +359,31 @@ describe("useSidebarDataOpenRuntime", () => { }); }); + it("preserves JDBC table schema through the table-data request", async () => { + mocks.databaseType = "jdbc"; + mocks.loadTableMetadata.mockImplementation(async (request: { database: string; schema?: string; tableName: string; tableType?: string }) => ({ + metadata: { + schema: request.schema, + tableName: request.tableName, + tableType: request.tableType, + database: request.database, + columns: [{ name: "id", data_type: "bigint", is_nullable: false, column_default: null, is_primary_key: true, extra: null }], + indexes: [], + primaryKeys: ["id"], + cachedAt: Date.now(), + }, + cacheStatus: "miss", + ageMs: 0, + })); + + await useSidebarDataOpenRuntime().openData(tableNode); + + await vi.waitFor(() => expect(mocks.tabs[0]?.tableMeta?.primaryKeys).toEqual(["id"])); + expect(mocks.loadTableMetadata).toHaveBeenCalledWith(expect.objectContaining({ database: "app", schema: "public" })); + expect(mocks.buildTableSelectSql).toHaveBeenCalledWith(expect.objectContaining({ database: "app", schema: "public", tableName: "users" })); + expect(mocks.tabs[0]?.tableMeta).toMatchObject({ database: "app", schema: "public", tableName: "users" }); + }); + it("keeps MySQL data-tab identity unqualified after metadata loads", async () => { mocks.databaseType = "mysql"; mocks.loadTableMetadata.mockImplementation(async (request: { database: string; schema?: string; tableName: string; tableType?: string }) => ({ diff --git a/apps/desktop/src/lib/__tests__/database/jdbcDialect.spec.ts b/apps/desktop/src/lib/__tests__/database/jdbcDialect.spec.ts index 25592547a5..6af9b15388 100644 --- a/apps/desktop/src/lib/__tests__/database/jdbcDialect.spec.ts +++ b/apps/desktop/src/lib/__tests__/database/jdbcDialect.spec.ts @@ -73,6 +73,17 @@ describe("jdbc dialect inference", () => { ).toBe("sqlserver"); }); + it("keeps Phoenix as generic JDBC while preserving its schema tree", () => { + const connection = { db_type: "jdbc" as const, driver_profile: "phoenix" }; + + expect(inferJdbcDialect(connection)).toBe("jdbc"); + expect(effectiveDatabaseTypeForConnection(connection)).toBe("jdbc"); + expect(connectionUsesDatabaseObjectTreeMode(connection)).toBe(false); + expect(connectionObjectTreeQuerySchema(connection, "default", "DEMO")).toBe("DEMO"); + expect(connectionObjectTreeNodeSchema(connection, "default", "DEMO")).toBe("DEMO"); + expect(connectionShouldLoadIdentifierQuote(connection)).toBe(true); + }); + it.each([ ["jdbc:oracle:thin:@//localhost:1521/XE", "oracle"], ["jdbc:dm://localhost:5236/DAMENG", "dameng"], diff --git a/apps/desktop/src/lib/__tests__/editor/queryEditorTableDrop.spec.ts b/apps/desktop/src/lib/__tests__/editor/queryEditorTableDrop.spec.ts index 5a1209b787..4b34c59fb9 100644 --- a/apps/desktop/src/lib/__tests__/editor/queryEditorTableDrop.spec.ts +++ b/apps/desktop/src/lib/__tests__/editor/queryEditorTableDrop.spec.ts @@ -14,6 +14,20 @@ describe("query editor table reference drop", () => { expect(tableReferenceInsertText(payload!)).toBe("`app-db`"); }); + it("preserves the Phoenix schema in dragged table references", () => { + const payload = createTableReferencePayload({ + connectionId: "conn-1", + database: "default", + schema: "APP", + tableName: "USERS", + databaseType: "jdbc", + driverProfile: "phoenix", + })!; + + expect(parseTableReferencePayload(JSON.stringify(payload))).toEqual(payload); + expect(tableReferenceInsertText(payload)).toBe("APP.USERS"); + }); + it("round-trips database reference payloads", () => { const payload = createTableReferencePayload({ connectionId: "conn-1", diff --git a/apps/desktop/src/lib/__tests__/sql/newQueryContext.spec.ts b/apps/desktop/src/lib/__tests__/sql/newQueryContext.spec.ts index 60e3032c67..1ab507cbee 100644 --- a/apps/desktop/src/lib/__tests__/sql/newQueryContext.spec.ts +++ b/apps/desktop/src/lib/__tests__/sql/newQueryContext.spec.ts @@ -204,6 +204,10 @@ describe("buildSelectAllSql", () => { expect(buildSelectAllSql("postgres", { schema: "public", tableName: "users" })).toBe('SELECT * FROM "public"."users"'); }); + it("preserves the Phoenix schema for new-query prefill", () => { + expect(buildSelectAllSql("jdbc", { schema: "APP", tableName: "USERS" }, '"', "phoenix")).toBe('SELECT * FROM "APP"."USERS"'); + }); + it("bracket-quotes a SQL Server table", () => { expect(buildSelectAllSql("sqlserver", { schema: "dbo", tableName: "users" })).toBe("SELECT * FROM [dbo].[users]"); expect(buildSelectAllSql("sqlserver", { tableName: "users" })).toBe("SELECT * FROM [users]"); @@ -258,6 +262,20 @@ describe("resolveNewQueryInitialSql", () => { ).toBe('SELECT * FROM "public"."users"'); }); + it("passes the Phoenix driver profile into the initial SQL builder", () => { + expect( + resolveNewQueryInitialSql({ + activeTab: dataTab({ schema: "APP", tableMeta: { schema: "APP", tableName: "USERS", columns: [], primaryKeys: [] } }), + prefillEnabled: true, + targetConnectionId: "conn-1", + targetDatabase: "app_db", + databaseType: "jdbc", + driverProfile: "phoenix", + identifierQuote: '"', + }), + ).toBe('SELECT * FROM "APP"."USERS"'); + }); + it("leaves new queries empty when the setting is disabled", () => { expect( resolveNewQueryInitialSql({ diff --git a/apps/desktop/src/lib/__tests__/table/tableSelectSql.spec.ts b/apps/desktop/src/lib/__tests__/table/tableSelectSql.spec.ts index 38854e6c21..2a291ccbf0 100644 --- a/apps/desktop/src/lib/__tests__/table/tableSelectSql.spec.ts +++ b/apps/desktop/src/lib/__tests__/table/tableSelectSql.spec.ts @@ -34,6 +34,20 @@ describe("qualifiedTableName — SQLite attached databases", () => { }); }); +describe("qualifiedTableName — schema-aware JDBC profiles", () => { + it("qualifies Phoenix tables without forcing identifier quotes", () => { + expect(qualifiedTableName({ databaseType: "jdbc", driverProfile: "phoenix", schema: "DEMO", tableName: "STUDENT" })).toBe("DEMO.STUDENT"); + }); + + it("uses the driver-reported quote for Phoenix special identifiers", () => { + expect(qualifiedTableName({ databaseType: "jdbc", driverProfile: "phoenix", identifierQuote: '"', schema: "MY_SCHEMA", tableName: "ORDER" })).toBe('"MY_SCHEMA"."ORDER"'); + }); + + it("keeps an unscoped JDBC table unqualified", () => { + expect(qualifiedTableName({ databaseType: "jdbc", driverProfile: "phoenix", tableName: "STUDENT" })).toBe("STUDENT"); + }); +}); + describe("qualifiedTableName — GBase 8s", () => { it("omits the metadata owner for GBase 8s table data", () => { expect(qualifiedTableName({ databaseType: "informix", driverProfile: "gbase8s", identifierQuote: "", schema: "gbasedbt", tableName: "connection_smoke" })).toBe("connection_smoke"); diff --git a/apps/desktop/src/lib/database/jdbcDialect.ts b/apps/desktop/src/lib/database/jdbcDialect.ts index da348b3a86..2ad0f1276b 100644 --- a/apps/desktop/src/lib/database/jdbcDialect.ts +++ b/apps/desktop/src/lib/database/jdbcDialect.ts @@ -21,6 +21,9 @@ const CONNECTION_ROOT_SCHEMA_TYPES = new Set(["oracle", "dameng", const JDBC_DIALECT_MATCHERS: Array<{ type: DatabaseType; patterns: RegExp[] }> = [ { type: "databend", patterns: [/jdbc:databend:/i, /com\.databend\.jdbc\.DatabendDriver/i, /databend-jdbc/i] }, { type: "starrocks", patterns: [/starrocks/i] }, + // Phoenix remains a generic JDBC connection, but exposes queryable schemas. + // Returning `jdbc` keeps its generic SQL behavior while enabling the schema tree. + { type: "jdbc", patterns: [/phoenix/i] }, { type: "doris", patterns: [/doris/i] }, { type: "goldendb", patterns: [/jdbc:goldendb:/i, /goldendb/i] }, { type: "mysql", patterns: [/kyuubi/i] }, @@ -54,6 +57,10 @@ export function inferJdbcDialect(connection?: JdbcDialectConnection): DatabaseTy return JDBC_DIALECT_MATCHERS.find((matcher) => matcher.patterns.some((pattern) => pattern.test(haystack)))?.type; } +export function jdbcDriverProfileUsesSchemaQualification(driverProfile?: string): boolean { + return inferJdbcDialect({ db_type: "jdbc", driver_profile: driverProfile }) === "jdbc"; +} + export function effectiveDatabaseTypeForConnection(connection?: JdbcDialectConnection): DatabaseType | undefined { if (!connection) return undefined; if (connection.db_type === "gbase" && isGbase8sProfile(connection.driver_profile)) return "informix"; @@ -90,7 +97,8 @@ export function connectionShouldLoadIdentifierQuote(connection: JdbcDialectConne if (gaussdbIdentifierQuoteStyle(connection) !== "auto") return false; if (connection.db_type === "gaussdb") return true; if (connection.db_type !== "jdbc") return false; - return ["gaussdb", "opengauss", "postgres"].includes(inferJdbcDialect(connection) ?? ""); + const dialect = inferJdbcDialect(connection); + return dialect === "jdbc" || ["gaussdb", "opengauss", "postgres"].includes(dialect ?? ""); } export function supportsGaussdbIdentifierQuoteStyle(connection: JdbcDialectConnection | undefined): boolean { diff --git a/apps/desktop/src/lib/editor/queryEditorTableDrop.ts b/apps/desktop/src/lib/editor/queryEditorTableDrop.ts index 71171ee098..b284e36c96 100644 --- a/apps/desktop/src/lib/editor/queryEditorTableDrop.ts +++ b/apps/desktop/src/lib/editor/queryEditorTableDrop.ts @@ -13,6 +13,7 @@ export interface QueryEditorTableReferencePayload { columnName?: string; referenceType?: "database" | "table" | "column"; databaseType?: DatabaseType; + driverProfile?: string; } export interface QueryEditorTableReferenceDropDetail { @@ -23,7 +24,7 @@ export interface QueryEditorTableReferenceDropDetail { let activeTableReferencePayload: QueryEditorTableReferencePayload | null = null; -export function createTableReferencePayload(options: { connectionId?: string; database?: string; schema?: string; tableName?: string; columnName?: string; referenceType?: "database" | "table" | "column"; databaseType?: DatabaseType }): QueryEditorTableReferencePayload | null { +export function createTableReferencePayload(options: { connectionId?: string; database?: string; schema?: string; tableName?: string; columnName?: string; referenceType?: "database" | "table" | "column"; databaseType?: DatabaseType; driverProfile?: string }): QueryEditorTableReferencePayload | null { if (!options.connectionId || options.database == null) return null; const referenceType = options.referenceType ?? (options.columnName ? "column" : "table"); if (referenceType !== "database" && !options.tableName) return null; @@ -43,6 +44,7 @@ export function createTableReferencePayload(options: { connectionId?: string; da } if (options.schema) payload.schema = options.schema; if (options.databaseType) payload.databaseType = options.databaseType; + if (options.driverProfile) payload.driverProfile = options.driverProfile; return payload; } @@ -65,6 +67,7 @@ export function parseTableReferencePayload(value: string | undefined | null): Qu referenceType: "database", }; if (parsed.databaseType) payload.databaseType = parsed.databaseType; + if (typeof parsed.driverProfile === "string" && parsed.driverProfile) payload.driverProfile = parsed.driverProfile; return payload; } if (typeof parsed.tableName !== "string" || !parsed.tableName) return null; @@ -83,6 +86,7 @@ export function parseTableReferencePayload(value: string | undefined | null): Qu } if (typeof parsed.schema === "string" && parsed.schema) payload.schema = parsed.schema; if (parsed.databaseType) payload.databaseType = parsed.databaseType; + if (typeof parsed.driverProfile === "string" && parsed.driverProfile) payload.driverProfile = parsed.driverProfile; return payload; } catch { return null; @@ -126,6 +130,7 @@ export function tableReferenceInsertText(payload: QueryEditorTableReferencePaylo const tableName = payload.tableName || payload.database; return qualifiedTableName({ databaseType, + driverProfile: payload.driverProfile, schema: payload.schema, tableName, }); diff --git a/apps/desktop/src/lib/sql/newQueryContext.ts b/apps/desktop/src/lib/sql/newQueryContext.ts index 50636658fe..89034dcba3 100644 --- a/apps/desktop/src/lib/sql/newQueryContext.ts +++ b/apps/desktop/src/lib/sql/newQueryContext.ts @@ -90,6 +90,7 @@ export interface ResolveNewQueryInitialSqlInput extends ResolveNewQueryTableInpu targetConnectionId: string; targetDatabase: string; databaseType?: DatabaseType; + driverProfile?: string; identifierQuote?: string; } @@ -146,9 +147,9 @@ export function resolveNewQueryTable(input: ResolveNewQueryTableInput): NewQuery * the same per-dialect identifier quoting and schema/catalog qualification used * by the table-data view. */ -export function buildSelectAllSql(databaseType: DatabaseType | undefined, table: Pick & Partial>, identifierQuote?: string): string { +export function buildSelectAllSql(databaseType: DatabaseType | undefined, table: Pick & Partial>, identifierQuote?: string, driverProfile?: string): string { if (databaseType === "victoriametrics") return metricRangeQuery(table.tableName); - const ref = qualifiedTableName({ databaseType, identifierQuote, database: table.database, schema: table.schema, catalog: table.catalog, tableName: table.tableName }); + const ref = qualifiedTableName({ databaseType, driverProfile, identifierQuote, database: table.database, schema: table.schema, catalog: table.catalog, tableName: table.tableName }); return `SELECT * FROM ${ref}`; } @@ -163,5 +164,5 @@ export function resolveNewQueryInitialSql(input: ResolveNewQueryInitialSqlInput) const table = resolveNewQueryTable(input); if (!table || table.connectionId !== input.targetConnectionId || table.database !== input.targetDatabase) return undefined; - return buildSelectAllSql(input.databaseType, table, input.identifierQuote); + return buildSelectAllSql(input.databaseType, table, input.identifierQuote, input.driverProfile); } diff --git a/apps/desktop/src/lib/table/tableSelectSql.ts b/apps/desktop/src/lib/table/tableSelectSql.ts index eea3c78c91..b21b98d62e 100644 --- a/apps/desktop/src/lib/table/tableSelectSql.ts +++ b/apps/desktop/src/lib/table/tableSelectSql.ts @@ -1,5 +1,6 @@ import type { DatabaseType } from "@/types/database.ts"; import { isSchemaAware, usesDatabaseObjectTreeMode } from "@/lib/database/databaseCapabilities.ts"; +import { jdbcDriverProfileUsesSchemaQualification } from "@/lib/database/jdbcDialect"; import * as api from "@/lib/backend/api.ts"; import { parseSqlServerLinkedSchema, sqlServerLinkedTableName } from "@/lib/database/sqlServerLinkedServers.ts"; import { isExplicitlyQuotedSqlIdentifier, quoteGaussDbJdbcIdentifier } from "@/lib/sql/sqlIdentifier.ts"; @@ -57,6 +58,10 @@ export function quoteTableIdentifier(databaseType: DatabaseType | undefined, nam } export function quoteTableDataIdentifier(databaseType: DatabaseType | undefined, name: string, identifierQuote?: string): string { + if (databaseType === "jdbc" && identifierQuote != null) { + if (!identifierQuote) return name; + return `${identifierQuote}${name.replaceAll(identifierQuote, identifierQuote + identifierQuote)}${identifierQuote}`; + } if ((databaseType === "gaussdb" || databaseType === "opengauss" || databaseType === "postgres") && identifierQuote != null) return quoteGaussDbJdbcIdentifier(name, identifierQuote); if ((databaseType === "kingbase" || databaseType === "informix" || databaseType === "spanner") && identifierQuote != null) { if (!identifierQuote) return name; @@ -103,6 +108,11 @@ export function qualifiedTableName(options: Pick, ) -> bool { database_type == Some(DatabaseType::Kingbase) + // JDBC table-data requests carry the schema returned by DatabaseMetaData. + // Keep the JDBC identifier unquoted when no driver quote was reported, but + // still qualify the table with that schema. + || database_type == Some(DatabaseType::Jdbc) // Spanner is dual-dialect: GoogleSQL uses backticks, the PostgreSQL dialect uses // double quotes, and only the connected agent knows which. Unconditional like // Kingbase — when no quote was reported the callers fall back to diff --git a/crates/dbx-core/src/sql_dialect/tests.rs b/crates/dbx-core/src/sql_dialect/tests.rs index 6795380ef3..bab6111583 100644 --- a/crates/dbx-core/src/sql_dialect/tests.rs +++ b/crates/dbx-core/src/sql_dialect/tests.rs @@ -378,6 +378,44 @@ fn jdbc_non_tdengine_and_unscoped_tdengine_previews_remain_unqualified() { } } +#[test] +fn jdbc_table_data_qualifies_schema_without_forcing_identifier_quotes() { + assert_eq!( + build_table_data_select_sql(TableDataSelectSqlOptions { + database_type: Some(DatabaseType::Jdbc), + driver_profile: Some("phoenix".to_string()), + schema: Some("DEMO".to_string()), + table_name: "STUDENT".to_string(), + limit: Some(100), + ..Default::default() + }), + "SELECT * FROM DEMO.STUDENT;" + ); + assert_eq!( + build_table_data_select_sql(TableDataSelectSqlOptions { + database_type: Some(DatabaseType::Jdbc), + driver_profile: Some("phoenix".to_string()), + identifier_quote: Some("\"".to_string()), + schema: Some("MY_SCHEMA".to_string()), + table_name: "ORDER".to_string(), + limit: Some(100), + ..Default::default() + }), + "SELECT * FROM \"MY_SCHEMA\".\"ORDER\";" + ); + assert_eq!( + build_table_data_select_sql(TableDataSelectSqlOptions { + database_type: Some(DatabaseType::Jdbc), + driver_profile: Some("phoenix".to_string()), + schema: None, + table_name: "STUDENT".to_string(), + limit: Some(100), + ..Default::default() + }), + "SELECT * FROM STUDENT;" + ); +} + #[test] fn builds_table_data_where_and_schema_queries() { assert_eq!( diff --git a/packages/app-tests/jdbcDialect.test.ts b/packages/app-tests/jdbcDialect.test.ts index b976a448fd..6b114ee62e 100644 --- a/packages/app-tests/jdbcDialect.test.ts +++ b/packages/app-tests/jdbcDialect.test.ts @@ -139,10 +139,10 @@ test("keeps Phoenix on the generic JDBC metadata and object tree path", () => { jdbc_driver_class: "org.apache.phoenix.jdbc.PhoenixDriver", }; - assert.equal(inferJdbcDialect(connection), undefined); + assert.equal(inferJdbcDialect(connection), "jdbc"); assert.equal(effectiveDatabaseTypeForConnection(connection), "jdbc"); - assert.equal(connectionShouldDiscoverJdbcSchemas(connection), true); - assert.equal(connectionUsesDatabaseObjectTreeMode(connection), true); + assert.equal(connectionShouldDiscoverJdbcSchemas(connection), false); + assert.equal(connectionUsesDatabaseObjectTreeMode(connection), false); }); test("uses SQL Server editor syntax for ASE without changing its effective JDBC type", () => { diff --git a/packages/app-tests/tableSqlTemplates.test.ts b/packages/app-tests/tableSqlTemplates.test.ts index 34ad6a791a..856cdd54d6 100644 --- a/packages/app-tests/tableSqlTemplates.test.ts +++ b/packages/app-tests/tableSqlTemplates.test.ts @@ -98,3 +98,19 @@ test("builds GaussDB M templates with the detected backtick identifier mode", () assert.equal(buildTableUpdateTemplate(options), "UPDATE app_schema.`order`\nSET `DisplayName` = 'DisplayName_value'\nWHERE id = 0;"); assert.equal(buildTableDeleteTemplate(options), "DELETE FROM app_schema.`order`\nWHERE id = 0;"); }); + +test("preserves the Phoenix schema in all SQL templates", () => { + const options = { + databaseType: "jdbc" as const, + driverProfile: "phoenix", + identifierQuote: '"', + schema: "APP", + tableName: "USERS", + columns: [col({ name: "ID", data_type: "integer", is_primary_key: true }), col({ name: "NAME", data_type: "varchar" })], + }; + + assert.equal(buildTableSelectTemplate(options), 'SELECT "ID", "NAME"\nFROM "APP"."USERS";'); + assert.equal(buildTableInsertTemplate(options), `INSERT INTO "APP"."USERS" ("ID", "NAME")\nVALUES (0, 'NAME_value');`); + assert.equal(buildTableUpdateTemplate(options), `UPDATE "APP"."USERS"\nSET "NAME" = 'NAME_value'\nWHERE "ID" = 0;`); + assert.equal(buildTableDeleteTemplate(options), `DELETE FROM "APP"."USERS"\nWHERE "ID" = 0;`); +});