@sequelize/core
Version:
Sequelize is a promise-based Node.js ORM tool for Postgres, MySQL, MariaDB, SQLite, Microsoft SQL Server, Amazon Redshift, Snowflake’s Data Cloud, Db2, Oracle, and IBM i. It features solid transaction support, relations, eager and lazy loading, read repli
386 lines (385 loc) • 13.3 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var sql_exports = {};
__export(sql_exports, {
assertNoReservedBind: () => assertNoReservedBind,
combineBinds: () => combineBinds,
createBindParamGenerator: () => createBindParamGenerator,
createNamedParamBindCollector: () => createNamedParamBindCollector,
createSpecifiedOrderedBindCollector: () => createSpecifiedOrderedBindCollector,
createUnspecifiedOrderedBindCollector: () => createUnspecifiedOrderedBindCollector,
escapeMysqlMariaDbString: () => escapeMysqlMariaDbString,
formatDb2StyleLimitOffset: () => formatDb2StyleLimitOffset,
formatMySqlStyleLimitOffset: () => formatMySqlStyleLimitOffset,
injectReplacements: () => injectReplacements,
mapBindParameters: () => mapBindParameters,
withSqliteForeignKeysOff: () => withSqliteForeignKeysOff
});
module.exports = __toCommonJS(sql_exports);
var import_isPlainObject = __toESM(require("lodash/isPlainObject"));
var import_base_sql_expression = require("../expression-builders/base-sql-expression.js");
function mapBindParametersAndReplacements(sqlString, dialect, replacements, onBind, options) {
const isNamedReplacements = (0, import_isPlainObject.default)(replacements);
const isPositionalReplacements = Array.isArray(replacements);
const escapeOptions = { replacements };
let lastConsumedPositionalReplacementIndex = -1;
let output = "";
let currentDollarStringTagName = null;
let isString = false;
let isColumn = false;
let previousSliceEnd = 0;
let isSingleLineComment = false;
let isCommentBlock = false;
let stringIsBackslashEscapable = false;
for (let i = 0; i < sqlString.length; i++) {
const char = sqlString[i];
if (isColumn) {
if (char === dialect.TICK_CHAR_RIGHT) {
isColumn = false;
}
continue;
}
if (isString) {
if (char === `'` && (!stringIsBackslashEscapable || !isBackslashEscaped(sqlString, i - 1))) {
isString = false;
stringIsBackslashEscapable = false;
}
continue;
}
if (currentDollarStringTagName !== null) {
if (char !== "$") {
continue;
}
const remainingString = sqlString.slice(i, sqlString.length);
const dollarStringStartMatch = remainingString.match(/^\$(?<name>[a-z_][0-9a-z_]*)?(\$)/i);
const tagName = dollarStringStartMatch?.groups?.name ?? "";
if (currentDollarStringTagName === tagName) {
currentDollarStringTagName = null;
}
continue;
}
if (isSingleLineComment) {
if (char === "\n") {
isSingleLineComment = false;
}
continue;
}
if (isCommentBlock) {
if (char === "*" && sqlString[i + 1] === "/") {
isCommentBlock = false;
}
continue;
}
if (char === dialect.TICK_CHAR_LEFT) {
isColumn = true;
continue;
}
if (char === `'`) {
isString = true;
stringIsBackslashEscapable = // all ''-style strings in this dialect can be backslash escaped
dialect.canBackslashEscape() || // checking if this is a postgres-style E-prefixed string, which also supports backslash escaping
dialect.supports.escapeStringConstants && // is this a E-prefixed string, such as `E'abc'`, `e'abc'` ?
(sqlString[i - 1] === "E" || sqlString[i - 1] === "e") && // reject things such as `AE'abc'` (the prefix must be exactly E)
canPrecedeNewToken(sqlString[i - 2]);
continue;
}
if (char === "-" && sqlString.slice(i, i + 3) === "-- ") {
isSingleLineComment = true;
continue;
}
if (char === "/" && sqlString.slice(i, i + 2) === "/*") {
isCommentBlock = true;
continue;
}
if (char === "$") {
const previousChar = sqlString[i - 1];
if (/[0-9a-z_]/i.test(previousChar)) {
continue;
}
const remainingString = sqlString.slice(i, sqlString.length);
const dollarStringStartMatch = remainingString.match(/^\$(?<name>[a-z_][0-9a-z_]*)?\$/i);
if (dollarStringStartMatch) {
currentDollarStringTagName = dollarStringStartMatch.groups?.name ?? "";
i += dollarStringStartMatch[0].length - 1;
continue;
}
if (onBind) {
if (!canPrecedeNewToken(previousChar)) {
continue;
}
const match = remainingString.match(
/^\$(?<name>([a-z_][0-9a-z_]*|[1-9][0-9]*))(?:\]|\)|,|$|\s|::|;)/i
);
const bindParamName = match?.groups?.name;
if (!bindParamName) {
continue;
}
const newName = onBind(bindParamName);
output += sqlString.slice(previousSliceEnd, i);
previousSliceEnd = i + bindParamName.length + 1;
output += newName;
}
continue;
}
if (isNamedReplacements && char === ":") {
const previousChar = sqlString[i - 1];
if (!canPrecedeNewToken(previousChar) && previousChar !== "[") {
continue;
}
const remainingString = sqlString.slice(i, sqlString.length);
const match = remainingString.match(/^:(?<name>[a-z_][0-9a-z_]*)(?:\)|,|$|\s|::|;|])/i);
const replacementName = match?.groups?.name;
if (!replacementName) {
continue;
}
const replacementValue = replacements[replacementName];
if (!Object.hasOwn(replacements, replacementName) || replacementValue === void 0) {
throw new Error(
`Named replacement ":${replacementName}" has no entry in the replacement map.`
);
}
const escapedReplacement = escapeValueWithBackCompat(
replacementValue,
dialect,
escapeOptions
);
output += sqlString.slice(previousSliceEnd, i);
previousSliceEnd = i + replacementName.length + 1;
output += escapedReplacement;
continue;
}
if (isPositionalReplacements && char === "?") {
const previousChar = sqlString[i - 1];
if (!canPrecedeNewToken(previousChar) && previousChar !== "[") {
continue;
}
const nextChar = sqlString[i + 1];
if (nextChar === "|" || nextChar === "&") {
continue;
}
if (options?.onPositionalReplacement) {
options.onPositionalReplacement();
}
const replacementIndex = ++lastConsumedPositionalReplacementIndex;
const replacementValue = replacements[lastConsumedPositionalReplacementIndex];
if (replacementValue === void 0) {
throw new Error(
`Positional replacement (?) ${replacementIndex} has no entry in the replacement map (replacements[${replacementIndex}] is undefined).`
);
}
const escapedReplacement = escapeValueWithBackCompat(
replacementValue,
dialect,
escapeOptions
);
output += sqlString.slice(previousSliceEnd, i);
previousSliceEnd = i + 1;
output += escapedReplacement;
}
}
if (isString) {
throw new Error(
`The following SQL query includes an unterminated string literal:
${sqlString}`
);
}
output += sqlString.slice(previousSliceEnd, sqlString.length);
return output;
}
function escapeValueWithBackCompat(value, dialect, escapeOptions) {
if (Array.isArray(value) && value.some((item) => item instanceof import_base_sql_expression.BaseSqlExpression)) {
return value.map((item) => dialect.queryGenerator.escape(item, escapeOptions)).join(", ");
}
return dialect.queryGenerator.escape(value, escapeOptions);
}
function canPrecedeNewToken(char) {
return char === void 0 || /[\s([>,=]/.test(char);
}
function mapBindParameters(sqlString, dialect) {
const parameterCollector = dialect.createBindCollector();
const parameterSet = /* @__PURE__ */ new Set();
const newSql = mapBindParametersAndReplacements(
sqlString,
dialect,
void 0,
(foundBindParamName) => {
parameterSet.add(foundBindParamName);
return parameterCollector.collect(foundBindParamName);
}
);
return { sql: newSql, bindOrder: parameterCollector.getBindParameterOrder(), parameterSet };
}
function injectReplacements(sqlString, dialect, replacements, opts) {
if (replacements == null) {
return sqlString;
}
if (!Array.isArray(replacements) && !(0, import_isPlainObject.default)(replacements)) {
throw new TypeError(
`"replacements" must be an array or a plain object, but received ${JSON.stringify(replacements)} instead.`
);
}
return mapBindParametersAndReplacements(sqlString, dialect, replacements, void 0, opts);
}
function isBackslashEscaped(string, pos) {
let escaped = false;
for (let i = pos; i >= 0; i--) {
const char = string[i];
if (char !== "\\") {
break;
}
escaped = !escaped;
}
return escaped;
}
function createUnspecifiedOrderedBindCollector(token = "?") {
const parameterOrder = [];
return {
collect(bindParameterName) {
parameterOrder.push(bindParameterName);
return token;
},
getBindParameterOrder() {
return parameterOrder;
}
};
}
function createSpecifiedOrderedBindCollector(prefix = "$") {
const parameterOrder = [];
return {
collect(bindParameterName) {
const cachedPosition = parameterOrder.indexOf(bindParameterName);
if (cachedPosition === -1) {
parameterOrder.push(bindParameterName);
return `${prefix}${parameterOrder.length}`;
}
return `${prefix}${cachedPosition + 1}`;
},
getBindParameterOrder() {
return parameterOrder;
}
};
}
function createNamedParamBindCollector(parameterPrefix) {
return {
collect(bindParameterName) {
return parameterPrefix + bindParameterName;
},
getBindParameterOrder() {
return null;
}
};
}
function assertNoReservedBind(bind) {
if (Array.isArray(bind)) {
return;
}
for (const key of Object.keys(bind)) {
if (key.startsWith("sequelize_")) {
throw new Error(
'Bind parameters cannot start with "sequelize_", these bind parameters are reserved by Sequelize.'
);
}
}
}
function combineBinds(bindA, bindB) {
if (Array.isArray(bindA)) {
bindA = arrayBindToNamedBind(bindA);
}
return {
...bindA,
...bindB
};
}
function arrayBindToNamedBind(bind) {
const out = /* @__PURE__ */ Object.create(null);
for (let i = 0; i < bind.length; i++) {
out[i + 1] = bind[i];
}
return out;
}
function escapeMysqlMariaDbString(value) {
value = value.replaceAll(/[\b\0\t\n\r\u001A'\\]/g, (s) => {
switch (s) {
case "\0":
return "\\0";
case "\n":
return "\\n";
case "\r":
return "\\r";
case "\b":
return "\\b";
case " ":
return "\\t";
case "":
return "\\Z";
default:
return `\\${s}`;
}
});
return `'${value}'`;
}
function formatDb2StyleLimitOffset(options, queryGenerator) {
let fragment = "";
if (options.offset) {
fragment += ` OFFSET ${queryGenerator.escape(options.offset, options)} ROWS`;
}
if (options.limit != null) {
fragment += ` FETCH NEXT ${queryGenerator.escape(options.limit, options)} ROWS ONLY`;
}
return fragment;
}
function formatMySqlStyleLimitOffset(options, queryGenerator) {
let fragment = "";
if (options.limit != null) {
fragment += ` LIMIT ${queryGenerator.escape(options.limit, options)}`;
} else if (options.offset) {
fragment += ` LIMIT 18446744073709551615`;
}
if (options.offset) {
fragment += ` OFFSET ${queryGenerator.escape(options.offset, options)}`;
}
return fragment;
}
async function withSqliteForeignKeysOff(sequelize, options, cb) {
try {
await sequelize.queryRaw("PRAGMA foreign_keys = OFF", options);
return await cb();
} finally {
await sequelize.queryRaw("PRAGMA foreign_keys = ON", options);
}
}
function createBindParamGenerator(bind, preserveNumbering = false) {
let i = preserveNumbering ? Object.keys(bind).length : 0;
return (value) => {
const bindName = `sequelize_${++i}`;
bind[bindName] = value;
return `$${bindName}`;
};
}
//# sourceMappingURL=sql.js.map