@@ -483,28 +483,67 @@ interface ExternalQueryResponse {
483483// Converts a raw result (from an external HTTP endpoint) into a QueryResult.
484484const rawResultToJSON = ( rawResult : string ) : QueryResult => {
485485 try {
486- const parsed : unknown = JSON . parse ( rawResult ) ;
486+ // Try parsing as single JSON first (standard format)
487+ let parsed : Partial < ExternalQueryResponse > ;
487488
488- if ( ! parsed || typeof parsed !== 'object' ) {
489- throw new Error ( "Invalid raw result format: not a valid JSON object" ) ;
490- }
489+ try {
490+ parsed = JSON . parse ( rawResult ) ;
491+ } catch ( singleJsonError ) {
492+ // If single JSON fails, try NDJSON (newline-delimited JSON)
493+ // DuckDB httpserver may return multiple JSON objects, one per line
494+ const lines = rawResult . trim ( ) . split ( '\n' ) . filter ( line => line . trim ( ) ) ;
495+
496+ if ( lines . length === 0 ) {
497+ throw new Error ( "Empty response" ) ;
498+ }
491499
492- const response = parsed as Partial < ExternalQueryResponse > ;
500+ // Parse each line as JSON
501+ const objects = lines . map ( ( line , idx ) => {
502+ try {
503+ return JSON . parse ( line ) ;
504+ } catch {
505+ throw new Error ( `Failed to parse line ${ idx + 1 } : ${ line . substring ( 0 , 50 ) } ...` ) ;
506+ }
507+ } ) ;
493508
494- if (
495- ! response . meta ||
496- ! response . data ||
497- ! Array . isArray ( response . meta ) ||
498- ! Array . isArray ( response . data )
499- ) {
500- throw new Error (
501- "Invalid raw result format: meta or data are missing or have the wrong format"
509+ // Find the result object (has meta and data)
510+ const resultObj = objects . find (
511+ ( obj ) : obj is ExternalQueryResponse =>
512+ obj && typeof obj === 'object' && 'meta' in obj && 'data' in obj
502513 ) ;
514+
515+ if ( resultObj ) {
516+ parsed = resultObj ;
517+ } else {
518+ // If no single result object, try to merge (meta from one, data from others)
519+ const metaObj = objects . find ( obj => obj ?. meta ) ;
520+ const dataObj = objects . find ( obj => obj ?. data ) ;
521+
522+ if ( metaObj && dataObj ) {
523+ parsed = {
524+ meta : metaObj . meta ,
525+ data : dataObj . data ,
526+ rows : dataObj . rows || dataObj . data ?. length || 0 ,
527+ } ;
528+ } else {
529+ throw singleJsonError ; // Re-throw original error
530+ }
531+ }
532+ }
533+
534+ // Validate required fields
535+ if ( ! parsed || typeof parsed !== 'object' ) {
536+ throw new Error ( "Invalid response: not a valid JSON object" ) ;
537+ }
538+
539+ if ( ! parsed . meta || ! parsed . data || ! Array . isArray ( parsed . meta ) || ! Array . isArray ( parsed . data ) ) {
540+ throw new Error ( "Invalid response: meta or data missing or wrong format" ) ;
503541 }
504542
505- const columns = response . meta . map ( m => m . name ) ;
506- const columnTypes = response . meta . map ( m => m . type ) ;
507- const data = response . data . map ( ( row : unknown ) => {
543+ // Convert to QueryResult format
544+ const columns = parsed . meta . map ( m => m . name ) ;
545+ const columnTypes = parsed . meta . map ( m => m . type ) ;
546+ const data = parsed . data . map ( ( row : unknown ) => {
508547 if ( ! Array . isArray ( row ) ) {
509548 throw new Error ( "Invalid row format: expected array" ) ;
510549 }
@@ -519,13 +558,11 @@ const rawResultToJSON = (rawResult: string): QueryResult => {
519558 columns,
520559 columnTypes,
521560 data,
522- rowCount : response . rows || data . length ,
561+ rowCount : parsed . rows || data . length ,
523562 } ;
524563 } catch ( error ) {
525564 throw new Error (
526- `Failed to parse raw result: ${
527- error instanceof Error ? error . message : "Unknown error"
528- } `
565+ `Failed to parse raw result: ${ error instanceof Error ? error . message : "Unknown error" } `
529566 ) ;
530567 }
531568} ;
0 commit comments