node-sql-parser
Version:
simple node sql parser
260 lines (259 loc) • 10.4 kB
JavaScript
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define(["exports", "./collate", "./constrain", "./expr", "./func", "./tables", "./util"], factory);
} else if (typeof exports !== "undefined") {
factory(exports, require("./collate"), require("./constrain"), require("./expr"), require("./func"), require("./tables"), require("./util"));
} else {
var mod = {
exports: {}
};
factory(mod.exports, global.collate, global.constrain, global.expr, global.func, global.tables, global.util);
global.column = mod.exports;
}
})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _collate, _constrain, _expr, _func, _tables, _util) {
"use strict";
Object.defineProperty(_exports, "__esModule", {
value: true
});
_exports.arrayIndexToSQL = arrayIndexToSQL;
_exports.asToSQL = asToSQL;
_exports.columnDataType = columnDataType;
_exports.columnDefinitionToSQL = columnDefinitionToSQL;
_exports.columnOffsetToSQL = columnOffsetToSQL;
_exports.columnOrderToSQL = columnOrderToSQL;
_exports.columnRefToSQL = columnRefToSQL;
_exports.columnReferenceDefinitionToSQL = columnReferenceDefinitionToSQL;
_exports.columnToSQL = columnToSQL;
_exports.columnsToSQL = columnsToSQL;
_exports.fullTextSearchToSQL = fullTextSearchToSQL;
_exports.getDual = getDual;
function columnOffsetToSQL(column, isDual) {
if (typeof column === 'string') return (0, _util.identifierToSql)(column, isDual);
const {
expr,
offset,
suffix
} = column;
const offsetExpr = offset && offset.map(offsetItem => ['[', offsetItem.name, `${offsetItem.name ? '(' : ''}`, (0, _util.literalToSQL)(offsetItem.value), `${offsetItem.name ? ')' : ''}`, ']'].filter(_util.hasVal).join('')).join('');
const result = [(0, _expr.exprToSQL)(expr), offsetExpr, suffix].filter(_util.hasVal).join('');
return result;
}
function arrayIndexToSQL(arrayIndexList) {
if (!arrayIndexList || arrayIndexList.length === 0) return '';
const result = [];
for (const arrayIndex of arrayIndexList) {
let arrayIndexStr = arrayIndex.brackets ? `[${(0, _expr.exprToSQL)(arrayIndex.index)}]` : `${arrayIndex.notation}${(0, _expr.exprToSQL)(arrayIndex.index)}`;
if (arrayIndex.property) arrayIndexStr = `${arrayIndexStr}.${(0, _util.literalToSQL)(arrayIndex.property)}`;
result.push(arrayIndexStr);
}
return result.join('');
}
function columnRefToSQL(expr) {
const {
array_index,
as,
column,
collate,
db,
isDual,
notations = [],
options,
schema,
table,
parentheses,
suffix,
order_by,
subFields = []
} = expr;
let str = column === '*' ? '*' : columnOffsetToSQL(column, isDual);
const prefix = [db, schema, table].filter(_util.hasVal).map(val => `${typeof val === 'string' ? (0, _util.identifierToSql)(val) : (0, _expr.exprToSQL)(val)}`);
let prefixStr = prefix[0];
if (prefixStr) {
let i = 1;
for (; i < prefix.length; ++i) {
prefixStr = `${prefixStr}${notations[i] || '.'}${prefix[i]}`;
}
str = `${prefixStr}${notations[i] || '.'}${str}`;
}
str = [`${str}${arrayIndexToSQL(array_index)}`, ...subFields].join('.');
const result = [str, (0, _collate.collateToSQL)(collate), (0, _expr.exprToSQL)(options), (0, _util.commonOptionConnector)('AS', _expr.exprToSQL, as)];
result.push(typeof suffix === 'string' ? (0, _util.toUpper)(suffix) : (0, _expr.exprToSQL)(suffix));
result.push((0, _util.toUpper)(order_by));
const sql = result.filter(_util.hasVal).join(' ');
return parentheses ? `(${sql})` : sql;
}
function columnDataType(definition) {
if (!definition) return;
const {
dataType,
length,
suffix,
scale,
expr
} = definition;
const parentheses = length != null && true || false;
let result = (0, _util.dataTypeToSQL)({
dataType,
length,
suffix,
scale,
parentheses
});
if (expr) result += (0, _expr.exprToSQL)(expr);
if (definition.array) {
const arrayExpr = (0, _func.arrayDimensionToSymbol)(definition);
const space = /^\[.*\]$/.test(arrayExpr) ? '' : ' ';
result += [space, arrayExpr].join('');
}
return result;
}
function columnReferenceDefinitionToSQL(referenceDefinition) {
const reference = [];
if (!referenceDefinition) return reference;
const {
definition,
keyword,
match,
table,
on_action: onAction
} = referenceDefinition;
reference.push((0, _util.toUpper)(keyword));
reference.push((0, _tables.tablesToSQL)(table));
reference.push(definition && `(${definition.map(col => (0, _expr.exprToSQL)(col)).join(', ')})`);
reference.push((0, _util.toUpper)(match));
onAction.map(onRef => reference.push((0, _util.toUpper)(onRef.type), (0, _expr.exprToSQL)(onRef.value)));
return reference.filter(_util.hasVal);
}
function generatedExpressionToSQL(generated) {
if (!generated) return;
const result = [(0, _util.toUpper)(generated.value), `(${(0, _expr.exprToSQL)(generated.expr)})`, (0, _util.toUpper)(generated.storage_type)];
return result.filter(_util.hasVal).join(' ');
}
function columnOption(definition) {
const columnOpt = [];
const {
nullable,
character_set: characterSet,
check,
comment,
constraint,
collate,
storage,
using,
default_val: defaultOpt,
generated,
auto_increment: autoIncrement,
unique: uniqueKey,
primary_key: primaryKey,
column_format: columnFormat,
reference_definition: referenceDefinition,
generated_by_default: generateByDefault
} = definition;
const nullSQL = [(0, _util.toUpper)(nullable && nullable.action), (0, _util.toUpper)(nullable && nullable.value)].filter(_util.hasVal).join(' ');
if (!generated) columnOpt.push(nullSQL);
if (defaultOpt) {
const {
type,
value
} = defaultOpt;
columnOpt.push(type.toUpperCase(), (0, _expr.exprToSQL)(value));
}
const {
database
} = (0, _util.getParserOpt)();
if (constraint) columnOpt.push((0, _util.toUpper)(constraint.keyword), (0, _util.literalToSQL)(constraint.constraint));
columnOpt.push((0, _constrain.constraintDefinitionToSQL)(check));
columnOpt.push(generatedExpressionToSQL(generated));
if (generated) columnOpt.push(nullSQL);
columnOpt.push((0, _util.autoIncrementToSQL)(autoIncrement), (0, _util.toUpper)(primaryKey), (0, _util.toUpper)(uniqueKey), (0, _util.literalToSQL)(generateByDefault), (0, _util.commentToSQL)(comment));
columnOpt.push(...(0, _util.commonTypeValue)(characterSet));
if (database.toLowerCase() !== 'sqlite') columnOpt.push((0, _expr.exprToSQL)(collate));
columnOpt.push(...(0, _util.commonTypeValue)(columnFormat));
columnOpt.push(...(0, _util.commonTypeValue)(storage));
columnOpt.push(...columnReferenceDefinitionToSQL(referenceDefinition));
columnOpt.push((0, _util.commonOptionConnector)('USING', _expr.exprToSQL, using));
return columnOpt.filter(_util.hasVal).join(' ');
}
function columnOrderToSQL(columnOrder) {
const {
column,
collate,
nulls,
opclass,
order_by
} = columnOrder;
const columnExpr = typeof column === 'string' ? {
type: 'column_ref',
table: columnOrder.table,
column
} : columnOrder;
columnExpr.collate = null;
const result = [(0, _expr.exprToSQL)(columnExpr), (0, _expr.exprToSQL)(collate), opclass, (0, _util.toUpper)(order_by), (0, _util.toUpper)(nulls)];
return result.filter(_util.hasVal).join(' ');
}
function columnDefinitionToSQL(columnDefinition) {
const column = [];
const name = columnRefToSQL(columnDefinition.column);
const dataType = columnDataType(columnDefinition.definition);
column.push(name);
column.push(dataType);
column.push(columnOption(columnDefinition));
return column.filter(_util.hasVal).join(' ');
}
function asToSQL(asStr) {
if (!asStr) return '';
if (typeof asStr === 'object') return ['AS', (0, _expr.exprToSQL)(asStr)].join(' ');
return ['AS', /^(`?)[a-z_][0-9a-z_]*(`?)$/i.test(asStr) ? (0, _util.identifierToSql)(asStr) : (0, _util.columnIdentifierToSql)(asStr)].join(' ');
}
function fullTextSearchToSQL(expr) {
const {
against,
as,
columns,
match,
mode
} = expr;
const matchExpr = [(0, _util.toUpper)(match), `(${columns.map(col => columnRefToSQL(col)).join(', ')})`].join(' ');
const againstExpr = [(0, _util.toUpper)(against), ['(', (0, _expr.exprToSQL)(expr.expr), mode && ` ${(0, _util.literalToSQL)(mode)}`, ')'].filter(_util.hasVal).join('')].join(' ');
return [matchExpr, againstExpr, asToSQL(as)].filter(_util.hasVal).join(' ');
}
function columnToSQL(column, isDual) {
const {
expr,
type
} = column;
if (type === 'cast') return (0, _func.castToSQL)(column);
if (isDual) expr.isDual = isDual;
let str = (0, _expr.exprToSQL)(expr);
const {
expr_list: exprList
} = column;
if (exprList) {
const result = [str];
const columnsStr = exprList.map(col => columnToSQL(col, isDual)).join(', ');
result.push([(0, _util.toUpper)(type), type && '(', columnsStr, type && ')'].filter(_util.hasVal).join(''));
return result.filter(_util.hasVal).join(' ');
}
if (expr.parentheses && Reflect.has(expr, 'array_index') && expr.type !== 'cast') str = `(${str})`;
if (expr.array_index && expr.type !== 'column_ref' && expr.type !== 'function') {
str = `${str}${arrayIndexToSQL(expr.array_index)}`;
}
return [str, asToSQL(column.as)].filter(_util.hasVal).join(' ');
}
function getDual(tables) {
const baseTable = Array.isArray(tables) && tables[0];
if (baseTable && baseTable.type === 'dual') return true;
return false;
}
/**
* Stringify column expressions
*
* @param {Array} columns
* @return {string}
*/
function columnsToSQL(columns, tables) {
if (!columns || columns === '*') return columns;
const isDual = getDual(tables);
return columns.map(col => columnToSQL(col, isDual)).join(', ');
}
});