libpg-query
Version:
The real PostgreSQL query parser
407 lines (406 loc) • 15 kB
JavaScript
;
/**
* 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
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.scan = exports.normalize = exports.fingerprint = exports.parsePlPgSQL = exports.parse = exports.SqlError = void 0;
exports.hasSqlDetails = hasSqlDetails;
exports.formatSqlError = formatSqlError;
exports.loadModule = loadModule;
exports.parseSync = parseSync;
exports.parsePlPgSQLSync = parsePlPgSQLSync;
exports.fingerprintSync = fingerprintSync;
exports.normalizeSync = normalizeSync;
exports.scanSync = scanSync;
__exportStar(require("@pgsql/types"), exports);
class SqlError extends Error {
sqlDetails;
constructor(message, details) {
super(message);
this.name = 'SqlError';
this.sqlDetails = details;
}
}
exports.SqlError = SqlError;
function hasSqlDetails(error) {
return error instanceof SqlError && error.sqlDetails !== undefined;
}
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
const libpg_query_js_1 = __importDefault(require("./libpg-query.js"));
let wasmModule;
const initPromise = (0, libpg_query_js_1.default)().then((module) => {
wasmModule = module;
});
function ensureLoaded() {
if (!wasmModule)
throw new Error("WASM module not initialized. Call `loadModule()` first.");
}
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);
}
exports.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);
}
}
});
exports.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);
}
}
});
exports.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);
}
}
});
exports.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
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);
}
}
}
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);
}
}
}
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);
}
}
}
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);
}
}
}
exports.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);
}
}
});
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);
}
}
}