Skip to content
Snippets Groups Projects
Unverified Commit e99e2da7 authored by Tom Robinson's avatar Tom Robinson Committed by GitHub
Browse files

Fix expression string literal performance. Resolves #12154 (#12213)

parent a1ab89e8
Branches
Tags
No related merge requests found
......@@ -196,6 +196,14 @@ const getQuoteCategories = character => {
: [];
};
const quotedStringRegex = (character, closed = true) => {
const open = character;
const close = closed ? character : "";
return new RegExp(
`${open}(?:[^\\\\${character}]|\\\\(?:[bfnrtv${character}\\\\/]|u[0-9a-fA-F]{4}))*${close}`,
);
};
export const BracketQuotedString = createToken({
name: "BracketQuotedString",
pattern: /\[[^\]]*\]/,
......@@ -203,12 +211,12 @@ export const BracketQuotedString = createToken({
});
export const SingleQuotedString = createToken({
name: "SingleQuotedString",
pattern: /'(?:[^\\']+|\\(?:[bfnrtv'\\/]|u[0-9a-fA-F]{4}))*'/,
pattern: quotedStringRegex("'"),
categories: getQuoteCategories("'"),
});
export const DoubleQuotedString = createToken({
name: "DoubleQuotedString",
pattern: /"(?:[^\\"]+|\\(?:[bfnrtv"\\/]|u[0-9a-fA-F]{4}))*"/,
pattern: quotedStringRegex('"'),
categories: getQuoteCategories('"'),
});
......@@ -274,12 +282,12 @@ export const UnclosedBracketQuotedString = createToken({
});
export const UnclosedSingleQuotedString = createToken({
name: "UnclosedSingleQuotedString",
pattern: /'(?:[^\\']+|\\(?:[bfnrtv'\\/]|u[0-9a-fA-F]{4}))*/,
pattern: quotedStringRegex("'", false),
categories: [RecoveryToken, UnclosedQuotedString, ...getQuoteCategories("'")],
});
export const UnclosedDoubleQuotedString = createToken({
name: "DoubleQuoUnclosedDoubleQuotedStringtedString",
pattern: /"(?:[^\\"]+|\\(?:[bfnrtv"\\/]|u[0-9a-fA-F]{4}))*/,
name: "UnclosedDoubleQuotedString",
pattern: quotedStringRegex('"', false),
categories: [RecoveryToken, UnclosedQuotedString, ...getQuoteCategories('"')],
});
export const Any = createToken({
......
......@@ -6,17 +6,26 @@ import {
expressionOpts,
} from "./__support__/expressions";
const ENABLE_PERF_TESTS = false;
const ENABLE_PERF_TESTS = !process.env["CI"];
function expectFast(fn, milliseconds = 1000) {
const start = Date.now();
fn();
const end = Date.now();
if (ENABLE_PERF_TESTS) {
expect(end - start).toBeLessThan(milliseconds);
}
}
describe("metabase/lib/expressions/compile", () => {
let compile, parseOperators;
it("should load compile within 3 seconds", () => {
const start = Date.now();
({ compile, parseOperators } = require("metabase/lib/expressions/compile"));
const end = Date.now();
if (ENABLE_PERF_TESTS) {
expect(end - start).toBeLessThan(3000);
}
it("should load compile quickly", () => {
expectFast(() => {
({
compile,
parseOperators,
} = require("metabase/lib/expressions/compile"));
});
});
describe("parseOperators", () => {
......@@ -58,21 +67,15 @@ describe("metabase/lib/expressions/compile", () => {
for (const [source, mbql, description] of cases) {
if (mbql) {
it(`should compile ${description}`, () => {
const start = Date.now();
expect(compile({ source, ...opts })).toEqual(mbql);
const elapsed = Date.now() - start;
if (ENABLE_PERF_TESTS) {
expect(elapsed).toBeLessThan(250);
}
expectFast(() => {
expect(compile({ source, ...opts })).toEqual(mbql);
}, 250);
});
} else {
it(`should not compile ${description}`, () => {
const start = Date.now();
expect(() => compile({ source, ...opts })).toThrow();
const elapsed = Date.now() - start;
if (ENABLE_PERF_TESTS) {
expect(elapsed).toBeLessThan(250);
}
expectFast(() => {
expect(() => compile({ source, ...opts })).toThrow();
}, 250);
});
}
}
......@@ -97,5 +100,16 @@ describe("metabase/lib/expressions/compile", () => {
["field-id", 1],
]);
});
it("should not take a long time to parse long string literals", () => {
expectFast(() => {
try {
compile({
source: '"12345678901234567901234567890',
...expressionOpts,
});
} catch (e) {}
});
});
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment