@@ -438,11 +438,12 @@ describe('Browser SpiceClient', () => {
438438
439439 describe ( 'NSQL (Natural Language SQL)' , ( ) => {
440440 test ( 'should execute NSQL query' , async ( ) => {
441+ // Shape the runtime returns for application/vnd.spiceai.nsql.v1+json.
441442 const mockResponse = {
442- sql : 'SELECT * FROM users LIMIT 10' ,
443- schema : [ { name : 'id' , data_type : 'Int32' } ] ,
444- rows : [ [ 1 ] ] ,
445443 row_count : 1 ,
444+ schema : { fields : [ { name : 'id' , data_type : 'Int32' } ] } ,
445+ data : [ { id : 1 } ] ,
446+ sql : 'SELECT * FROM users LIMIT 10' ,
446447 } ;
447448
448449 ( global . fetch as jest . Mock ) . mockResolvedValueOnce ( {
@@ -457,16 +458,70 @@ describe('Browser SpiceClient', () => {
457458
458459 const result = await client . nsql ( 'show me users' ) ;
459460
460- expect ( result ) . toHaveProperty ( 'sql' ) ;
461461 expect ( result . sql ) . toBe ( 'SELECT * FROM users LIMIT 10' ) ;
462+ expect ( result . row_count ) . toBe ( 1 ) ;
463+ expect ( result . data ) . toEqual ( [ { id : 1 } ] ) ;
464+ expect ( result . schema . fields ) . toEqual ( [ { name : 'id' , data_type : 'Int32' } ] ) ;
462465 expect ( global . fetch ) . toHaveBeenCalledWith (
463466 'http://localhost:8090/v1/nsql' ,
464467 expect . objectContaining ( {
465468 method : 'POST' ,
469+ headers : expect . objectContaining ( {
470+ Accept : 'application/vnd.spiceai.nsql.v1+json' ,
471+ } ) ,
466472 } ) ,
467473 ) ;
468474 } ) ;
469475
476+ test ( 'should normalize a bare row array into the documented shape' , async ( ) => {
477+ // What the runtime sends when the Accept header is absent or stripped.
478+ const rows = [ { id : 1 } , { id : 2 } ] ;
479+
480+ ( global . fetch as jest . Mock ) . mockResolvedValueOnce ( {
481+ ok : true ,
482+ status : 200 ,
483+ headers : {
484+ get : jest . fn ( ) ,
485+ } ,
486+ text : jest . fn ( ) . mockResolvedValue ( JSON . stringify ( rows ) ) ,
487+ json : jest . fn ( ) . mockResolvedValue ( rows ) ,
488+ } ) ;
489+
490+ const result = await client . nsql ( 'show me users' ) ;
491+
492+ expect ( result . data ) . toEqual ( rows ) ;
493+ expect ( result . row_count ) . toBe ( 2 ) ;
494+ expect ( result . schema . fields ) . toEqual ( [ ] ) ;
495+ expect ( result . sql ) . toBe ( '' ) ;
496+ } ) ;
497+
498+ test ( 'should tolerate an empty result set' , async ( ) => {
499+ // The runtime omits schema fields entirely when no rows are returned.
500+ const mockResponse = {
501+ row_count : 0 ,
502+ schema : { } ,
503+ data : [ ] ,
504+ sql : 'SELECT * FROM users WHERE false' ,
505+ } ;
506+
507+ ( global . fetch as jest . Mock ) . mockResolvedValueOnce ( {
508+ ok : true ,
509+ status : 200 ,
510+ headers : {
511+ get : jest . fn ( ) ,
512+ } ,
513+ text : jest . fn ( ) . mockResolvedValue ( JSON . stringify ( mockResponse ) ) ,
514+ json : jest . fn ( ) . mockResolvedValue ( mockResponse ) ,
515+ } ) ;
516+
517+ const result = await client . nsql ( 'show me users' ) ;
518+
519+ expect ( result . schema . fields ) . toEqual ( [ ] ) ;
520+ expect ( result . data ) . toEqual ( [ ] ) ;
521+ expect ( result . row_count ) . toBe ( 0 ) ;
522+ expect ( result . sql ) . toBe ( 'SELECT * FROM users WHERE false' ) ;
523+ } ) ;
524+
470525 test ( 'should handle NSQL errors' , async ( ) => {
471526 ( global . fetch as jest . Mock ) . mockResolvedValueOnce ( {
472527 ok : false ,
0 commit comments