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

Allow . separator in expression identifiers (#12148)

* Allow . separator in expression identifiers

* Make fk separator configurable
parent 9bf90b61
No related branches found
No related tags found
No related merge requests found
......@@ -29,6 +29,11 @@ export const EDITOR_QUOTES = {
// identifierAlwaysQuoted: false,
// };
export const EDITOR_FK_SYMBOLS = {
symbols: [".", ""],
default: "",
};
// copied relevant parts from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
export const OPERATOR_PRECEDENCE = {
not: 17,
......
export * from "./config";
import Dimension from "metabase-lib/lib/Dimension";
import { OPERATORS, FUNCTIONS, EDITOR_QUOTES, getMBQLName } from "./config";
import { FK_SYMBOL } from "metabase/lib/formatting";
import {
OPERATORS,
FUNCTIONS,
EDITOR_QUOTES,
EDITOR_FK_SYMBOLS,
getMBQLName,
} from "./config";
// IDENTIFIERS
......@@ -60,15 +67,22 @@ export function parseDimension(name, { query }) {
return query
.dimensionOptions()
.all()
.find(d => getDimensionName(d) === name);
.find(d =>
EDITOR_FK_SYMBOLS.symbols.some(
separator => getDimensionName(d, separator) === name,
),
);
}
export function formatDimensionName(dimension, options) {
return formatIdentifier(getDimensionName(dimension), options);
}
export function getDimensionName(dimension) {
return dimension.render();
export function getDimensionName(
dimension,
separator = EDITOR_FK_SYMBOLS.default,
) {
return dimension.render().replace(` ${FK_SYMBOL} `, separator);
}
// STRING LITERALS
......
......@@ -37,7 +37,7 @@ function createClauseToken(name, options = {}) {
export const Identifier = createToken({
name: "Identifier",
pattern: /\w+/,
pattern: /(\w|\.)+/,
label: "identfier",
});
export const IdentifierString = createToken({
......
......@@ -52,6 +52,7 @@ import {
isExpressionType,
getFunctionArgType,
EXPRESSION_TYPES,
EDITOR_FK_SYMBOLS,
} from "./config";
const FUNCTIONS_BY_TYPE = {};
......@@ -91,13 +92,23 @@ export function suggest({
if (
lastInputToken &&
((isTokenType(lastInputToken.tokenType, Identifier) &&
/\w/.test(partialSource[partialSource.length - 1])) ||
Identifier.PATTERN.test(partialSource[partialSource.length - 1])) ||
lastInputTokenIsUnclosedIdentifierString)
) {
tokenVector = tokenVector.slice(0, -1);
partialSuggestionMode = true;
}
const identifierTrimOptions = lastInputTokenIsUnclosedIdentifierString
? {
// use the last token's pattern anchored to the end of the text
prefixTrim: new RegExp(lastInputToken.tokenType.PATTERN.source + "$"),
}
: {
prefixTrim: new RegExp(Identifier.PATTERN.source + "$"),
postfixTrim: new RegExp("^" + Identifier.PATTERN.source + "\\s*"),
};
const context = getContext({
cst,
tokenVector,
......@@ -136,15 +147,6 @@ export function suggest({
parentRule === "metricExpression" &&
isExpressionType(expectedType, "aggregation");
const trimOptions = lastInputTokenIsUnclosedIdentifierString
? {
// use the last token's pattern anchored to the end of the text
prefixTrim: new RegExp(
lastInputToken.tokenType.PATTERN.source + "$",
),
}
: { prefixTrim: /\w+$/, postfixTrim: /^\w+\s*/ };
if (isDimension) {
let dimensions = [];
if (
......@@ -178,7 +180,10 @@ export function suggest({
type: "fields",
name: getDimensionName(dimension),
text: formatDimensionName(dimension) + " ",
...trimOptions,
alternates: EDITOR_FK_SYMBOLS.symbols.map(symbol =>
getDimensionName(dimension, symbol),
),
...identifierTrimOptions,
})),
);
}
......@@ -188,7 +193,7 @@ export function suggest({
type: "segments",
name: segment.name,
text: formatSegmentName(segment),
...trimOptions,
...identifierTrimOptions,
})),
);
}
......@@ -198,7 +203,7 @@ export function suggest({
type: "metrics",
name: metric.name,
text: formatMetricName(metric),
...trimOptions,
...identifierTrimOptions,
})),
);
}
......@@ -315,11 +320,16 @@ export function suggest({
// throw away any suggestion that is not a suffix of the last partialToken.
if (partialSuggestionMode) {
const input = lastInputToken.image;
const partial = lastInputTokenIsUnclosedIdentifierString
? lastInputToken.image.slice(1).toLowerCase()
: lastInputToken.image.toLowerCase();
? input.slice(1).toLowerCase()
: input.toLowerCase();
for (const suggestion of finalSuggestions) {
suggestion: for (const text of [suggestion.name, suggestion.text]) {
suggestion: for (const text of [
suggestion.name,
suggestion.text,
...(suggestion.alternates || []),
]) {
const lower = (text || "").toLowerCase();
if (lower.startsWith(partial)) {
suggestion.range = [0, partial.length];
......
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