Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/appkit/src/type-generator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,9 @@ export async function generateFromEntryPoint(options: {
mvOutFile?: string;
mvMetadataOutFile?: string;
metricFetcher?: DescribeFetcher;
/** Session catalog/schema for DESCRIBE — see generateQueriesFromDescribe. */
catalog?: string;
schema?: string;
}) {
const {
outFile,
Expand All @@ -308,6 +311,8 @@ export async function generateFromEntryPoint(options: {
mvOutFile,
mvMetadataOutFile,
metricFetcher,
catalog,
schema,
} = options;
const projectRoot = resolveProjectRoot(outFile);

Expand All @@ -320,6 +325,8 @@ export async function generateFromEntryPoint(options: {
const result = await generateQueriesFromDescribe(queryFolder, warehouseId, {
noCache,
mode,
catalog,
schema,
});
queryRegistry = result.schemas;
syntaxErrors = result.syntaxErrors ?? [];
Expand Down
11 changes: 11 additions & 0 deletions packages/appkit/src/type-generator/query-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -487,12 +487,22 @@ export async function generateQueriesFromDescribe(
noCache?: boolean;
concurrency?: number;
mode?: PreflightMode;
/**
* Session catalog/schema for the DESCRIBE statements. Lets schema-relative
* SQL (unqualified table names) resolve at typegen time the same way it
* does at runtime. Optional — when omitted, queries must be fully
* qualified to describe successfully.
*/
catalog?: string;
schema?: string;
} = {},
): Promise<QueryGenerationResult> {
const {
noCache = false,
concurrency: rawConcurrency = 10,
mode = "non-blocking",
catalog,
schema,
} = options;
const concurrency =
typeof rawConcurrency === "number" && Number.isFinite(rawConcurrency)
Expand Down Expand Up @@ -740,6 +750,7 @@ export async function generateQueriesFromDescribe(
`DESCRIBE QUERY ${cleanedSql}`,
warehouseId,
describeFormat,
{ catalog, schema },
);

completed++;
Expand Down
8 changes: 8 additions & 0 deletions packages/appkit/src/type-generator/statement-result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export async function describeAdaptive(
statement: string,
warehouseId: string,
memo: DescribeFormatMemo,
context?: { catalog?: string; schema?: string },
): Promise<DatabricksStatementExecutionResponse> {
const formats: DescribeFormat[] = memo.format
? [memo.format]
Expand All @@ -178,6 +179,13 @@ export async function describeAdaptive(
const response = (await client.statementExecution.executeStatement({
statement,
warehouse_id: warehouseId,
// Session context for the statement. The Statement Execution API honors
// top-level catalog/schema as the equivalent of USE CATALOG / USE SCHEMA
// for that one statement — so schema-relative SQL (e.g. `FROM orders`,
// no catalog.schema qualifier) resolves during DESCRIBE. Omitted keys
// are simply absent, so callers that pass no context are unaffected.
...(context?.catalog ? { catalog: context.catalog } : {}),
...(context?.schema ? { schema: context.schema } : {}),
// Synchronous wait: without it the call can return PENDING/RUNNING with
// no rows, which downstream misreads as a no-result degrade.
wait_timeout: "30s",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,15 +272,17 @@ describe("describeAdaptive", () => {
// each executeStatement to behavior(format), which may resolve or throw.
function stubClient(behavior: StubBehavior) {
const formats: string[] = [];
const requests: Record<string, unknown>[] = [];
const client = {
statementExecution: {
executeStatement: async (req: { format: string }) => {
formats.push(req.format);
requests.push(req);
return behavior(req.format);
},
},
} as unknown as WorkspaceClient;
return { client, formats };
return { client, formats, requests };
}

const rows = (
Expand Down Expand Up @@ -484,4 +486,39 @@ describe("describeAdaptive", () => {
expect(memo.format).toBeUndefined();
expect(formats).toEqual(["JSON_ARRAY"]);
});

test("session context: forwards catalog/schema to executeStatement", async () => {
const memo: DescribeFormatMemo = {};
const { client, requests } = stubClient((format) => {
if (format === "JSON_ARRAY") return rows([["schema"]]);
throw new Error("ARROW should not be tried");
});

await describeAdaptive(client, "DESCRIBE QUERY x", "wh", memo, {
catalog: "my_catalog",
schema: "my_schema",
});

// The catalog/schema reach executeStatement as top-level session context,
// so schema-relative SQL (unqualified table names) resolves at DESCRIBE.
expect(requests[0]).toMatchObject({
catalog: "my_catalog",
schema: "my_schema",
});
});

test("session context: omitted keys are absent (back-compat)", async () => {
const memo: DescribeFormatMemo = {};
const { client, requests } = stubClient((format) => {
if (format === "JSON_ARRAY") return rows([["schema"]]);
throw new Error("ARROW should not be tried");
});

// No context arg at all → the request carries no catalog/schema, exactly
// as before this parameter existed.
await describeAdaptive(client, "DESCRIBE QUERY x", "wh", memo);

expect(requests[0]).not.toHaveProperty("catalog");
expect(requests[0]).not.toHaveProperty("schema");
});
});
8 changes: 8 additions & 0 deletions packages/appkit/src/type-generator/vite-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ export function appKitTypesPlugin(options?: AppKitTypesPluginOptions): Plugin {
return;
}

// Optional session context so schema-relative queries (unqualified table
// names) resolve during DESCRIBE. Read from env alongside the warehouse
// id; unset → DESCRIBE runs without a default catalog/schema as before.
const catalog = process.env.DATABRICKS_CATALOG || undefined;
const schema = process.env.DATABRICKS_SCHEMA || undefined;

await generateFromEntryPoint({
outFile,
queryFolder: watchFolders[0],
Expand All @@ -110,6 +116,8 @@ export function appKitTypesPlugin(options?: AppKitTypesPluginOptions): Plugin {
mode,
mvOutFile,
mvMetadataOutFile,
catalog,
schema,
});
} catch (error) {
// TypegenSyntaxError / TypegenFatalError carry a complete, actionable
Expand Down
Loading