-
Alexander Polyankin authoredAlexander Polyankin authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
nested-card-query-table.ts 2.63 KiB
import {
getQuestionIdFromVirtualTableId,
getQuestionVirtualTableId,
} from "metabase-lib/metadata/utils/saved-questions";
import type Table from "metabase-lib/metadata/Table";
import type Question from "metabase-lib/Question";
import type StructuredQuery from "../StructuredQuery";
import type NativeQuery from "../NativeQuery";
import { createVirtualField, createVirtualTable } from "./virtual-table";
// This function expects a `sourceTableId` to exist in the `metadata.table` cache
// It also expects the card associated with the `sourceTableId` to exist in the `metadata.question` cache
export function getNestedCardTable(query: StructuredQuery): Table | null {
const sourceTableId = query.sourceTableId();
const metadata = query.metadata();
const nestedCardTable = metadata.table(sourceTableId);
if (nestedCardTable) {
return nestedCardTable;
}
const questionId = getQuestionIdFromVirtualTableId(sourceTableId);
const nestedQuestion = metadata.question(questionId);
// There are scenarios (and possible race conditions) in the application where
// the nested card table might not be available, but if we have access to a Question
// with result_metadata then we might as well use it to create virtual fields
if (nestedQuestion) {
return createVirtualTableUsingQuestionMetadata(nestedQuestion);
}
return null;
}
// Treat the Dataset/Model like a Question that uses itself as its source table
// Expects the Question to have been fetched as a virtual table
export function getDatasetTable(
query: StructuredQuery | NativeQuery,
): Table | null {
const question = query.question();
const composedDatasetQuestion = question.composeDataset();
const composedQuestionQuery =
composedDatasetQuestion.query() as StructuredQuery;
return getNestedCardTable(composedQuestionQuery);
}
function createVirtualTableUsingQuestionMetadata(question: Question): Table {
const metadata = question.metadata();
const questionResultMetadata = question.getResultMetadata();
const questionDisplayName = question.displayName() as string;
const query = question.query() as StructuredQuery | NativeQuery;
const fields = questionResultMetadata.map((fieldMetadata: any) => {
const field = metadata.field(fieldMetadata.id);
const virtualField = field
? field.clone(fieldMetadata)
: createVirtualField(fieldMetadata);
virtualField.query = query;
virtualField.metadata = metadata;
return virtualField;
});
return createVirtualTable({
id: getQuestionVirtualTableId(question.id()),
name: questionDisplayName,
display_name: questionDisplayName,
db: question?.database(),
fields,
metadata,
});
}