import { SQlComparisons, ServerQueryOperators } from "../types"; const IDENTIFIER_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/; const FIELD_REGEX = /^([A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*|\*)$/; const JOIN_TYPES = ["INNER JOIN", "JOIN", "LEFT JOIN", "RIGHT JOIN"]; /** * # Validate a bare SQL identifier (table, column, alias) * @description Identifiers can't be bound as parameters, so anything that * gets interpolated into SQL must pass this check first. */ export function sqlIdent(name, label = "identifier") { const str = String(name); if (typeof name == "symbol" || !IDENTIFIER_REGEX.test(str)) { throw new Error(`Invalid SQL ${label}: ${JSON.stringify(str)}`); } return str; } /** * # Validate a column reference * @description Accepts `field`, `table.field` or `table.*` */ export function sqlField(name, label = "field name") { const str = String(name); if (typeof name == "symbol" || !FIELD_REGEX.test(str)) { throw new Error(`Invalid SQL ${label}: ${JSON.stringify(str)}`); } return str; } /** * # Quote an identifier for DDL statements */ export function sqlQuoteIdent(name) { return `"${name.replace(/"/g, '""')}"`; } /** * # Quote a string literal */ export function sqlStringLiteral(value) { return `'${value.replace(/'/g, "''")}'`; } /** * # Validate a non-negative integer (LIMIT, OFFSET, page) */ export function sqlInt(value, label = "integer") { const num = Number(value); if (!Number.isSafeInteger(num) || num < 0) { throw new Error(`Invalid SQL ${label}: ${JSON.stringify(value)}`); } return num; } export function sqlOrderStrategy(strategy) { if (strategy === undefined || strategy === null) return "ASC"; const str = String(strategy).toUpperCase(); if (str !== "ASC" && str !== "DESC") { throw new Error(`Invalid SQL order strategy: ${JSON.stringify(strategy)}`); } return str; } export function sqlOperator(operator, fallback = "AND") { if (operator === undefined || operator === null) return fallback; const str = String(operator).toUpperCase(); if (!ServerQueryOperators.includes(str)) { throw new Error(`Invalid SQL operator: ${JSON.stringify(operator)}`); } return str; } export function sqlRawEquality(equality) { if (!SQlComparisons.includes(equality)) { throw new Error(`Invalid SQL comparison: ${JSON.stringify(equality)}`); } return equality; } export function sqlJoinType(joinType) { if (!JOIN_TYPES.includes(joinType)) { throw new Error(`Invalid SQL join type: ${JSON.stringify(joinType)}`); } return joinType; }