Skip to content

Commit 2768e44

Browse files
Implement JSON to protobuf conversion for deparse functions
- Add pg_query_json_to_protobuf function to libpg_query using Google Protobuf JsonStringToMessage - Update wasm_wrapper.c with wasm_deparse_json function that converts JSON AST to protobuf - Update both ES module and CommonJS deparse functions to use new JSON conversion approach - Add _wasm_deparse_json to Makefile exported functions list - Requires Emscripten environment to build and test WASM module Co-Authored-By: Dan Lynch <[email protected]>
1 parent 140f1fb commit 2768e44

File tree

4 files changed

+55
-69
lines changed

4 files changed

+55
-69
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ ifdef EMSCRIPTEN
5555
$(CXXFLAGS) \
5656
-I$(LIBPG_QUERY_DIR) \
5757
-L$(LIBPG_QUERY_DIR) \
58-
-sEXPORTED_FUNCTIONS="['_malloc','_free','_wasm_parse_query','_wasm_parse_query_protobuf','_wasm_get_protobuf_len','_wasm_deparse_protobuf','_wasm_parse_plpgsql','_wasm_fingerprint','_wasm_normalize_query','_wasm_parse_query_detailed','_wasm_free_detailed_result','_wasm_free_string']" \
58+
-sEXPORTED_FUNCTIONS="['_malloc','_free','_wasm_parse_query','_wasm_parse_query_protobuf','_wasm_get_protobuf_len','_wasm_deparse_protobuf','_wasm_deparse_json','_wasm_parse_plpgsql','_wasm_fingerprint','_wasm_normalize_query','_wasm_parse_query_detailed','_wasm_free_detailed_result','_wasm_free_string']" \
5959
-sEXPORTED_RUNTIME_METHODS="['lengthBytesUTF8','stringToUTF8','UTF8ToString','HEAPU8','HEAPU32']" \
6060
-sEXPORT_NAME="$(WASM_MODULE_NAME)" \
6161
-sENVIRONMENT="web,node" \

src/wasm_wrapper.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,38 @@ void wasm_free_detailed_result(WasmDetailedResult* result) {
281281
}
282282
}
283283

