Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@synatic/noql

Package Overview
Dependencies
Maintainers
3
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@synatic/noql - npm Package Compare versions

Comparing version 2.0.4 to 2.1.0

lib/errors/column-does-not-exist-error.js

2

lib/make/createResultObject.js

@@ -18,3 +18,3 @@ /**

count: [],
unset: [],
unset: null,
countDistinct: null,

@@ -21,0 +21,0 @@ };

@@ -95,3 +95,4 @@ const _allowableFunctions = require('../MongoFunctions');

column.as &&
column.expr.name === 'COUNT' &&
column.expr.name &&
column.expr.name.toUpperCase() === 'COUNT' &&
column.expr.args &&

@@ -98,0 +99,0 @@ column.expr.args.distinct === 'DISTINCT'

@@ -105,2 +105,7 @@ const $check = require('check-types');

parsedQuery.projection = result.parsedProject.$project;
if (result.unset && result.unset.$unset) {
for (const colToUnset of result.unset.$unset) {
parsedQuery.projection[colToUnset] = 0;
}
}
}

@@ -107,0 +112,0 @@

@@ -345,2 +345,5 @@ const groupByColumnParserModule = require('./groupByColumnParser');

}
if (result.unset) {
pipeline.push(result.unset);
}
if (!$check.emptyObject(result.parsedProject.$project)) {

@@ -347,0 +350,0 @@ if (result.exprToMerge && result.exprToMerge.length > 0) {

@@ -38,2 +38,3 @@ const makeProjectionExpressionPartModule = require('./makeProjectionExpressionPart');

* @param {boolean} [prefixTable] - include the table in the prefix
* @param {string[]} [aliases] - the aliases used in the joins
* @returns {any} - the filter expression

@@ -47,92 +48,16 @@ */

