UNPKG

libpg-query

Version:
378 lines (377 loc) • 13.6 kB
/** * DO NOT MODIFY MANUALLY — this is generated from the templates dir * * To make changes, edit the files in the templates/ directory and run: * npm run copy:templates */ export * from "@pgsql/types"; export class SqlError extends Error { sqlDetails; constructor(message, details) { super(message); this.name = 'SqlError'; this.sqlDetails = details; } } export function hasSqlDetails(error) { return error instanceof SqlError && error.sqlDetails !== undefined; } export function formatSqlError(error, query, options = {}) { const { showPosition = true, showQuery = true, color = false, maxQueryLength } = options; const lines = []; // ANSI color codes const red = color ? '\x1b[31m' : ''; const yellow = color ? '\x1b[33m' : ''; const reset = color ? '\x1b[0m' : ''; // Add error message lines.push(`${red}Error: ${error.message}${reset}`); // Add SQL details if available if (error.sqlDetails) { const { cursorPosition, fileName, functionName, lineNumber } = error.sqlDetails; if (cursorPosition !== undefined && cursorPosition >= 0) { lines.push(`Position: ${cursorPosition}`); } if (fileName || functionName || lineNumber) { const details = []; if (fileName) details.push(`file: ${fileName}`); if (functionName) details.push(`function: ${functionName}`); if (lineNumber) details.push(`line: ${lineNumber}`); lines.push(`Source: ${details.join(', ')}`); } // Show query with position marker if (showQuery && showPosition && cursorPosition !== undefined && cursorPosition >= 0) { let displayQuery = query; let adjustedPosition = cursorPosition; // Truncate if needed if (maxQueryLength && query.length > maxQueryLength) { const start = Math.max(0, cursorPosition - Math.floor(maxQueryLength / 2)); const end = Math.min(query.length, start + maxQueryLength); displayQuery = (start > 0 ? '...' : '') + query.substring(start, end) + (end < query.length ? '...' : ''); // Adjust cursor position for truncation adjustedPosition = cursorPosition - start + (start > 0 ? 3 : 0); } lines.push(displayQuery); lines.push(' '.repeat(adjustedPosition) + `${yellow}^${reset}`); } } else if (showQuery) { // No SQL details, just show the query if requested let displayQuery = query; if (maxQueryLength && query.length > maxQueryLength) { displayQuery = query.substring(0, maxQueryLength) + '...'; } lines.push(`Query: ${displayQuery}`); } return lines.join('\n'); } // @ts-ignore import PgQueryModule from './libpg-query.js'; let wasmModule; const initPromise = PgQueryModule().then((module) => { wasmModule = module; }); function ensureLoaded() { if (!wasmModule) throw new Error("WASM module not initialized. Call `loadModule()` first."); } export async function loadModule() { if (!wasmModule) { await initPromise; } } function awaitInit(fn) { return (async (...args) => { await initPromise; return fn(...args); }); } function stringToPtr(str) { ensureLoaded(); if (typeof str !== 'string') { throw new TypeError(`Expected a string, got ${typeof str}`); } const len = wasmModule.lengthBytesUTF8(str) + 1; const ptr = wasmModule._malloc(len); try { wasmModule.stringToUTF8(str, ptr, len); return ptr; } catch (error) { wasmModule._free(ptr); throw error; } } function ptrToString(ptr) { ensureLoaded(); if (typeof ptr !== 'number') { throw new TypeError(`Expected a number, got ${typeof ptr}`); } return wasmModule.UTF8ToString(ptr); } export const parse = awaitInit(async (query) => { // Input validation if (query === null || query === undefined) { throw new Error('Query cannot be null or undefined'); } if (query === '') { throw new Error('Query cannot be empty'); } const queryPtr = stringToPtr(query); let resultPtr = 0; try { resultPtr = wasmModule._wasm_parse_query_raw(queryPtr); if (!resultPtr) { throw new Error('Failed to parse query: memory allocation failed'); } // Read the PgQueryParseResult struct const parseTreePtr = wasmModule.getValue(resultPtr, 'i32'); const stderrBufferPtr = wasmModule.getValue(resultPtr + 4, 'i32'); const errorPtr = wasmModule.getValue(resultPtr + 8, 'i32'); if (errorPtr) { // Read PgQueryError struct const messagePtr = wasmModule.getValue(errorPtr, 'i32'); const funcnamePtr = wasmModule.getValue(errorPtr + 4, 'i32'); const filenamePtr = wasmModule.getValue(errorPtr + 8, 'i32'); const lineno = wasmModule.getValue(errorPtr + 12, 'i32'); const cursorpos = wasmModule.getValue(errorPtr + 16, 'i32'); const message = messagePtr ? wasmModule.UTF8ToString(messagePtr) : 'Unknown error'; const funcname = funcnamePtr ? wasmModule.UTF8ToString(funcnamePtr) : undefined; const filename = filenamePtr ? wasmModule.UTF8ToString(filenamePtr) : undefined; throw new SqlError(message, { message, cursorPosition: cursorpos > 0 ? cursorpos - 1 : 0, // Convert to 0-based fileName: filename, functionName: funcname, lineNumber: lineno > 0 ? lineno : undefined }); } if (!parseTreePtr) { throw new Error('No parse tree generated'); } const parseTreeStr = wasmModule.UTF8ToString(parseTreePtr); return JSON.parse(parseTreeStr); } finally { wasmModule._free(queryPtr); if (resultPtr) { wasmModule._wasm_free_parse_result(resultPtr); } } }); export const parsePlPgSQL = awaitInit(async (query) => { const queryPtr = stringToPtr(query); let resultPtr = 0; try { resultPtr = wasmModule._wasm_parse_plpgsql(queryPtr); const resultStr = ptrToString(resultPtr); // Success is always a JSON object; anything else is an error message if (!resultStr.startsWith('{')) { throw new Error(resultStr); } return JSON.parse(resultStr); } finally { wasmModule._free(queryPtr); if (resultPtr) { wasmModule._wasm_free_string(resultPtr); } } }); export const fingerprint = awaitInit(async (query) => { const queryPtr = stringToPtr(query); let resultPtr = 0; try { resultPtr = wasmModule._wasm_fingerprint(queryPtr); const resultStr = ptrToString(resultPtr); if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.startsWith('ERROR')) { throw new Error(resultStr); } return resultStr; } finally { wasmModule._free(queryPtr); if (resultPtr) { wasmModule._wasm_free_string(resultPtr); } } }); export const normalize = awaitInit(async (query) => { const queryPtr = stringToPtr(query); let resultPtr = 0; try { resultPtr = wasmModule._wasm_normalize_query(queryPtr); const resultStr = ptrToString(resultPtr); if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.startsWith('ERROR')) { throw new Error(resultStr); } return resultStr; } finally { wasmModule._free(queryPtr); if (resultPtr) { wasmModule._wasm_free_string(resultPtr); } } }); // Sync versions export function parseSync(query) { if (!wasmModule) { throw new Error('WASM module not initialized. Call loadModule() first.'); } // Input validation if (query === null || query === undefined) { throw new Error('Query cannot be null or undefined'); } if (query === '') { throw new Error('Query cannot be empty'); } const queryPtr = stringToPtr(query); let resultPtr = 0; try { resultPtr = wasmModule._wasm_parse_query_raw(queryPtr); if (!resultPtr) { throw new Error('Failed to parse query: memory allocation failed'); } // Read the PgQueryParseResult struct const parseTreePtr = wasmModule.getValue(resultPtr, 'i32'); const stderrBufferPtr = wasmModule.getValue(resultPtr + 4, 'i32'); const errorPtr = wasmModule.getValue(resultPtr + 8, 'i32'); if (errorPtr) { // Read PgQueryError struct const messagePtr = wasmModule.getValue(errorPtr, 'i32'); const funcnamePtr = wasmModule.getValue(errorPtr + 4, 'i32'); const filenamePtr = wasmModule.getValue(errorPtr + 8, 'i32'); const lineno = wasmModule.getValue(errorPtr + 12, 'i32'); const cursorpos = wasmModule.getValue(errorPtr + 16, 'i32'); const message = messagePtr ? wasmModule.UTF8ToString(messagePtr) : 'Unknown error'; const funcname = funcnamePtr ? wasmModule.UTF8ToString(funcnamePtr) : undefined; const filename = filenamePtr ? wasmModule.UTF8ToString(filenamePtr) : undefined; throw new SqlError(message, { message, cursorPosition: cursorpos > 0 ? cursorpos - 1 : 0, // Convert to 0-based fileName: filename, functionName: funcname, lineNumber: lineno > 0 ? lineno : undefined }); } if (!parseTreePtr) { throw new Error('No parse tree generated'); } const parseTreeStr = wasmModule.UTF8ToString(parseTreePtr); return JSON.parse(parseTreeStr); } finally { wasmModule._free(queryPtr); if (resultPtr) { wasmModule._wasm_free_parse_result(resultPtr); } } } export function parsePlPgSQLSync(query) { if (!wasmModule) { throw new Error('WASM module not initialized. Call loadModule() first.'); } const queryPtr = stringToPtr(query); let resultPtr = 0; try { resultPtr = wasmModule._wasm_parse_plpgsql(queryPtr); const resultStr = ptrToString(resultPtr); // Success is always a JSON object; anything else is an error message if (!resultStr.startsWith('{')) { throw new Error(resultStr); } return JSON.parse(resultStr); } finally { wasmModule._free(queryPtr); if (resultPtr) { wasmModule._wasm_free_string(resultPtr); } } } export function fingerprintSync(query) { if (!wasmModule) { throw new Error('WASM module not initialized. Call loadModule() first.'); } const queryPtr = stringToPtr(query); let resultPtr = 0; try { resultPtr = wasmModule._wasm_fingerprint(queryPtr); const resultStr = ptrToString(resultPtr); if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.startsWith('ERROR')) { throw new Error(resultStr); } return resultStr; } finally { wasmModule._free(queryPtr); if (resultPtr) { wasmModule._wasm_free_string(resultPtr); } } } export function normalizeSync(query) { if (!wasmModule) { throw new Error('WASM module not initialized. Call loadModule() first.'); } const queryPtr = stringToPtr(query); let resultPtr = 0; try { resultPtr = wasmModule._wasm_normalize_query(queryPtr); const resultStr = ptrToString(resultPtr); if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.startsWith('ERROR')) { throw new Error(resultStr); } return resultStr; } finally { wasmModule._free(queryPtr); if (resultPtr) { wasmModule._wasm_free_string(resultPtr); } } } export const scan = awaitInit(async (query) => { const queryPtr = stringToPtr(query); let resultPtr = 0; try { resultPtr = wasmModule._wasm_scan(queryPtr); const resultStr = ptrToString(resultPtr); if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.startsWith('ERROR')) { throw new Error(resultStr); } return JSON.parse(resultStr); } finally { wasmModule._free(queryPtr); if (resultPtr) { wasmModule._wasm_free_string(resultPtr); } } }); export function scanSync(query) { if (!wasmModule) { throw new Error('WASM module not initialized. Call loadModule() first.'); } const queryPtr = stringToPtr(query); let resultPtr = 0; try { resultPtr = wasmModule._wasm_scan(queryPtr); const resultStr = ptrToString(resultPtr); if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.startsWith('ERROR')) { throw new Error(resultStr); } return JSON.parse(resultStr); } finally { wasmModule._free(queryPtr); if (resultPtr) { wasmModule._wasm_free_string(resultPtr); } } }