Skip to content
Snippets Groups Projects
Unverified Commit defd866e authored by Ariya Hidayat's avatar Ariya Hidayat Committed by GitHub
Browse files

Native query: construct `parameters[]` when necessary (#23210)

parent 56357c04
No related merge requests found
......@@ -1355,6 +1355,10 @@ export default class Question extends memoizeClass<QuestionInner>(
dataset_query,
};
if (type === "native") {
card = assocIn(card, ["parameters"], []);
}
if (tableId != null) {
card = assocIn(card, ["dataset_query", "query", "source-table"], tableId);
}
......
......@@ -26,6 +26,11 @@ import { fetchAlertsForQuestion } from "metabase/alert/alert";
import Question from "metabase-lib/lib/Question";
import StructuredQuery from "metabase-lib/lib/queries/StructuredQuery";
import {
getTemplateTagsForParameters,
getTemplateTagParameters,
} from "metabase/parameters/utils/cards";
import { trackNewQuestionSaved } from "../../analytics";
import {
getCard,
......@@ -307,6 +312,14 @@ export const updateQuestion = (
);
}
const newDatasetQuery = newQuestion.query().datasetQuery();
// Sync card's parameters with the template tags;
if (newDatasetQuery.type === "native") {
const templateTags = getTemplateTagsForParameters(newQuestion.card());
const parameters = getTemplateTagParameters(templateTags);
newQuestion = newQuestion.setParameters(parameters);
}
// Replace the current question with a new one
await dispatch.action(UPDATE_QUESTION, { card: newQuestion.card() });
......
......@@ -20,7 +20,6 @@ import { SET_UI_CONTROLS } from "./ui";
import {
getTemplateTagsForParameters,
getTemplateTagParameters,
getTemplateTagParameter,
} from "metabase/parameters/utils/cards";
export const TOGGLE_DATA_REFERENCE = "metabase/qb/TOGGLE_DATA_REFERENCE";
......@@ -144,29 +143,11 @@ export const setTemplateTag = createThunkAction(
},
);
const { parameters } = updatedTagsCard;
if (parameters && Array.isArray(parameters)) {
if (parameters.length === 0) {
// reconstruct from the existing template tags
const tags = getTemplateTagsForParameters(updatedTagsCard);
const newParameters = getTemplateTagParameters(tags);
return assoc(updatedTagsCard, "parameters", newParameters);
} else {
// update an existing parameter
const index = parameters.findIndex(p => p.id === templateTag.id);
if (index < 0) {
console.warn(`Can't find parameter with id=${templateTag.id}!`);
} else {
parameters[index] = getTemplateTagParameter(templateTag);
}
}
} else {
const tags = getTemplateTagsForParameters(updatedTagsCard);
const newParameters = getTemplateTagParameters(tags);
return assoc(updatedTagsCard, "parameters", newParameters);
}
return updatedTagsCard;
return assoc(
updatedTagsCard,
"parameters",
getTemplateTagParameters(getTemplateTagsForParameters(updatedTagsCard)),
);
};
},
);
......@@ -50,6 +50,7 @@ export default class TagEditorSidebar extends React.Component {
setParameterValue,
onClose,
} = this.props;
// The tag editor sidebar excludes snippets since they have a separate sidebar.
const tags = query.templateTagsWithoutSnippets();
const database = query.database();
......
......@@ -216,6 +216,42 @@ describe("scenarios > question > native", () => {
cy.get("@sidebar").contains(/added/i);
});
it("should recognize template tags and save them as parameters", () => {
openNativeEditor().type(
"select * from PRODUCTS where CATEGORY={{cat}} and RATING >= {{stars}}",
{
parseSpecialCharSequences: false,
},
);
cy.get("input[placeholder*='Cat']").type("Gizmo");
cy.get("input[placeholder*='Stars']").type("3");
cy.get(".NativeQueryEditor .Icon-play").click();
cy.wait("@dataset");
cy.contains("Save").click();
modal().within(() => {
cy.findByLabelText("Name").type("SQL Products");
cy.findByText("Save").click();
// parameters[] should reflect the template tags
cy.wait("@card").should(xhr => {
const requestBody = xhr.request?.body;
expect(requestBody?.parameters?.length).to.equal(2);
});
});
cy.findByText("Not now").click();
// Now load the question again and parameters[] should still be there
cy.intercept("GET", "/api/card/4").as("cardQuestion");
cy.visit("/question/4?cat=Gizmo&stars=3");
cy.wait("@cardQuestion").should(xhr => {
const responseBody = xhr.response?.body;
expect(responseBody?.parameters?.length).to.equal(2);
});
});
it("should link correctly from the variables sidebar (metabase#16212)", () => {
cy.createNativeQuestion({
name: "test-question",
......
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