├── .babelrc
├── .gitignore
├── .travis.yml
├── README.md
├── dist
└── soql-parse.js
├── index.html
├── lib
└── index.js
├── package.json
├── src
└── parser.pegjs
├── test
├── data
│ ├── expected
│ │ ├── 00-simple-01.json5
│ │ ├── 01-simple-02.json5
│ │ ├── 02-select-clause-01.json5
│ │ ├── 03-select-clause-02.json5
│ │ ├── 04-select-clause-03.json5
│ │ ├── 05-from-object-with-alias-01.json5
│ │ ├── 06-from-object-with-alias-02.json5
│ │ ├── 07-from-object-group-03.json5
│ │ ├── 08-from-object-order-04.json5
│ │ ├── 10-where-clause-01.json5
│ │ ├── 11-where-clause-02.json5
│ │ ├── 12-where-clause-03.json5
│ │ ├── 13-where-clause-04.json5
│ │ ├── 14-where-clause-05.json5
│ │ ├── 15-where-clause-06.json5
│ │ ├── 16-where-clause-07.json5
│ │ ├── 20-order-by-clause-01.json5
│ │ ├── 21-order-by-clause-02.json5
│ │ ├── 30-group-by-clause-01.json5
│ │ ├── 31-group-by-clause-02.json5
│ │ ├── 32-group-by-clause-03.json5
│ │ ├── 40-date-literal-01.json5
│ │ ├── 41-date-literal-02.json5
│ │ ├── 41-date-literal-03.json5
│ │ ├── 41-date-literal-04.json5
│ │ ├── 50-dates-01.json5
│ │ └── 90-complex-01.json5
│ └── parsable
│ │ ├── 00-simple-01.soql
│ │ ├── 01-simple-02.soql
│ │ ├── 02-select-clause-01.soql
│ │ ├── 03-select-clause-02.soql
│ │ ├── 04-select-clause-03.soql
│ │ ├── 05-from-object-with-alias-01.soql
│ │ ├── 06-from-object-with-alias-02.soql
│ │ ├── 07-from-object-group-03.soql
│ │ ├── 08-from-object-order-04.soql
│ │ ├── 10-where-clause-01.soql
│ │ ├── 11-where-clause-02.soql
│ │ ├── 12-where-clause-03.soql
│ │ ├── 13-where-clause-04.soql
│ │ ├── 14-where-clause-05.soql
│ │ ├── 15-where-clause-06.soql
│ │ ├── 16-where-clause-07.soql
│ │ ├── 20-order-by-clause-01.soql
│ │ ├── 21-order-by-clause-02.soql
│ │ ├── 30-group-by-clause-01.soql
│ │ ├── 31-group-by-clause-02.soql
│ │ ├── 32-group-by-clause-03.soql
│ │ ├── 40-date-literal-01.soql
│ │ ├── 41-date-literal-02.soql
│ │ ├── 41-date-literal-03.soql
│ │ ├── 41-date-literal-04.soql
│ │ ├── 50-dates-01.soql
│ │ └── 90-complex-01.soql
└── index.test.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env"]
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### https://raw.github.com/github/gitignore/f31b319dca10213163411cb710c27dc37ed3eac5/Node.gitignore
2 |
3 | lib-cov
4 | *.seed
5 | *.log
6 | *.csv
7 | *.dat
8 | *.out
9 | *.pid
10 | *.gz
11 |
12 | pids
13 | logs
14 | results
15 |
16 | npm-debug.log
17 | node_modules
18 |
19 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - stable
4 | sudo: false
5 | cache:
6 | directories:
7 | - node_modules
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # soql-parse
2 |
3 | Parse [SOQL](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql.htm) query string to abstract syntax tree in JavaScript.
4 |
5 | [](https://travis-ci.org/stomita/soql-parse)
6 |
7 | ## Online Demo
8 |
9 | https://stomita.github.io/soql-parse/
10 |
11 | ## Install
12 |
13 | ```
14 | npm install soql-parse
15 | ```
16 |
17 | ## Usage
18 |
19 | ```js
20 | import { parse } from 'soql-parse';
21 |
22 | const soql = `
23 | Select Id, Name, toLabel(Type) from Account
24 | WHERE Name like 'A%' and Type IN ('Partner', 'Customer')
25 | ORDER by CreatedDate DESC
26 | LIMIT 10
27 | `;
28 |
29 | const parsed = parse(soql);
30 | console.log(parsed);
31 | ```
32 |
33 | Result:
34 |
35 | ```json
36 | {
37 | "type": "Query",
38 | "fields": [
39 | {
40 | "type": "FieldReference",
41 | "path": [
42 | "Id"
43 | ]
44 | },
45 | {
46 | "type": "FieldReference",
47 | "path": [
48 | "Name"
49 | ]
50 | },
51 | {
52 | "type": "FunctionCall",
53 | "name": "toLabel",
54 | "arguments": [
55 | {
56 | "type": "FieldReference",
57 | "path": [
58 | "Type"
59 | ]
60 | }
61 | ]
62 | }
63 | ],
64 | "object": {
65 | "type": "ObjectReference",
66 | "name": "Account"
67 | },
68 | "condition": {
69 | "type": "LogicalCondition",
70 | "operator": "AND",
71 | "left": {
72 | "type": "ComparisonCondition",
73 | "field": {
74 | "type": "FieldReference",
75 | "path": [
76 | "Name"
77 | ]
78 | },
79 | "operator": "LIKE",
80 | "value": {
81 | "type": "string",
82 | "value": "A%"
83 | }
84 | },
85 | "right": {
86 | "type": "ComparisonCondition",
87 | "field": {
88 | "type": "FieldReference",
89 | "path": [
90 | "Type"
91 | ]
92 | },
93 | "operator": "IN",
94 | "value": {
95 | "type": "list",
96 | "values": [
97 | {
98 | "type": "string",
99 | "value": "Partner"
100 | },
101 | {
102 | "type": "string",
103 | "value": "Customer"
104 | }
105 | ]
106 | }
107 | }
108 | },
109 | "sort": [
110 | {
111 | "field": {
112 | "type": "FieldReference",
113 | "path": [
114 | "CreatedDate"
115 | ]
116 | },
117 | "direction": "DESC"
118 | }
119 | ],
120 | "limit": {
121 | "type": "number",
122 | "value": 10
123 | }
124 | }
125 | ```
126 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SOQL Parse Demo
5 |
33 |
34 |
35 |
36 |
SOQL Parse Demo
37 |
38 |
39 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
56 |
57 |
58 |
59 |
64 |
65 |
66 |
67 |
68 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "soql-parse",
3 | "version": "1.1.1",
4 | "main": "lib/index.js",
5 | "license": "MIT",
6 | "scripts": {
7 | "prepare": "npm run build",
8 | "build": "npm run build:parser && npm run build:web",
9 | "build:parser": "pegjs -o lib/index.js src/parser.pegjs",
10 | "build:web": "webpack lib/index.js dist/soql-parse.js --output-library SOQLParse",
11 | "test": "ava"
12 | },
13 | "devDependencies": {
14 | "ava": "^0.24.0",
15 | "json5": "^0.5.1",
16 | "pegjs": "^0.10.0",
17 | "webpack": "^3.10.0"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/parser.pegjs:
--------------------------------------------------------------------------------
1 | {
2 | function assign() {
3 | return Object.assign.apply(null, arguments);
4 | }
5 |
6 | function createLogicalConditionTree(operator, head, tail) {
7 | var result = head;
8 | for (var i = 0; i < tail.length; i++) {
9 | result = {
10 | type: 'LogicalCondition',
11 | operator: operator,
12 | left: result,
13 | right: tail[i],
14 | };
15 | }
16 | return result;
17 | }
18 |
19 | function isReserved(word) {
20 | return /^(SELECT|FROM|AS|USING|WHERE|AND|OR|NOT|GROUP|BY|ORDER|LIMIT|OFFSET|FOR|TRUE|FALSE|NULL)$/i.test(word);
21 | }
22 | }
23 |
24 | Query =
25 | _ SELECT
26 | __ fields:QueryFieldList
27 | __ object:FromClause
28 | scope:(__ ScopeClause)?
29 | condition:(__ WhereClause)?
30 | group:(__ GroupByClause)?
31 | sort:(__ OrderByClause)?
32 | limit:(__ LimitClause)?
33 | offset:(__ OffsetClause)?
34 | selectFor:(__ SelectForClause)?
35 | _ {
36 | return assign(
37 | {
38 | type: 'Query',
39 | fields: fields,
40 | object: object,
41 | },
42 | scope ? { scope: scope[1] } : {},
43 | condition ? { condition: condition[1] } : {},
44 | group ? { group: group[1] } : {},
45 | sort ? { sort: sort[1] } : {},
46 | limit ? { limit: limit[1] } : {},
47 | offset ? { offset: offset[1] } : {},
48 | selectFor ? { selectFor: selectFor[1] } : {}
49 | );
50 | }
51 |
52 | QueryFieldList =
53 | head:QueryFieldListItem _ COMMA _ tail:QueryFieldList {
54 | return [head].concat(tail);
55 | }
56 | / field:QueryFieldListItem {
57 | return [field]
58 | }
59 |
60 | QueryFieldListItem =
61 | SubQuery
62 | / QueryField
63 |
64 | QueryField =
65 | field:FieldExpr alias:(__? Identifier)? {
66 | return (
67 | alias ?
68 | assign({}, field, { alias: alias[1] }) :
69 | field
70 | );
71 | }
72 |
73 | FieldExpr =
74 | FunctionCall
75 | / FieldReference
76 |
77 | FunctionCall =
78 | func:Identifier _ LPAREN _ args:FunctionArg* _ RPAREN {
79 | return {
80 | type: 'FunctionCall',
81 | name: func,
82 | arguments: args,
83 | };
84 | }
85 |
86 | FunctionArg =
87 | FieldReference
88 |
89 | FieldReference =
90 | path:FieldPath {
91 | return {
92 | type: 'FieldReference',
93 | path: path,
94 | };
95 | }
96 |
97 | FieldPath =
98 | head:Identifier _ DOT _ tail:FieldPath {
99 | return [head].concat(tail);
100 | }
101 | / field:Identifier {
102 | return [field];
103 | }
104 |
105 | FromClause =
106 | FROM __
107 | object:ObjectReference
108 | aliasObjects:(_ COMMA _ AliasObjectList)? {
109 | return (
110 | aliasObjects ?
111 | assign({}, object, { aliasObjects: aliasObjects[3] }) :
112 | object
113 | );
114 | }
115 |
116 | ObjectReference =
117 | name:ObjectIdentifier alias:(__ (AS __)? Identifier)? {
118 | return assign(
119 | {
120 | type: 'ObjectReference',
121 | name: name,
122 | },
123 | alias ? { alias: alias[2] } : {}
124 | );
125 | }
126 |
127 | AliasObjectList =
128 | head:AliasObjectReference _ COMMA _ tail:AliasObjectList {
129 | return [head].concat(tail || []);
130 | }
131 | / head:AliasObjectReference {
132 | return [head];
133 | }
134 |
135 | AliasObjectReference =
136 | path:FieldPath alias:(__ (AS __)? Identifier)? {
137 | return assign(
138 | {
139 | type: 'AliasObjectReference',
140 | path: path
141 | },
142 | alias ? { alias: alias[2] } : {}
143 | );
144 | }
145 |
146 | ScopeClause =
147 | USING __ SCOPE __ scope:FilterScope {
148 | return scope;
149 | }
150 |
151 | FilterScope =
152 | "Delegated"i { return 'Delegated'; }
153 | / "Everything"i { return 'Everything'; }
154 | / "Mine"i { return 'Mine'; }
155 | / "My_Territory"i { return 'My_My_Territory'; }
156 | / "My_Team_Territory"i { return 'My_Team_Territory'; }
157 | / "Team"i { return 'Team'; }
158 |
159 | WhereClause =
160 | WHERE __ condition: Condition {
161 | return condition
162 | }
163 |
164 | Condition =
165 | OrCondition
166 |
167 | OrCondition =
168 | head:AndCondition tail:(__ OR __ condition:AndCondition { return condition; })* {
169 | return createLogicalConditionTree('OR', head, tail);
170 | }
171 |
172 | AndCondition =
173 | head:NotCondition tail:(__ AND __ condition:NotCondition { return condition; })* {
174 | return createLogicalConditionTree('AND', head, tail);
175 | }
176 |
177 | NotCondition =
178 | NOT __ condition:ParenCondition {
179 | return {
180 | type: 'NegateCondition',
181 | operator: 'NOT',
182 | condition: condition,
183 | };
184 | }
185 | / ParenCondition
186 |
187 | ParenCondition =
188 | LPAREN _ condition:Condition _ RPAREN {
189 | return assign({}, condition, { parentheses: true });
190 | }
191 | / ComparisonCondition
192 |
193 | ComparisonCondition =
194 | field:FieldExpr
195 | operator:(
196 | _ o:SpecialCharComparisonOperator _ { return o; }
197 | / __ o:ComparisonOperator __ { return o; }
198 | )
199 | value:ComparisonValue {
200 | return {
201 | type: 'ComparisonCondition',
202 | field: field,
203 | operator: operator,
204 | value: value,
205 | };
206 | }
207 |
208 | SpecialCharComparisonOperator =
209 | "=" / "!=" / "<=" / ">=" / "<" / ">"
210 |
211 | ComparisonOperator =
212 | "LIKE"i { return 'LIKE'; }
213 | / "IN"i { return 'IN'; }
214 | / "NOT"i __ "IN"i { return 'NOT IN'; }
215 | / "INCLUDES"i { return 'INCLUDES'; }
216 | / "EXCLUDES"i { return 'EXCLUDES'; }
217 |
218 | ComparisonValue =
219 | SubQuery
220 | / ListLiteral
221 | / Literal
222 | / BindVariable
223 |
224 | GroupByClause =
225 | GROUP __ BY __ ROLLUP _ LPAREN _ fields:GroupItemList _ RPAREN {
226 | return {
227 | type: 'RollupGrouping',
228 | fields: fields
229 | };
230 | }
231 | / GROUP __ BY __ CUBE _ LPAREN _ fields:GroupItemList _ RPAREN {
232 | return {
233 | type: 'CubeGrouping',
234 | fields: fields
235 | };
236 | }
237 | / GROUP __ BY __ fields:GroupItemList {
238 | return {
239 | type: 'Grouping',
240 | fields: fields,
241 | };
242 | }
243 |
244 | GroupItemList =
245 | head:GroupItem _ COMMA _ tail:GroupItemList {
246 | return [head].concat(tail);
247 | }
248 | / group:GroupItem {
249 | return [group];
250 | }
251 |
252 | GroupItem =
253 | FieldExpr
254 |
255 | OrderByClause =
256 | ORDER __ BY __ sort:SortItemList {
257 | return sort;
258 | }
259 |
260 | SortItemList =
261 | head:SortItem _ COMMA _ tail:SortItemList {
262 | return [head].concat(tail);
263 | }
264 | / sort:SortItem {
265 | return [sort];
266 | }
267 |
268 | SortItem =
269 | field:FieldExpr
270 | direction:(__ SortDir)?
271 | nullOrder:(__ NullOrder)? {
272 | return assign(
273 | { field: field },
274 | direction ? { direction: direction[1] } : {},
275 | nullOrder ? { nullOrder: nullOrder[1] } : {}
276 | );
277 | }
278 |
279 | SortDir =
280 | ASC { return 'ASC'; }
281 | / DESC { return 'DESC'; }
282 |
283 | NullOrder =
284 | NULLS __ FIRST { return 'FIRST'; }
285 | / NULLS __ LAST { return 'LAST'; }
286 |
287 | LimitClause =
288 | LIMIT __ value:LimitValue {
289 | return value;
290 | }
291 |
292 | LimitValue =
293 | NumberLiteral
294 | / BindVariable
295 |
296 | OffsetClause =
297 | OFFSET __ value:OffsetValue {
298 | return value;
299 | }
300 |
301 | OffsetValue =
302 | NumberLiteral
303 | / BindVariable
304 |
305 | SelectForClause =
306 | FOR __ VIEW { return 'VIEW'; }
307 | / FOR __ REFERENCE { return 'REFERENCE'; }
308 |
309 | SubQuery =
310 | LPAREN
311 | _ SELECT
312 | __ fields:SubQueryFieldList
313 | __ object:FromClause
314 | condition:(__ WhereClause)?
315 | sort:(__ OrderByClause)?
316 | limit:(__ LimitClause)?
317 | _ RPAREN {
318 | return assign(
319 | {
320 | type: 'Query',
321 | fields: fields,
322 | object: object,
323 | },
324 | condition ? { condition: condition[1] } : {},
325 | sort ? { sort: sort[1] } : {},
326 | limit ? { limit: limit[1] } : {}
327 | );
328 | }
329 |
330 | SubQueryFieldList =
331 | head:SubQueryFieldListItem _ COMMA _ tail:SubQueryFieldList {
332 | return [head].concat(tail);
333 | }
334 | / field:SubQueryFieldListItem {
335 | return [field]
336 | }
337 |
338 | SubQueryFieldListItem = FieldExpr
339 |
340 | Identifier =
341 | id:([a-zA-Z][0-9a-zA-Z_]* { return text() }) & { return !isReserved(id) } { return id; }
342 |
343 | // 'Group' and 'Order' are valid sobjects to query from,
344 | // as well as are part of the reserved keywords 'GROUP BY' and 'ORDER BY',
345 | // so we need this special identifier pattern for FromClause
346 | ObjectIdentifier =
347 | "GROUP"i { return text() }
348 | / "ORDER"i { return text() }
349 | / Identifier
350 |
351 | BindVariable =
352 | COLON identifier:Identifier {
353 | return {
354 | type: 'BindVariable',
355 | identifier: identifier,
356 | };
357 | }
358 |
359 | ListLiteral =
360 | LPAREN _ values:LiteralList _ RPAREN {
361 | return {
362 | type: 'list',
363 | values: values,
364 | };
365 | }
366 |
367 | LiteralList =
368 | head:Literal _ COMMA _ tail:LiteralList {
369 | return [head].concat(tail);
370 | }
371 | / Literal
372 |
373 | Literal =
374 | StringLiteral
375 | / ISODateLiteral
376 | / DateLiteral
377 | / NumberLiteral
378 | / BooleanLiteral
379 | / NullLiteral
380 |
381 | NumberLiteral =
382 | n:Number {
383 | return {
384 | type: 'number',
385 | value: n
386 | }
387 | }
388 |
389 | Number =
390 | int_:Int frac:Frac { return parseFloat(int_ + frac); }
391 | / int_:Int { return parseFloat(int_); }
392 |
393 | Int
394 | = digit19:Digit19 digits:Digits { return digit19 + digits; }
395 | / digit:Digit
396 | / op:[+-] digits:Digits { return op + digit19 + digits; }
397 | / op:[+-] digit:Digit { return op + digit; }
398 |
399 | Frac
400 | = "." digits:Digits { return "." + digits; }
401 |
402 | Digits
403 | = digits:Digit+ { return digits.join(""); }
404 |
405 | Integer2
406 | = $(Digit Digit)
407 |
408 | Integer4
409 | = $(Digit Digit Digit Digit)
410 |
411 | Digit = [0-9]
412 | Digit19 = [1-9]
413 |
414 | HexDigit
415 | = [0-9a-fA-F]
416 |
417 | StringLiteral =
418 | QUOTE ca:(SingleChar*) QUOTE {
419 | return {
420 | type: 'string',
421 | value: ca.join('')
422 | };
423 | }
424 |
425 |
426 | SingleChar =
427 | [^'\\\0-\x1F\x7f]
428 | / EscapeChar
429 |
430 | EscapeChar =
431 | "\\'" { return "'"; }
432 | / '\\"' { return '"'; }
433 | / "\\\\" { return "\\"; }
434 | / "\\/" { return "/"; }
435 | / "\\b" { return "\b"; }
436 | / "\\f" { return "\f"; }
437 | / "\\n" { return "\n"; }
438 | / "\\r" { return "\r"; }
439 | / "\\t" { return "\t"; }
440 | / "\\u" h1:HexDigit h2:HexDigit h3:HexDigit h4:HexDigit {
441 | return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4));
442 | }
443 |
444 | ISODate
445 | = Integer4 "-" Integer2 "-" Integer2
446 |
447 | ISOTZ
448 | = "Z"
449 | / $(("+" / "-") Integer2 ":" Integer2 )
450 | / $(("+" / "-") Integer4 )
451 |
452 | DateFormatLiteral =
453 | Integer4 "-" Integer2 "-" Integer2 {
454 | return {
455 | type: 'date',
456 | value: text()
457 | };
458 | }
459 |
460 | ISOTime
461 | = $(Integer2 ":" Integer2 ":" Integer2)
462 |
463 | ISODateLiteral
464 | = d:ISODate t:$("T" ISOTime)? z:$ISOTZ? {
465 | return {
466 | type: t || z ? 'datetime' : 'date',
467 | value: text()
468 | }
469 | }
470 |
471 | DateLiteral =
472 | d:TODAY {
473 | return {
474 | type: 'dateLiteral',
475 | value: text()
476 | }
477 | }
478 | / d:YESTERDAY {
479 | return {
480 | type: 'dateLiteral',
481 | value: text()
482 | }
483 | }
484 | / d:TOMORROW {
485 | return {
486 | type: 'dateLiteral',
487 | value: text()
488 | }
489 | }
490 | / d:LAST_WEEK {
491 | return {
492 | type: 'dateLiteral',
493 | value: text()
494 | }
495 | }
496 | / d:THIS_WEEK {
497 | return {
498 | type: 'dateLiteral',
499 | value: text()
500 | }
501 | }
502 | / d:NEXT_WEEK {
503 | return {
504 | type: 'dateLiteral',
505 | value: text()
506 | }
507 | }
508 | / d:LAST_MONTH {
509 | return {
510 | type: 'dateLiteral',
511 | value: text()
512 | }
513 | }
514 | / d:THIS_MONTH {
515 | return {
516 | type: 'dateLiteral',
517 | value: text()
518 | }
519 | }
520 | / d:NEXT_MONTH {
521 | return {
522 | type: 'dateLiteral',
523 | value: text()
524 | }
525 | }
526 | / d:LAST_90_DAYS {
527 | return {
528 | type: 'dateLiteral',
529 | value: text()
530 | }
531 | }
532 | / d:NEXT_90_DAYS {
533 | return {
534 | type: 'dateLiteral',
535 | value: text()
536 | }
537 | }
538 | / d:THIS_QUARTER {
539 | return {
540 | type: 'dateLiteral',
541 | value: text()
542 | }
543 | }
544 | / d:LAST_QUARTER {
545 | return {
546 | type: 'dateLiteral',
547 | value: text()
548 | }
549 | }
550 | / d:NEXT_QUARTER {
551 | return {
552 | type: 'dateLiteral',
553 | value: text()
554 | }
555 | }
556 | / d:THIS_YEAR {
557 | return {
558 | type: 'dateLiteral',
559 | value: text()
560 | }
561 | }
562 | / d:LAST_YEAR {
563 | return {
564 | type: 'dateLiteral',
565 | value: text()
566 | }
567 | }
568 | / d:NEXT_YEAR {
569 | return {
570 | type: 'dateLiteral',
571 | value: text()
572 | }
573 | }
574 | / d:THIS_FISCAL_QUARTER {
575 | return {
576 | type: 'dateLiteral',
577 | value: text()
578 | }
579 | }
580 | / d:LAST_FISCAL_QUARTER {
581 | return {
582 | type: 'dateLiteral',
583 | value: text()
584 | }
585 | }
586 | / d:NEXT_FISCAL_QUARTER {
587 | return {
588 | type: 'dateLiteral',
589 | value: text()
590 | }
591 | }
592 | / d:THIS_FISCAL_YEAR {
593 | return {
594 | type: 'dateLiteral',
595 | value: text()
596 | }
597 | }
598 | / d:LAST_FISCAL_YEAR {
599 | return {
600 | type: 'dateLiteral',
601 | value: text()
602 | }
603 | }
604 | / d:NEXT_FISCAL_YEAR {
605 | return {
606 | type: 'dateLiteral',
607 | value: text()
608 | }
609 | }
610 | / d:LAST_N_DAYS c:_":"_ n:$(Digit+) {
611 | return {
612 | type: 'dateLiteral',
613 | value: d,
614 | argument: parseInt(n)
615 | }
616 | }
617 | / d:NEXT_N_DAYS c:_":"_ n:$(Digit+) {
618 | return {
619 | type: 'dateLiteral',
620 | value: d,
621 | argument: parseInt(n)
622 | }
623 | }
624 | / d:NEXT_N_WEEKS c:_":"_ n:$(Digit+) {
625 | return {
626 | type: 'dateLiteral',
627 | value: d,
628 | argument: parseInt(n)
629 | }
630 | }
631 | / d:LAST_N_WEEKS c:_":"_ n:$(Digit+) {
632 | return {
633 | type: 'dateLiteral',
634 | value: d,
635 | argument: parseInt(n)
636 | }
637 | }
638 | / d:NEXT_N_MONTHS c:_":"_ n:$(Digit+) {
639 | return {
640 | type: 'dateLiteral',
641 | value: d,
642 | argument: parseInt(n)
643 | }
644 | }
645 | / d:LAST_N_MONTHS c:_":"_ n:$(Digit+) {
646 | return {
647 | type: 'dateLiteral',
648 | value: d,
649 | argument: parseInt(n)
650 | }
651 | }
652 | / d:NEXT_N_QUARTERS c:_":"_ n:$(Digit+) {
653 | return {
654 | type: 'dateLiteral',
655 | value: d,
656 | argument: parseInt(n)
657 | }
658 | }
659 | / d:LAST_N_QUARTERS c:_":"_ n:$(Digit+) {
660 | return {
661 | type: 'dateLiteral',
662 | value: d,
663 | argument: parseInt(n)
664 | }
665 | }
666 | / d:NEXT_N_YEARS c:_":"_ n:$(Digit+) {
667 | return {
668 | type: 'dateLiteral',
669 | value: d,
670 | argument: parseInt(n)
671 | }
672 | }
673 | / d:LAST_N_YEARS c:_":"_ n:$(Digit+) {
674 | return {
675 | type: 'dateLiteral',
676 | value: d,
677 | argument: parseInt(n)
678 | }
679 | }
680 | / d:NEXT_N_FISCAL_QUARTERS c:_":"_ n:$(Digit+) {
681 | return {
682 | type: 'dateLiteral',
683 | value: d,
684 | argument: parseInt(n)
685 | }
686 | }
687 | / d:LAST_N_FISCAL_QUARTERS c:_":"_ n:$(Digit+) {
688 | return {
689 | type: 'dateLiteral',
690 | value: d,
691 | argument: parseInt(n)
692 | }
693 | }
694 | / d:NEXT_N_FISCAL_YEARS c:_":"_ n:$(Digit+) {
695 | return {
696 | type: 'dateLiteral',
697 | value: d,
698 | argument: parseInt(n)
699 | }
700 | }
701 | / d:LAST_N_FISCAL_YEARS c:_":"_ n:$(Digit+) {
702 | return {
703 | type: 'dateLiteral',
704 | value: d,
705 | argument: parseInt(n)
706 | }
707 | }
708 |
709 | BooleanLiteral =
710 | TRUE {
711 | return {
712 | type: 'boolean',
713 | value: true
714 | };
715 | }
716 | / FALSE {
717 | return {
718 | type: 'boolean',
719 | value: false
720 | };
721 | }
722 |
723 | NullLiteral =
724 | NULL {
725 | return {
726 | type: 'null',
727 | value: null
728 | };
729 | }
730 |
731 | COMMA = ","
732 | DOT = "."
733 | LPAREN = "("
734 | RPAREN = ")"
735 | QUOTE = "'"
736 | COLON = ":"
737 |
738 | _ "spacer" =
739 | [ \t\n\r]*
740 |
741 | __ "whitespaces" =
742 | [ \t\n\r]+
743 |
744 |
745 | // Keywords
746 |
747 | SELECT = "SELECT"i
748 | FROM = "FROM"i
749 | AS = "AS"i
750 | USING = "USING"i
751 | SCOPE = "SCOPE"i
752 | WHERE = "WHERE"i
753 | OR = "OR"i
754 | AND = "AND"i
755 | NOT = "NOT"i
756 | GROUP = "GROUP"i
757 | BY = "BY"i
758 | ROLLUP = "ROLLUP"i
759 | CUBE = "CUBE"i
760 | ORDER = "ORDER"i
761 | ASC = "ASC"i
762 | DESC = "DESC"i
763 | NULLS = "NULLS"i
764 | FIRST = "FIRST"i
765 | LAST = "LAST"i
766 | LIMIT = "LIMIT"i
767 | OFFSET = "OFFSET"i
768 | FOR = "FOR"i
769 | VIEW = "VIEW"i
770 | REFERENCE = "REFERENCE"i
771 | TRUE = "TRUE"i
772 | FALSE = "FALSE"i
773 | NULL = "NULL"i
774 |
775 | // Date Literals
776 |
777 | YESTERDAY = "YESTERDAY"i
778 | TODAY = "TODAY"i
779 | TOMORROW = "TOMORROW"i
780 | LAST_WEEK = "LAST_WEEK"i
781 | THIS_WEEK = "THIS_WEEK"i
782 | NEXT_WEEK = "NEXT_WEEK"i
783 | LAST_MONTH = "LAST_MONTH"i
784 | THIS_MONTH = "THIS_MONTH"i
785 | NEXT_MONTH = "NEXT_MONTH"i
786 | LAST_90_DAYS = "LAST_90_DAYS"i
787 | NEXT_90_DAYS = "NEXT_90_DAYS"i
788 | THIS_QUARTER = "THIS_QUARTER"i
789 | LAST_QUARTER = "LAST_QUARTER"i
790 | NEXT_QUARTER = "NEXT_QUARTER"i
791 | THIS_YEAR = "THIS_YEAR"i
792 | LAST_YEAR = "LAST_YEAR"i
793 | NEXT_YEAR = "NEXT_YEAR"i
794 | THIS_FISCAL_QUARTER = "THIS_FISCAL_QUARTER"i
795 | LAST_FISCAL_QUARTER = "LAST_FISCAL_QUARTER"i
796 | NEXT_FISCAL_QUARTER = "NEXT_FISCAL_QUARTER"i
797 | THIS_FISCAL_YEAR = "THIS_FISCAL_YEAR"i
798 | LAST_FISCAL_YEAR = "LAST_FISCAL_YEAR"i
799 | NEXT_FISCAL_YEAR = "NEXT_FISCAL_YEAR"i
800 | LAST_N_DAYS = "LAST_N_DAYS"i
801 | NEXT_N_DAYS = "NEXT_N_DAYS"i
802 | NEXT_N_WEEKS = "NEXT_N_WEEKS"i
803 | LAST_N_WEEKS = "LAST_N_WEEKS"i
804 | NEXT_N_MONTHS = "NEXT_N_MONTHS"i
805 | LAST_N_MONTHS = "LAST_N_MONTHS"i
806 | NEXT_N_QUARTERS = "NEXT_N_QUARTERS"i
807 | LAST_N_QUARTERS = "LAST_N_QUARTERS"i
808 | NEXT_N_YEARS = "NEXT_N_YEARS"i
809 | LAST_N_YEARS = "LAST_N_YEARS"i
810 | NEXT_N_FISCAL_QUARTERS = "NEXT_N_FISCAL_QUARTERS"i
811 | LAST_N_FISCAL_QUARTERS = "LAST_N_FISCAL_QUARTERS"i
812 | NEXT_N_FISCAL_YEARS = "NEXT_N_FISCAL_YEARS"i
813 | LAST_N_FISCAL_YEARS = "LAST_N_FISCAL_YEARS"i
--------------------------------------------------------------------------------
/test/data/expected/00-simple-01.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Name'],
6 | }],
7 | object: {
8 | type: 'ObjectReference',
9 | name: 'Account',
10 | },
11 | }
12 |
--------------------------------------------------------------------------------
/test/data/expected/01-simple-02.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Name'],
6 | }],
7 | object: {
8 | type: 'ObjectReference',
9 | name: 'Account',
10 | },
11 | }
12 |
--------------------------------------------------------------------------------
/test/data/expected/02-select-clause-01.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }, {
10 | type: 'FieldReference',
11 | path: ['Owner', 'Name'],
12 | }],
13 | object: {
14 | type: 'ObjectReference',
15 | name: 'Account',
16 | },
17 | }
18 |
--------------------------------------------------------------------------------
/test/data/expected/03-select-clause-02.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }, {
10 | type: 'FunctionCall',
11 | name: 'toLabel',
12 | arguments: [{
13 | type: 'FieldReference',
14 | path: ['Account', 'Type'],
15 | }],
16 | }, {
17 | type: 'FunctionCall',
18 | name: 'convertCurrency',
19 | arguments: [{
20 | type: 'FieldReference',
21 | path: ['Amount'],
22 | }],
23 | }],
24 | object: {
25 | type: 'ObjectReference',
26 | name: 'Opportunity',
27 | },
28 | }
29 |
--------------------------------------------------------------------------------
/test/data/expected/04-select-clause-03.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }, {
10 | type: 'Query',
11 | fields: [{
12 | type: 'FieldReference',
13 | path: ['Id'],
14 | }, {
15 | type: 'FieldReference',
16 | path: ['Name'],
17 | }],
18 | object: {
19 | type: 'ObjectReference',
20 | name: 'Contacts',
21 | },
22 | }],
23 | object: {
24 | type: 'ObjectReference',
25 | name: 'Account',
26 | },
27 | }
28 |
--------------------------------------------------------------------------------
/test/data/expected/05-from-object-with-alias-01.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }, {
10 | type: 'FieldReference',
11 | path: ['Amount'],
12 | }, {
13 | type: 'FieldReference',
14 | path: ['a', 'Id'],
15 | }, {
16 | type: 'FieldReference',
17 | path: ['a', 'Name'],
18 | }],
19 | object: {
20 | type: 'ObjectReference',
21 | name: 'Opportunity',
22 | aliasObjects: [{
23 | type: 'AliasObjectReference',
24 | path: ['Opportunity', 'Account'],
25 | alias: 'a'
26 | }],
27 | },
28 | }
29 |
--------------------------------------------------------------------------------
/test/data/expected/06-from-object-with-alias-02.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['o', 'Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['o', 'Name'],
9 | }, {
10 | type: 'FieldReference',
11 | path: ['o', 'Amount'],
12 | }, {
13 | type: 'FieldReference',
14 | path: ['a', 'Id'],
15 | }, {
16 | type: 'FieldReference',
17 | path: ['a', 'Name'],
18 | }, {
19 | type: 'FieldReference',
20 | path: ['u', 'Username'],
21 | }],
22 | object: {
23 | type: 'ObjectReference',
24 | name: 'Opportunity',
25 | alias: 'o',
26 | aliasObjects: [{
27 | type: 'AliasObjectReference',
28 | path: ['o', 'Account'],
29 | alias: 'a'
30 | }, {
31 | type: 'AliasObjectReference',
32 | path: ['a', 'Owner'],
33 | alias: 'u'
34 | }],
35 | },
36 | }
37 |
--------------------------------------------------------------------------------
/test/data/expected/07-from-object-group-03.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Name'],
6 | }, {
7 | type: 'FunctionCall',
8 | name: 'COUNT',
9 | arguments: [{
10 | type: 'FieldReference',
11 | path: ['Id'],
12 | }],
13 | alias: 'c'
14 | }],
15 | object: {
16 | type: 'ObjectReference',
17 | name: 'Group',
18 | },
19 | condition: {
20 | type: 'ComparisonCondition',
21 | operator: '=',
22 | field: {
23 | type: 'FieldReference',
24 | path: ['Type'],
25 | },
26 | value: {
27 | type: 'string',
28 | value: 'Queue',
29 | },
30 | },
31 | group: {
32 | type: 'Grouping',
33 | fields: [{
34 | type: 'FieldReference',
35 | path: ['Name'],
36 | }],
37 | },
38 | sort: [{
39 | field: {
40 | type: 'FieldReference',
41 | path: ['Name'],
42 | },
43 | direction: 'ASC',
44 | }],
45 | }
--------------------------------------------------------------------------------
/test/data/expected/08-from-object-order-04.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Name'],
6 | }, {
7 | type: 'FunctionCall',
8 | name: 'COUNT',
9 | arguments: [{
10 | type: 'FieldReference',
11 | path: ['Id'],
12 | }],
13 | alias: 'c'
14 | }],
15 | object: {
16 | type: 'ObjectReference',
17 | name: 'Order',
18 | },
19 | condition: {
20 | type: 'ComparisonCondition',
21 | operator: '=',
22 | field: {
23 | type: 'FieldReference',
24 | path: ['Type'],
25 | },
26 | value: {
27 | type: 'string',
28 | value: 'Standard',
29 | },
30 | },
31 | group: {
32 | type: 'Grouping',
33 | fields: [{
34 | type: 'FieldReference',
35 | path: ['Name'],
36 | }],
37 | },
38 | sort: [{
39 | field: {
40 | type: 'FieldReference',
41 | path: ['Name'],
42 | },
43 | direction: 'ASC',
44 | }],
45 | }
--------------------------------------------------------------------------------
/test/data/expected/10-where-clause-01.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }],
10 | object: {
11 | type: 'ObjectReference',
12 | name: 'Account',
13 | },
14 | condition: {
15 | type: 'ComparisonCondition',
16 | operator: '=',
17 | field: {
18 | type: 'FieldReference',
19 | path: ['Name'],
20 | },
21 | value: {
22 | type: 'string',
23 | value: 'Apple',
24 | },
25 | },
26 | }
27 |
--------------------------------------------------------------------------------
/test/data/expected/11-where-clause-02.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }],
10 | object: {
11 | type: 'ObjectReference',
12 | name: 'Account',
13 | },
14 | condition: {
15 | type: 'LogicalCondition',
16 | operator: 'AND',
17 | left: {
18 | type: 'ComparisonCondition',
19 | operator: '=',
20 | field: {
21 | type: 'FieldReference',
22 | path: ['Name'],
23 | },
24 | value: {
25 | type: 'string',
26 | value: 'Apple',
27 | },
28 | },
29 | right: {
30 | type: 'ComparisonCondition',
31 | operator: '=',
32 | field: {
33 | type: 'FieldReference',
34 | path: ['Owner', 'Active'],
35 | },
36 | value: {
37 | type: 'boolean',
38 | value: true,
39 | },
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/test/data/expected/12-where-clause-03.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }],
10 | object: {
11 | type: 'ObjectReference',
12 | name: 'Account',
13 | },
14 | condition: {
15 | type: 'LogicalCondition',
16 | operator: 'OR',
17 | left: {
18 | type: 'ComparisonCondition',
19 | operator: 'LIKE',
20 | field: {
21 | type: 'FieldReference',
22 | path: ['Name'],
23 | },
24 | value: {
25 | type: 'string',
26 | value: 'A%',
27 | },
28 | },
29 | right: {
30 | type: 'LogicalCondition',
31 | operator: 'AND',
32 | left: {
33 | type: 'ComparisonCondition',
34 | operator: '=',
35 | field: {
36 | type: 'FieldReference',
37 | path: ['Type'],
38 | },
39 | value: {
40 | type: 'string',
41 | value: 'Partner',
42 | },
43 | },
44 | right: {
45 | type: 'ComparisonCondition',
46 | operator: '!=',
47 | field: {
48 | type: 'FieldReference',
49 | path: ['Owner', 'Username'],
50 | },
51 | value: {
52 | type: 'string',
53 | value: 'user01@example.com',
54 | },
55 | },
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/test/data/expected/13-where-clause-04.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }],
10 | object: {
11 | type: 'ObjectReference',
12 | name: 'Account',
13 | },
14 | condition: {
15 | type: 'LogicalCondition',
16 | operator: 'AND',
17 | left: {
18 | type: 'LogicalCondition',
19 | operator: 'OR',
20 | left: {
21 | type: 'ComparisonCondition',
22 | operator: 'LIKE',
23 | field: {
24 | type: 'FieldReference',
25 | path: ['Name'],
26 | },
27 | value: {
28 | type: 'string',
29 | value: 'A%',
30 | },
31 | },
32 | right: {
33 | type: 'ComparisonCondition',
34 | operator: '=',
35 | field: {
36 | type: 'FieldReference',
37 | path: ['Type'],
38 | },
39 | value: {
40 | type: 'string',
41 | value: 'Partner',
42 | },
43 | },
44 | parentheses: true,
45 | },
46 | right: {
47 | type: 'ComparisonCondition',
48 | operator: '!=',
49 | field: {
50 | type: 'FieldReference',
51 | path: ['Owner', 'Username'],
52 | },
53 | value: {
54 | type: 'string',
55 | value: 'user01@example.com',
56 | },
57 | },
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/test/data/expected/14-where-clause-05.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }],
10 | object: {
11 | type: 'ObjectReference',
12 | name: 'Account',
13 | },
14 | condition: {
15 | type: 'LogicalCondition',
16 | operator: 'OR',
17 | left: {
18 | type: 'ComparisonCondition',
19 | operator: 'IN',
20 | field: {
21 | type: 'FieldReference',
22 | path: ['Type'],
23 | },
24 | value: {
25 | type: 'list',
26 | values: [{
27 | type: 'string',
28 | value: 'Partner',
29 | }, {
30 | type: 'string',
31 | value: 'Customer',
32 | }],
33 | },
34 | },
35 | right: {
36 | type: 'LogicalCondition',
37 | operator: 'AND',
38 | left: {
39 | type: 'ComparisonCondition',
40 | operator: 'IN',
41 | field: {
42 | type: 'FunctionCall',
43 | name: 'CALENDAR_YEAR',
44 | arguments: [{
45 | type: 'FieldReference',
46 | path: ['CreatedDate'],
47 | }],
48 | },
49 | value: {
50 | type: 'list',
51 | values: [{
52 | type: 'number',
53 | value: 2016,
54 | }, {
55 | type: 'number',
56 | value: 2017,
57 | }],
58 | },
59 | },
60 | right: {
61 | type: 'ComparisonCondition',
62 | operator: 'NOT IN',
63 | field: {
64 | type: 'FunctionCall',
65 | name: 'CALENDAR_MONTH',
66 | arguments: [{
67 | type: 'FieldReference',
68 | path: ['CreatedDate'],
69 | }],
70 | },
71 | value: {
72 | type: 'list',
73 | values: [{
74 | type: 'number',
75 | value: 2,
76 | }, {
77 | type: 'number',
78 | value: 4,
79 | }, {
80 | type: 'number',
81 | value: 6,
82 | }, {
83 | type: 'number',
84 | value: 9,
85 | }, {
86 | type: 'number',
87 | value: 11,
88 | }],
89 | },
90 | },
91 | parentheses: true,
92 | },
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/test/data/expected/15-where-clause-06.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['SomeNumberField__c'],
9 | }],
10 | object: {
11 | type: 'ObjectReference',
12 | name: 'Account',
13 | },
14 | condition: {
15 | type: 'ComparisonCondition',
16 | operator: '<=',
17 | field: {
18 | type: 'FieldReference',
19 | path: ['SomeNumberField__c'],
20 | },
21 | value: {
22 | type: 'number',
23 | value: 10,
24 | },
25 | },
26 | }
27 |
--------------------------------------------------------------------------------
/test/data/expected/16-where-clause-07.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [
4 | {
5 | type: 'FieldReference',
6 | path: ['Id']
7 | },
8 | {
9 | type: 'FieldReference',
10 | path: ['SomeNumberField__c']
11 | }
12 | ],
13 | object: {
14 | type: 'ObjectReference',
15 | name: 'Account'
16 | },
17 | condition: {
18 | type: 'LogicalCondition',
19 | operator: 'OR',
20 | left: {
21 | type: 'LogicalCondition',
22 | operator: 'OR',
23 | left: {
24 | type: 'LogicalCondition',
25 | operator: 'OR',
26 | left: {
27 | type: 'LogicalCondition',
28 | operator: 'OR',
29 | left: {
30 | type: 'ComparisonCondition',
31 | field: {
32 | type: 'FieldReference',
33 | path: ['CreatedDate']
34 | },
35 | operator: '<',
36 | value: {
37 | type: 'datetime',
38 | value: '1999-01-01T23:01:01+01:00'
39 | }
40 | },
41 | right: {
42 | type: 'ComparisonCondition',
43 | field: {
44 | type: 'FieldReference',
45 | path: ['CreatedDate']
46 | },
47 | operator: '<=',
48 | value: {
49 | type: 'datetime',
50 | value: '1999-01-01T23:01:01-08:00'
51 | }
52 | }
53 | },
54 | right: {
55 | type: 'ComparisonCondition',
56 | field: {
57 | type: 'FieldReference',
58 | path: ['CreatedDate']
59 | },
60 | operator: '>=',
61 | value: {
62 | type: 'datetime',
63 | value: '1999-01-01T23:01:01Z'
64 | }
65 | }
66 | },
67 | right: {
68 | type: 'ComparisonCondition',
69 | field: {
70 | type: 'FieldReference',
71 | path: ['CreatedDate']
72 | },
73 | operator: '<=',
74 | value: {
75 | type: 'date',
76 | value: '1999-01-01'
77 | }
78 | }
79 | },
80 | right: {
81 | type: 'ComparisonCondition',
82 | field: {
83 | type: 'FieldReference',
84 | path: ['CreatedDate']
85 | },
86 | operator: '=',
87 | value: {
88 | type: 'datetime',
89 | value: '1999-01-01T23:01:01+01:00'
90 | }
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/test/data/expected/20-order-by-clause-01.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }],
10 | object: {
11 | type: 'ObjectReference',
12 | name: 'Account',
13 | },
14 | sort: [{
15 | field: {
16 | type: 'FieldReference',
17 | path: ['CreatedDate'],
18 | },
19 | }],
20 | }
21 |
--------------------------------------------------------------------------------
/test/data/expected/21-order-by-clause-02.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }],
10 | object: {
11 | type: 'ObjectReference',
12 | name: 'Account',
13 | },
14 | sort: [{
15 | field: {
16 | type: 'FieldReference',
17 | path: ['Type'],
18 | },
19 | direction: 'ASC',
20 | nullOrder: 'LAST',
21 | }, {
22 | field: {
23 | type: 'FieldReference',
24 | path: ['CreatedDate'],
25 | },
26 | direction: 'DESC',
27 | }],
28 | }
29 |
--------------------------------------------------------------------------------
/test/data/expected/30-group-by-clause-01.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FunctionCall',
5 | name: 'count',
6 | arguments: [{
7 | type: 'FieldReference',
8 | path: ['Id'],
9 | }],
10 | }, {
11 | type: 'FieldReference',
12 | path: ['Type'],
13 | }],
14 | object: {
15 | type: 'ObjectReference',
16 | name: 'Account',
17 | },
18 | group: {
19 | type: 'Grouping',
20 | fields: [{
21 | type: 'FieldReference',
22 | path: ['Type'],
23 | }],
24 | },
25 | }
26 |
--------------------------------------------------------------------------------
/test/data/expected/31-group-by-clause-02.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FunctionCall',
5 | name: 'count',
6 | arguments: [{
7 | type: 'FieldReference',
8 | path: ['Id'],
9 | }],
10 | alias: 'Cnt',
11 | }, {
12 | type: 'FieldReference',
13 | path: ['Type'],
14 | }, {
15 | type: 'FunctionCall',
16 | name: 'CALENDAR_YEAR',
17 | arguments: [{
18 | type: 'FieldReference',
19 | path: ['CreatedDate'],
20 | }],
21 | alias: 'Year',
22 | }],
23 | object: {
24 | type: 'ObjectReference',
25 | name: 'Account',
26 | },
27 | group: {
28 | type: 'Grouping',
29 | fields: [{
30 | type: 'FieldReference',
31 | path: ['Type'],
32 | }, {
33 | type: 'FunctionCall',
34 | name: 'CALENDAR_YEAR',
35 | arguments: [{
36 | type: 'FieldReference',
37 | path: ['CreatedDate'],
38 | }],
39 | }],
40 | },
41 | }
42 |
--------------------------------------------------------------------------------
/test/data/expected/32-group-by-clause-03.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FunctionCall',
5 | name: 'count',
6 | arguments: [{
7 | type: 'FieldReference',
8 | path: ['Id'],
9 | }],
10 | alias: 'Cnt',
11 | }, {
12 | type: 'FieldReference',
13 | path: ['Type'],
14 | }, {
15 | type: 'FunctionCall',
16 | name: 'CALENDAR_YEAR',
17 | arguments: [{
18 | type: 'FieldReference',
19 | path: ['CreatedDate'],
20 | }],
21 | alias: 'Year',
22 | }],
23 | object: {
24 | type: 'ObjectReference',
25 | name: 'Account',
26 | },
27 | group: {
28 | type: 'Grouping',
29 | fields: [{
30 | type: 'FieldReference',
31 | path: ['Type'],
32 | }, {
33 | type: 'FunctionCall',
34 | name: 'CALENDAR_YEAR',
35 | arguments: [{
36 | type: 'FieldReference',
37 | path: ['CreatedDate'],
38 | }],
39 | }],
40 | },
41 | sort: [{
42 | field: {
43 | type: 'FieldReference',
44 | path: ['Type'],
45 | },
46 | }, {
47 | field: {
48 | type: 'FunctionCall',
49 | name: 'count',
50 | arguments: [{
51 | type: 'FieldReference',
52 | path: ['Id'],
53 | }],
54 | },
55 | direction: 'ASC',
56 | }],
57 | }
58 |
--------------------------------------------------------------------------------
/test/data/expected/40-date-literal-01.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }, {
10 | type: 'FieldReference',
11 | path: ['CreatedDate'],
12 | }],
13 | object: {
14 | type: 'ObjectReference',
15 | name: 'Account',
16 | },
17 | condition: {
18 | type: 'ComparisonCondition',
19 | operator: '=',
20 | field: {
21 | type: 'FieldReference',
22 | path: ['CreatedDate'],
23 | },
24 | value: {
25 | type: 'dateLiteral',
26 | value: 'TODAY',
27 | },
28 | },
29 | }
30 |
--------------------------------------------------------------------------------
/test/data/expected/41-date-literal-02.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }, {
10 | type: 'FieldReference',
11 | path: ['CreatedDate'],
12 | }],
13 | object: {
14 | type: 'ObjectReference',
15 | name: 'Account',
16 | },
17 | condition: {
18 | type: 'ComparisonCondition',
19 | operator: '>=',
20 | field: {
21 | type: 'FieldReference',
22 | path: ['CreatedDate'],
23 | },
24 | value: {
25 | type: 'dateLiteral',
26 | value: 'LAST_N_DAYS',
27 | argument: 1,
28 | },
29 | },
30 | }
31 |
--------------------------------------------------------------------------------
/test/data/expected/41-date-literal-03.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [
4 | {
5 | type: 'FieldReference',
6 | path: ['Id']
7 | },
8 | {
9 | type: 'FieldReference',
10 | path: ['SomeNumberField__c']
11 | }
12 | ],
13 | object: {
14 | type: 'ObjectReference',
15 | name: 'Account'
16 | },
17 | condition: {
18 | type: 'LogicalCondition',
19 | operator: 'OR',
20 | left: {
21 | type: 'LogicalCondition',
22 | operator: 'OR',
23 | left: {
24 | type: 'LogicalCondition',
25 | operator: 'OR',
26 | left: {
27 | type: 'LogicalCondition',
28 | operator: 'OR',
29 | left: {
30 | type: 'LogicalCondition',
31 | operator: 'OR',
32 | left: {
33 | type: 'LogicalCondition',
34 | operator: 'OR',
35 | left: {
36 | type: 'LogicalCondition',
37 | operator: 'OR',
38 | left: {
39 | type: 'LogicalCondition',
40 | operator: 'OR',
41 | left: {
42 | type: 'LogicalCondition',
43 | operator: 'OR',
44 | left: {
45 | type: 'LogicalCondition',
46 | operator: 'OR',
47 | left: {
48 | type: 'LogicalCondition',
49 | operator: 'OR',
50 | left: {
51 | type: 'LogicalCondition',
52 | operator: 'OR',
53 | left: {
54 | type: 'LogicalCondition',
55 | operator: 'OR',
56 | left: {
57 | type: 'LogicalCondition',
58 | operator: 'OR',
59 | left: {
60 | type: 'LogicalCondition',
61 | operator: 'OR',
62 | left: {
63 | type: 'LogicalCondition',
64 | operator: 'OR',
65 | left: {
66 | type: 'LogicalCondition',
67 | operator: 'OR',
68 | left: {
69 | type: 'LogicalCondition',
70 | operator: 'OR',
71 | left: {
72 | type: 'LogicalCondition',
73 | operator: 'OR',
74 | left: {
75 | type: 'LogicalCondition',
76 | operator: 'OR',
77 | left: {
78 | type: 'LogicalCondition',
79 | operator: 'OR',
80 | left: {
81 | type: 'LogicalCondition',
82 | operator: 'OR',
83 | left: {
84 | type: 'LogicalCondition',
85 | operator: 'OR',
86 | left: {
87 | type: 'LogicalCondition',
88 | operator: 'OR',
89 | left: {
90 | type: 'LogicalCondition',
91 | operator: 'OR',
92 | left: {
93 | type: 'LogicalCondition',
94 | operator: 'OR',
95 | left: {
96 | type: 'LogicalCondition',
97 | operator: 'OR',
98 | left: {
99 | type: 'LogicalCondition',
100 | operator: 'OR',
101 | left: {
102 | type: 'LogicalCondition',
103 | operator: 'OR',
104 | left: {
105 | type: 'LogicalCondition',
106 | operator: 'OR',
107 | left: {
108 | type: 'LogicalCondition',
109 | operator: 'OR',
110 | left: {
111 | type: 'LogicalCondition',
112 | operator: 'OR',
113 | left: {
114 | type: 'LogicalCondition',
115 | operator: 'OR',
116 | left: {
117 | type: 'LogicalCondition',
118 | operator: 'OR',
119 | left: {
120 | type: 'LogicalCondition',
121 | operator: 'OR',
122 | left: {
123 | type: 'LogicalCondition',
124 | operator: 'OR',
125 | left: {
126 | type: 'ComparisonCondition',
127 | field: {
128 | type: 'FieldReference',
129 | path: ['CreadedDate']
130 | },
131 | operator: '=',
132 | value: {
133 | type: 'dateLiteral',
134 | value: 'YESTERDAY'
135 | }
136 | },
137 | right: {
138 | type: 'ComparisonCondition',
139 | field: {
140 | type: 'FieldReference',
141 | path: ['CreadedDate']
142 | },
143 | operator: '=',
144 | value: {
145 | type: 'dateLiteral',
146 | value: 'TODAY'
147 | }
148 | }
149 | },
150 | right: {
151 | type: 'ComparisonCondition',
152 | field: {
153 | type: 'FieldReference',
154 | path: ['CreadedDate']
155 | },
156 | operator: '=',
157 | value: {
158 | type: 'dateLiteral',
159 | value: 'TOMORROW'
160 | }
161 | }
162 | },
163 | right: {
164 | type: 'ComparisonCondition',
165 | field: {
166 | type: 'FieldReference',
167 | path: ['CreadedDate']
168 | },
169 | operator: '=',
170 | value: {
171 | type: 'dateLiteral',
172 | value: 'LAST_WEEK'
173 | }
174 | }
175 | },
176 | right: {
177 | type: 'ComparisonCondition',
178 | field: {
179 | type: 'FieldReference',
180 | path: ['CreadedDate']
181 | },
182 | operator: '=',
183 | value: {
184 | type: 'dateLiteral',
185 | value: 'THIS_WEEK'
186 | }
187 | }
188 | },
189 | right: {
190 | type: 'ComparisonCondition',
191 | field: {
192 | type: 'FieldReference',
193 | path: ['CreadedDate']
194 | },
195 | operator: '=',
196 | value: {
197 | type: 'dateLiteral',
198 | value: 'NEXT_WEEK'
199 | }
200 | }
201 | },
202 | right: {
203 | type: 'ComparisonCondition',
204 | field: {
205 | type: 'FieldReference',
206 | path: ['CreadedDate']
207 | },
208 | operator: '=',
209 | value: {
210 | type: 'dateLiteral',
211 | value: 'LAST_MONTH'
212 | }
213 | }
214 | },
215 | right: {
216 | type: 'ComparisonCondition',
217 | field: {
218 | type: 'FieldReference',
219 | path: ['CreadedDate']
220 | },
221 | operator: '=',
222 | value: {
223 | type: 'dateLiteral',
224 | value: 'THIS_MONTH'
225 | }
226 | }
227 | },
228 | right: {
229 | type: 'ComparisonCondition',
230 | field: {
231 | type: 'FieldReference',
232 | path: ['CreadedDate']
233 | },
234 | operator: '=',
235 | value: {
236 | type: 'dateLiteral',
237 | value: 'NEXT_MONTH'
238 | }
239 | }
240 | },
241 | right: {
242 | type: 'ComparisonCondition',
243 | field: {
244 | type: 'FieldReference',
245 | path: ['CreadedDate']
246 | },
247 | operator: '=',
248 | value: {
249 | type: 'dateLiteral',
250 | value: 'LAST_90_DAYS'
251 | }
252 | }
253 | },
254 | right: {
255 | type: 'ComparisonCondition',
256 | field: {
257 | type: 'FieldReference',
258 | path: ['CreadedDate']
259 | },
260 | operator: '=',
261 | value: {
262 | type: 'dateLiteral',
263 | value: 'NEXT_90_DAYS'
264 | }
265 | }
266 | },
267 | right: {
268 | type: 'ComparisonCondition',
269 | field: {
270 | type: 'FieldReference',
271 | path: ['CreadedDate']
272 | },
273 | operator: '=',
274 | value: {
275 | type: 'dateLiteral',
276 | value: 'THIS_QUARTER'
277 | }
278 | }
279 | },
280 | right: {
281 | type: 'ComparisonCondition',
282 | field: {
283 | type: 'FieldReference',
284 | path: ['CreadedDate']
285 | },
286 | operator: '=',
287 | value: {
288 | type: 'dateLiteral',
289 | value: 'LAST_QUARTER'
290 | }
291 | }
292 | },
293 | right: {
294 | type: 'ComparisonCondition',
295 | field: {
296 | type: 'FieldReference',
297 | path: ['CreadedDate']
298 | },
299 | operator: '=',
300 | value: {
301 | type: 'dateLiteral',
302 | value: 'NEXT_QUARTER'
303 | }
304 | }
305 | },
306 | right: {
307 | type: 'ComparisonCondition',
308 | field: {
309 | type: 'FieldReference',
310 | path: ['CreadedDate']
311 | },
312 | operator: '=',
313 | value: {
314 | type: 'dateLiteral',
315 | value: 'THIS_YEAR'
316 | }
317 | }
318 | },
319 | right: {
320 | type: 'ComparisonCondition',
321 | field: {
322 | type: 'FieldReference',
323 | path: ['CreadedDate']
324 | },
325 | operator: '=',
326 | value: {
327 | type: 'dateLiteral',
328 | value: 'LAST_YEAR'
329 | }
330 | }
331 | },
332 | right: {
333 | type: 'ComparisonCondition',
334 | field: {
335 | type: 'FieldReference',
336 | path: ['CreadedDate']
337 | },
338 | operator: '=',
339 | value: {
340 | type: 'dateLiteral',
341 | value: 'NEXT_YEAR'
342 | }
343 | }
344 | },
345 | right: {
346 | type: 'ComparisonCondition',
347 | field: {
348 | type: 'FieldReference',
349 | path: ['CreadedDate']
350 | },
351 | operator: '=',
352 | value: {
353 | type: 'dateLiteral',
354 | value: 'THIS_FISCAL_QUARTER'
355 | }
356 | }
357 | },
358 | right: {
359 | type: 'ComparisonCondition',
360 | field: {
361 | type: 'FieldReference',
362 | path: ['CreadedDate']
363 | },
364 | operator: '=',
365 | value: {
366 | type: 'dateLiteral',
367 | value: 'LAST_FISCAL_QUARTER'
368 | }
369 | }
370 | },
371 | right: {
372 | type: 'ComparisonCondition',
373 | field: {
374 | type: 'FieldReference',
375 | path: ['CreadedDate']
376 | },
377 | operator: '=',
378 | value: {
379 | type: 'dateLiteral',
380 | value: 'NEXT_FISCAL_QUARTER'
381 | }
382 | }
383 | },
384 | right: {
385 | type: 'ComparisonCondition',
386 | field: {
387 | type: 'FieldReference',
388 | path: ['CreadedDate']
389 | },
390 | operator: '=',
391 | value: {
392 | type: 'dateLiteral',
393 | value: 'THIS_FISCAL_YEAR'
394 | }
395 | }
396 | },
397 | right: {
398 | type: 'ComparisonCondition',
399 | field: {
400 | type: 'FieldReference',
401 | path: ['CreadedDate']
402 | },
403 | operator: '=',
404 | value: {
405 | type: 'dateLiteral',
406 | value: 'LAST_FISCAL_YEAR'
407 | }
408 | }
409 | },
410 | right: {
411 | type: 'ComparisonCondition',
412 | field: {
413 | type: 'FieldReference',
414 | path: ['CreadedDate']
415 | },
416 | operator: '=',
417 | value: {
418 | type: 'dateLiteral',
419 | value: 'NEXT_FISCAL_YEAR'
420 | }
421 | }
422 | },
423 | right: {
424 | type: 'ComparisonCondition',
425 | field: {
426 | type: 'FieldReference',
427 | path: ['CreadedDate']
428 | },
429 | operator: '=',
430 | value: {
431 | type: 'dateLiteral',
432 | value: 'LAST_N_DAYS',
433 | argument: 1
434 | }
435 | }
436 | },
437 | right: {
438 | type: 'ComparisonCondition',
439 | field: {
440 | type: 'FieldReference',
441 | path: ['CreadedDate']
442 | },
443 | operator: '=',
444 | value: {
445 | type: 'dateLiteral',
446 | value: 'NEXT_N_DAYS',
447 | argument: 1
448 | }
449 | }
450 | },
451 | right: {
452 | type: 'ComparisonCondition',
453 | field: {
454 | type: 'FieldReference',
455 | path: ['CreadedDate']
456 | },
457 | operator: '=',
458 | value: {
459 | type: 'dateLiteral',
460 | value: 'NEXT_N_WEEKS',
461 | argument: 1
462 | }
463 | }
464 | },
465 | right: {
466 | type: 'ComparisonCondition',
467 | field: {
468 | type: 'FieldReference',
469 | path: ['CreadedDate']
470 | },
471 | operator: '=',
472 | value: {
473 | type: 'dateLiteral',
474 | value: 'LAST_N_WEEKS',
475 | argument: 1
476 | }
477 | }
478 | },
479 | right: {
480 | type: 'ComparisonCondition',
481 | field: {
482 | type: 'FieldReference',
483 | path: ['CreadedDate']
484 | },
485 | operator: '=',
486 | value: {
487 | type: 'dateLiteral',
488 | value: 'NEXT_N_MONTHS',
489 | argument: 1
490 | }
491 | }
492 | },
493 | right: {
494 | type: 'ComparisonCondition',
495 | field: {
496 | type: 'FieldReference',
497 | path: ['CreadedDate']
498 | },
499 | operator: '=',
500 | value: {
501 | type: 'dateLiteral',
502 | value: 'LAST_N_MONTHS',
503 | argument: 1
504 | }
505 | }
506 | },
507 | right: {
508 | type: 'ComparisonCondition',
509 | field: {
510 | type: 'FieldReference',
511 | path: ['CreadedDate']
512 | },
513 | operator: '=',
514 | value: {
515 | type: 'dateLiteral',
516 | value: 'NEXT_N_QUARTERS',
517 | argument: 1
518 | }
519 | }
520 | },
521 | right: {
522 | type: 'ComparisonCondition',
523 | field: {
524 | type: 'FieldReference',
525 | path: ['CreadedDate']
526 | },
527 | operator: '=',
528 | value: {
529 | type: 'dateLiteral',
530 | value: 'LAST_N_QUARTERS',
531 | argument: 1
532 | }
533 | }
534 | },
535 | right: {
536 | type: 'ComparisonCondition',
537 | field: {
538 | type: 'FieldReference',
539 | path: ['CreadedDate']
540 | },
541 | operator: '=',
542 | value: {
543 | type: 'dateLiteral',
544 | value: 'NEXT_N_YEARS',
545 | argument: 1
546 | }
547 | }
548 | },
549 | right: {
550 | type: 'ComparisonCondition',
551 | field: {
552 | type: 'FieldReference',
553 | path: ['CreadedDate']
554 | },
555 | operator: '=',
556 | value: {
557 | type: 'dateLiteral',
558 | value: 'LAST_N_YEARS',
559 | argument: 1
560 | }
561 | }
562 | },
563 | right: {
564 | type: 'ComparisonCondition',
565 | field: {
566 | type: 'FieldReference',
567 | path: ['CreadedDate']
568 | },
569 | operator: '=',
570 | value: {
571 | type: 'dateLiteral',
572 | value: 'NEXT_N_FISCAL_QUARTERS',
573 | argument: 1
574 | }
575 | }
576 | },
577 | right: {
578 | type: 'ComparisonCondition',
579 | field: {
580 | type: 'FieldReference',
581 | path: ['CreadedDate']
582 | },
583 | operator: '=',
584 | value: {
585 | type: 'dateLiteral',
586 | value: 'LAST_N_FISCAL_QUARTERS',
587 | argument: 1
588 | }
589 | }
590 | },
591 | right: {
592 | type: 'ComparisonCondition',
593 | field: {
594 | type: 'FieldReference',
595 | path: ['CreadedDate']
596 | },
597 | operator: '=',
598 | value: {
599 | type: 'dateLiteral',
600 | value: 'NEXT_N_FISCAL_YEARS',
601 | argument: 1
602 | }
603 | }
604 | },
605 | right: {
606 | type: 'ComparisonCondition',
607 | field: {
608 | type: 'FieldReference',
609 | path: ['CreadedDate']
610 | },
611 | operator: '=',
612 | value: {
613 | type: 'dateLiteral',
614 | value: 'LAST_N_FISCAL_YEARS',
615 | argument: 1
616 | }
617 | }
618 | }
619 | }
--------------------------------------------------------------------------------
/test/data/expected/41-date-literal-04.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [
4 | {
5 | type: 'FieldReference',
6 | path: ['Id']
7 | },
8 | {
9 | type: 'FieldReference',
10 | path: ['SomeNumberField__c']
11 | }
12 | ],
13 | object: {
14 | type: 'ObjectReference',
15 | name: 'Account'
16 | },
17 | condition: {
18 | type: 'LogicalCondition',
19 | operator: 'OR',
20 | left: {
21 | type: 'LogicalCondition',
22 | operator: 'OR',
23 | left: {
24 | type: 'LogicalCondition',
25 | operator: 'OR',
26 | left: {
27 | type: 'LogicalCondition',
28 | operator: 'OR',
29 | left: {
30 | type: 'LogicalCondition',
31 | operator: 'OR',
32 | left: {
33 | type: 'LogicalCondition',
34 | operator: 'OR',
35 | left: {
36 | type: 'LogicalCondition',
37 | operator: 'OR',
38 | left: {
39 | type: 'LogicalCondition',
40 | operator: 'OR',
41 | left: {
42 | type: 'LogicalCondition',
43 | operator: 'OR',
44 | left: {
45 | type: 'LogicalCondition',
46 | operator: 'OR',
47 | left: {
48 | type: 'LogicalCondition',
49 | operator: 'OR',
50 | left: {
51 | type: 'LogicalCondition',
52 | operator: 'OR',
53 | left: {
54 | type: 'LogicalCondition',
55 | operator: 'OR',
56 | left: {
57 | type: 'LogicalCondition',
58 | operator: 'OR',
59 | left: {
60 | type: 'LogicalCondition',
61 | operator: 'OR',
62 | left: {
63 | type: 'LogicalCondition',
64 | operator: 'OR',
65 | left: {
66 | type: 'LogicalCondition',
67 | operator: 'OR',
68 | left: {
69 | type: 'LogicalCondition',
70 | operator: 'OR',
71 | left: {
72 | type: 'LogicalCondition',
73 | operator: 'OR',
74 | left: {
75 | type: 'LogicalCondition',
76 | operator: 'OR',
77 | left: {
78 | type: 'LogicalCondition',
79 | operator: 'OR',
80 | left: {
81 | type: 'LogicalCondition',
82 | operator: 'OR',
83 | left: {
84 | type: 'LogicalCondition',
85 | operator: 'OR',
86 | left: {
87 | type: 'LogicalCondition',
88 | operator: 'OR',
89 | left: {
90 | type: 'LogicalCondition',
91 | operator: 'OR',
92 | left: {
93 | type: 'LogicalCondition',
94 | operator: 'OR',
95 | left: {
96 | type: 'LogicalCondition',
97 | operator: 'OR',
98 | left: {
99 | type: 'LogicalCondition',
100 | operator: 'OR',
101 | left: {
102 | type: 'LogicalCondition',
103 | operator: 'OR',
104 | left: {
105 | type: 'LogicalCondition',
106 | operator: 'OR',
107 | left: {
108 | type: 'LogicalCondition',
109 | operator: 'OR',
110 | left: {
111 | type: 'LogicalCondition',
112 | operator: 'OR',
113 | left: {
114 | type: 'LogicalCondition',
115 | operator: 'OR',
116 | left: {
117 | type: 'LogicalCondition',
118 | operator: 'OR',
119 | left: {
120 | type: 'LogicalCondition',
121 | operator: 'OR',
122 | left: {
123 | type: 'LogicalCondition',
124 | operator: 'OR',
125 | left: {
126 | type: 'ComparisonCondition',
127 | field: {
128 | type: 'FieldReference',
129 | path: ['CreadedDate']
130 | },
131 | operator: '=',
132 | value: {
133 | type: 'dateLiteral',
134 | value: 'YESTERDAY'
135 | }
136 | },
137 | right: {
138 | type: 'ComparisonCondition',
139 | field: {
140 | type: 'FieldReference',
141 | path: ['CreadedDate']
142 | },
143 | operator: '=',
144 | value: {
145 | type: 'dateLiteral',
146 | value: 'TODAY'
147 | }
148 | }
149 | },
150 | right: {
151 | type: 'ComparisonCondition',
152 | field: {
153 | type: 'FieldReference',
154 | path: ['CreadedDate']
155 | },
156 | operator: '=',
157 | value: {
158 | type: 'dateLiteral',
159 | value: 'TOMORROW'
160 | }
161 | }
162 | },
163 | right: {
164 | type: 'ComparisonCondition',
165 | field: {
166 | type: 'FieldReference',
167 | path: ['CreadedDate']
168 | },
169 | operator: '=',
170 | value: {
171 | type: 'dateLiteral',
172 | value: 'LAST_WEEK'
173 | }
174 | }
175 | },
176 | right: {
177 | type: 'ComparisonCondition',
178 | field: {
179 | type: 'FieldReference',
180 | path: ['CreadedDate']
181 | },
182 | operator: '=',
183 | value: {
184 | type: 'dateLiteral',
185 | value: 'THIS_WEEK'
186 | }
187 | }
188 | },
189 | right: {
190 | type: 'ComparisonCondition',
191 | field: {
192 | type: 'FieldReference',
193 | path: ['CreadedDate']
194 | },
195 | operator: '=',
196 | value: {
197 | type: 'dateLiteral',
198 | value: 'NEXT_WEEK'
199 | }
200 | }
201 | },
202 | right: {
203 | type: 'ComparisonCondition',
204 | field: {
205 | type: 'FieldReference',
206 | path: ['CreadedDate']
207 | },
208 | operator: '=',
209 | value: {
210 | type: 'dateLiteral',
211 | value: 'LAST_MONTH'
212 | }
213 | }
214 | },
215 | right: {
216 | type: 'ComparisonCondition',
217 | field: {
218 | type: 'FieldReference',
219 | path: ['CreadedDate']
220 | },
221 | operator: '=',
222 | value: {
223 | type: 'dateLiteral',
224 | value: 'THIS_MONTH'
225 | }
226 | }
227 | },
228 | right: {
229 | type: 'ComparisonCondition',
230 | field: {
231 | type: 'FieldReference',
232 | path: ['CreadedDate']
233 | },
234 | operator: '=',
235 | value: {
236 | type: 'dateLiteral',
237 | value: 'NEXT_MONTH'
238 | }
239 | }
240 | },
241 | right: {
242 | type: 'ComparisonCondition',
243 | field: {
244 | type: 'FieldReference',
245 | path: ['CreadedDate']
246 | },
247 | operator: '=',
248 | value: {
249 | type: 'dateLiteral',
250 | value: 'LAST_90_DAYS'
251 | }
252 | }
253 | },
254 | right: {
255 | type: 'ComparisonCondition',
256 | field: {
257 | type: 'FieldReference',
258 | path: ['CreadedDate']
259 | },
260 | operator: '=',
261 | value: {
262 | type: 'dateLiteral',
263 | value: 'NEXT_90_DAYS'
264 | }
265 | }
266 | },
267 | right: {
268 | type: 'ComparisonCondition',
269 | field: {
270 | type: 'FieldReference',
271 | path: ['CreadedDate']
272 | },
273 | operator: '=',
274 | value: {
275 | type: 'dateLiteral',
276 | value: 'THIS_QUARTER'
277 | }
278 | }
279 | },
280 | right: {
281 | type: 'ComparisonCondition',
282 | field: {
283 | type: 'FieldReference',
284 | path: ['CreadedDate']
285 | },
286 | operator: '=',
287 | value: {
288 | type: 'dateLiteral',
289 | value: 'LAST_QUARTER'
290 | }
291 | }
292 | },
293 | right: {
294 | type: 'ComparisonCondition',
295 | field: {
296 | type: 'FieldReference',
297 | path: ['CreadedDate']
298 | },
299 | operator: '=',
300 | value: {
301 | type: 'dateLiteral',
302 | value: 'NEXT_QUARTER'
303 | }
304 | }
305 | },
306 | right: {
307 | type: 'ComparisonCondition',
308 | field: {
309 | type: 'FieldReference',
310 | path: ['CreadedDate']
311 | },
312 | operator: '=',
313 | value: {
314 | type: 'dateLiteral',
315 | value: 'THIS_YEAR'
316 | }
317 | }
318 | },
319 | right: {
320 | type: 'ComparisonCondition',
321 | field: {
322 | type: 'FieldReference',
323 | path: ['CreadedDate']
324 | },
325 | operator: '=',
326 | value: {
327 | type: 'dateLiteral',
328 | value: 'LAST_YEAR'
329 | }
330 | }
331 | },
332 | right: {
333 | type: 'ComparisonCondition',
334 | field: {
335 | type: 'FieldReference',
336 | path: ['CreadedDate']
337 | },
338 | operator: '=',
339 | value: {
340 | type: 'dateLiteral',
341 | value: 'NEXT_YEAR'
342 | }
343 | }
344 | },
345 | right: {
346 | type: 'ComparisonCondition',
347 | field: {
348 | type: 'FieldReference',
349 | path: ['CreadedDate']
350 | },
351 | operator: '=',
352 | value: {
353 | type: 'dateLiteral',
354 | value: 'THIS_FISCAL_QUARTER'
355 | }
356 | }
357 | },
358 | right: {
359 | type: 'ComparisonCondition',
360 | field: {
361 | type: 'FieldReference',
362 | path: ['CreadedDate']
363 | },
364 | operator: '=',
365 | value: {
366 | type: 'dateLiteral',
367 | value: 'LAST_FISCAL_QUARTER'
368 | }
369 | }
370 | },
371 | right: {
372 | type: 'ComparisonCondition',
373 | field: {
374 | type: 'FieldReference',
375 | path: ['CreadedDate']
376 | },
377 | operator: '=',
378 | value: {
379 | type: 'dateLiteral',
380 | value: 'NEXT_FISCAL_QUARTER'
381 | }
382 | }
383 | },
384 | right: {
385 | type: 'ComparisonCondition',
386 | field: {
387 | type: 'FieldReference',
388 | path: ['CreadedDate']
389 | },
390 | operator: '=',
391 | value: {
392 | type: 'dateLiteral',
393 | value: 'THIS_FISCAL_YEAR'
394 | }
395 | }
396 | },
397 | right: {
398 | type: 'ComparisonCondition',
399 | field: {
400 | type: 'FieldReference',
401 | path: ['CreadedDate']
402 | },
403 | operator: '=',
404 | value: {
405 | type: 'dateLiteral',
406 | value: 'LAST_FISCAL_YEAR'
407 | }
408 | }
409 | },
410 | right: {
411 | type: 'ComparisonCondition',
412 | field: {
413 | type: 'FieldReference',
414 | path: ['CreadedDate']
415 | },
416 | operator: '=',
417 | value: {
418 | type: 'dateLiteral',
419 | value: 'NEXT_FISCAL_YEAR'
420 | }
421 | }
422 | },
423 | right: {
424 | type: 'ComparisonCondition',
425 | field: {
426 | type: 'FieldReference',
427 | path: ['CreadedDate']
428 | },
429 | operator: '=',
430 | value: {
431 | type: 'dateLiteral',
432 | value: 'LAST_N_DAYS',
433 | argument: 12
434 | }
435 | }
436 | },
437 | right: {
438 | type: 'ComparisonCondition',
439 | field: {
440 | type: 'FieldReference',
441 | path: ['CreadedDate']
442 | },
443 | operator: '=',
444 | value: {
445 | type: 'dateLiteral',
446 | value: 'NEXT_N_DAYS',
447 | argument: 12
448 | }
449 | }
450 | },
451 | right: {
452 | type: 'ComparisonCondition',
453 | field: {
454 | type: 'FieldReference',
455 | path: ['CreadedDate']
456 | },
457 | operator: '=',
458 | value: {
459 | type: 'dateLiteral',
460 | value: 'NEXT_N_WEEKS',
461 | argument: 12
462 | }
463 | }
464 | },
465 | right: {
466 | type: 'ComparisonCondition',
467 | field: {
468 | type: 'FieldReference',
469 | path: ['CreadedDate']
470 | },
471 | operator: '=',
472 | value: {
473 | type: 'dateLiteral',
474 | value: 'LAST_N_WEEKS',
475 | argument: 12
476 | }
477 | }
478 | },
479 | right: {
480 | type: 'ComparisonCondition',
481 | field: {
482 | type: 'FieldReference',
483 | path: ['CreadedDate']
484 | },
485 | operator: '=',
486 | value: {
487 | type: 'dateLiteral',
488 | value: 'NEXT_N_MONTHS',
489 | argument: 12
490 | }
491 | }
492 | },
493 | right: {
494 | type: 'ComparisonCondition',
495 | field: {
496 | type: 'FieldReference',
497 | path: ['CreadedDate']
498 | },
499 | operator: '=',
500 | value: {
501 | type: 'dateLiteral',
502 | value: 'LAST_N_MONTHS',
503 | argument: 12
504 | }
505 | }
506 | },
507 | right: {
508 | type: 'ComparisonCondition',
509 | field: {
510 | type: 'FieldReference',
511 | path: ['CreadedDate']
512 | },
513 | operator: '=',
514 | value: {
515 | type: 'dateLiteral',
516 | value: 'NEXT_N_QUARTERS',
517 | argument: 12
518 | }
519 | }
520 | },
521 | right: {
522 | type: 'ComparisonCondition',
523 | field: {
524 | type: 'FieldReference',
525 | path: ['CreadedDate']
526 | },
527 | operator: '=',
528 | value: {
529 | type: 'dateLiteral',
530 | value: 'LAST_N_QUARTERS',
531 | argument: 12
532 | }
533 | }
534 | },
535 | right: {
536 | type: 'ComparisonCondition',
537 | field: {
538 | type: 'FieldReference',
539 | path: ['CreadedDate']
540 | },
541 | operator: '=',
542 | value: {
543 | type: 'dateLiteral',
544 | value: 'NEXT_N_YEARS',
545 | argument: 12
546 | }
547 | }
548 | },
549 | right: {
550 | type: 'ComparisonCondition',
551 | field: {
552 | type: 'FieldReference',
553 | path: ['CreadedDate']
554 | },
555 | operator: '=',
556 | value: {
557 | type: 'dateLiteral',
558 | value: 'LAST_N_YEARS',
559 | argument: 12
560 | }
561 | }
562 | },
563 | right: {
564 | type: 'ComparisonCondition',
565 | field: {
566 | type: 'FieldReference',
567 | path: ['CreadedDate']
568 | },
569 | operator: '=',
570 | value: {
571 | type: 'dateLiteral',
572 | value: 'NEXT_N_FISCAL_QUARTERS',
573 | argument: 12
574 | }
575 | }
576 | },
577 | right: {
578 | type: 'ComparisonCondition',
579 | field: {
580 | type: 'FieldReference',
581 | path: ['CreadedDate']
582 | },
583 | operator: '=',
584 | value: {
585 | type: 'dateLiteral',
586 | value: 'LAST_N_FISCAL_QUARTERS',
587 | argument: 12
588 | }
589 | }
590 | },
591 | right: {
592 | type: 'ComparisonCondition',
593 | field: {
594 | type: 'FieldReference',
595 | path: ['CreadedDate']
596 | },
597 | operator: '=',
598 | value: {
599 | type: 'dateLiteral',
600 | value: 'NEXT_N_FISCAL_YEARS',
601 | argument: 12
602 | }
603 | }
604 | },
605 | right: {
606 | type: 'ComparisonCondition',
607 | field: {
608 | type: 'FieldReference',
609 | path: ['CreadedDate']
610 | },
611 | operator: '=',
612 | value: {
613 | type: 'dateLiteral',
614 | value: 'LAST_N_FISCAL_YEARS',
615 | argument: 12
616 | }
617 | }
618 | }
619 | }
--------------------------------------------------------------------------------
/test/data/expected/50-dates-01.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [
4 | {
5 | type: 'FieldReference',
6 | path: ['Id']
7 | },
8 | {
9 | type: 'FieldReference',
10 | path: ['SomeNumberField__c']
11 | }
12 | ],
13 | object: {
14 | type: 'ObjectReference',
15 | name: 'Account'
16 | },
17 | condition: {
18 | type: 'LogicalCondition',
19 | operator: 'OR',
20 | left: {
21 | type: 'LogicalCondition',
22 | operator: 'OR',
23 | left: {
24 | type: 'LogicalCondition',
25 | operator: 'OR',
26 | left: {
27 | type: 'LogicalCondition',
28 | operator: 'OR',
29 | left: {
30 | type: 'ComparisonCondition',
31 | field: {
32 | type: 'FieldReference',
33 | path: ['CreatedDate']
34 | },
35 | operator: '<',
36 | value: {
37 | type: 'datetime',
38 | value: '1999-01-01T23:01:01+01:00'
39 | }
40 | },
41 | right: {
42 | type: 'ComparisonCondition',
43 | field: {
44 | type: 'FieldReference',
45 | path: ['CreatedDate']
46 | },
47 | operator: '<=',
48 | value: {
49 | type: 'datetime',
50 | value: '1999-01-01T23:01:01-08:00'
51 | }
52 | }
53 | },
54 | right: {
55 | type: 'ComparisonCondition',
56 | field: {
57 | type: 'FieldReference',
58 | path: ['CreatedDate']
59 | },
60 | operator: '>',
61 | value: {
62 | type: 'datetime',
63 | value: '1999-01-01T23:01:01Z'
64 | }
65 | }
66 | },
67 | right: {
68 | type: 'ComparisonCondition',
69 | field: {
70 | type: 'FieldReference',
71 | path: ['CreatedDate']
72 | },
73 | operator: '>=',
74 | value: {
75 | type: 'date',
76 | value: '1999-01-01'
77 | }
78 | }
79 | },
80 | right: {
81 | type: 'ComparisonCondition',
82 | field: {
83 | type: 'FieldReference',
84 | path: [
85 | 'CreatedDate'
86 | ]
87 | },
88 | operator: '=',
89 | value: {
90 | type: 'datetime',
91 | value: '1999-01-01T23:01:01+01:00'
92 | }
93 | }
94 | }
95 | }
--------------------------------------------------------------------------------
/test/data/expected/90-complex-01.json5:
--------------------------------------------------------------------------------
1 | {
2 | type: 'Query',
3 | fields: [{
4 | type: 'FieldReference',
5 | path: ['Id'],
6 | }, {
7 | type: 'FieldReference',
8 | path: ['Name'],
9 | }, {
10 | type: 'FieldReference',
11 | path: ['Owner', 'Id'],
12 | }, {
13 | type: 'FunctionCall',
14 | name: 'toLabel',
15 | arguments: [{
16 | type: 'FieldReference',
17 | path: ['StageName'],
18 | }],
19 | }, {
20 | type: 'Query',
21 | fields: [{
22 | type: 'FieldReference',
23 | path: ['Id'],
24 | }, {
25 | type: 'FieldReference',
26 | path: ['Contact', 'Id'],
27 | }, {
28 | type: 'FieldReference',
29 | path: ['Contact', 'Name'],
30 | }, {
31 | type: 'FunctionCall',
32 | name: 'format',
33 | arguments: [{
34 | type: 'FieldReference',
35 | path: ['Contact', 'Account', 'NumberOfEmployees'],
36 | }],
37 | }],
38 | object: {
39 | type: 'ObjectReference',
40 | name: 'OpportunityContactRoles',
41 | },
42 | limit: {
43 | type: 'number',
44 | value: 10,
45 | },
46 | }],
47 | object: {
48 | type: 'ObjectReference',
49 | name: 'Opportunity',
50 | },
51 | scope: 'Mine',
52 | condition: {
53 | type: 'LogicalCondition',
54 | operator: 'OR',
55 | left: {
56 | type: 'LogicalCondition',
57 | operator: 'OR',
58 | left: {
59 | type: 'ComparisonCondition',
60 | operator: 'LIKE',
61 | field: {
62 | type: 'FieldReference',
63 | path: ['Account', 'Name'],
64 | },
65 | value: {
66 | type: 'string',
67 | value: "O'reilly%",
68 | },
69 | },
70 | right: {
71 | type: 'LogicalCondition',
72 | operator: 'AND',
73 | left: {
74 | type: 'NegateCondition',
75 | operator: 'NOT',
76 | condition: {
77 | type: 'LogicalCondition',
78 | operator: 'AND',
79 | left: {
80 | type: 'ComparisonCondition',
81 | operator: '=',
82 | field: {
83 | type: 'FunctionCall',
84 | name: 'CALENDAR_MONTH',
85 | arguments: [{
86 | type: 'FieldReference',
87 | path: ['CreatedDate'],
88 | }],
89 | },
90 | value: {
91 | type: 'number',
92 | value: 10,
93 | },
94 | },
95 | right: {
96 | type: 'ComparisonCondition',
97 | operator: '>',
98 | field: {
99 | type: 'FieldReference',
100 | path: ['CreatedDate'],
101 | },
102 | value: {
103 | type: 'date',
104 | value: '2015-12-31',
105 | },
106 | },
107 | parentheses: true,
108 | },
109 | parentheses: true,
110 | },
111 | right: {
112 | type: 'ComparisonCondition',
113 | operator: '=',
114 | field: {
115 | type: 'FieldReference',
116 | path: ['Owner', 'Name'],
117 | },
118 | value: {
119 | type: 'string',
120 | value: 'Hello',
121 | },
122 | }
123 | },
124 | },
125 | right: {
126 | type: 'ComparisonCondition',
127 | operator: '>',
128 | field: {
129 | type: 'FieldReference',
130 | path: ['Probability'],
131 | },
132 | value: {
133 | type: 'number',
134 | value: 99.5,
135 | },
136 | },
137 | },
138 | sort: [{
139 | field: {
140 | type: 'FieldReference',
141 | path: ['Account', 'Type'],
142 | },
143 | direction: 'DESC',
144 | nullOrder: 'LAST',
145 | }, {
146 | field: {
147 | type: 'FieldReference',
148 | path: ['CreatedDate'],
149 | },
150 | }],
151 | limit: {
152 | type: 'number',
153 | value: 100,
154 | },
155 | offset: {
156 | type: 'number',
157 | value: 200,
158 | },
159 | }
160 |
--------------------------------------------------------------------------------
/test/data/parsable/00-simple-01.soql:
--------------------------------------------------------------------------------
1 | SELECT Name FROM Account
2 |
--------------------------------------------------------------------------------
/test/data/parsable/01-simple-02.soql:
--------------------------------------------------------------------------------
1 | Select Name froM Account
2 |
--------------------------------------------------------------------------------
/test/data/parsable/02-select-clause-01.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, Name, Owner.Name
2 | FROM Account
3 |
--------------------------------------------------------------------------------
/test/data/parsable/03-select-clause-02.soql:
--------------------------------------------------------------------------------
1 | SELECT
2 | Id, Name,
3 | toLabel(Account.Type),
4 | convertCurrency(Amount)
5 | FROM Opportunity
6 |
--------------------------------------------------------------------------------
/test/data/parsable/04-select-clause-03.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, Name, (SELECT Id, Name From Contacts)
2 | FROM Account
3 |
--------------------------------------------------------------------------------
/test/data/parsable/05-from-object-with-alias-01.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, Name, Amount, a.Id, a.Name
2 | FROM Opportunity, Opportunity.Account AS a
3 |
--------------------------------------------------------------------------------
/test/data/parsable/06-from-object-with-alias-02.soql:
--------------------------------------------------------------------------------
1 | SELECT o.Id, o.Name, o.Amount, a.Id, a.Name, u.Username
2 | FROM Opportunity o, o.Account a, a.Owner u
3 |
--------------------------------------------------------------------------------
/test/data/parsable/07-from-object-group-03.soql:
--------------------------------------------------------------------------------
1 | SELECT Name, COUNT(Id) c
2 | FROM Group
3 | WHERE Type = 'Queue'
4 | GROUP BY Name
5 | ORDER BY Name ASC
--------------------------------------------------------------------------------
/test/data/parsable/08-from-object-order-04.soql:
--------------------------------------------------------------------------------
1 | SELECT Name, COUNT(Id) c
2 | FROM Order
3 | WHERE Type = 'Standard'
4 | GROUP BY Name
5 | ORDER BY Name ASC
--------------------------------------------------------------------------------
/test/data/parsable/10-where-clause-01.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, Name FROM Account
2 | WHERE Name='Apple'
3 |
--------------------------------------------------------------------------------
/test/data/parsable/11-where-clause-02.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, Name FROM Account
2 | WHERE Name='Apple' AND Owner.Active = true
3 |
--------------------------------------------------------------------------------
/test/data/parsable/12-where-clause-03.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, Name FROM Account
2 | WHERE Name LIKE 'A%'
3 | OR Type = 'Partner'
4 | AND Owner.Username!= 'user01@example.com'
5 |
--------------------------------------------------------------------------------
/test/data/parsable/13-where-clause-04.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, Name FROM Account
2 | WHERE (Name LIKE 'A%' OR Type = 'Partner')
3 | AND Owner.Username!= 'user01@example.com'
4 |
--------------------------------------------------------------------------------
/test/data/parsable/14-where-clause-05.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, Name FROM Account
2 | WHERE Type IN ('Partner', 'Customer')
3 | OR (
4 | CALENDAR_YEAR(CreatedDate) IN (2016, 2017)
5 | AND CALENDAR_MONTH(CreatedDate) NOT IN (2, 4, 6, 9, 11)
6 | )
7 |
--------------------------------------------------------------------------------
/test/data/parsable/15-where-clause-06.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, SomeNumberField__c FROM Account
2 | WHERE SomeNumberField__c <= 10
3 |
--------------------------------------------------------------------------------
/test/data/parsable/16-where-clause-07.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, SomeNumberField__c FROM Account
2 | WHERE CreatedDate < 1999-01-01T23:01:01+01:00
3 | OR CreatedDate <= 1999-01-01T23:01:01-08:00
4 | OR CreatedDate >= 1999-01-01T23:01:01Z
5 | OR CreatedDate <= 1999-01-01
6 | OR CreatedDate = 1999-01-01T23:01:01+01:00
7 |
--------------------------------------------------------------------------------
/test/data/parsable/20-order-by-clause-01.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, Name FROM Account
2 | ORDER BY CreatedDate
3 |
--------------------------------------------------------------------------------
/test/data/parsable/21-order-by-clause-02.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, Name FROM Account
2 | ORDER BY Type ASC NULLS LAST, CreatedDate DESC
3 |
--------------------------------------------------------------------------------
/test/data/parsable/30-group-by-clause-01.soql:
--------------------------------------------------------------------------------
1 | SELECT count(Id), Type FROM Account
2 | GROUP BY Type
3 |
--------------------------------------------------------------------------------
/test/data/parsable/31-group-by-clause-02.soql:
--------------------------------------------------------------------------------
1 | SELECT count(Id) Cnt, Type, CALENDAR_YEAR(CreatedDate)Year FROM Account
2 | GROUP BY Type, CALENDAR_YEAR(CreatedDate)
3 |
--------------------------------------------------------------------------------
/test/data/parsable/32-group-by-clause-03.soql:
--------------------------------------------------------------------------------
1 | SELECT count(Id) Cnt, Type, CALENDAR_YEAR(CreatedDate) Year FROM Account
2 | GROUP BY Type, CALENDAR_YEAR(CreatedDate)
3 | ORDER BY Type, count(Id) ASC
4 |
--------------------------------------------------------------------------------
/test/data/parsable/40-date-literal-01.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, Name, CreatedDate
2 | FROM Account
3 | WHERE CreatedDate = TODAY
--------------------------------------------------------------------------------
/test/data/parsable/41-date-literal-02.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, Name, CreatedDate
2 | FROM Account
3 | WHERE CreatedDate >= LAST_N_DAYS:1
--------------------------------------------------------------------------------
/test/data/parsable/41-date-literal-03.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, SomeNumberField__c
2 | FROM Account
3 | WHERE CreadedDate = YESTERDAY
4 | OR CreadedDate = TODAY
5 | OR CreadedDate = TOMORROW
6 | OR CreadedDate = LAST_WEEK
7 | OR CreadedDate = THIS_WEEK
8 | OR CreadedDate = NEXT_WEEK
9 | OR CreadedDate = LAST_MONTH
10 | OR CreadedDate = THIS_MONTH
11 | OR CreadedDate = NEXT_MONTH
12 | OR CreadedDate = LAST_90_DAYS
13 | OR CreadedDate = NEXT_90_DAYS
14 | OR CreadedDate = THIS_QUARTER
15 | OR CreadedDate = LAST_QUARTER
16 | OR CreadedDate = NEXT_QUARTER
17 | OR CreadedDate = THIS_YEAR
18 | OR CreadedDate = LAST_YEAR
19 | OR CreadedDate = NEXT_YEAR
20 | OR CreadedDate = THIS_FISCAL_QUARTER
21 | OR CreadedDate = LAST_FISCAL_QUARTER
22 | OR CreadedDate = NEXT_FISCAL_QUARTER
23 | OR CreadedDate = THIS_FISCAL_YEAR
24 | OR CreadedDate = LAST_FISCAL_YEAR
25 | OR CreadedDate = NEXT_FISCAL_YEAR
26 | OR CreadedDate = LAST_N_DAYS:1
27 | OR CreadedDate = NEXT_N_DAYS:1
28 | OR CreadedDate = NEXT_N_WEEKS:1
29 | OR CreadedDate = LAST_N_WEEKS:1
30 | OR CreadedDate = NEXT_N_MONTHS:1
31 | OR CreadedDate = LAST_N_MONTHS:1
32 | OR CreadedDate = NEXT_N_QUARTERS:1
33 | OR CreadedDate = LAST_N_QUARTERS:1
34 | OR CreadedDate = NEXT_N_YEARS:1
35 | OR CreadedDate = LAST_N_YEARS:1
36 | OR CreadedDate = NEXT_N_FISCAL_QUARTERS:1
37 | OR CreadedDate = LAST_N_FISCAL_QUARTERS:1
38 | OR CreadedDate = NEXT_N_FISCAL_YEARS:1
39 | OR CreadedDate = LAST_N_FISCAL_YEARS:1
--------------------------------------------------------------------------------
/test/data/parsable/41-date-literal-04.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, SomeNumberField__c
2 | FROM Account
3 | WHERE CreadedDate = YESTERDAY
4 | OR CreadedDate = TODAY
5 | OR CreadedDate = TOMORROW
6 | OR CreadedDate = LAST_WEEK
7 | OR CreadedDate = THIS_WEEK
8 | OR CreadedDate = NEXT_WEEK
9 | OR CreadedDate = LAST_MONTH
10 | OR CreadedDate = THIS_MONTH
11 | OR CreadedDate = NEXT_MONTH
12 | OR CreadedDate = LAST_90_DAYS
13 | OR CreadedDate = NEXT_90_DAYS
14 | OR CreadedDate = THIS_QUARTER
15 | OR CreadedDate = LAST_QUARTER
16 | OR CreadedDate = NEXT_QUARTER
17 | OR CreadedDate = THIS_YEAR
18 | OR CreadedDate = LAST_YEAR
19 | OR CreadedDate = NEXT_YEAR
20 | OR CreadedDate = THIS_FISCAL_QUARTER
21 | OR CreadedDate = LAST_FISCAL_QUARTER
22 | OR CreadedDate = NEXT_FISCAL_QUARTER
23 | OR CreadedDate = THIS_FISCAL_YEAR
24 | OR CreadedDate = LAST_FISCAL_YEAR
25 | OR CreadedDate = NEXT_FISCAL_YEAR
26 | OR CreadedDate = LAST_N_DAYS : 12
27 | OR CreadedDate = NEXT_N_DAYS : 12
28 | OR CreadedDate = NEXT_N_WEEKS : 12
29 | OR CreadedDate = LAST_N_WEEKS : 12
30 | OR CreadedDate = NEXT_N_MONTHS : 12
31 | OR CreadedDate = LAST_N_MONTHS : 12
32 | OR CreadedDate = NEXT_N_QUARTERS : 12
33 | OR CreadedDate = LAST_N_QUARTERS : 12
34 | OR CreadedDate = NEXT_N_YEARS : 12
35 | OR CreadedDate = LAST_N_YEARS : 12
36 | OR CreadedDate = NEXT_N_FISCAL_QUARTERS : 12
37 | OR CreadedDate = LAST_N_FISCAL_QUARTERS : 12
38 | OR CreadedDate = NEXT_N_FISCAL_YEARS : 12
39 | OR CreadedDate = LAST_N_FISCAL_YEARS : 12
--------------------------------------------------------------------------------
/test/data/parsable/50-dates-01.soql:
--------------------------------------------------------------------------------
1 | SELECT Id, SomeNumberField__c
2 | FROM Account
3 | WHERE CreatedDate < 1999-01-01T23:01:01+01:00
4 | OR CreatedDate <= 1999-01-01T23:01:01-08:00
5 | OR CreatedDate > 1999-01-01T23:01:01Z
6 | OR CreatedDate >= 1999-01-01
7 | OR CreatedDate = 1999-01-01T23:01:01+01:00
--------------------------------------------------------------------------------
/test/data/parsable/90-complex-01.soql:
--------------------------------------------------------------------------------
1 | SELECT
2 | Id, Name, Owner.Id, toLabel(StageName),
3 | (SELECT Id, Contact.Id, Contact.Name, format(Contact.Account.NumberOfEmployees)
4 | FROM OpportunityContactRoles
5 | LIMIT 10)
6 | FROM Opportunity
7 | USING SCOPE Mine
8 | WHERE
9 | Account.Name LIKE 'O\'reilly%'
10 | OR
11 | (NOT (
12 | CALENDAR_MONTH(CreatedDate) = 10
13 | AND
14 | CreatedDate > 2015-12-31
15 | ))
16 | AND
17 | Owner.Name = 'Hello'
18 | OR
19 | Probability > 99.5
20 | ORDER BY
21 | Account.Type DESC NULLS LAST,
22 | CreatedDate
23 | LIMIT 100
24 | OFFSET 200
25 |
--------------------------------------------------------------------------------
/test/index.test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava';
2 | import fs from 'fs';
3 | import path from 'path';
4 | import JSON5 from 'json5';
5 | import { parse } from '..';
6 |
7 | function getSyntaxErrorIndicator(text, location) {
8 | const lno = location.start.line - 1;
9 | const cno = location.start.column - 1;
10 | const lines = text.split(/\n/);
11 | const indicator = Array.from(new Array(cno)).map(() => ' ').join('') + '^';
12 | return [
13 | ...lines.slice(0, lno + 1),
14 | indicator,
15 | ...lines.slice(lno + 1),
16 | ].slice(Math.max(lno - 2, 0), lno + 3).join('\n');
17 | }
18 |
19 | const PARSABLE_DIR = path.join(__dirname, 'data', 'parsable');
20 | const EXPECTED_DIR = path.join(__dirname, 'data', 'expected');
21 |
22 | fs.readdirSync(PARSABLE_DIR)
23 | .filter((filename) => /\.soql$/.test(filename))
24 | .forEach((filename) => {
25 | const name = path.basename(filename, '.soql');
26 | test(`parse soql test: ${name}`, (t) => {
27 | const soql = fs.readFileSync(path.join(PARSABLE_DIR, filename), 'utf8');
28 | const expected = JSON5.parse(
29 | fs.readFileSync(path.join(EXPECTED_DIR, `${name}.json5`), 'utf8')
30 | );
31 | let parsed;
32 | try {
33 | parsed = parse(soql);
34 | } catch (e) {
35 | let message = e.message;
36 | if (e.location) {
37 | const indicator = getSyntaxErrorIndicator(soql, e.location);
38 | message = `${message}\n\n[${name}]\n${indicator}`;
39 | }
40 | t.fail(message);
41 | }
42 | t.deepEqual(parsed, expected);
43 | });
44 | });
45 |
--------------------------------------------------------------------------------