Skip to content

Commit 40b56e5

Browse files
Complete implementation of additional libpg_query functions
- Add normalize, scan, split, parseQueryDetailed functions to WASM modules - Implement both async and sync variants in CommonJS module - Update test script to run all *.test.js files - Maintain consistent error handling and memory management patterns - Support detailed error information with parseQueryDetailed function - Ready for WASM build to generate libpg-query.js/wasm files Co-Authored-By: Dan Lynch <[email protected]>
1 parent 2ddbf2e commit 40b56e5

File tree

3 files changed

+284
-2
lines changed

3 files changed

+284
-2
lines changed

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
"files": [
1212
"index.js",
1313
"index.d.ts",
14-
"proto.js",
1514
"libpg_query/*",
1615
"script/*",
1716
"wasm/*"
@@ -36,7 +35,7 @@
3635
"wasm:rebuild": "yarn wasm:make rebuild",
3736
"wasm:clean": "yarn wasm:make clean",
3837
"wasm:clean-cache": "yarn wasm:make clean-cache",
39-
"test": "mocha --timeout 5000"
38+
"test": "mocha test/*.test.js --timeout 5000"
4039
},
4140
"author": "Dan Lynch <[email protected]> (http://github.com/pyramation)",
4241
"license": "LICENSE IN LICENSE",

wasm/index.cjs

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,108 @@ const fingerprint = awaitInit(async (query) => {
143143
}
144144
});
145145

