@synatic/noql
Version:
Convert SQL statements to mongo queries or aggregates
1,393 lines (1,368 loc) • 103 kB
JavaScript
const $check = require('check-types');
const $convert = require('@synatic/type-magic');
const {ObjectId} = require('bson');
// https://docs.mongodb.com/manual/meta/aggregation-quick-reference/#arithmetic-expression-operators
/**
* Manages mapping functions from sql to mongo
*
*/
class AllowableFunctions {
// eslint-disable-next-line jsdoc/require-returns
/**
* The type mapping from sql to mongo for cast
*/
static get _sqlTypeMapping() {
return {
double: 'double',
string: 'string',
bool: 'bool',
date: 'date',
int: 'int',
objectId: 'objectId',
long: 'long',
decimal: 'decimal',
varchar: 'string',
datetime: 'date',
time: 'date',
float: 'number',
char: 'string',
nchar: 'string',
text: 'string',
};
}
// eslint-disable-next-line jsdoc/require-returns
/**
* The type mapping from sql to mongo for cast
* @returns {import("./types").JsonSchemaTypeMap}
*/
static get _jsonSchemaTypeMapping() {
return {
double: 'number',
string: 'string',
bool: 'boolean',
date: 'date',
int: 'number',
integer: 'number',
objectId: 'string',
long: 'number',
decimal: 'number',
varchar: 'string',
datetime: 'date',
time: 'date',
float: 'number',
char: 'string',
nchar: 'string',
text: 'string',
object: 'object',
number: 'number',
};
}
/**
* Gets an allowed function by name, returns null if not found
* @param name
* @readonly
* @static
* @memberof AllowableFunctions
* @returns {import("./types").MongoQueryFunction|null}
*/
static functionByName(name) {
if (!name) {
return null;
}
const lowerName = name.toLowerCase();
return AllowableFunctions.functionMappings.find((fn) =>
filterFunctionsByName(fn, lowerName)
);
}
static functionByNameAndType(name, type) {
if (!name) {
return null;
}
if (!type) {
return AllowableFunctions.functionByName(name);
}
const lowerName = name.toLowerCase();
const lowerType = type.toLowerCase();
return AllowableFunctions.functionMappings.find(
(fn) =>
filterFunctionsByName(fn, lowerName) &&
filterFunctionsByType(fn, lowerType)
);
}
static functionByNameAndTypeThatAllowsQuery(name, type) {
if (!name) {
return null;
}
if (!type) {
return AllowableFunctions.functionByName(name);
}
const lowerName = name.toLowerCase();
const lowerType = type.toLowerCase();
return AllowableFunctions.functionMappings.find(
(fn) =>
filterFunctionsByName(fn, lowerName) &&
filterFunctionsByType(fn, lowerType) &&
fn.allowQuery
);
}
/**
* Gets the list of function mappings between sql and mongo
* @returns {import("./types").MongoQueryFunction[]}
*/
static get functionMappings() {
return [
/* #region Columns */
{
name: 'field_exists',
allowQuery: true,
parse: ([fieldName, doesExist]) => {
return {
[fieldName.$literal ? fieldName.$literal : fieldName]: {
$exists: doesExist,
},
};
},
jsonSchemaReturnType: 'boolean',
},
/* #endregion */
/* #region Object Operators */
{
name: 'parse_json',
allowQuery: true,
parse: (parameters) => {
const jsonToParse =
AllowableFunctions._getSingleParameter(parameters);
if (jsonToParse.$literal) {
return {$literal: JSON.parse(jsonToParse.$literal)};
} else {
return JSON.parse(jsonToParse);
}
},
jsonSchemaReturnType: 'object',
},
{
name: 'merge_objects',
allowQuery: true,
parse: (parameters) => {
return {$mergeObjects: parameters};
},
jsonSchemaReturnType: 'object',
},
{
name: 'empty_object',
allowQuery: true,
parse: (parameters) => {
return {$literal: {}};
},
jsonSchemaReturnType: 'object',
},
/* #endregion */
/* #region Arithmetic Operators */
{
name: 'avg',
allowQuery: true,
type: 'function',
parse: (parameters) => {
return {$avg: parameters};
},
jsonSchemaReturnType: 'number',
},
{
name: 'abs',
allowQuery: true,
parse: (parameters) => {
return {
$abs: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'acos',
allowQuery: true,
parse: (parameters) => {
return {
$acos: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'acosh',
allowQuery: true,
parse: (parameters) => {
return {
$acosh: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'asin',
allowQuery: true,
parse: (parameters) => {
return {
$asin: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'asinh',
allowQuery: true,
parse: (parameters) => {
return {
$asinh: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'atan',
allowQuery: true,
parse: (parameters) => {
return {
$atan: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'atan2',
allowQuery: true,
parse: (parameters) => {
return {$atan2: parameters};
},
jsonSchemaReturnType: 'number',
},
{
name: 'atanh',
allowQuery: true,
parse: (parameters) => {
return {
$atanh: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'binary_size',
allowQuery: true,
parse: (parameters) => {
return {
$binarySize:
AllowableFunctions._getSingleParameter(parameters),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'ceil',
allowQuery: true,
parse: (parameters) => {
return {
$ceil: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'degrees_to_radians',
allowQuery: true,
parse: (parameters) => {
return {
$degreesToRadians:
AllowableFunctions._getSingleParameter(parameters),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'divide',
allowQuery: true,
parse: (parameters) => {
return {$divide: parameters};
},
jsonSchemaReturnType: 'number',
},
{
name: 'exp',
allowQuery: true,
parse: (parameters) => {
return {
$exp: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'floor',
allowQuery: true,
parse: (parameters) => {
return {
$floor: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'ln',
allowQuery: true,
parse: (parameters) => {
return {
$ln: AllowableFunctions._getSingleParameter(parameters),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'log',
allowQuery: true,
parse: (parameters) => {
return {$log: parameters};
},
jsonSchemaReturnType: 'number',
},
{
name: 'log10',
allowQuery: true,
parse: (parameters) => {
return {
$log10: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'max',
allowQuery: true,
type: 'function',
parse: (parameters) => {
return {$max: parameters};
},
jsonSchemaReturnType: 'number',
},
{
name: 'min',
allowQuery: true,
type: 'function',
parse: (parameters) => {
return {$min: parameters};
},
jsonSchemaReturnType: 'number',
},
{
name: 'mod',
allowQuery: true,
parse: (parameters) => {
return {$mod: parameters};
},
jsonSchemaReturnType: 'number',
},
{
name: 'multiply',
allowQuery: true,
parse: (parameters) => {
return {$multiply: parameters};
},
jsonSchemaReturnType: 'number',
},
{
name: 'pow',
allowQuery: true,
parse: (parameters) => {
return {$pow: parameters};
},
jsonSchemaReturnType: 'number',
},
{
name: 'radians_to_degrees',
allowQuery: true,
parse: (parameters) => {
return {
$radiansToDegrees:
AllowableFunctions._getSingleParameter(parameters),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'rand',
allowQuery: true,
parse: (parameters) => {
return {$rand: {}};
},
jsonSchemaReturnType: 'number',
},
{
name: 'round',
allowQuery: true,
parse: (parameters) => {
return {$round: parameters};
},
jsonSchemaReturnType: 'number',
},
{
name: 'sin',
allowQuery: true,
parse: (parameters) => {
return {
$sin: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'sinh',
allowQuery: true,
parse: (parameters) => {
return {
$sinh: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'sqrt',
allowQuery: true,
parse: (parameters) => {
return {
$sqrt: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'subtract',
allowQuery: true,
type: 'function',
parse: (parameters) => {
return {$subtract: parameters};
},
jsonSchemaReturnType: 'number',
},
{
name: 'sum',
allowQuery: true,
type: 'function',
parse: (parameters) => {
return {$add: parameters};
},
jsonSchemaReturnType: 'number',
},
{
name: 'tan',
allowQuery: true,
parse: (parameters) => {
return {
$tan: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'tanh',
allowQuery: true,
parse: (parameters) => {
return {
$tanh: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'trunc',
allowQuery: true,
parse: (parameters) => {
return {$trunc: parameters};
},
jsonSchemaReturnType: 'number',
},
/* #endregion */
/* #region Aggregate Functions */
{
name: 'sum',
type: 'aggr_func',
allowQuery: false,
forceGroup: true,
parse: (parameters) => {
const firstParam =
AllowableFunctions._getSingleParameter(parameters);
const valueToSum = firstParam.$literal
? typeof firstParam.$literal === 'string'
? `$${firstParam.$literal}`
: firstParam.$literal
: firstParam;
return {
$sum: valueToSum,
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'avg',
allowQuery: false,
type: 'aggr_func',
forceGroup: true,
parse: (parameters) => {
return {
$avg: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'min',
allowQuery: false,
type: 'aggr_func',
forceGroup: true,
parse: (parameters) => {
return {
$min: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'max',
type: 'aggr_func',
allowQuery: false,
forceGroup: true,
parse: (parameters) => {
return {
$max: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'number',
},
{
// todo check count
name: 'count',
allowQuery: false,
forceGroup: true,
type: 'function',
parse: (parameter) => {
return {$sum: 1};
},
jsonSchemaReturnType: 'number',
},
{
// todo check count
name: 'count',
allowQuery: false,
forceGroup: true,
type: 'aggr_func',
parse: (parameter) => {
return {$sum: 1};
},
jsonSchemaReturnType: 'number',
},
{
name: 'firstn',
allowQuery: false,
forceGroup: true,
type: 'aggr_func',
parse: (parameters) => {
if (!$check.array(parameters)) {
throw new Error('Invalid parameters for FirstN');
}
if (parameters.length < 1) {
throw new Error('Invalid parameters for FirstN');
}
return {
$firstN: {
input: $check.assigned(parameters[1])
? '$' +
AllowableFunctions._getLiteral(parameters[1])
: '$$ROOT',
n: parameters[0],
},
};
},
jsonSchemaReturnType: (parameters) => {
if (!$check.array(parameters)) {
throw new Error('Invalid parameters for substring');
}
if (parameters.length < 1) {
throw new Error('Invalid parameters for FirstN');
}
if ($check.assigned(parameters[1])) {
return {
type: 'fieldName',
fieldName: parameters[1].value,
};
}
return {
type: 'jsonSchemaValue',
jsonSchemaValue: 'object',
isArray: true,
};
},
},
{
name: 'lastn',
allowQuery: false,
forceGroup: true,
type: 'aggr_func',
parse: (parameters) => {
if (!$check.array(parameters)) {
throw new Error('Invalid parameters for substring');
}
if (parameters.length < 1) {
throw new Error('Invalid parameters for LastN');
}
return {
$lastN: {
input: $check.assigned(parameters[1])
? '$' +
AllowableFunctions._getLiteral(parameters[1])
: '$$ROOT',
n: parameters[0],
},
};
},
jsonSchemaReturnType: (parameters) => {
if (!$check.array(parameters)) {
throw new Error('Invalid parameters for substring');
}
if (parameters.length < 1) {
throw new Error('Invalid parameters for FirstN');
}
if ($check.assigned(parameters[1])) {
return {
type: 'fieldName',
fieldName: parameters[1].value,
};
}
return {
type: 'jsonSchemaValue',
jsonSchemaValue: 'object',
isArray: true,
};
},
},
// ToDo:add aggregate function with
// $addToSet
/* #endregion */
/* #region String Functions */
/*
$strcasecmp
*/
{
name: 'wrapParam',
allowQuery: true,
parse: (parameters) => {
const value = parameters[0];
const forceString = parameters[1]
? parameters[1].$literal
: false;
let unescaped;
if (typeof value === 'object' && value.$literal) {
unescaped = value.$literal;
} else {
unescaped = value.substring(1);
}
unescaped = unescaped
.replace(/\\"/g, '"')
.replace(/\\'/g, "'")
.replace(/\\\\/g, '\\');
if (forceString) {
return unescaped;
}
return {
$literal: unescaped,
};
},
jsonSchemaReturnType: 'string',
},
{
name: 'concat',
parsedName: '$concat',
allowQuery: true,
parse: (parameters) => {
return {$concat: parameters};
},
jsonSchemaReturnType: 'string',
},
{
name: 'join',
allowQuery: true,
parse: (parameters) => {
if (!$check.array(parameters))
throw new Error('Invalid parameters for join');
if (parameters.length !== 2) {
throw new Error(
`Invalid parameter length for join, should be two but was ${parameters.length}`
);
}
const input = parameters[0];
if ($check.emptyString(input) || !$check.string(input)) {
throw new Error(
`The first parameter passed to join should be a non empty string but was ${input}`
);
}
const joinCharacter = parameters[1].$literal;
if (
$check.emptyString(joinCharacter) ||
!$check.string(joinCharacter)
) {
throw new Error(
`The second parameter passed to join should be a non empty string but was ${joinCharacter}`
);
}
return {
$reduce: {
input,
initialValue: '',
in: {
$concat: [
'$$value',
{
$cond: [
{$eq: ['$$value', '']},
'',
joinCharacter,
],
},
'$$this',
],
},
},
};
},
jsonSchemaReturnType: 'string',
},
{
name: 'trim',
allowQuery: true,
parse: (parameters) => {
const params = {
input: AllowableFunctions._getSingleParameter(
parameters
),
};
if (parameters[1]) {
params.chars = parameters[1];
}
return {$trim: params};
},
jsonSchemaReturnType: 'string',
},
{
name: 'ltrim',
allowQuery: true,
parse: (parameters) => {
const params = {
input: AllowableFunctions._getSingleParameter(
parameters
),
};
if (parameters[1]) {
params.chars = parameters[1];
}
return {$ltrim: params};
},
jsonSchemaReturnType: 'string',
},
{
name: 'rtrim',
allowQuery: true,
parse: (parameters) => {
const params = {
input: AllowableFunctions._getSingleParameter(
parameters
),
};
if (parameters[1]) {
params.chars = parameters[1];
}
return {$rtrim: params};
},
jsonSchemaReturnType: 'string',
},
{
name: 'substr',
allowQuery: true,
parse: (parameters) => {
if (!$check.array(parameters))
throw new Error('Invalid parameters for substring');
if (parameters.length !== 3) {
throw new Error(
'Invalid parameters required for substring'
);
}
return {$substr: parameters};
},
jsonSchemaReturnType: 'string',
},
{
name: 'left',
allowQuery: true,
parse: (parameters) => {
if (!$check.array(parameters))
throw new Error('Invalid parameters for left');
if (parameters.length !== 2) {
throw new Error('Invalid parameters required for left');
}
return {$substr: [parameters[0], 0, parameters[1]]};
},
jsonSchemaReturnType: 'string',
},
{
name: 'starts_with',
allowQuery: true,
parse: (parameters) => {
if (!$check.array(parameters))
throw new Error('Invalid parameters for substring');
if (parameters.length !== 2) {
throw new Error('Invalid parameters starts_with');
}
return {
$regexMatch: {
input: parameters[0],
regex: {$concat: [parameters[1], {$literal: '$'}]},
},
};
},
jsonSchemaReturnType: 'boolean',
},
{
name: 'strpos',
allowQuery: true,
parse: (parameters) => {
if (!$check.array(parameters))
throw new Error('Invalid parameters for substring');
if (parameters.length !== 2) {
throw new Error('Invalid parameters starts_with');
}
return {
$add: [{$indexOfCP: parameters}, 1],
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'locate',
allowQuery: true,
parse: (parameters) => {
if (!$check.array(parameters))
throw new Error('Invalid parameters for substring');
if (parameters.length !== 2) {
throw new Error('Invalid parameters starts_with');
}
return {
$add: [{$indexOfCP: [parameters[1], parameters[0]]}, 1],
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'substr_bytes',
allowQuery: true,
parse: (parameters) => {
if (!$check.array(parameters))
throw new Error('Invalid parameters for substring');
if (parameters.length !== 3) {
throw new Error(
'Invalid parameters required for substring'
);
}
return {$substrBytes: parameters};
},
jsonSchemaReturnType: 'string',
},
{
name: 'substr_cp',
allowQuery: true,
parse: (parameters) => {
if (!$check.array(parameters))
throw new Error('Invalid parameters for substring');
if (parameters.length !== 3) {
throw new Error(
'Invalid parameters required for substring'
);
}
return {$substrCP: parameters};
},
jsonSchemaReturnType: 'string',
},
{
name: 'to_upper',
allowQuery: true,
parse: (parameters) => {
return {
$toUpper:
AllowableFunctions._getSingleParameter(parameters),
};
},
jsonSchemaReturnType: 'string',
},
{
name: 'upper',
allowQuery: true,
parse: (parameters) => {
return {
$toUpper:
AllowableFunctions._getSingleParameter(parameters),
};
},
jsonSchemaReturnType: 'string',
},
{
name: 'to_lower',
allowQuery: true,
parse: (parameters) => {
return {
$toLower:
AllowableFunctions._getSingleParameter(parameters),
};
},
jsonSchemaReturnType: 'string',
},
{
name: 'lower',
allowQuery: true,
parse: (parameters) => {
return {
$toLower:
AllowableFunctions._getSingleParameter(parameters),
};
},
jsonSchemaReturnType: 'string',
},
{
name: 'replace',
allowQuery: true,
parse: (parameters) => {
if (!$check.array(parameters))
throw new Error('Invalid parameters for substring');
if (parameters.length !== 3) {
throw new Error(
'Invalid parameters required for substring'
);
}
return {
$replaceOne: {
input: parameters[0],
find: parameters[1],
replacement: parameters[2],
},
};
},
jsonSchemaReturnType: 'string',
},
{
name: 'replace_all',
allowQuery: true,
parse: (parameters) => {
if (!$check.array(parameters))
throw new Error('Invalid parameters for substring');
if (parameters.length !== 3) {
throw new Error(
'Invalid parameters required for substring'
);
}
return {
$replaceAll: {
input: parameters[0],
find: parameters[1],
replacement: parameters[2],
},
};
},
jsonSchemaReturnType: 'string',
},
{
name: 'strlen',
allowQuery: true,
parse: (parameters) => {
return {
$strLenBytes:
AllowableFunctions._getSingleParameter(parameters),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'strlen_cp',
allowQuery: true,
parse: (parameters) => {
return {
$strLenCP:
AllowableFunctions._getSingleParameter(parameters),
};
},
jsonSchemaReturnType: 'number',
},
{
name: 'split',
allowQuery: true,
parse: (parameters) => {
const params = [
AllowableFunctions._getSingleParameter(parameters),
];
if (
$check.array(parameters) &&
parameters[1] &&
parameters[1].$literal !== null
) {
params.push(parameters[1]);
}
return {$split: params};
},
jsonSchemaReturnType: (parameters) => {
return {
type: 'fieldName',
fieldName: parameters[0].column,
isArray: true,
};
},
},
/* #endregion */
/* #region Conversion Functions */
{
name: 'convert',
allowQuery: true,
type: 'function',
parse: (parameters, depth, forceLiteralParse) => {
const toSQLType = parameters[1]
? parameters[1].$literal || parameters[1]
: null;
if (!$check.string(toSQLType)) {
throw new Error('Type not specified for convert');
}
const toType =
AllowableFunctions._sqlTypeMapping[
toSQLType.toLowerCase()
] || toSQLType;
if (!toType) {
throw new Error(`Invalid type for convert:${toType}`);
}
return {$convert: {input: parameters[0], to: toType}};
},
jsonSchemaReturnType: (parameters) => {
const toSQLType = parameters[1]
? parameters[1].$literal || parameters[1].value
: null;
if (!$check.string(toSQLType)) {
throw new Error('Type not specified for convert');
}
const toType =
AllowableFunctions._jsonSchemaTypeMapping[
toSQLType.toLowerCase()
] || toSQLType;
if (!toType) {
throw new Error(`Invalid type for convert:${toType}`);
}
return {
type: 'jsonSchemaValue',
jsonSchemaValue: toType,
isArray: false,
};
},
},
{
name: 'to_date',
allowQuery: true,
parse: (parameters, depth, forceLiteralParse) => {
const paramVal =
AllowableFunctions._getSingleParameter(parameters);
if (
forceLiteralParse &&
AllowableFunctions._isLiteral(paramVal)
) {
try {
return $convert.convert(
AllowableFunctions._getLiteral(paramVal),
'date'
);
} catch (exp) {
throw new Error(
`Error converting ${AllowableFunctions._getLiteral(
paramVal
)} to date`
);
}
} else {
return {
$toDate:
AllowableFunctions._getSingleParameter(
parameters
),
};
}
},
jsonSchemaReturnType: 'date',
},
{
name: 'to_string',
allowQuery: true,
parse: (parameters, depth, forceLiteralParse) => {
const paramVal =
AllowableFunctions._getSingleParameter(parameters);
if (
forceLiteralParse &&
AllowableFunctions._isLiteral(paramVal)
) {
try {
return $convert.convert(
AllowableFunctions._getLiteral(paramVal),
'string'
);
} catch (exp) {
throw new Error(
`Error converting ${AllowableFunctions._getLiteral(
paramVal
)} to string`
);
}
} else {
return {$toString: paramVal};
}
},
jsonSchemaReturnType: 'string',
},
{
name: 'to_decimal',
allowQuery: true,
parse: (parameters, depth, forceLiteralParse) => {
const paramVal =
AllowableFunctions._getSingleParameter(parameters);
if (
forceLiteralParse &&
AllowableFunctions._isLiteral(paramVal)
) {
try {
return $convert.convert(
AllowableFunctions._getLiteral(paramVal),
'number'
);
} catch (exp) {
throw new Error(
`Error converting ${AllowableFunctions._getLiteral(
paramVal
)} to number`
);
}
} else {
return {$toDecimal: paramVal};
}
},
jsonSchemaReturnType: 'number',
},
{
name: 'to_double',
allowQuery: true,
parse: (parameters, depth, forceLiteralParse) => {
const paramVal =
AllowableFunctions._getSingleParameter(parameters);
if (
forceLiteralParse &&
AllowableFunctions._isLiteral(paramVal)
) {
try {
return $convert.convert(
AllowableFunctions._getLiteral(paramVal),
'number'
);
} catch (exp) {
throw new Error(
`Error converting ${AllowableFunctions._getLiteral(
paramVal
)} to number`
);
}
} else {
return {$toDouble: paramVal};
}
},
jsonSchemaReturnType: 'number',
},
{
name: 'to_int',
allowQuery: true,
parse: (parameters, depth, forceLiteralParse) => {
const paramVal =
AllowableFunctions._getSingleParameter(parameters);
if (
forceLiteralParse &&
AllowableFunctions._isLiteral(paramVal)
) {
try {
return $convert.convert(
AllowableFunctions._getLiteral(paramVal),
'integer'
);
} catch (exp) {
throw new Error(
`Error converting ${AllowableFunctions._getLiteral(
paramVal
)} to integer`
);
}
} else {
return {$toInt: paramVal};
}
},
jsonSchemaReturnType: 'number',
},
{
name: 'to_long',
allowQuery: true,
parse: (parameters, depth, forceLiteralParse) => {
const paramVal =
AllowableFunctions._getSingleParameter(parameters);
if (
forceLiteralParse &&
AllowableFunctions._isLiteral(paramVal)
) {
try {
return $convert.convert(
AllowableFunctions._getLiteral(paramVal),
'integer'
);
} catch (exp) {
throw new Error(
`Error converting ${AllowableFunctions._getLiteral(
paramVal
)} to integer`
);
}
} else {
return {$toLong: paramVal};
}
},
jsonSchemaReturnType: 'number',
},
{
name: 'to_bool',
allowQuery: true,
parse: (parameters, depth, forceLiteralParse) => {
const paramVal =
AllowableFunctions._getSingleParameter(parameters);
if (
forceLiteralParse &&
AllowableFunctions._isLiteral(paramVal)
) {
try {
return $convert.convert(
AllowableFunctions._getLiteral(paramVal),
'boolean'
);
} catch (exp) {
throw new Error(
`Error converting ${AllowableFunctions._getLiteral(
paramVal
)} to boolean`
);
}
} else {
return {$toBool: paramVal};
}
},
jsonSchemaReturnType: 'boolean',
},
{
name: 'to_objectid',
allowQuery: true,
parse: (parameters, depth, forceLiteralParse) => {
const paramVal =
AllowableFunctions._getSingleParameter(parameters);
if (
forceLiteralParse &&
AllowableFunctions._isLiteral(paramVal)
) {
try {
const param =
AllowableFunctions._getLiteral(paramVal);
return new ObjectId(param);
} catch (exp) {
throw new Error(
`Error converting ${AllowableFunctions._getLiteral(
paramVal
)} to ObjectId`
);
}
} else {
return {$toObjectId: paramVal};
}
},
jsonSchemaReturnType: 'string',
},
{
name: 'typeof',
allowQuery: true,
parse: (parameters) => {
return {
$type: AllowableFunctions._getSingleParameter(
parameters
),
};
},
jsonSchemaReturnType: 'string',
},
{
name: 'ifnull',
aliases: ['coalesce'],
allowQuery: true,
parse: (parameters) => {
return {$ifNull: parameters};
},
jsonSchemaReturnType: (parameters) => {
if (parameters[0].type === 'column_ref') {
return {
type: 'fieldName',
fieldName: parameters[0].column,
};
}
if (parameters[0].type === 'null') {
if (
[
'single_quote_string',
'string',
'backticks_quote_string',
].includes(parameters[1].type)
) {
return {
type: 'jsonSchemaValue',
jsonSchemaValue: 'string',
};
}