Security News
The Unpaid Backbone of Open Source: Solo Maintainers Face Increasing Security Demands
Solo open source maintainers face burnout and security challenges, with 60% unpaid and 60% considering quitting.
soql-parser-js
Advanced tools
SOQL Parser JS will parse a SOQL query string into an object that is easy to work with and has the query broken down into usable parts.
This works in the browser as long as npm is used to install the package with dependencies and the browser supports ES6 or a transpiler is used.
Warning: antlr4 is a very large library and is required for the parser to function, so be aware of this prior to including in your browser bundles.
For an example of the parser, check out the example application.
parseQuery(soqlQueryString, options)
isQueryValid(SoqlQuery, options)
composeQuery(SoqlQuery, options)
The parser takes a SOQL query and returns structured data.
Options:
export interface SoqlQueryConfig {
continueIfErrors?: boolean; // default=false
logging: boolean; // default=false
}
import { parseQuery } from 'soql-parser-js';
const soql = 'SELECT UserId, COUNT(Id) from LoginHistory WHERE LoginTime > 2010-09-20T22:16:30.000Z AND LoginTime < 2010-09-21T22:16:30.000Z GROUP BY UserId';
const soqlQuery = parseQuery(soql);
console.log(JSON.stringify(soqlQuery, null, 2));
var soqlParserJs = require('soql-parser-js');
const soql = 'SELECT UserId, COUNT(Id) from LoginHistory WHERE LoginTime > 2010-09-20T22:16:30.000Z AND LoginTime < 2010-09-21T22:16:30.000Z GROUP BY UserId';
const soqlQuery = soqlParserJs.parseQuery(soql);
console.log(JSON.stringify(soqlQuery, null, 2));
This yields an object with the following structure:
{
"fields": [
{
"text": "UserId"
},
{
"fn": {
"text": "COUNT(Id)",
"name": "COUNT",
"parameter": "Id"
}
}
],
"subqueries": [],
"sObject": "LoginHistory",
"whereClause": {
"left": {
"field": "LoginTime",
"operator": ">",
"value": "2010-09-20T22:16:30.000Z"
},
"operator": "AND",
"right": {
"left": {
"field": "LoginTime",
"operator": "<",
"value": "2010-09-21T22:16:30.000Z"
}
}
},
"groupBy": {
"field": "UserId"
}
}
This will parse the AST tree to confirm the syntax is valid, but will not parse the tree into a data structure. This method is faster than parsing the full query.
Options:
export interface ConfigBase {
logging: boolean; // default=false
}
import { isQueryValid } from 'soql-parser-js';
const soql = 'SELECT UserId, COUNT(Id) from LoginHistory WHERE LoginTime > 2010-09-20T22:16:30.000Z AND LoginTime < 2010-09-21T22:16:30.000Z GROUP BY UserId';
const isValid = isQueryValid(soql);
console.log('isValid', isValid);
var soqlParserJs = require('soql-parser-js');
const soql = 'SELECT UserId, COUNT(Id) from LoginHistory WHERE LoginTime > 2010-09-20T22:16:30.000Z AND LoginTime < 2010-09-21T22:16:30.000Z GROUP BY UserId';
const isValid = isQueryValid(soql);
console.log('isValid', isValid);
Composing a query turns a parsed query back into a SOQL query. For some operators, they may be converted to upper case (e.x. NOT, AND)
Options:
export interface SoqlComposeConfig {
logging: boolean; // default=false
format: boolean; // default=false
}
import { composeQuery } from 'soql-parser-js';
const soqlQuery = {
fields: [
{
text: 'UserId',
},
{
fn: {
text: 'COUNT(Id)',
name: 'COUNT',
parameter: 'Id',
},
},
],
subqueries: [],
sObject: 'LoginHistory',
whereClause: {
left: {
field: 'LoginTime',
operator: '>',
value: '2010-09-20T22:16:30.000Z',
},
operator: 'AND',
right: {
left: {
field: 'LoginTime',
operator: '<',
value: '2010-09-21T22:16:30.000Z',
},
},
},
groupBy: {
field: 'UserId',
},
};
const query = composeQuery(soqlQuery);
console.log(query);
This yields an object with the following structure:
SELECT UserId, COUNT(Id) from LoginHistory WHERE LoginTime > 2010-09-20T22:16:30.000Z AND LoginTime < 2010-09-21T22:16:30.000Z GROUP BY UserId
export interface SoqlQueryConfig {
continueIfErrors?: boolean; // default=false
logging: boolean; // default=false
includeSubqueryAsField: boolean; // default=true
}
export interface SoqlComposeConfig {
logging: boolean; // default=false
}
type LogicalOperator = 'AND' | 'OR';
type Operator = '=' | '<=' | '>=' | '>' | '<' | 'LIKE' | 'IN' | 'NOT IN' | 'INCLUDES' | 'EXCLUDES';
type TypeOfFieldConditionType = 'WHEN' | 'ELSE';
type GroupSelector = 'ABOVE' | 'AT' | 'BELOW' | 'ABOVE_OR_BELOW';
type LogicalPrefix = 'NOT';
type ForClause = 'VIEW' | 'UPDATE' | 'REFERENCE';
type UpdateClause = 'TRACKING' | 'VIEWSTAT';
interface Query {
fields: Field[];
subqueries: Query[];
sObject?: string;
sObjectAlias?: string;
sObjectPrefix?: string[];
sObjectRelationshipName?: string;
where?: WhereClause;
limit?: number;
offset?: number;
groupBy?: GroupByClause;
having?: HavingClause;
orderBy?: OrderByClause | OrderByClause[];
withDataCategory?: WithDataCategoryClause;
for?: ForClause;
update?: UpdateClause;
}
interface SelectStatement {
fields: Field[];
}
interface Field {
text?: string;
alias?: string;
relationshipFields?: string[];
fn?: FunctionExp;
subqueryObjName?: string; // populated if subquery
typeOf?: TypeOfField;
}
interface TypeOfField {
field: string;
conditions: TypeOfFieldCondition[];
}
interface TypeOfFieldCondition {
type: TypeOfFieldConditionType;
objectType?: string; // not present when ELSE
fieldList: string[];
}
interface WhereClause {
left: Condition;
right?: WhereClause;
operator?: LogicalOperator;
}
interface Condition {
openParen?: number;
closeParen?: number;
logicalPrefix?: LogicalPrefix;
field?: string;
fn?: FunctionExp;
operator: Operator;
value?: string | string[];
valueQuery?: Query;
}
interface OrderByClause {
field?: string;
fn?: FunctionExp;
order?: 'ASC' | 'DESC';
nulls?: 'FIRST' | 'LAST';
}
interface GroupByClause {
field: string | string[];
type?: 'CUBE' | 'ROLLUP';
}
interface HavingClause {
left: HavingCondition;
right?: HavingClause;
operator?: LogicalOperator;
}
interface HavingCondition {
openParen?: number;
closeParen?: number;
field?: string;
fn?: FunctionExp;
operator: string;
value: string | number;
}
interface FunctionExp {
text?: string; // Count(Id)
name?: string; // Count
alias?: string;
parameter?: string | string[];
isAggregateFn?: boolean;
fn?: FunctionExp; // used for nested functions FORMAT(MIN(CloseDate))
}
interface WithDataCategoryClause {
conditions: WithDataCategoryCondition[];
}
interface WithDataCategoryCondition {
groupName: string;
selector: GroupSelector;
parameters: string[];
}
The CLI can be used to parse a query or compose a previously parsed query back to SOQL.
Examples:
$ npm install -g soql-parser-js
$ soql --help
$ soql --query "SELECT Id FROM Account"
$ soql -query "SELECT Id FROM Account"
$ soql -query "SELECT Id FROM Account" -output some-output-file.json
$ soql -query "SELECT Id FROM Account" -json
$ soql -query some-input-file.txt
$ soql -compose some-input-file.json
$ soql -compose some-input-file.json
$ soql -compose some-input-file.json -output some-output-file.json
Arguments:
--query, -q A SOQL query surrounded in quotes or a file path to a text file containing a SOQL query.
--compose, -c An escaped and quoted parsed SOQL JSON string or a file path to a text file containing a parsed query JSON object.
--output, -o Filepath.
--json, -j Provide all output messages as JSON.
--debug, -d Print additional debug log messages.
--help, -h Show this help message.
All contributions are welcome on the project. Please read the contribution guidelines.
FAQs
Salesforce.com SOQL parser and composer
The npm package soql-parser-js receives a total of 10,362 weekly downloads. As such, soql-parser-js popularity was classified as popular.
We found that soql-parser-js demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Solo open source maintainers face burnout and security challenges, with 60% unpaid and 60% considering quitting.
Security News
License exceptions modify the terms of open source licenses, impacting how software can be used, modified, and distributed. Developers should be aware of the legal implications of these exceptions.
Security News
A developer is accusing Tencent of violating the GPL by modifying a Python utility and changing its license to BSD, highlighting the importance of copyleft compliance.