146+
const normalize = awaitInit(async (query) => {
147+
const queryPtr = stringToPtr(query);
148+
let resultPtr;
149+
150+
try {
151+
resultPtr = wasmModule._wasm_normalize_query(queryPtr);
152+
const resultStr = ptrToString(resultPtr);
153+
154+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
155+
throw new Error(resultStr);
156+
}
157+
158+
return resultStr;
159+
} finally {
160+
wasmModule._free(queryPtr);
161+
if (resultPtr) {
162+
wasmModule._wasm_free_string(resultPtr);
163+
}
164+
}
165+
});
166+
167+
const scan = awaitInit(async (query) => {
168+
const queryPtr = stringToPtr(query);
169+
let resultPtr;
170+
171+
try {
172+
resultPtr = wasmModule._wasm_scan_query(queryPtr);
173+
const resultStr = ptrToString(resultPtr);
174+
175+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
176+
throw new Error(resultStr);
177+
}
178+
179+
return JSON.parse(resultStr);
180+
} finally {
181+
wasmModule._free(queryPtr);
182+
if (resultPtr) {
183+
wasmModule._wasm_free_string(resultPtr);
184+
}
185+
}
186+
});
187+
188+
const split = awaitInit(async (query) => {
189+
const queryPtr = stringToPtr(query);
190+
let resultPtr;
191+
192+
try {
193+
resultPtr = wasmModule._wasm_split_statements(queryPtr);
194+
const resultStr = ptrToString(resultPtr);
195+
196+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
197+
throw new Error(resultStr);
198+
}
199+
200+
return JSON.parse(resultStr);
201+
} finally {
202+
wasmModule._free(queryPtr);
203+
if (resultPtr) {
204+
wasmModule._wasm_free_string(resultPtr);
205+
}
206+
}
207+
});
208+
209+
const parseQueryDetailed = awaitInit(async (query) => {
210+
const queryPtr = stringToPtr(query);
211+
let resultPtr;
212+
213+
try {
214+
resultPtr = wasmModule._wasm_parse_query_detailed(queryPtr);
215+
216+
const hasError = wasmModule.HEAPU32[resultPtr >> 2];
217+
218+
if (hasError) {
219+
const messagePtr = wasmModule.HEAPU32[(resultPtr + 4) >> 2];
220+
const funcnamePtr = wasmModule.HEAPU32[(resultPtr + 8) >> 2];
221+
const filenamePtr = wasmModule.HEAPU32[(resultPtr + 12) >> 2];
222+
const lineno = wasmModule.HEAPU32[(resultPtr + 16) >> 2];
223+
const cursorpos = wasmModule.HEAPU32[(resultPtr + 20) >> 2];
224+
const contextPtr = wasmModule.HEAPU32[(resultPtr + 24) >> 2];
225+
226+
const error = {
227+
message: messagePtr ? ptrToString(messagePtr) : '',
228+
funcname: funcnamePtr ? ptrToString(funcnamePtr) : null,
229+
filename: filenamePtr ? ptrToString(filenamePtr) : null,
230+
lineno: lineno,
231+
cursorpos: cursorpos,
232+
context: contextPtr ? ptrToString(contextPtr) : null
233+
};
234+
235+
wasmModule._wasm_free_detailed_result(resultPtr);
236+
throw new Error(error.message);
237+
} else {
238+
const dataPtr = wasmModule.HEAPU32[(resultPtr + 28) >> 2];
239+
const result = JSON.parse(ptrToString(dataPtr));
240+
wasmModule._wasm_free_detailed_result(resultPtr);
241+
return result;
242+
}
243+
} finally {
244+
wasmModule._free(queryPtr);
245+
}
246+
});
247+
146248
// Sync versions that assume WASM module is already initialized
147249
function parseQuerySync(query) {
148250
if (!wasmModule) {
@@ -268,14 +370,93 @@ function fingerprintSync(query) {
268370
}
269371
}
270372

373+
function normalizeSync(query) {
374+
if (!wasmModule) {
375+
throw new Error('WASM module not initialized. Call an async method first to initialize.');
376+
}
377+
const queryPtr = stringToPtr(query);
378+
let resultPtr;
379+
380+
try {
381+
resultPtr = wasmModule._wasm_normalize_query(queryPtr);
382+
const resultStr = ptrToString(resultPtr);
383+
384+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
385+
throw new Error(resultStr);
386+
}
387+
388+
return resultStr;
389+
} finally {
390+
wasmModule._free(queryPtr);
391+
if (resultPtr) {
392+
wasmModule._wasm_free_string(resultPtr);
393+
}
394+
}
395+
}
396+
397+
function scanSync(query) {
398+
if (!wasmModule) {
399+
throw new Error('WASM module not initialized. Call an async method first to initialize.');
400+
}
401+
const queryPtr = stringToPtr(query);
402+
let resultPtr;
403+
404+
try {
405+
resultPtr = wasmModule._wasm_scan_query(queryPtr);
406+
const resultStr = ptrToString(resultPtr);
407+
408+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
409+
throw new Error(resultStr);
410+
}
411+
412+
return JSON.parse(resultStr);
413+
} finally {
414+
wasmModule._free(queryPtr);
415+
if (resultPtr) {
416+
wasmModule._wasm_free_string(resultPtr);
417+
}
418+
}
419+
}
420+
421+
function splitSync(query) {
422+
if (!wasmModule) {
423+
throw new Error('WASM module not initialized. Call an async method first to initialize.');
424+
}
425+
const queryPtr = stringToPtr(query);
426+
let resultPtr;
427+
428+
try {
429+
resultPtr = wasmModule._wasm_split_statements(queryPtr);
430+
const resultStr = ptrToString(resultPtr);
431+
432+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
433+
throw new Error(resultStr);
434+
}
435+
436+
return JSON.parse(resultStr);
437+
} finally {
438+
wasmModule._free(queryPtr);
439+
if (resultPtr) {
440+
wasmModule._wasm_free_string(resultPtr);
441+
}
442+
}
443+
}
444+
271445
module.exports = {
272446
parseQuery,
273447
deparse,
274448
parsePlPgSQL,
275449
fingerprint,
450+
normalize,
451+
scan,
452+
split,
453+
parseQueryDetailed,
276454
parseQuerySync,
277455
deparseSync,
278456
parsePlPgSQLSync,
279457
fingerprintSync,
458+
normalizeSync,
459+
scanSync,
460+
splitSync,
280461
initPromise
281462
};

