@jitterbit/soql-parser-js
Version:
Salesforce.com SOQL parser and composer
669 lines (668 loc) • 30.6 kB
JavaScript
import { CstParser } from 'chevrotain';
import * as lexer from './lexer';
export class LexingError extends Error {
constructor(lexingError) {
super(`${lexingError.message} (${lexingError.line}:${lexingError.column})`);
this.name = 'LexingError';
}
}
export class ParsingError extends Error {
constructor(parsingError) {
super(parsingError.message);
this.name = parsingError.name;
}
}
export class SoqlParser extends CstParser {
$_dateFunctionOr = undefined;
$_aggregateFunction = undefined;
$_otherFunction = undefined;
$_atomicExpression = undefined;
$_apexBindVariableExpression = undefined;
$_arrayExpression = undefined;
$_relationalOperator = undefined;
$_selectClause = undefined;
$_selectClauseFunctionIdentifier = undefined;
$_withDataCategoryArr = undefined;
allowApexBindVariables = false;
ignoreParseErrors = false;
constructor({ ignoreParseErrors } = { ignoreParseErrors: false }) {
super(lexer.allTokens, {
skipValidations: false,
recoveryEnabled: !!ignoreParseErrors,
});
this.ignoreParseErrors = !!ignoreParseErrors;
this.performSelfAnalysis();
}
selectStatement = this.RULE('selectStatement', () => {
this.SUBRULE(this.selectClause);
this.SUBRULE(this.fromClause);
this.SUBRULE(this.clauseStatements);
});
selectStatementPartial = this.RULE('selectStatementPartial', () => {
this.OPTION(() => {
this.SUBRULE(this.selectClause);
});
this.OPTION1(() => {
this.SUBRULE(this.fromClause);
});
this.SUBRULE(this.clauseStatements);
});
clauseStatements = this.RULE('clauseStatements', () => {
this.OPTION(() => {
this.SUBRULE(this.usingScopeClause);
});
this.OPTION1(() => {
this.SUBRULE(this.whereClause);
});
this.OPTION2(() => {
this.MANY({
DEF: () => {
this.SUBRULE(this.withClause);
},
});
});
this.OPTION3(() => {
this.SUBRULE(this.groupByClause);
this.OPTION4(() => {
this.SUBRULE(this.havingClause);
});
});
this.OPTION5(() => {
this.SUBRULE(this.orderByClause);
});
this.OPTION6(() => {
this.SUBRULE(this.limitClause);
});
this.OPTION7(() => {
this.SUBRULE(this.offsetClause);
});
this.OPTION8(() => {
this.SUBRULE(this.forViewOrReference);
});
this.OPTION9(() => {
this.SUBRULE(this.updateTrackingViewstat);
});
});
$_checkBalancedParens(parenCount) {
if (!this.RECORDING_PHASE && parenCount) {
const parenMatch = parenCount.left - parenCount.right;
if (parenMatch !== 0) {
this.CONSUME(lexer.RParenMismatch, { ERR_MSG: `Expecting a token type of --> RParen <-- but found --> '' <--` });
}
}
}
selectClause = this.RULE('selectClause', () => {
this.CONSUME(lexer.Select);
this.AT_LEAST_ONE_SEP({
SEP: lexer.Comma,
DEF: () => {
this.OR(this.$_selectClause ||
(this.$_selectClause = [
{ ALT: () => this.SUBRULE(this.selectClauseFunctionIdentifier, { LABEL: 'field' }) },
{ ALT: () => this.SUBRULE(this.selectClauseSubqueryIdentifier, { LABEL: 'field' }) },
{ ALT: () => this.SUBRULE(this.selectClauseTypeOf, { LABEL: 'field' }) },
{ ALT: () => this.SUBRULE(this.selectClauseIdentifier, { LABEL: 'field' }) },
]));
},
});
}, { resyncEnabled: false });
selectClauseFunctionIdentifier = this.RULE('selectClauseFunctionIdentifier', () => {
this.OR(this.$_selectClauseFunctionIdentifier ||
(this.$_selectClauseFunctionIdentifier = [
{ ALT: () => this.SUBRULE(this.dateFunction, { LABEL: 'fn' }) },
{ ALT: () => this.SUBRULE(this.aggregateFunction, { LABEL: 'fn' }) },
{ ALT: () => this.SUBRULE(this.locationFunction, { LABEL: 'fn' }) },
{ ALT: () => this.SUBRULE(this.fieldsFunction, { LABEL: 'fn' }) },
{ ALT: () => this.SUBRULE(this.otherFunction, { LABEL: 'fn' }) },
]));
this.OPTION(() => this.CONSUME(lexer.Identifier, { LABEL: 'alias' }));
}, { resyncEnabled: false });
selectClauseSubqueryIdentifier = this.RULE('selectClauseSubqueryIdentifier', () => {
this.CONSUME(lexer.LParen);
this.SUBRULE(this.selectStatement);
this.CONSUME(lexer.RParen);
}, { resyncEnabled: false });
selectClauseTypeOf = this.RULE('selectClauseTypeOf', () => {
this.CONSUME(lexer.Typeof);
this.CONSUME(lexer.Identifier, { LABEL: 'typeOfField' });
this.AT_LEAST_ONE({
DEF: () => {
this.SUBRULE(this.selectClauseTypeOfThen);
},
});
this.OPTION(() => {
this.SUBRULE(this.selectClauseTypeOfElse);
});
this.CONSUME(lexer.End);
}, { resyncEnabled: false });
selectClauseIdentifier = this.RULE('selectClauseIdentifier', () => {
this.CONSUME(lexer.Identifier, { LABEL: 'field' });
this.OPTION(() => this.CONSUME1(lexer.Identifier, { LABEL: 'alias' }));
}, { resyncEnabled: false });
selectClauseTypeOfThen = this.RULE('selectClauseTypeOfThen', () => {
this.CONSUME(lexer.When);
this.CONSUME(lexer.Identifier, { LABEL: 'typeOfField' });
this.CONSUME(lexer.Then);
this.AT_LEAST_ONE_SEP({
SEP: lexer.Comma,
DEF: () => {
this.CONSUME1(lexer.Identifier, { LABEL: 'field' });
},
});
}, { resyncEnabled: false });
selectClauseTypeOfElse = this.RULE('selectClauseTypeOfElse', () => {
this.CONSUME(lexer.Else);
this.AT_LEAST_ONE_SEP({
SEP: lexer.Comma,
DEF: () => {
this.CONSUME(lexer.Identifier, { LABEL: 'field' });
},
});
}, { resyncEnabled: false });
fromClause = this.RULE('fromClause', () => {
this.CONSUME(lexer.From);
this.CONSUME(lexer.Identifier);
this.OPTION({
GATE: () => !(this.LA(1).tokenType === lexer.Offset && this.LA(2).tokenType === lexer.UnsignedInteger),
DEF: () => this.CONSUME1(lexer.Identifier, { LABEL: 'alias' }),
});
}, { resyncEnabled: false });
usingScopeClause = this.RULE('usingScopeClause', () => {
this.CONSUME(lexer.Using);
this.CONSUME(lexer.Scope);
this.CONSUME(lexer.UsingScopeEnumeration);
});
whereClause = this.RULE('whereClause', () => {
this.CONSUME(lexer.Where);
const parenCount = this.getParenCount();
this.AT_LEAST_ONE({
DEF: () => {
this.SUBRULE(this.conditionExpression, { ARGS: [parenCount, true, true] });
},
});
this.$_checkBalancedParens(parenCount);
});
whereClauseSubqueryIdentifier = this.RULE('whereClauseSubqueryIdentifier', () => {
this.CONSUME(lexer.LParen);
this.SUBRULE(this.selectStatement);
this.CONSUME(lexer.RParen);
});
conditionExpression = this.RULE('conditionExpression', (parenCount, allowAggregateFn, allowLocationFn) => {
parenCount = this.getParenCount(parenCount);
this.OPTION(() => {
this.OR([
{ ALT: () => this.CONSUME(lexer.And, { LABEL: 'logicalOperator' }) },
{ ALT: () => this.CONSUME(lexer.Or, { LABEL: 'logicalOperator' }) },
]);
});
this.MANY({
MAX_LOOKAHEAD: 10,
DEF: () => this.SUBRULE(this.expressionPartWithNegation, { ARGS: [parenCount], LABEL: 'expressionNegation' }),
});
this.OR1({
MAX_LOOKAHEAD: 10,
DEF: [{ ALT: () => this.SUBRULE(this.expression, { ARGS: [parenCount, false, allowAggregateFn, allowLocationFn] }) }],
});
});
withClause = this.RULE('withClause', () => {
this.CONSUME(lexer.With);
this.OR([
{ ALT: () => this.CONSUME(lexer.SecurityEnforced, { LABEL: 'withSecurityEnforced' }) },
{ ALT: () => this.CONSUME(lexer.UserMode, { LABEL: 'withAccessLevel' }) },
{ ALT: () => this.CONSUME(lexer.SystemMode, { LABEL: 'withAccessLevel' }) },
{ ALT: () => this.SUBRULE(this.withDataCategory) },
]);
});
withDataCategory = this.RULE('withDataCategory', () => {
this.CONSUME(lexer.DataCategory);
this.AT_LEAST_ONE_SEP({
SEP: lexer.And,
DEF: () => {
this.SUBRULE(this.withDataCategoryArr);
},
});
});
withDataCategoryArr = this.RULE('withDataCategoryArr', () => {
this.CONSUME(lexer.Identifier, { LABEL: 'dataCategoryGroupName' });
this.OR(this.$_withDataCategoryArr ||
(this.$_withDataCategoryArr = [
{ ALT: () => this.CONSUME(lexer.At, { LABEL: 'filteringSelector' }) },
{ ALT: () => this.CONSUME(lexer.Above, { LABEL: 'filteringSelector' }) },
{ ALT: () => this.CONSUME(lexer.Below, { LABEL: 'filteringSelector' }) },
{ ALT: () => this.CONSUME(lexer.AboveOrBelow, { LABEL: 'filteringSelector' }) },
]));
this.OPTION(() => {
this.CONSUME1(lexer.LParen);
});
this.AT_LEAST_ONE_SEP1({
SEP: lexer.Comma,
DEF: () => {
this.CONSUME1(lexer.Identifier, { LABEL: 'dataCategoryName' });
},
});
this.OPTION1(() => {
this.CONSUME2(lexer.RParen);
});
});
groupByClause = this.RULE('groupByClause', () => {
this.CONSUME(lexer.GroupBy);
this.AT_LEAST_ONE_SEP({
SEP: lexer.Comma,
DEF: () => {
this.OR([
{ ALT: () => this.SUBRULE(this.cubeFunction, { LABEL: 'groupBy' }) },
{ ALT: () => this.SUBRULE(this.rollupFunction, { LABEL: 'groupBy' }) },
{ ALT: () => this.SUBRULE(this.dateFunction, { LABEL: 'groupBy' }) },
{ ALT: () => this.CONSUME(lexer.Identifier, { LABEL: 'groupBy' }) },
]);
},
});
});
havingClause = this.RULE('havingClause', () => {
this.CONSUME(lexer.Having);
const parenCount = this.getParenCount();
this.AT_LEAST_ONE({
DEF: () => {
this.SUBRULE(this.conditionExpression, { ARGS: [parenCount, true, false] });
},
});
this.$_checkBalancedParens(parenCount);
});
orderByClause = this.RULE('orderByClause', () => {
this.CONSUME(lexer.OrderBy);
this.AT_LEAST_ONE_SEP({
SEP: lexer.Comma,
DEF: () => {
this.OR([
{ ALT: () => this.SUBRULE(this.orderByGroupingFunctionExpression, { LABEL: 'orderByExpressionOrFn' }) },
{ ALT: () => this.SUBRULE(this.orderBySpecialFunctionExpression, { LABEL: 'orderByExpressionOrFn' }) },
{ ALT: () => this.SUBRULE(this.orderByExpression, { LABEL: 'orderByExpressionOrFn' }) },
]);
},
});
});
orderByExpression = this.RULE('orderByExpression', () => {
this.CONSUME(lexer.Identifier);
this.OPTION(() => {
this.OR([{ ALT: () => this.CONSUME(lexer.Asc, { LABEL: 'order' }) }, { ALT: () => this.CONSUME(lexer.Desc, { LABEL: 'order' }) }]);
});
this.OPTION1(() => {
this.CONSUME(lexer.Nulls);
this.OR1([{ ALT: () => this.CONSUME(lexer.First, { LABEL: 'nulls' }) }, { ALT: () => this.CONSUME(lexer.Last, { LABEL: 'nulls' }) }]);
});
});
orderByGroupingFunctionExpression = this.RULE('orderByGroupingFunctionExpression', () => {
this.CONSUME(lexer.Grouping, { LABEL: 'fn' });
this.SUBRULE(this.functionExpression);
});
orderBySpecialFunctionExpression = this.RULE('orderBySpecialFunctionExpression', () => {
this.OR([
{ ALT: () => this.SUBRULE(this.aggregateFunction) },
{ ALT: () => this.SUBRULE(this.dateFunction) },
{ ALT: () => this.SUBRULE(this.locationFunction) },
]);
this.OPTION(() => {
this.OR1([{ ALT: () => this.CONSUME(lexer.Asc, { LABEL: 'order' }) }, { ALT: () => this.CONSUME(lexer.Desc, { LABEL: 'order' }) }]);
});
this.OPTION1(() => {
this.CONSUME(lexer.Nulls);
this.OR2([{ ALT: () => this.CONSUME(lexer.First, { LABEL: 'nulls' }) }, { ALT: () => this.CONSUME(lexer.Last, { LABEL: 'nulls' }) }]);
});
});
limitClause = this.RULE('limitClause', () => {
this.CONSUME(lexer.Limit);
this.CONSUME(lexer.UnsignedInteger, { LABEL: 'value' });
});
offsetClause = this.RULE('offsetClause', () => {
this.CONSUME(lexer.Offset);
this.CONSUME(lexer.UnsignedInteger, { LABEL: 'value' });
});
dateFunction = this.RULE('dateFunction', () => {
this.OR(this.$_dateFunctionOr ||
(this.$_dateFunctionOr = [
{ ALT: () => this.CONSUME(lexer.CalendarMonth, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.CalendarQuarter, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.CalendarYear, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.DayInMonth, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.DayInWeek, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.DayInYear, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.DayOnly, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.FiscalMonth, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.FiscalQuarter, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.FiscalYear, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.HourInDay, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.WeekInMonth, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.WeekInYear, { LABEL: 'fn' }) },
]));
this.SUBRULE(this.functionExpression);
});
aggregateFunction = this.RULE('aggregateFunction', () => {
this.OR(this.$_aggregateFunction ||
(this.$_aggregateFunction = [
{ ALT: () => this.CONSUME(lexer.Avg, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.Count, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.CountDistinct, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.Min, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.Max, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.Sum, { LABEL: 'fn' }) },
]));
this.SUBRULE(this.functionExpression, { ARGS: [true] });
});
fieldsFunction = this.RULE('fieldsFunction', () => {
this.CONSUME(lexer.Fields, { LABEL: 'fn' });
this.CONSUME(lexer.LParen);
this.CONSUME(lexer.FieldsFunctionParamIdentifier, { LABEL: 'params' });
this.CONSUME(lexer.RParen);
});
otherFunction = this.RULE('otherFunction', () => {
this.OR(this.$_otherFunction ||
(this.$_otherFunction = [
{ ALT: () => this.CONSUME(lexer.Format, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.Tolabel, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.ConvertTimeZone, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.ConvertCurrency, { LABEL: 'fn' }) },
{ ALT: () => this.CONSUME(lexer.Grouping, { LABEL: 'fn' }) },
]));
this.SUBRULE(this.functionExpression);
});
cubeFunction = this.RULE('cubeFunction', () => {
this.CONSUME(lexer.Cube, { LABEL: 'fn' });
this.SUBRULE(this.functionExpression);
});
rollupFunction = this.RULE('rollupFunction', () => {
this.CONSUME(lexer.Rollup, { LABEL: 'fn' });
this.SUBRULE(this.functionExpression);
});
functionExpression = this.RULE('functionExpression', (skipAggregate) => {
this.CONSUME(lexer.LParen);
this.MANY_SEP({
SEP: lexer.Comma,
DEF: () => {
this.OR([
{ GATE: () => !skipAggregate, ALT: () => this.SUBRULE(this.aggregateFunction, { LABEL: 'params' }) },
{ ALT: () => this.SUBRULE(this.otherFunction, { LABEL: 'params' }) },
{ ALT: () => this.CONSUME(lexer.StringIdentifier, { LABEL: 'params' }) },
{ ALT: () => this.CONSUME(lexer.NumberIdentifier, { LABEL: 'params' }) },
{ ALT: () => this.CONSUME(lexer.Identifier, { LABEL: 'params' }) },
]);
},
});
this.CONSUME(lexer.RParen);
});
locationFunction = this.RULE('locationFunction', () => {
this.CONSUME(lexer.Distance);
this.CONSUME(lexer.LParen);
this.CONSUME(lexer.Identifier, { LABEL: 'location1' });
this.CONSUME(lexer.Comma);
this.OR([
{ ALT: () => this.SUBRULE(this.geolocationFunction, { LABEL: 'location2' }) },
{ ALT: () => this.CONSUME1(lexer.Identifier, { LABEL: 'location2' }) },
]);
this.CONSUME1(lexer.Comma);
this.CONSUME(lexer.GeolocationUnit, { LABEL: 'unit' });
this.CONSUME(lexer.RParen);
});
geolocationFunction = this.RULE('geolocationFunction', () => {
this.CONSUME(lexer.Geolocation);
this.CONSUME(lexer.LParen);
this.CONSUME(lexer.NumberIdentifier, { LABEL: 'latitude' });
this.CONSUME(lexer.Comma);
this.CONSUME1(lexer.NumberIdentifier, { LABEL: 'longitude' });
this.CONSUME(lexer.RParen);
});
expressionPartWithNegation = this.RULE('expressionPartWithNegation', (parenCount) => {
let leftParenCount = 0;
this.MANY(() => {
this.CONSUME(lexer.LParen);
leftParenCount++;
});
this.CONSUME(lexer.Not, { LABEL: 'expressionNegation' });
if (parenCount && leftParenCount) {
parenCount.left += leftParenCount;
}
});
expression = this.RULE('expression', (parenCount, allowSubquery, allowAggregateFn, allowLocationFn) => {
this.OPTION1(() => {
this.MANY1(() => {
this.CONSUME(lexer.LParen);
if (parenCount) {
parenCount.left++;
}
});
});
this.OR1([
{ GATE: () => !!allowAggregateFn, ALT: () => this.SUBRULE(this.aggregateFunction, { LABEL: 'lhs' }) },
{ GATE: () => !!allowLocationFn, ALT: () => this.SUBRULE(this.locationFunction, { LABEL: 'lhs' }) },
{ ALT: () => this.SUBRULE(this.dateFunction, { LABEL: 'lhs' }) },
{ ALT: () => this.SUBRULE(this.otherFunction, { LABEL: 'lhs' }) },
{ ALT: () => this.CONSUME(lexer.Identifier, { LABEL: 'lhs' }) },
]);
this.OR2([
{ ALT: () => this.SUBRULE(this.expressionWithRelationalOperator, { LABEL: 'operator' }) },
{ ALT: () => this.SUBRULE(this.expressionWithSetOperator, { LABEL: 'operator', ARGS: [allowSubquery] }) },
]);
this.OPTION3(() => {
this.MANY2({
GATE: () => (parenCount ? parenCount.left > parenCount.right : true),
DEF: () => {
this.CONSUME(lexer.RParen);
if (parenCount) {
parenCount.right++;
}
},
});
});
});
expressionWithRelationalOperator = this.RULE('expressionWithRelationalOperator', () => {
this.SUBRULE(this.relationalOperator);
this.SUBRULE(this.atomicExpression, { LABEL: 'rhs' });
});
expressionWithSetOperator = this.RULE('expressionWithSetOperator', (allowSubquery) => {
this.SUBRULE(this.setOperator);
this.SUBRULE2(this.atomicExpression, { LABEL: 'rhs', ARGS: [true, allowSubquery] });
});
atomicExpression = this.RULE('atomicExpression', (isArray, allowSubquery) => {
this.OR(this.$_atomicExpression ||
(this.$_atomicExpression = [
{ GATE: () => this.allowApexBindVariables, ALT: () => this.SUBRULE(this.apexBindVariableExpression) },
{ GATE: () => isArray, ALT: () => this.SUBRULE(this.arrayExpression) },
{ GATE: () => isArray && allowSubquery, ALT: () => this.SUBRULE(this.whereClauseSubqueryIdentifier) },
{ GATE: () => !isArray, ALT: () => this.CONSUME(lexer.JitterbitVariable, { LABEL: 'jitterbitVariableExpression' }) },
{ GATE: () => !isArray, ALT: () => this.CONSUME(lexer.DateIdentifier) },
{ GATE: () => !isArray, ALT: () => this.CONSUME(lexer.CurrencyPrefixedDecimal, { LABEL: 'CurrencyPrefixedDecimal' }) },
{ GATE: () => !isArray, ALT: () => this.CONSUME(lexer.CurrencyPrefixedInteger, { LABEL: 'CurrencyPrefixedInteger' }) },
{ GATE: () => !isArray, ALT: () => this.CONSUME(lexer.NumberIdentifier) },
{ GATE: () => !isArray, ALT: () => this.CONSUME(lexer.Null) },
{ GATE: () => !isArray, ALT: () => this.SUBRULE(this.booleanValue) },
{ GATE: () => !isArray, ALT: () => this.CONSUME(lexer.DateLiteral) },
{ GATE: () => !isArray, ALT: () => this.SUBRULE(this.dateNLiteral) },
{ GATE: () => !isArray, ALT: () => this.CONSUME(lexer.GeolocationUnit, { LABEL: 'StringIdentifier' }) },
{ GATE: () => !isArray, ALT: () => this.CONSUME(lexer.StringIdentifier) },
]));
});
apexBindVariableExpression = this.RULE('apexBindVariableExpression', () => {
this.CONSUME(lexer.Colon);
this.OPTION(() => {
this.SUBRULE(this.apexBindVariableNewInstantiation, { LABEL: 'apex' });
this.OPTION1(() => {
this.CONSUME(lexer.Decimal);
});
});
this.MANY_SEP({
SEP: lexer.Decimal,
DEF: () => {
this.OR(this.$_apexBindVariableExpression ||
(this.$_apexBindVariableExpression = [
{ ALT: () => this.SUBRULE(this.apexBindVariableFunctionCall, { LABEL: 'apex' }) },
{ ALT: () => this.SUBRULE(this.apexBindVariableIdentifier, { LABEL: 'apex' }) },
]));
},
});
});
apexBindVariableIdentifier = this.RULE('apexBindVariableIdentifier', () => {
this.CONSUME(lexer.Identifier);
this.OPTION(() => this.SUBRULE(this.apexBindVariableFunctionArrayAccessor));
});
apexBindVariableNewInstantiation = this.RULE('apexBindVariableNewInstantiation', () => {
this.CONSUME(lexer.ApexNew, { LABEL: 'new' });
this.CONSUME(lexer.Identifier, { LABEL: 'function' });
this.OPTION(() => {
this.SUBRULE(this.apexBindVariableGeneric);
});
this.SUBRULE(this.apexBindVariableFunctionParams);
this.OPTION1(() => this.SUBRULE(this.apexBindVariableFunctionArrayAccessor));
});
apexBindVariableFunctionCall = this.RULE('apexBindVariableFunctionCall', () => {
this.CONSUME(lexer.Identifier, { LABEL: 'function' });
this.SUBRULE(this.apexBindVariableFunctionParams);
this.OPTION(() => this.SUBRULE(this.apexBindVariableFunctionArrayAccessor));
});
apexBindVariableGeneric = this.RULE('apexBindVariableGeneric', () => {
this.CONSUME(lexer.LessThan);
this.AT_LEAST_ONE_SEP({
SEP: lexer.Comma,
DEF: () => {
this.CONSUME(lexer.Identifier, { LABEL: 'parameter' });
},
});
this.CONSUME(lexer.GreaterThan);
});
apexBindVariableFunctionParams = this.RULE('apexBindVariableFunctionParams', () => {
this.CONSUME(lexer.LParen);
this.MANY_SEP({
SEP: lexer.Comma,
DEF: () => {
this.CONSUME(lexer.Identifier, { LABEL: 'parameter' });
},
});
this.CONSUME(lexer.RParen);
});
apexBindVariableFunctionArrayAccessor = this.RULE('apexBindVariableFunctionArrayAccessor', () => {
this.CONSUME(lexer.LSquareBracket);
this.OR([
{ ALT: () => this.CONSUME(lexer.UnsignedInteger, { LABEL: 'value' }) },
{ ALT: () => this.CONSUME(lexer.Identifier, { LABEL: 'value' }) },
]);
this.CONSUME(lexer.RSquareBracket);
});
arrayExpression = this.RULE('arrayExpression', () => {
this.CONSUME(lexer.LParen);
this.AT_LEAST_ONE_SEP({
SEP: lexer.Comma,
DEF: () => {
this.OR(this.$_arrayExpression ||
(this.$_arrayExpression = [
{ ALT: () => this.CONSUME(lexer.CurrencyPrefixedDecimal, { LABEL: 'value' }) },
{ ALT: () => this.CONSUME(lexer.CurrencyPrefixedInteger, { LABEL: 'value' }) },
{ ALT: () => this.CONSUME(lexer.NumberIdentifier, { LABEL: 'value' }) },
{ ALT: () => this.CONSUME(lexer.DateIdentifier, { LABEL: 'value' }) },
{ ALT: () => this.CONSUME(lexer.Null, { LABEL: 'value' }) },
{ ALT: () => this.CONSUME(lexer.True, { LABEL: 'value' }) },
{ ALT: () => this.CONSUME(lexer.False, { LABEL: 'value' }) },
{ ALT: () => this.CONSUME(lexer.DateLiteral, { LABEL: 'value' }) },
{ ALT: () => this.SUBRULE(this.dateNLiteral, { LABEL: 'value' }) },
{ ALT: () => this.CONSUME(lexer.GeolocationUnit, { LABEL: 'value' }) },
{ ALT: () => this.CONSUME(lexer.StringIdentifier, { LABEL: 'value' }) },
]));
},
});
this.CONSUME(lexer.RParen);
});
relationalOperator = this.RULE('relationalOperator', () => {
this.OR(this.$_relationalOperator ||
(this.$_relationalOperator = [
{ ALT: () => this.CONSUME(lexer.Equal, { LABEL: 'operator' }) },
{ ALT: () => this.CONSUME(lexer.NotEqual, { LABEL: 'operator' }) },
{ ALT: () => this.CONSUME(lexer.GreaterThan, { LABEL: 'operator' }) },
{ ALT: () => this.CONSUME(lexer.GreaterThanOrEqual, { LABEL: 'operator' }) },
{ ALT: () => this.CONSUME(lexer.LessThan, { LABEL: 'operator' }) },
{ ALT: () => this.CONSUME(lexer.LessThanOrEqual, { LABEL: 'operator' }) },
{ ALT: () => this.CONSUME(lexer.Like, { LABEL: 'operator' }) },
]));
});
setOperator = this.RULE('setOperator', () => {
this.OR([
{ ALT: () => this.CONSUME(lexer.In, { LABEL: 'operator' }) },
{ ALT: () => this.SUBRULE(this.notInOperator, { LABEL: 'notIn' }) },
{ ALT: () => this.CONSUME(lexer.Includes, { LABEL: 'operator' }) },
{ ALT: () => this.CONSUME(lexer.Excludes, { LABEL: 'operator' }) },
]);
});
notInOperator = this.RULE('notInOperator', () => {
this.CONSUME(lexer.Not, { LABEL: 'operator' });
this.CONSUME(lexer.In, { LABEL: 'operator' });
});
booleanValue = this.RULE('booleanValue', () => {
this.OR([
{ ALT: () => this.CONSUME(lexer.True, { LABEL: 'boolean' }) },
{ ALT: () => this.CONSUME(lexer.False, { LABEL: 'boolean' }) },
]);
});
dateNLiteral = this.RULE('dateNLiteral', () => {
this.CONSUME(lexer.DateNLiteral, { LABEL: 'dateNLiteral' });
this.CONSUME(lexer.Colon);
this.OR1([
{ ALT: () => this.CONSUME(lexer.UnsignedInteger, { LABEL: 'variable' }) },
{ ALT: () => this.CONSUME(lexer.SignedInteger, { LABEL: 'variable' }) },
]);
});
forViewOrReference = this.RULE('forViewOrReference', () => {
this.CONSUME(lexer.For);
this.OR([
{ ALT: () => this.CONSUME(lexer.View, { LABEL: 'value' }) },
{ ALT: () => this.CONSUME(lexer.Reference, { LABEL: 'value' }) },
{ ALT: () => this.CONSUME(lexer.Update, { LABEL: 'value' }) },
]);
});
updateTrackingViewstat = this.RULE('updateTrackingViewstat', () => {
this.CONSUME(lexer.Update);
this.OR([
{ ALT: () => this.CONSUME(lexer.Tracking, { LABEL: 'value' }) },
{ ALT: () => this.CONSUME(lexer.Viewstat, { LABEL: 'value' }) },
]);
});
getParenCount(parenCount) {
return parenCount || { right: 0, left: 0 };
}
}
let parser = new SoqlParser();
export function parse(soql, options) {
const { allowApexBindVariables, logErrors, ignoreParseErrors, allowPartialQuery } = options || {
allowApexBindVariables: false,
logErrors: false,
ignoreParseErrors: false,
};
const lexResult = lexer.lex(soql);
if (lexResult.errors.length > 0) {
if (logErrors) {
console.log('Lexing Errors:');
console.log(JSON.stringify(lexResult.errors, null, 4));
}
throw new LexingError(lexResult.errors[0]);
}
if (parser.ignoreParseErrors !== ignoreParseErrors) {
parser = new SoqlParser({ ignoreParseErrors });
}
parser.input = lexResult.tokens;
parser.allowApexBindVariables = allowApexBindVariables || false;
let cst;
if (allowPartialQuery) {
cst = parser.selectStatementPartial();
}
else {
cst = parser.selectStatement();
}
if (parser.errors.length > 0) {
if (logErrors) {
console.log('Parsing Errors:');
console.log(JSON.stringify(parser.errors, null, 4));
}
if (!ignoreParseErrors) {
throw new ParsingError(parser.errors[0]);
}
}
return {
cst,
parseErrors: parser.errors.map(err => new ParsingError(err)),
};
}