fix: support legacy metabase native queries

This commit is contained in:
Andrey Avtomonov 2026-05-13 14:39:04 +02:00
parent a517c834fe
commit 8620b9ed08
3 changed files with 45 additions and 2 deletions

View file

@ -116,11 +116,17 @@ interface MetabaseNativeStage {
'template-tags'?: Record<string, MetabaseTemplateTag>;
}
interface MetabaseLegacyNativeQuery {
query?: string;
'template-tags'?: Record<string, MetabaseTemplateTag>;
}
export interface MetabaseDatasetQuery {
'lib/type'?: 'mbql/query';
database?: number;
type?: 'native' | 'query';
stages?: MetabaseNativeStage[];
native?: MetabaseLegacyNativeQuery;
}
export interface MetabaseNativeQueryResult {

View file

@ -37,6 +37,21 @@ function nativeCard(query: string, templateTags: Record<string, MetabaseTemplate
};
}
function legacyNativeCard(query: string, templateTags: Record<string, MetabaseTemplateTag> = {}): MetabaseCard {
return {
id: 1,
name: 'Legacy native card',
type: 'model',
query_type: 'native',
database_id: 6,
dataset_query: {
type: 'native',
database: 6,
native: { query, 'template-tags': templateTags },
},
};
}
describe('DefaultMetabaseConnectionClientFactory', () => {
it('resolves runtime credentials by the explicit Metabase source connection id and merges overrides', async () => {
const resolveCredentials = vi.fn().mockResolvedValue(runtime);
@ -274,6 +289,25 @@ describe('getDummyValueForWidgetType', () => {
});
});
describe('MetabaseClient legacy native dataset query support', () => {
it('reads SQL and template tags from dataset_query.native', async () => {
const client = new MetabaseClient(runtime, fastRetryConfig);
const card = legacyNativeCard('SELECT * FROM orders WHERE status = {{ status }}', {
status: {
name: 'status',
type: 'text',
default: 'paid',
},
});
expect(client.getNativeSql(card)).toBe('SELECT * FROM orders WHERE status = {{ status }}');
expect(client.getTemplateTags(card)).toEqual({
status: expect.objectContaining({ name: 'status', type: 'text' }),
});
await expect(client.getCardSql(card)).resolves.toBe('SELECT * FROM orders WHERE status = {{ status }}');
});
});
describe('MetabaseClient.getResolvedSql', () => {
function makeClient(setup?: (client: MetabaseClient) => void): MetabaseClient {
const client = new MetabaseClient({ apiUrl: 'http://test', apiKey: 'k' });

View file

@ -150,6 +150,9 @@ function injectNativeSql(datasetQuery: MetabaseDatasetQuery, sql: string): Metab
stages[0] = { ...stages[0], native: sql };
return { ...datasetQuery, stages };
}
if (datasetQuery?.native?.query !== undefined) {
return { ...datasetQuery, native: { ...datasetQuery.native, query: sql } };
}
return datasetQuery;
}
@ -368,11 +371,11 @@ export class MetabaseClient implements MetabaseRuntimeClient {
}
getNativeSql(card: MetabaseCard): string | null {
return card.dataset_query?.stages?.[0]?.native ?? null;
return card.dataset_query?.stages?.[0]?.native ?? card.dataset_query?.native?.query ?? null;
}
getTemplateTags(card: MetabaseCard): Record<string, MetabaseTemplateTag> {
return card.dataset_query?.stages?.[0]?.['template-tags'] ?? {};
return card.dataset_query?.stages?.[0]?.['template-tags'] ?? card.dataset_query?.native?.['template-tags'] ?? {};
}
async getCardSql(card: MetabaseCard): Promise<string | null> {