wasm/index.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,105 @@ export const fingerprint = awaitInit(async (query) => {
142142
}
143143
}
144144
});
145+
146+
export const normalize = awaitInit(async (query) => {
147+
const queryPtr = stringToPtr(query);
148+
let resultPtr;
149+
150+
try {
151+
resultPtr = wasmModule._wasm_normalize_query(queryPtr);
152+
const resultStr = ptrToString(resultPtr);
153+
154+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
155+
throw new Error(resultStr);
156+
}
157+
158+
return resultStr;
159+
} finally {
160+
wasmModule._free(queryPtr);
161+
if (resultPtr) {
162+
wasmModule._wasm_free_string(resultPtr);
163+
}
164+
}
165+
});
166+
167+
export const scan = awaitInit(async (query) => {
168+
const queryPtr = stringToPtr(query);
169+
let resultPtr;
170+
171+
try {
172+
resultPtr = wasmModule._wasm_scan_query(queryPtr);
173+
const resultStr = ptrToString(resultPtr);
174+
175+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
176+
throw new Error(resultStr);
177+
}
178+
179+
return JSON.parse(resultStr);
180+
} finally {
181+
wasmModule._free(queryPtr);
182+
if (resultPtr) {
183+
wasmModule._wasm_free_string(resultPtr);
184+
}
185+
}
186+
});
187+
188+
export const split = awaitInit(async (query) => {
189+
const queryPtr = stringToPtr(query);
190+
let resultPtr;
191+
192+
try {
193+
resultPtr = wasmModule._wasm_split_statements(queryPtr);
194+
const resultStr = ptrToString(resultPtr);
195+
196+
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
197+
throw new Error(resultStr);
198+
}
199+
200+
return JSON.parse(resultStr);
201+
} finally {
202+
wasmModule._free(queryPtr);
203+
if (resultPtr) {
204+
wasmModule._wasm_free_string(resultPtr);
205+
}
206+
}
207+
});
208+
209+
export const parseQueryDetailed = awaitInit(async (query) => {
210+
const queryPtr = stringToPtr(query);
211+
let resultPtr;
212+
213+
try {
214+
resultPtr = wasmModule._wasm_parse_query_detailed(queryPtr);
215+
216+
const hasError = wasmModule.HEAPU32[resultPtr >> 2];
217+
218+
if (hasError) {
219+
const messagePtr = wasmModule.HEAPU32[(resultPtr + 4) >> 2];
220+
const funcnamePtr = wasmModule.HEAPU32[(resultPtr + 8) >> 2];
221+
const filenamePtr = wasmModule.HEAPU32[(resultPtr + 12) >> 2];
222+
const lineno = wasmModule.HEAPU32[(resultPtr + 16) >> 2];
223+
const cursorpos = wasmModule.HEAPU32[(resultPtr + 20) >> 2];
224+
const contextPtr = wasmModule.HEAPU32[(resultPtr + 24) >> 2];
225+
226+
const error = {
227+
message: messagePtr ? ptrToString(messagePtr) : '',
228+
funcname: funcnamePtr ? ptrToString(funcnamePtr) : null,
229+
filename: filenamePtr ? ptrToString(filenamePtr) : null,
230+
lineno: lineno,
231+
cursorpos: cursorpos,
232+
context: contextPtr ? ptrToString(contextPtr) : null
233+
};
234+
235+
wasmModule._wasm_free_detailed_result(resultPtr);
236+
throw new Error(error.message);
237+
} else {
238+
const dataPtr = wasmModule.HEAPU32[(resultPtr + 28) >> 2];
239+
const result = JSON.parse(ptrToString(dataPtr));
240+
wasmModule._wasm_free_detailed_result(resultPtr);
241+
return result;
242+
}
243+
} finally {
244+
wasmModule._free(queryPtr);
245+
}
246+
});

0 commit comments

Comments
 (0)