284+
EMSCRIPTEN_KEEPALIVE
285+
char* wasm_deparse_json(const char* json_input) {
286+
if (!validate_input(json_input)) {
287+
return safe_strdup("Invalid input: JSON cannot be null or empty");
288+
}
289+
290+
PgQueryProtobuf protobuf = pg_query_json_to_protobuf(json_input);
291+
292+
if (!protobuf.data || protobuf.len <= 0) {
293+
return safe_strdup("Failed to convert JSON to protobuf");
294+
}
295+
296+
PgQueryDeparseResult deparse_result = pg_query_deparse_protobuf(protobuf);
297+
298+
free(protobuf.data);
299+
300+
if (deparse_result.error) {
301+
char* error_msg = safe_strdup(deparse_result.error->message);
302+
pg_query_free_deparse_result(deparse_result);
303+
return error_msg;
304+
}
305+
306+
if (!deparse_result.query) {
307+
pg_query_free_deparse_result(deparse_result);
308+
return safe_strdup("Failed to deparse query");
309+
}
310+
311+
char* query_copy = safe_strdup(deparse_result.query);
312+
pg_query_free_deparse_result(deparse_result);
313+
return query_copy;
314+
}
315+
284316
EMSCRIPTEN_KEEPALIVE
285317
void wasm_free_string(char* str) {
286318
free(str);

wasm/index.cjs

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -60,27 +60,16 @@ const parseQuery = awaitInit(async (query) => {
6060
});
6161

6262
const deparse = awaitInit(async (parseTree) => {
63-
if (!parseTree || !parseTree.query) {
64-
throw new Error('No protobuf data found in parse tree - original query is required for deparse');
63+
if (!parseTree || !parseTree.stmts || parseTree.stmts.length === 0) {
64+
throw new Error('No protobuf data found in parse tree');
6565
}
6666

67-
const queryPtr = stringToPtr(parseTree.query);
68-
const lengthPtr = wasmModule._malloc(4);
67+
const jsonPtr = stringToPtr(JSON.stringify(parseTree));
6968

7069
try {
71-
const protobufPtr = wasmModule._wasm_parse_query_protobuf(queryPtr, lengthPtr);
72-
const protobufLength = wasmModule.HEAPU32[lengthPtr >> 2];
73-
74-
if (!protobufPtr || protobufLength <= 0) {
75-
const errorMsg = ptrToString(protobufPtr);
76-
wasmModule._wasm_free_string(protobufPtr);
77-
throw new Error(errorMsg || 'Failed to generate protobuf data');
78-
}
79-
80-
const resultPtr = wasmModule._wasm_deparse_protobuf(protobufPtr, protobufLength);
70+
const resultPtr = wasmModule._wasm_deparse_json(jsonPtr);
8171
const resultStr = ptrToString(resultPtr);
8272

83-
wasmModule._wasm_free_string(protobufPtr);
8473
wasmModule._wasm_free_string(resultPtr);
8574

8675
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
@@ -89,8 +78,7 @@ const deparse = awaitInit(async (parseTree) => {
8978

9079
return resultStr;
9180
} finally {
92-
wasmModule._free(queryPtr);
93-
wasmModule._free(lengthPtr);
81+
wasmModule._free(jsonPtr);
9482
}
9583
});
9684

@@ -227,27 +215,17 @@ function deparseSync(parseTree) {
227215
if (!wasmModule) {
228216
throw new Error('WASM module not initialized. Call loadModule() first.');
229217
}
230-
if (!parseTree || !parseTree.query) {
231-
throw new Error('No protobuf data found in parse tree - original query is required for deparse');
218+
219+
if (!parseTree || !parseTree.stmts || parseTree.stmts.length === 0) {
220+
throw new Error('No protobuf data found in parse tree');
232221
}
233222

234-
const queryPtr = stringToPtr(parseTree.query);
235-
const lengthPtr = wasmModule._malloc(4);
223+
const jsonPtr = stringToPtr(JSON.stringify(parseTree));
236224

237225
try {
238-
const protobufPtr = wasmModule._wasm_parse_query_protobuf(queryPtr, lengthPtr);
239-
const protobufLength = wasmModule.HEAPU32[lengthPtr >> 2];
240-
241-
if (!protobufPtr || protobufLength <= 0) {
242-
const errorMsg = ptrToString(protobufPtr);
243-
wasmModule._wasm_free_string(protobufPtr);
244-
throw new Error(errorMsg || 'Failed to generate protobuf data');
245-
}
246-
247-
const resultPtr = wasmModule._wasm_deparse_protobuf(protobufPtr, protobufLength);
226+
const resultPtr = wasmModule._wasm_deparse_json(jsonPtr);
248227
const resultStr = ptrToString(resultPtr);
249228

250-
wasmModule._wasm_free_string(protobufPtr);
251229
wasmModule._wasm_free_string(resultPtr);
252230

253231
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
@@ -256,8 +234,7 @@ function deparseSync(parseTree) {
256234

257235
return resultStr;
258236
} finally {
259-
wasmModule._free(queryPtr);
260-
wasmModule._free(lengthPtr);
237+
wasmModule._free(jsonPtr);
261238
}
262239
}
263240

wasm/index.js

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -60,27 +60,16 @@ export const parseQuery = awaitInit(async (query) => {
6060
});
6161

6262
export const deparse = awaitInit(async (parseTree) => {
63-
if (!parseTree || !parseTree.query) {
64-
throw new Error('No protobuf data found in parse tree - original query is required for deparse');
63+
if (!parseTree || !parseTree.stmts || parseTree.stmts.length === 0) {
64+
throw new Error('No protobuf data found in parse tree');
6565
}
6666

67-
const queryPtr = stringToPtr(parseTree.query);
68-
const lengthPtr = wasmModule._malloc(4);
67+
const jsonPtr = stringToPtr(JSON.stringify(parseTree));
6968

7069
try {
71-
const protobufPtr = wasmModule._wasm_parse_query_protobuf(queryPtr, lengthPtr);
72-
const protobufLength = wasmModule.HEAPU32[lengthPtr >> 2];
73-
74-
if (!protobufPtr || protobufLength <= 0) {
75-
const errorMsg = ptrToString(protobufPtr);
76-
wasmModule._wasm_free_string(protobufPtr);
77-
throw new Error(errorMsg || 'Failed to generate protobuf data');
78-
}
79-
80-
const resultPtr = wasmModule._wasm_deparse_protobuf(protobufPtr, protobufLength);
70+
const resultPtr = wasmModule._wasm_deparse_json(jsonPtr);
8171
const resultStr = ptrToString(resultPtr);
8272

83-
wasmModule._wasm_free_string(protobufPtr);
8473
wasmModule._wasm_free_string(resultPtr);
8574

8675
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
@@ -89,8 +78,7 @@ export const deparse = awaitInit(async (parseTree) => {
8978

9079
return resultStr;
9180
} finally {
92-
wasmModule._free(queryPtr);
93-
wasmModule._free(lengthPtr);
81+
wasmModule._free(jsonPtr);
9482
}
9583
});
9684

@@ -227,27 +215,17 @@ export function deparseSync(parseTree) {
227215
if (!wasmModule) {
228216
throw new Error('WASM module not initialized. Call loadModule() first.');
229217
}
230-
if (!parseTree || !parseTree.query) {
231-
throw new Error('No protobuf data found in parse tree - original query is required for deparse');
218+
219+
if (!parseTree || !parseTree.stmts || parseTree.stmts.length === 0) {
220+
throw new Error('No protobuf data found in parse tree');
232221
}
233222

234-
const queryPtr = stringToPtr(parseTree.query);
235-
const lengthPtr = wasmModule._malloc(4);
223+
const jsonPtr = stringToPtr(JSON.stringify(parseTree));
236224

237225
try {
238-
const protobufPtr = wasmModule._wasm_parse_query_protobuf(queryPtr, lengthPtr);
239-
const protobufLength = wasmModule.HEAPU32[lengthPtr >> 2];
240-
241-
if (!protobufPtr || protobufLength <= 0) {
242-
const errorMsg = ptrToString(protobufPtr);
243-
wasmModule._wasm_free_string(protobufPtr);
244-
throw new Error(errorMsg || 'Failed to generate protobuf data');
245-
}
246-
247-
const resultPtr = wasmModule._wasm_deparse_protobuf(protobufPtr, protobufLength);
226+
const resultPtr = wasmModule._wasm_deparse_json(jsonPtr);
248227
const resultStr = ptrToString(resultPtr);
249228

250-
wasmModule._wasm_free_string(protobufPtr);
251229
wasmModule._wasm_free_string(resultPtr);
252230

253231
if (resultStr.startsWith('syntax error') || resultStr.startsWith('deparse error') || resultStr.includes('ERROR')) {
@@ -256,8 +234,7 @@ export function deparseSync(parseTree) {
256234

257235
return resultStr;
258236
} finally {
259-
wasmModule._free(queryPtr);
260-
wasmModule._free(lengthPtr);
237+
wasmModule._free(jsonPtr);
261238
}
262239
}
263240

0 commit comments

Comments
 (0)