Releases: jetstreamapp/soql-parser-js
Release 2.1.0
Release 2.0.0
2.0.0
Summary
Version 2.0 brings some significant bundle size and performance improvements. This library now uses Chevrotain instead of antlr4. With this change, everything related to parsing had to be re-written from scratch. Chevrotain uses pure javascript to handle lexing, parsing, and visiting the generated ast/cst as opposed to using a grammar file and generating a javascript parser based on the grammar.
With this change, the data model was reviewed and analyzed, and there are some significant breaking changes to the data structures. Review the 🔥breaking changes🔥 below for a detailed description of each breaking change.
Bundle Size
soql-parser-js
bundles all of the library code and three dependencies chevrotain
(which relies on regexp-to-ast
) and lodash.get
(required by chevrotain) into the javascript bundle. Previously, antlr4
was not bundled and was required to be installed separately.
To compare the bundle size, the following small program was written and then compiled using the default configuration of webpack, and the output bundle was compared.
- Version 1.x: 545kb (this includes all required dependencies)
- Version 2.0: 197kb (this includes all required dependencies)
var soqlParser = require('soql-parser-js');
const query = soqlParser.parseQuery(`SELECT Id FROM Account WHERE Id = 'FOO'`);
console.log('query', query);
const soql = soqlParser.composeQuery(query);
console.log('soql', soql);
Benchmarks
Here is an example benchmark of parsing all the unit tests 1,000 times
OLD PARSER: ~6.2 seconds for ~60K parses
NEW PARSER: ~2.25 seconds for 60K parses
Breaking Changes 🔥
General Changes
- The CLI was removed.
- The
parseQuery()
function no longer acceptsoptions
as a second parameter. rawValue
will always have a space between parametersGROUPING(Id, BillingCountry)
- Some
literalType
values may have differing case from prior versions, regardless of the data input.TRUE
,FALSE
, and all functions except those listed below will always be returned in uppercase, regardless of case of input.- Exceptions:
toLabel
,convertTimezone
,convertCurrency
will always be in camelCase.
- Added new available types for
DateLiteral
andDateNLiteral
.
- A new
LiteralType
value was added forAPEX_BIND_VARIABLE
.
Compose Query
getComposedField()
is deprecated, you should now usegetField()
.getComposedField()
will remain available for backward compatibility.getField()
/getComposedField()
has the following changes:fn
property is has been deprecated (but still exists), you should now usefunctionName
instead.- The
from
property has been removed for subqueries. TherelationshipName
is required to be populated to compose a subquery.
- On the FormatOptions interface
fieldMaxLineLen
was renamed tofieldMaxLineLength
.
export interface FormatOptions {
numIndent?: number;
- fieldMaxLineLen?: number;
+ fieldMaxLineLength?: number;
fieldSubqueryParensOnOwnLine?: boolean;
whereClauseOperatorsIndented?: boolean;
logging?: boolean;
}
Parse Query
rawValue
will now be included onField
ifobjectPrefix
is defined.alias
may be included onField
, if defined.- On
FieldFunctionExpression
,fn
was renamed tofunctionName
. this was done because all other usages offn
wereFunctionExp
, but it was a string in this case. - The
parameters
type onFieldFunctionExpression
was modified to allow an array of varying types. - Removed
from
property fromFieldSubquery
. having
was removed fromQueryBase
and now lives as a property onGroupByClause
.- On the
Condition
object,literalType
may be an array. This will be an array ifvalue
is an array and there are variable types within thevalue
. For example:WHERE Foo IN ('a', null, 'b')
would produceliteralType: ['STRING', 'NULL', 'STRING']
. - The
GroupByClause
has the following modifications:field
is now optional, and will be populated only if the grouping is on a single field.type
has been renamed tofn
and will be populated whenCUBE
andROLLUP
are used.- The
having
clause has been moved as a top-level property to theGroupByClause
and will be populated only if ahaving
clause is present.
- The
HavingCondition
now has aliteralType
that will be populated with the type of thevalue
property. FunctionExp
has the following modificationstext
was renamed torawValue
to be more consistent with other places in the data model.name
was renamed tofunctionName
.parameter
was renamed toparameters
and the type was changed to(string | FunctionExp)[]
to support nested functions. This will ALWAYS be an array now even if there is only one parameter.fn
was removed, as nested functionParameters are always stored as an entry in theparameters
array.
export interface Field {
type: 'Field';
field: string;
objectPrefix?: string;
+ rawValue?: string;
+ alias?: string;
}
export interface FieldFunctionExpression {
type: 'FieldFunctionExpression';
- fn: string;
+ functionName: string;
- parameters?: string[] | FieldFunctionExpression[];
+ parameters?: (string | FieldFunctionExpression)[];
alias?: string;
isAggregateFn?: boolean;
rawValue?: string;
}
export interface FieldRelationship {
type: 'FieldRelationship';
field: string;
relationships: string[];
objectPrefix?: string;
rawValue?: string;
+ alias?: string;
}
export interface FieldSubquery {
type: 'FieldSubquery';
subquery: Subquery;
- from?: string;
}
export interface QueryBase {
fields: FieldType[];
sObjectAlias?: string;
where?: WhereClause;
limit?: number;
offset?: number;
groupBy?: GroupByClause;
- having?: HavingClause;
orderBy?: OrderByClause | OrderByClause[];
withDataCategory?: WithDataCategoryClause;
withSecurityEnforced?: boolean;
for?: ForClause;
update?: UpdateClause;
}
export interface Condition {
openParen?: number;
closeParen?: number;
logicalPrefix?: LogicalPrefix;
field?: string;
fn?: FunctionExp;
operator: Operator;
value?: string | string[];
valueQuery?: Query;
- literalType?: LiteralType;
+ literalType?: LiteralType | LiteralType[];
dateLiteralVariable?: number;parsed
}
export interface GroupByClause {
- field: string | string[];
+ field?: string | string[];
- type?: GroupByType;
+ fn?: FunctionExp;
+ having?: HavingClause;
}
export interface HavingCondition {
openParen?: number;
closeParen?: number;
field?: string;
fn?: FunctionExp;
operator: string;
value: string | number;
+ literalType?: String;
}
export interface FunctionExp {
- text?: string;
+ rawValue?: string;
- name?: string;
+ functionName?: string;
alias?: string;
- parameter?: string | string[];
+ parameters?: (string | FunctionExp)[];
isAggregateFn?: boolean;
- fn?: FunctionExp;
}
Release 2.0.0-rc.6
Release 2.0.0-rc.5
Release 2.0.0-rc.4
Release 1.2.1
Release 1.2.0
1.2.0
- Changed compose methods to public to allow external access (#65)
- Fixed lodash security vulnerability
- Updated README to reflect new changes and other minor changes
Release 1.1.1
1.1.1
- Removed files that accidentally got included with release with update of
release-it
- Updated
Contributing.md
with more detailed instructions on grammar updates - Added support for
WITH SECURITY_ENFORCED
(#61)
Release 1.0.2
1.0.2
- If a field in a query happened to have a function reserved word, such as
Format
, then parsing the query failed. (#59)