prefixLeft = false,
prefixTable = false
prefixTable = false,
aliases = []
) {
if (queryPart.type === 'binary_expr') {
if (queryPart.operator === 'LIKE') {
const likeVal = queryPart.right.value;
const regex = sqlStringToRegex(likeVal);
return {
$regexMatch: {
input: makeFilterCondition(
queryPart.left,
includeThis,
prefixRight,
'left',
prefixLeft,
prefixTable
),
regex: regex,
options: 'i',
},
};
}
if (queryPart.operator === 'NOT LIKE') {
const likeVal = queryPart.right.value;
const regexString = sqlStringToRegex(likeVal);
const input = makeFilterCondition(
queryPart.left,
includeThis,
prefixRight,
'left',
prefixLeft,
prefixTable
);
return {
$not: [
{
$regexMatch: {
input,
regex: regexString,
options: 'i',
},
},
],
};
}
if (queryOperatorMap[queryPart.operator]) {
const left = makeQueryPart.makeQueryPart(
queryPart.left,
false,
[],
includeThis
);
return {
[queryOperatorMap[queryPart.operator]]: [
$check.string(left) ? `$${left}` : left,
makeQueryPart.makeQueryPart(
queryPart.right,
false,
[],
includeThis
),
],
};
}
const operation = operatorMap[queryPart.operator];
if (!operation) {
throw new Error(`Unsupported operator:${queryPart.operator}`);
}
return {
[operation]: [
makeFilterCondition(
queryPart.left,
includeThis,
prefixRight,
'left',
prefixLeft,
prefixTable
),
makeFilterCondition(
queryPart.right,
includeThis,
prefixRight,
'right',
prefixLeft,
prefixTable
),
],
};
const binaryResult = processBinaryExpression(
queryPart,
includeThis,
prefixRight,
side,
prefixLeft,
prefixTable,
aliases
);
if (binaryResult) {
return binaryResult;
}

@@ -153,12 +78,18 @@

if (queryPart.type === 'column_ref') {
let prefix;
if (prefixRight && side === 'right') {
prefix = `$${queryPart.table ? queryPart.table + '.' : ''}`;
} else if (prefixLeft && side === 'left') {
prefix = `$${queryPart.table ? queryPart.table + '.' : ''}`;
} else if (prefixTable) {
prefix = `${queryPart.table ? queryPart.table + '.' : ''}`;
const foundAlias = aliases.find((a) => a === queryPart.table);
let prefix = '';
if (aliases.length) {
if (foundAlias) {
prefix = foundAlias + '.';
}
} else {
prefix = ``;
if (prefixRight && side === 'right') {
prefix = `$${queryPart.table ? queryPart.table + '.' : ''}`;
} else if (prefixLeft && side === 'left') {
prefix = `$${queryPart.table ? queryPart.table + '.' : ''}`;
} else if (prefixTable) {
prefix = `${queryPart.table ? queryPart.table + '.' : ''}`;
}
}
if (includeThis) {

@@ -184,1 +115,248 @@ prefix = `$$this.${prefix}`;

}
/**
* @param {import('../types').Expression} queryPart - The query part to create filter
* @param {boolean} [includeThis] - include the $$this prefix on sub selects
* @param {boolean} [prefixRight] - include $$ for inner variables
* @param {string} [side] - which side of the expression we're working with: left or right
* @param {boolean} [prefixLeft] - include $$ for inner variables
* @param {boolean} [prefixTable] - include the table in the prefix
* @param {string[]} [aliases] - the aliases used in the joins
* @returns {any} - the filter expression
*/
function processBinaryExpression(
queryPart,
includeThis,
prefixRight,
side,
prefixLeft,
prefixTable,
aliases
) {
if (queryPart.type !== 'binary_expr') {
return;
}
let result;
result = processLikeExpression(
queryPart,
includeThis,
prefixRight,
side,
prefixLeft,
prefixTable,
aliases
);
if (result) {
return result;
}
result = processNotLikeExpression(
queryPart,
includeThis,
prefixRight,
side,
prefixLeft,
prefixTable,
aliases
);
if (result) {
return result;
}
result = processQueryOperator(
queryPart,
includeThis,
prefixRight,
side,
prefixLeft,
prefixTable,
aliases
);
if (result) {
return result;
}
return processOperator(
queryPart,
includeThis,
prefixRight,
side,
prefixLeft,
prefixTable,
aliases
);
}
/**
* @param {import('../types').Expression} queryPart - The query part to create filter
* @param {boolean} [includeThis] - include the $$this prefix on sub selects
* @param {boolean} [prefixRight] - include $$ for inner variables
* @param {string} [side] - which side of the expression we're working with: left or right
* @param {boolean} [prefixLeft] - include $$ for inner variables
* @param {boolean} [prefixTable] - include the table in the prefix
* @param {string[]} [aliases] - the aliases used in the joins
* @returns {any} - the filter expression
*/
function processLikeExpression(
queryPart,
includeThis,
prefixRight,
side,
prefixLeft,
prefixTable,
aliases
) {
if (queryPart.operator !== 'LIKE') {
return;
}
const likeVal = queryPart.right.value;
const regex = sqlStringToRegex(likeVal);
return {
$regexMatch: {
input: makeFilterCondition(
queryPart.left,
includeThis,
prefixRight,
'left',
prefixLeft,
prefixTable,
aliases
),
regex: regex,
options: 'i',
},
};
}
/**
* @param {import('../types').Expression} queryPart - The query part to create filter
* @param {boolean} [includeThis] - include the $$this prefix on sub selects
* @param {boolean} [prefixRight] - include $$ for inner variables
* @param {string} [side] - which side of the expression we're working with: left or right
* @param {boolean} [prefixLeft] - include $$ for inner variables
* @param {boolean} [prefixTable] - include the table in the prefix
* @param {string[]} [aliases] - the aliases used in the joins
* @returns {any} - the filter expression
*/
function processNotLikeExpression(
queryPart,
includeThis,
prefixRight,
side,
prefixLeft,
prefixTable,
aliases
) {
if (queryPart.operator !== 'NOT LIKE') {
return;
}
const likeVal = queryPart.right.value;
const regexString = sqlStringToRegex(likeVal);
const input = makeFilterCondition(
queryPart.left,
includeThis,
prefixRight,
'left',
prefixLeft,
prefixTable,
aliases
);
return {
$not: [
{
$regexMatch: {
input,
regex: regexString,
options: 'i',
},
},
],
};
}
/**
* @param {import('../types').Expression} queryPart - The query part to create filter
* @param {boolean} [includeThis] - include the $$this prefix on sub selects
* @param {boolean} [prefixRight] - include $$ for inner variables
* @param {string} [side] - which side of the expression we're working with: left or right
* @param {boolean} [prefixLeft] - include $$ for inner variables
* @param {boolean} [prefixTable] - include the table in the prefix
* @param {string[]} [aliases] - the aliases used in the joins
* @returns {any} - the filter expression
*/
function processQueryOperator(
queryPart,
includeThis,
prefixRight,
side,
prefixLeft,
prefixTable,
aliases
) {
const queryOperator = queryOperatorMap[queryPart.operator];
if (!queryOperator) {
return;
}
const left = makeQueryPart.makeQueryPart(
queryPart.left,
false,
[],
includeThis
);
return {
[queryOperator]: [
$check.string(left) ? `$${left}` : left,
makeQueryPart.makeQueryPart(
queryPart.right,
false,
[],
includeThis
),
],
};
}
/**
* @param {import('../types').Expression} queryPart - The query part to create filter
* @param {boolean} [includeThis] - include the $$this prefix on sub selects
* @param {boolean} [prefixRight] - include $$ for inner variables
* @param {string} [side] - which side of the expression we're working with: left or right
* @param {boolean} [prefixLeft] - include $$ for inner variables
* @param {boolean} [prefixTable] - include the table in the prefix
* @param {string[]} [aliases] - the aliases used in the joins
* @returns {any} - the filter expression
*/
function processOperator(
queryPart,
includeThis,
prefixRight,
side,
prefixLeft,
prefixTable,
aliases
) {
const operation = operatorMap[queryPart.operator];
if (!operation) {
throw new Error(`Unsupported operator:${queryPart.operator}`);
}
const firstFilter = makeFilterCondition(
queryPart.left,
includeThis,
prefixRight,
'left',
prefixLeft,
prefixTable,
aliases
);
const secondFilter = makeFilterCondition(
queryPart.right,
includeThis,
prefixRight,
'right',
prefixLeft,
prefixTable,
aliases
);
return {
[operation]: [firstFilter, secondFilter],
};
}

@@ -9,2 +9,16 @@ const makeFilterConditionModule = require('./makeFilterCondition');

/**
*
* @param {import('../types').TableDefinition} join
* @param {string[]} aliases - the aliases used in the joins
* @param {string} toAs
*/
function getJoinAliases(join, aliases, toAs) {
const joinAliases = [];
if ((join.join === 'INNER JOIN' || join.join === 'LEFT JOIN') && join.as) {
return aliases.filter((a) => a !== toAs);
}
return joinAliases;
}
/**
* Creates the pipeline components for a join

@@ -43,3 +57,3 @@ *

* @param {import('../types').TableDefinition} previousJoin
* @param {string[]} aliases - the aliases used int he joins
* @param {string[]} aliases - the aliases used in the joins
* @param {import('../types').PipelineFn[]} pipeline

@@ -77,6 +91,5 @@ * @returns {void}

}
const prefixLeft =
join.as && join.on.left.table ? join.on.left.table !== toAs : false;
const prefixRight =
join.as && join.on.right.table ? join.on.right.table !== toAs : true;
const prefixLeft = shouldPrefixSide('left');
const prefixRight = shouldPrefixSide('right');
const joinAliases = getJoinAliases(join, aliases, toAs);
const joinQuery = makeFilterConditionModule.makeFilterCondition(

@@ -87,3 +100,5 @@ join.on,

null,
prefixLeft
prefixLeft,
null,
joinAliases
);

@@ -95,3 +110,10 @@ const inputVars = {};

const varName = val.substring(2).replace(/[.-]/g, '_');
inputVars[varName] = `$${val.substring(2)}`;
if (join.as) {
inputVars[varName] = `$${val.substring(2)}`;
} else {
const parts = val.substring(2).split('.');
inputVars[varName] = `$${
parts.length > 1 ? parts[1] : parts[0]
}`;
}
replacePaths.push({path: path, newVal: `$$${varName}`});

@@ -134,3 +156,3 @@ } else if (

from: toTable,
as: toAs,
as: toAs || toTable,
let: inputVars,

@@ -183,2 +205,15 @@ pipeline: lookupPipeline,

}
/**
* @param {'left'|'right'} side The side of the join
* @returns {boolean} if the side should be prefixed or not
*/
function shouldPrefixSide(side) {
const defaultPrefix = side === 'left' ? false : true;
const table = join.on[side].table;
if (join.as && table) {
return table !== toAs;
}
return defaultPrefix;
}
}

@@ -185,0 +220,0 @@

@@ -67,6 +67,3 @@ const getParsedValueFromBinaryExpressionModule = require('./getParsedValueFromBinaryExpression');

});
return {
$arrayToObject: {$concatArrays: [{$objectToArray: toParse}]},
};
return toParse;
}

