UNPKG

n8n

Version:

n8n Workflow Automation Tool

260 lines 9.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.toDslColumns = toDslColumns; exports.isValidColumnName = isValidColumnName; exports.addColumnQuery = addColumnQuery; exports.deleteColumnQuery = deleteColumnQuery; exports.renameColumnQuery = renameColumnQuery; exports.quoteIdentifier = quoteIdentifier; exports.extractReturningData = extractReturningData; exports.extractInsertedIds = extractInsertedIds; exports.normalizeRows = normalizeRows; exports.normalizeValueForDatabase = normalizeValueForDatabase; exports.toSqliteGlobFromPercent = toSqliteGlobFromPercent; exports.escapeLikeSpecials = escapeLikeSpecials; exports.toTableName = toTableName; exports.toTableId = toTableId; const api_types_1 = require("@n8n/api-types"); const config_1 = require("@n8n/config"); const db_1 = require("@n8n/db"); const di_1 = require("@n8n/di"); const n8n_workflow_1 = require("n8n-workflow"); const not_found_error_1 = require("../../../errors/response-errors/not-found.error"); function toDslColumns(columns) { return columns.map((col) => { const name = new db_1.DslColumn(col.name.trim()); switch (col.type) { case 'number': return name.double; case 'boolean': return name.bool; case 'string': return name.text; case 'date': return name.timestampTimezone(); default: return name.text; } }); } function dataTableColumnTypeToSql(type, dbType) { switch (type) { case 'string': return 'TEXT'; case 'number': switch (dbType) { case 'postgres': return 'DOUBLE PRECISION'; case 'mysql': case 'mariadb': return 'DOUBLE'; case 'sqlite': return 'REAL'; default: return 'DOUBLE'; } case 'boolean': return 'BOOLEAN'; case 'date': if (dbType === 'postgres') { return 'TIMESTAMP'; } return 'DATETIME'; default: throw new not_found_error_1.NotFoundError(`Unsupported field type: ${type}`); } } function columnToWildcardAndType(column, dbType) { return `${quoteIdentifier(column.name, dbType)} ${dataTableColumnTypeToSql(column.type, dbType)}`; } function isValidColumnName(name) { return api_types_1.dataTableColumnNameSchema.safeParse(name).success; } function addColumnQuery(tableName, column, dbType) { if (!isValidColumnName(column.name)) { throw new n8n_workflow_1.UnexpectedError(api_types_1.DATA_TABLE_COLUMN_ERROR_MESSAGE); } const quotedTableName = quoteIdentifier(tableName, dbType); return `ALTER TABLE ${quotedTableName} ADD ${columnToWildcardAndType(column, dbType)}`; } function deleteColumnQuery(tableName, column, dbType) { const quotedTableName = quoteIdentifier(tableName, dbType); return `ALTER TABLE ${quotedTableName} DROP COLUMN ${quoteIdentifier(column, dbType)}`; } function renameColumnQuery(tableName, oldColumnName, newColumnName, dbType) { if (!isValidColumnName(oldColumnName) || !isValidColumnName(newColumnName)) { throw new n8n_workflow_1.UnexpectedError(api_types_1.DATA_TABLE_COLUMN_ERROR_MESSAGE); } const quotedTableName = quoteIdentifier(tableName, dbType); const quotedOldName = quoteIdentifier(oldColumnName, dbType); const quotedNewName = quoteIdentifier(newColumnName, dbType); return `ALTER TABLE ${quotedTableName} RENAME COLUMN ${quotedOldName} TO ${quotedNewName}`; } function quoteIdentifier(name, dbType) { switch (dbType) { case 'mysql': case 'mariadb': return `\`${name}\``; case 'postgres': case 'sqlite': default: return `"${name}"`; } } const isArrayOf = (data, itemGuard) => Array.isArray(data) && data.every(itemGuard); const isNumber = (value) => { return typeof value === 'number' && Number.isFinite(value); }; const isDate = (value) => { return value instanceof Date; }; function hasInsertId(data) { return typeof data === 'object' && data !== null && 'insertId' in data && isNumber(data.insertId); } function hasRowReturnData(data) { return (typeof data === 'object' && data !== null && 'id' in data && isNumber(data.id) && 'createdAt' in data && (isDate(data.createdAt) || typeof data.createdAt === 'string') && 'updatedAt' in data && (isDate(data.updatedAt) || typeof data.updatedAt === 'string')); } function hasRowId(data) { return typeof data === 'object' && data !== null && 'id' in data && isNumber(data.id); } function extractReturningData(raw) { if (!isArrayOf(raw, hasRowReturnData)) { throw new n8n_workflow_1.UnexpectedError(`Expected INSERT INTO raw to be { id: number; createdAt: string; updatedAt: string }[] on Postgres or MariaDB. Is '${JSON.stringify(raw)}'`); } return raw; } function extractInsertedIds(raw, dbType) { switch (dbType) { case 'postgres': case 'mariadb': { if (!isArrayOf(raw, hasRowId)) { throw new n8n_workflow_1.UnexpectedError(`Expected INSERT INTO raw to be { id: number }[] on Postgres or MariaDB. Is '${JSON.stringify(raw)}'`); } return raw.map((r) => r.id); } case 'mysql': { if (!hasInsertId(raw)) { throw new n8n_workflow_1.UnexpectedError('Expected INSERT INTO raw.insertId: number for MySQL'); } return [raw.insertId]; } case 'sqlite': default: { if (!isNumber(raw)) { throw new n8n_workflow_1.UnexpectedError('Expected INSERT INTO raw to be a number for SQLite'); } return [raw]; } } } function normalizeDate(value) { if (value instanceof Date) return value; if (typeof value === 'string') { const parsed = new Date(value.endsWith('Z') ? value : value + 'Z'); if (!isNaN(parsed.getTime())) return parsed; } if (typeof value === 'number') { const parsed = new Date(value); if (!isNaN(parsed.getTime())) return parsed; } return null; } function normalizeRows(rows, columns) { const typeMap = { ...Object.fromEntries(columns.map((col) => [col.name, col.type])), ...n8n_workflow_1.DATA_TABLE_SYSTEM_COLUMN_TYPE_MAP, }; return rows.map((row) => { const { id, createdAt, updatedAt, ...rest } = row; const normalized = { ...rest, id, createdAt: normalizeDate(createdAt) ?? new Date(), updatedAt: normalizeDate(updatedAt) ?? new Date(), }; for (const [key, value] of Object.entries(rest)) { const type = typeMap[key]; if (type === 'boolean') { if (typeof value === 'boolean') { normalized[key] = value; } else if (value === 1 || value === '1') { normalized[key] = true; } else if (value === 0 || value === '0') { normalized[key] = false; } } if (type === 'date' && value !== null && value !== undefined) { normalized[key] = normalizeDate(value) ?? value; } } return normalized; }); } function formatDateForDatabase(value, dbType) { let date; if (value instanceof Date) { date = value; } else if (typeof value === 'string') { date = new Date(value); } else { throw new n8n_workflow_1.UnexpectedError(`Expected Date object or ISO date string, got ${typeof value}: ${String(value)}`); } if (isNaN(date.getTime())) { throw new n8n_workflow_1.UnexpectedError(`Invalid date: ${String(value)}`); } if (dbType && ['sqlite', 'sqlite-pooled', 'mysql', 'mariadb'].includes(dbType)) { return date.toISOString().replace('T', ' ').replace('Z', ''); } return date.toISOString(); } function normalizeValueForDatabase(value, columnType, dbType) { if (columnType === 'date' && value !== null) { return formatDateForDatabase(value, dbType); } return value; } function toSqliteGlobFromPercent(input) { const out = []; for (const ch of String(input ?? '')) { if (ch === '%') out.push('*'); else if (ch === '[') out.push('[[]'); else if (ch === ']') out.push('[]]'); else if (ch === '*') out.push('[*]'); else if (ch === '?') out.push('[?]'); else out.push(ch); } return out.join(''); } function escapeLikeSpecials(input) { return input .replace(/\\/g, '\\\\') .replace(/_/g, '\\_'); } function toTableName(dataTableId) { const { tablePrefix } = di_1.Container.get(config_1.GlobalConfig).database; return `${tablePrefix}data_table_user_${dataTableId}`; } function toTableId(tableName) { return tableName.replace(/.*data_table_user_/, ''); } //# sourceMappingURL=sql-utils.js.map