Skip to content

Commit fa9d3cd

Browse files
authored
Merge pull request #73 from paustint/v2
Version 2.0
2 parents 5b20ca2 + cdf04bf commit fa9d3cd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+17003
-29992
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
build/tests
55
.rpt2_cache
66
dist/
7+
dist_esm/
78
.env
89
debug/lib
9-
10+
archive/
1011
.idea/
1112

1213
# Created by https://www.gitignore.io/api/node

.npmignore

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
lib/
2+
src/
23
test/
34
docs/
45
.vscode/
@@ -12,11 +13,7 @@ tsconfig.json
1213
.env
1314
.git
1415
.release-it.json
15-
rollup-plugins
16-
.nyc_output
17-
.rpt2_cache
18-
SOQL.g4
1916
ISSUE_TEMPLATE
2017
CONTRIBUTING.md
2118
CHANGELOG.md
22-
rollup.config.js
19+
webpack.config.js

.prettierrc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
{
2-
"printWidth": 120,
2+
"printWidth": 140,
33
"semi": true,
44
"tabWidth": 2,
55
"useTabs": false,
66
"singleQuote": true,
7-
"trailingComma": "es5",
7+
"trailingComma": "all",
88
"bracketSpacing": true,
9+
"arrowParens": "avoid",
910
"insertPragma": false
1011
}

.release-it.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
{
2-
"buildCommand": "npm run build",
32
"github": {
43
"release": true
54
},
6-
"dist": {
7-
"afterReleaseCommand": "cd ../docs && npm install soql-parser-js@latest && npm run deploy"
5+
"hooks": {
6+
"before:init": ["npm test"],
7+
"after:bump": "npm run build",
8+
"after:release": "npm run copy-tc-to-docs && cd docs && npm install soql-parser-js@${version} && git add package*.json && git commit -m \"Updated docs version\" && git push && npm run deploy"
89
}
9-
}
10+
}

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
language: node_js
22
node_js:
3-
- "10"
3+
- '12'
44
install:
5-
- npm install
5+
- npm install

CHANGELOG.md

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,289 @@
11
# Changelog
22

