Skip to content
Snippets Groups Projects
Unverified Commit d4c03209 authored by Dalton's avatar Dalton Committed by GitHub
Browse files

Convert parameter target utils to TypeScript (#24571)

parent c8704344
No related branches found
No related tags found
No related merge requests found
......@@ -20,6 +20,7 @@ import {
ExpressionReference,
DatetimeUnit,
} from "metabase-types/types/Query";
import { VariableTarget } from "metabase-types/types/Parameter";
import ValidationError, {
VALIDATION_ERROR_TYPES,
} from "metabase-lib/lib/ValidationError";
......@@ -28,6 +29,7 @@ import { getFieldValues, getRemappings } from "metabase/lib/query/field";
import { DATETIME_UNITS, formatBucketing } from "metabase/lib/query_time";
import Aggregation from "metabase-lib/lib/queries/structured/Aggregation";
import StructuredQuery from "metabase-lib/lib/queries/StructuredQuery";
import NativeQuery from "metabase-lib/lib/queries/NativeQuery";
import { infer, MONOTYPE } from "metabase/lib/expressions/typeinferencer";
import { isa } from "cljs/metabase.types";
......@@ -105,9 +107,9 @@ export default class Dimension {
* Metadata should be provided if you intend to use the display name or render methods.
*/
static parseMBQL(
mbql: ConcreteField,
mbql: ConcreteField | VariableTarget,
metadata?: Metadata,
query?: StructuredQuery | null | undefined,
query?: StructuredQuery | NativeQuery | null | undefined,
): Dimension | null | undefined {
for (const D of DIMENSION_TYPES) {
const dimension = D.parseMBQL(mbql, metadata, query);
......@@ -1542,16 +1544,16 @@ export class AggregationDimension extends Dimension {
}
}
export class TemplateTagDimension extends FieldDimension {
constructor(tagName, metadata, query) {
constructor(tagName: string, metadata: Metadata, query: NativeQuery) {
super(null, null, metadata, query, {
_tagName: tagName,
});
}
static parseMBQL(
mbql,
metadata = null,
query = null,
mbql: VariableTarget,
metadata: Metadata = null,
query: NativeQuery = null,
): FieldDimension | null | undefined {
return TemplateTagDimension.isTemplateTagClause(mbql)
? Object.freeze(new TemplateTagDimension(mbql[1], metadata, query))
......
......@@ -141,7 +141,7 @@ export function remapParameterValuesToTemplateTags(
const { target } = dashboardParameter;
const tag = getTemplateTagFromTarget(target);
if (templateTagParametersByName[tag]) {
if (tag != null && templateTagParametersByName[tag]) {
const templateTagParameter = templateTagParametersByName[tag];
const parameterValue =
parameterValuesByDashboardParameterId[dashboardParameter.id];
......
import Dimension from "metabase-lib/lib/Dimension";
export function isDimensionTarget(target) {
return target?.[0] === "dimension";
}
export function isVariableTarget(target) {
return target?.[0] === "variable";
}
export function getTemplateTagFromTarget(target) {
if (!target?.[1]) {
return null;
}
const [, [type, tag]] = target;
return type === "template-tag" ? tag : null;
}
export function getParameterTargetField(target, metadata, question) {
if (isDimensionTarget(target)) {
const dimension = Dimension.parseMBQL(
target[1],
metadata,
question.query(),
);
return dimension?.field();
}
return null;
}
import Dimension from "metabase-lib/lib/Dimension";
import {
ParameterTarget,
ParameterDimensionTarget,
} from "metabase-types/types/Parameter";
import Metadata from "metabase-lib/lib/metadata/Metadata";
import Question from "metabase-lib/lib/Question";
import StructuredQuery from "metabase-lib/lib/queries/StructuredQuery";
import NativeQuery from "metabase-lib/lib/queries/NativeQuery";
export function isDimensionTarget(
target: ParameterTarget,
): target is ParameterDimensionTarget {
return target?.[0] === "dimension";
}
export function isVariableTarget(target: ParameterTarget) {
return target?.[0] === "variable";
}
export function getTemplateTagFromTarget(target: ParameterTarget) {
if (!target?.[1]) {
return null;
}
const [, [type, tag]] = target;
return type === "template-tag" ? tag : null;
}
export function getParameterTargetField(
target: ParameterTarget,
metadata: Metadata,
question: Question,
) {
if (isDimensionTarget(target)) {
const query = question.query() as NativeQuery | StructuredQuery;
const dimension = Dimension.parseMBQL(target[1], metadata, query);
return dimension?.field();
}
return null;
}
......@@ -9,21 +9,40 @@ import {
PRODUCTS,
SAMPLE_DATABASE,
} from "__support__/sample_database_fixture";
import { ParameterDimensionTarget } from "metabase-types/types/Parameter";
describe("parameters/utils/targets", () => {
describe("isDimensionTarget", () => {
it('should return true for a target that contanis a "dimension" string in the first entry', () => {
expect(isDimensionTarget(["foo"])).toBe(false);
it("should return false for non-dimension targets", () => {
expect(isDimensionTarget(["variable", ["template-tag", "foo"]])).toBe(
false,
);
// @ts-expect-error - this function is still used in untyped code -- making sure non-arrays don't blow up
expect(isDimensionTarget()).toBe(false);
expect(isDimensionTarget(["dimension"])).toBe(true);
});
it('should return true for a target that contains a "dimension" string in the first entry', () => {
expect(isDimensionTarget(["dimension", ["field", 1, null]])).toBe(true);
expect(isDimensionTarget(["dimension", ["template-tag", "foo"]])).toBe(
true,
);
});
});
describe("isVariableTarget", () => {
it('should return true for a target that contanis a "dimension" string in the first entry', () => {
expect(isVariableTarget(["foo"])).toBe(false);
it("should return false for non-variable targets", () => {
expect(isVariableTarget(["dimension", ["field", 1, null]])).toBe(false);
expect(isVariableTarget(["dimension", ["template-tag", "foo"]])).toBe(
false,
);
// @ts-expect-error - this function is still used in untyped code -- making sure non-arrays don't blow up
expect(isVariableTarget()).toBe(false);
expect(isVariableTarget(["variable"])).toBe(true);
});
it("should return true for a variable target", () => {
expect(isVariableTarget(["variable", ["template-tag", "foo"]])).toBe(
true,
);
});
});
......@@ -38,7 +57,9 @@ describe("parameters/utils/targets", () => {
});
it("should return null for targets that are not template tags", () => {
expect(getTemplateTagFromTarget(["foo"])).toBe(null);
// @ts-expect-error - this function is still used in untyped code -- making sure non-arrays don't blow up
expect(getTemplateTagFromTarget(["dimension"])).toBe(null);
// @ts-expect-error - this function is still used in untyped code -- making sure non-arrays don't blow up
expect(getTemplateTagFromTarget()).toBe(null);
expect(
getTemplateTagFromTarget(["dimension", ["field", 123, null]]),
......@@ -48,11 +69,31 @@ describe("parameters/utils/targets", () => {
describe("getParameterTargetField", () => {
it("should return null when the target is not a dimension", () => {
expect(getParameterTargetField(["variable", "foo"], metadata)).toBe(null);
// @ts-expect-error - SAMPLE_DATABASE is defined
const question = SAMPLE_DATABASE.nativeQuestion({
query: "select * from PRODUCTS where CATEGORY = {{foo}}",
"template-tags": {
foo: {
type: "text",
},
},
});
expect(
getParameterTargetField(
["variable", ["template-tag", "foo"]],
metadata,
question,
),
).toBe(null);
});
it("should return the mapped field behind a template tag field filter", () => {
const target = ["dimension", ["template-tag", "foo"]];
const target: ParameterDimensionTarget = [
"dimension",
["template-tag", "foo"],
];
// @ts-expect-error - SAMPLE_DATABASE is defined
const question = SAMPLE_DATABASE.nativeQuestion({
query: "select * from PRODUCTS where {{foo}}",
"template-tags": {
......@@ -69,7 +110,11 @@ describe("parameters/utils/targets", () => {
});
it("should return the target field", () => {
const target = ["dimension", ["field", PRODUCTS.CATEGORY.id, null]];
const target: ParameterDimensionTarget = [
"dimension",
["field", PRODUCTS.CATEGORY.id, null],
];
// @ts-expect-error - SAMPLE_DATABASE is defined
const question = SAMPLE_DATABASE.question({
"source-table": PRODUCTS.id,
});
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment