export function quoteIdentifier(identifier) { const trimmed = identifier.trim(); if (!trimmed) { throw new Error("SQL identifier must not be empty."); } return `[${trimmed.replaceAll("]", "]]")}]`; } export function qualifyName(schemaName, objectName) { return `${quoteIdentifier(schemaName)}.${quoteIdentifier(objectName)}`; } export function assertSafeSelect(query) { const trimmed = query.trim(); if (!trimmed) { throw new Error("SELECT query must not be empty."); } const withoutTrailingSemicolon = trimmed.replace(/;+\s*$/u, ""); if (withoutTrailingSemicolon.includes(";")) { throw new Error("Only a single SELECT statement is allowed."); } if (!/^(select|with)\b/iu.test(withoutTrailingSemicolon)) { throw new Error("Only SELECT queries or CTE queries starting with WITH are allowed."); } if (/\b(insert|update|delete|merge|drop|alter|create|truncate|exec|execute|grant|revoke)\b/iu.test(withoutTrailingSemicolon)) { throw new Error("SELECT query contains a disallowed mutating keyword."); } } export function buildWhereClause(criteria, prefix) { const entries = Object.entries(criteria).filter(([, value]) => value !== undefined); if (entries.length === 0) { throw new Error("WHERE criteria must include at least one field."); } const params = []; const parts = entries.map(([key, value], index) => { const column = quoteIdentifier(key); if (value === null) { return `${column} IS NULL`; } const name = `${prefix}${index}`; params.push({ name, value }); return `${column} = @${name}`; }); return { clause: parts.join(" AND "), params }; } export function resolveDatabaseName(requested, defaultDatabase, allowedDatabases) { const databaseName = (requested?.trim() || defaultDatabase.trim()); if (!databaseName) { throw new Error("Database name is required."); } if (allowedDatabases.length === 0) { return databaseName; } const match = allowedDatabases.find((allowed) => allowed.toLowerCase() === databaseName.toLowerCase()); if (!match) { throw new Error(`Database '${databaseName}' is not in the configured allowed database list.`); } return match; } export function validateProcedureDefinition(definition, schemaName, procedureName) { const trimmed = definition.trim(); if (!/^(create\s+(or\s+alter\s+)?|alter\s+)proc(edure)?\b/iu.test(trimmed)) { throw new Error("Stored procedure definition must start with CREATE PROCEDURE, ALTER PROCEDURE, or CREATE OR ALTER PROCEDURE."); } const nameMatch = trimmed.match(/^(?:create\s+(?:or\s+alter\s+)?|alter\s+)proc(?:edure)?\s+([^\s(@;]+)/iu); if (!nameMatch) { throw new Error("Stored procedure definition must include a procedure name."); } const normalizedExpected = normalizeObjectName(`${schemaName}.${procedureName}`); const normalizedActual = normalizeObjectName(nameMatch[1]); if (normalizedActual !== normalizedExpected) { throw new Error(`Stored procedure definition name '${nameMatch[1]}' does not match requested name '${schemaName}.${procedureName}'.`); } } function normalizeObjectName(name) { return name .replaceAll("[", "") .replaceAll("]", "") .replaceAll("\"", "") .split(".") .map((part) => part.trim().toLowerCase()) .filter(Boolean) .join("."); } //# sourceMappingURL=sql.js.map