3+
## 2.0.0
4+
5+
### Summary
6+
7+
Version 2.0 brings some significant bundle size and performance improvements. This library now uses [Chevrotain](https://github.com/SAP/chevrotain) instead of [antlr4](https://github.com/antlr/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.
8+
9+
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.
10+
11+
#### Bundle Size
12+
13+
To compare the bundle size, the following small program was written and then compiled using the default configuration of webpack, and the resulting webpack bundle was compared to determine the full size of the library.
14+
15+
Minified, uncompressed:
16+
17+
- Version 1.x: **545kb**
18+
- Version 2.0: **207kb**
19+
20+
```javascript
21+
var soqlParser = require('soql-parser-js');
22+
23+
const query = soqlParser.parseQuery(`SELECT Id FROM Account WHERE Id = 'FOO'`);
24+
console.log('query', query);
25+
const soql = soqlParser.composeQuery(query);
26+
console.log('soql', soql);
27+
```
28+
29+
#### Benchmarks
30+
31+
Performance testing was done by iterating the unit tests 60K times, here are the results:
32+
33+
**Version 1.x parser**
34+
35+
```
36+
Library import (startup time): 0.8671 milliseconds
37+
Parsing: 58 X 1000 = 58000 iterations.
38+
Duration: 5.7648 seconds
39+
Average of 0.0994 milliseconds per query
40+
```
41+
42+
**Version 2.0 parser**
43+
44+
```
45+
Library import (startup time): 1.3793 milliseconds
46+
Parsing: 87 X 1000 = 87000 iterations.
47+
Duration: 3.6582 seconds
48+
Average of 0.0420 milliseconds per query
49+
```
50+
51+
### Breaking Changes 🔥
52+
53+
#### General Changes
54+
55+
- The CLI was removed.
56+
- The `parseQuery()` `options` have changed. The only option allowed is `allowApexBindVariables` with will allow parsing queries with apex variables.
57+
- `rawValue` will always have a space between parameters `GROUPING(Id, BillingCountry)`
58+
- Some `literalType` values may have differing case from prior versions, regardless of the data input.
59+
- `TRUE`, `FALSE`, and all functions except those listed below will always be returned in uppercase, regardless of case of input.
60+
- **Exceptions**:
61+
- `toLabel`, `convertTimezone`, `convertCurrency` will always be in camelCase.
62+
- Added types for `DateLiteral` and `DateNLiteral` values. If you are using TypeScript, you can utilize these types.
63+
- A new `LiteralType` value was added for `APEX_BIND_VARIABLE`.
64+
- When composing functions in a where clause or group by clause, the `rawValue` will be preferred (if it exists) (no change here), but if rawValue is not provided, then the function will be composed using the `functionName` and `parameters`.
65+
- A new `LiteralType` value was added for `INTEGER_WITH_CURRENCY_PREFIX` and `DECIMAL_WITH_CURRENCY_PREFIX`. e.x. `USD500.01`
66+
67+
#### Compose Query
68+
69+
- `getComposedField()` is deprecated, you should now use `getField()`. `getComposedField()` will remain available for backward compatibility.
70+
- `getField()`/`getComposedField()` has the following changes:
71+
1. `fn` property is has been deprecated (but still exists), you should now use `functionName` instead.
72+
2. The `from` property has been removed for subqueries. The `relationshipName` is required to be populated to compose a subquery.
73+
- On the FormatOptions interface `fieldMaxLineLen` was renamed to `fieldMaxLineLength`.
74+
- Added support for `usingScope` - https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_using_scope.htm?search_text=format()
75+
- The `having` clause condition (e.x. `left`) now uses the `Condition` interface instead of having it's own structure.
76+
77+
```diff
78+
export interface FormatOptions {
79+
numIndent?: number;
80+
- fieldMaxLineLen?: number;
81+
+ fieldMaxLineLength?: number;
82+
fieldSubqueryParensOnOwnLine?: boolean;
83+
whereClauseOperatorsIndented?: boolean;
84+
logging?: boolean;
85+
}
86+
```
87+
88+
#### Parse Query
89+
90+
- `rawValue` will now be included on `Field` if `objectPrefix` is defined.
91+
- `alias` may be included on `Field`, if defined.
92+
- On `FieldFunctionExpression`, `fn` was renamed to `functionName`. this was done because all other usages of `fn` were `FunctionExp`, but it was a string in this case.
93+
- The `parameters` type on `FieldFunctionExpression` was modified to allow an array of varying types.
94+
- Removed `from` property from `FieldSubquery`.
95+
- `having` was removed from `QueryBase` and now lives as a property on `GroupByClause`.
96+
- On the `Condition` object, `literalType` may be an array. This will be an array if `value` is an array and there are variable types within the `value`. For example: `WHERE Foo IN ('a', null, 'b')` would produce `literalType: ['STRING', 'NULL', 'STRING']`.
97+
- The `GroupByClause` has the following modifications:
98+
- `field` is now optional, and will be populated only if the grouping is on a single field.
99+
- `type` has been renamed to `fn` and will be populated when `CUBE` and `ROLLUP` are used.
100+
- The `having` clause has been added as a top-level property to the `GroupByClause` and will be populated only if a `having` clause is present.
101+
- The `HavingCondition` interface has been removed and now uses the same `Condition` interface that the `WhereClause` uses, but without `valueQuery`.
102+
- The parser uses the same code to process both of these, so the `having` clause now supports the exact same capability as a `where` clause.
103+
- `FunctionExp` has the following modifications
104+
- `text` was renamed to `rawValue` to be more consistent with other places in the data model.
105+
- `name` was renamed to `functionName`.
106+
- `parameter` was renamed to `parameters` 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.
107+
- `fn` was removed, as nested functionParameters are always stored as an entry in the `parameters` array.
108+
- Added support for `usingScope` - https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_using_scope.htm?search_text=format()
109+
110+
```diff
111+
export type LiteralType =
112+
| 'STRING'
113+
| 'INTEGER'
114+
| 'DECIMAL'
115+
+ | 'INTEGER_WITH_CURRENCY_PREFIX'
116+
+ | 'DECIMAL_WITH_CURRENCY_PREFIX'
117+
| 'BOOLEAN'
118+
| 'NULL'
119+
| 'DATETIME'
120+
| 'DATE'
121+
| 'DATE_LITERAL'
122+
| 'DATE_N_LITERAL'
123+
+ | 'APEX_BIND_VARIABLE';
124+
125+
+ export type DateLiteral =
126+
+ | 'YESTERDAY'
127+
+ | 'TODAY'
128+
+ | 'TOMORROW'
129+
+ | 'LAST_WEEK'
130+
+ | 'THIS_WEEK'
131+
+ | 'NEXT_WEEK'
132+
+ | 'LAST_MONTH'
133+
+ | 'THIS_MONTH'
134+
+ | 'NEXT_MONTH'
135+
+ | 'LAST_90_DAYS'
136+
+ | 'NEXT_90_DAYS'
137+
+ | 'THIS_QUARTER'
138+
+ | 'LAST_QUARTER'
139+
+ | 'NEXT_QUARTER'
140+
+ | 'THIS_YEAR'
141+
+ | 'LAST_YEAR'
142+
+ | 'NEXT_YEAR'
143+
+ | 'THIS_FISCAL_QUARTER'
144+
+ | 'LAST_FISCAL_QUARTER'
145+
+ | 'NEXT_FISCAL_QUARTER'
146+
+ | 'THIS_FISCAL_YEAR'
147+
+ | 'LAST_FISCAL_YEAR'
148+
+ | 'NEXT_FISCAL_YEAR';
149+
150+
+ export type DateNLiteral =
151+
+ | 'YESTERDAY'
152+
+ | 'NEXT_N_DAYS'
153+
+ | 'LAST_N_DAYS'
154+
+ | 'N_DAYS_AGO'
155+
+ | 'NEXT_N_WEEKS'
156+
+ | 'LAST_N_WEEKS'
157+
+ | 'N_WEEKS_AGO'
158+
+ | 'NEXT_N_MONTHS'
159+
+ | 'LAST_N_MONTHS'
160+
+ | 'N_MONTHS_AGO'
161+
+ | 'NEXT_N_QUARTERS'
162+
+ | 'LAST_N_QUARTERS'
163+
+ | 'N_QUARTERS_AGO'
164+
+ | 'NEXT_N_YEARS'
165+
+ | 'LAST_N_YEARS'
166+
+ | 'N_YEARS_AGO'
167+
+ | 'NEXT_N_FISCAL_QUARTERS'
168+
+ | 'LAST_N_FISCAL_QUARTERS'
169+
+ | 'N_FISCAL_QUARTERS_AGO'
170+
+ | 'NEXT_N_FISCAL_YEARS'
171+
+ | 'LAST_N_FISCAL_YEARS'
172+
+ | 'N_FISCAL_YEARS_AGO';
173+
174+
export interface Field {
175+
type: 'Field';
176+
field: string;
177+
objectPrefix?: string;
178+
+ rawValue?: string;
179+
+ alias?: string;
180+
}
181+
182+
export interface FieldFunctionExpression {
183+
type: 'FieldFunctionExpression';
184+
- fn: string;
185+
+ functionName: string;
186+
- parameters?: string[] | FieldFunctionExpression[];
187+
+ parameters: (string | FieldFunctionExpression)[];
188+
alias?: string;
189+
isAggregateFn?: boolean;
190+
rawValue?: string;
191+
}
192+
193+
export interface FieldRelationship {
194+
type: 'FieldRelationship';
195+
field: string;
196+
relationships: string[];
197+
objectPrefix?: string;
198+
rawValue?: string;
199+
+ alias?: string;
200+
}
201+
202+
export interface FieldSubquery {
203+
type: 'FieldSubquery';
204+
subquery: Subquery;
205+
- from?: string;
206+
}
207+
208+
export interface QueryBase {
209+
fields: FieldType[];
210+
sObjectAlias?: string;
211+
+ usingScope?: string;
212+
where?: WhereClause;
213+
limit?: number;
214+
offset?: number;
215+
groupBy?: GroupByClause;
216+
- having?: HavingClause;
217+
orderBy?: OrderByClause | OrderByClause[];
218+
withDataCategory?: WithDataCategoryClause;
219+
withSecurityEnforced?: boolean;
220+
for?: ForClause;
221+
update?: UpdateClause;
222+
}
223+
224+
export interface WhereClause {
225+
- left: Condition;
226+
+ left: Condition & ValueQuery;
227+
right?: WhereClause;
228+
operator?: LogicalOperator;
229+
}
230+
231+
232+
+ export interface ValueQuery {
233+
+ valueQuery?: Query;
234+
+ }
235+
236+
export interface Condition {
237+
openParen?: number;
238+
closeParen?: number;
239+
logicalPrefix?: LogicalPrefix;
240+
field?: string;
241+
fn?: FunctionExp;
242+
operator: Operator;
243+
value?: string | string[];
244+
- valueQuery?: Query;
245+
- literalType?: LiteralType;
246+
+ literalType?: LiteralType | LiteralType[];
247+
dateLiteralVariable?: number;
248+
}
249+
250+
export interface GroupByClause {
251+
- field: string | string[];
252+
+ field?: string | string[];
253+
- type?: GroupByType;
254+
+ fn?: FunctionExp;
255+
+ having?: HavingClause;
256+
}
257+
258+
export interface HavingClause {
259+
+ left: Condition;
260+
right?: HavingClause;
261+
operator?: LogicalOperator;
262+
}
263+
264+
- export interface HavingCondition {
265+
- openParen?: number;
266+
- closeParen?: number;
267+
- field?: string;
268+
- fn?: FunctionExp;
269+
- operator: string;
270+
- value: string | number;
271+
- }
272+
273+
export interface FunctionExp {
274+
- text?: string;
275+
+ rawValue?: string;
276+
- name?: string;
277+
+ functionName?: string;
278+
alias?: string;
279+
- parameter?: string | string[];
280+
+ parameters?: (string | FunctionExp)[];
281+
isAggregateFn?: boolean;
282+
- fn?: FunctionExp;
283+
}
284+
285+
```
286+
3287
## 1.2.1
4288

5289
- Queries with multiple consecutive left parens in a where clause were not correctly parsed. (#69)

LICENCE.txt renamed to LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright 2018 Austin Turner
1+
Copyright 2019 Austin Turner
22

33
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
44
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,

0 commit comments

Comments
 (0)