@@ -74,11 +74,11 @@ const makeProjectionExpressionPartModule = require('./makeProjectionExpressionPart');

};
const upperOperator = queryPart.operator || ''.toUpperCase();
if (queryPart.type === 'binary_expr') {
if (queryPart.operator === '=') return makeOperator('$eq');
if (queryPart.operator === '>') return makeOperator('$gt');
if (queryPart.operator === '<') return makeOperator('$lt');
if (queryPart.operator === '>=') return makeOperator('$gte');
if (queryPart.operator === '<=') return makeOperator('$lte');
if (queryPart.operator === '!=') return makeOperator('$ne');
if (queryPart.operator === 'AND') {
if (upperOperator === '=') return makeOperator('$eq');
if (upperOperator === '>') return makeOperator('$gt');
if (upperOperator === '<') return makeOperator('$lt');
if (upperOperator === '>=') return makeOperator('$gte');
if (upperOperator === '<=') return makeOperator('$lte');
if (upperOperator === '!=') return makeOperator('$ne');
if (upperOperator === 'AND') {
return {

@@ -103,3 +103,3 @@ $and: [

}
if (queryPart.operator === 'OR') {
if (upperOperator === 'OR') {
return {

@@ -124,11 +124,11 @@ $or: [

}
if (queryPart.operator === 'IN') {
if (upperOperator === 'IN') {
return makeOperator('$in');
// return {$in: [makeQueryPart(queryPart.left, ignorePrefix,allowedTypes,includeThis), makeQueryPart(queryPart.right, ignorePrefix,allowedTypes,includeThis)]};
}
if (queryPart.operator === 'NOT IN') {
if (upperOperator === 'NOT IN') {
return makeOperator('$nin');
// return {$in: [makeQueryPart(queryPart.left, ignorePrefix,allowedTypes,includeThis), makeQueryPart(queryPart.right, ignorePrefix,allowedTypes,includeThis)]};
}
if (queryPart.operator === 'LIKE' || queryPart.operator === 'ILIKE') {
if (upperOperator === 'LIKE' || upperOperator === 'ILIKE') {
const likeVal = queryPart.right.value;

@@ -147,6 +147,3 @@ const regex = sqlStringToRegex(likeVal);

}
if (
queryPart.operator === 'NOT LIKE' ||
queryPart.operator === 'NOT ILIKE'
) {
if (upperOperator === 'NOT LIKE' || upperOperator === 'NOT ILIKE') {
const likeVal = queryPart.right.value;

@@ -162,14 +159,18 @@ const regexString = sqlStringToRegex(likeVal);

}
if (queryPart.operator === 'IS NOT') {
if (upperOperator === 'IS NOT') {
return makeOperator('$ne');
}
if (queryPart.operator === 'IS') {
if (upperOperator === 'IS') {
return makeOperator('$eq');
}
throw new Error(`Unsupported operator:${queryPart.operator}`);
throw new Error(`Unsupported operator: ${upperOperator}`);
}
if (queryPart.type === 'function' && queryPart.name === 'NOT') {
if (
queryPart.type === 'function' &&
queryPart.name &&
queryPart.name.toUpperCase() === 'NOT'
) {
return {

@@ -200,6 +201,7 @@ $nor: makeQueryPart(

queryPart.type === 'unary_expr' &&
queryPart.operator === 'NOT' &&
upperOperator === 'NOT' &&
queryPart.expr &&
queryPart.expr.type === 'binary_expr' &&
queryPart.expr.operator === 'IS' &&
queryPart.expr.operator &&
queryPart.expr.operator.toUpperCase() === 'IS' &&
queryPart.expr.left &&

@@ -220,3 +222,3 @@ queryPart.expr.left.type === 'column_ref' &&

queryPart.type === 'unary_expr' &&
queryPart.operator === 'NOT' &&
upperOperator === 'NOT' &&
queryPart.expr

@@ -223,0 +225,0 @@ ) {

@@ -86,11 +86,7 @@ const getParsedValueFromBinaryExpressionModule = require('./getParsedValueFromBinaryExpression');

}
const fieldsToUnset = column.expr.args.value
.map((v) => v.column)
.reduce((obj, col) => {
return {...obj, [col]: 0};
}, {});
result.parsedProject.$project = {
...result.parsedProject.$project,
...fieldsToUnset,
};
const parsedExpr =
makeProjectionExpressionPartModule.makeProjectionExpressionPart(
column.expr
);
result.unset = parsedExpr;
return;

@@ -97,0 +93,0 @@ }

@@ -35,12 +35,16 @@ const {Parser} = require('node-sql-parser');

} catch (exp) {
throw new Error(
`${
exp.location && exp.location.start
? exp.location.start.line +
':' +
exp.location.start.column +
' - '
: ''
}${exp.message}`
);
let message = '';
if (exp.location && exp.location.start) {
message = `[Start: Line ${exp.location.start.line}, Col:${exp.location.start.column}]`;
if (exp.location.end) {
message =
message +
`[End: Line ${exp.location.end.line}, Col:${exp.location.end.column}]`;
}
}
if (message.length) {
message = message + ' - ';
}
message = message + exp.message;
throw new Error(message);
}

@@ -47,0 +51,0 @@ parsedAST = fixAST(parsedAST);

const {parseSQLtoAST} = require('./parseSQLtoAST');
const {canQuery} = require('./canQuery');
const {makeMongoAggregate, makeMongoQuery} = require('./make');
const {getResultSchemaForStatement} = require('./metadata');
/**

@@ -101,4 +102,18 @@ * Class representing a SQL parser

}
/**
* @param {string} statement
* @param {import('./types').GetSchemaFunction} getSchemaFunction
* @param {import('./types').ParserOptions} [options] - the AST options
* @returns {Promise<import('./types').ResultSchema[]>}
*/
static async getResultSchema(statement, getSchemaFunction, options) {
return getResultSchemaForStatement(
statement,
getSchemaFunction,
options
);
}
}
module.exports = SQLParser;

@@ -66,3 +66,3 @@ import type {Document, Sort} from 'mongodb';

name?: string;
args?: Expression[];
args?: Expression | Expression[];
from?: TableDefinition[];

@@ -178,3 +178,3 @@ value?: any;

count: {$count: string}[];
unset: string[];
unset: {$unset: string[]};
countDistinct: string;

@@ -222,5 +222,7 @@ groupByProject?: object;

type SchemaFn = (params: any) => {
type SchemaFn = (params: any) => SchemaFnResult | SchemaFnResult[];
export interface SchemaFnResult {
/** Specifies if there is a json schema type returned or the name of the field that defines the type */
type: 'fieldName' | 'jsonSchemaValue';
type: 'fieldName' | 'jsonSchemaValue' | 'unset';
jsonSchemaValue?: JSONSchemaTypeName;

@@ -230,6 +232,34 @@ fieldName?: 'string';

isArray?: boolean;
};
}
export type JsonSchemaTypeMap = {
[key: string]: JSONSchemaTypeName;
};
export interface FlattenedSchema {
/** The path to the field within the document/json object */
path: string;
/** The JsonSchema type */
type: JSONSchemaTypeName | JSONSchemaTypeName[];
/** The JsonSchema format if it's a string */
format?: string | 'date-time' | 'mongoid';
/** Specifies if the field is an array or not */
isArray: boolean;
/** Specifies if it's a required field or not */
required: boolean;
}
export interface FlattenedSchemas {
[key: string]: FlattenedSchema[];
}
export interface ResultSchema extends FlattenedSchema {
/** The order for this result, lowest should come first */
order: number;
/** the collection from which this column comes */
collectionName: string;
/** If the column has an "as" name, it will be here */
as?: string;
}
export type GetSchemaFunction = (
collectionName: string
) => Promise<FlattenedSchema[]>;
{
"name": "@synatic/noql",
"version": "2.0.4",
"version": "2.1.0",
"description": "Convert SQL statements to mongo queries or aggregates",

@@ -65,2 +65,3 @@ "main": "index.js",

"@synatic/json-magic": "^1.0.0",
"@synatic/schema-magic": "^1.2.0",
"@synatic/type-magic": "^1.0.0",

@@ -67,0 +68,0 @@ "bson-objectid": "2.0.4",

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc