@@ -148,6 +148,76 @@ describe('SQL API', () => {
148148 expect ( rows ) . toBe ( ROWS_LIMIT ) ;
149149 } ) ;
150150
151+ it ( 'streams schema and empty data with LIMIT 0' , async ( ) => {
152+ const response = await fetch ( `${ birdbox . configuration . apiUrl } /cubesql` , {
153+ method : 'POST' ,
154+ headers : {
155+ 'Content-Type' : 'application/json' ,
156+ Authorization : token ,
157+ } ,
158+ body : JSON . stringify ( {
159+ query : `SELECT orderDate FROM ECommerce LIMIT 0;` ,
160+ } ) ,
161+ } ) ;
162+
163+ const reader = response . body ;
164+ let isFirstChunk = true ;
165+ let schemaReceived = false ;
166+ let emptyDataReceived = false ;
167+
168+ let data = '' ;
169+ const execute = ( ) => new Promise < void > ( ( resolve , reject ) => {
170+ const onData = jest . fn ( ( chunk : Buffer ) => {
171+ const chunkStr = chunk . toString ( 'utf-8' ) ;
172+
173+ if ( isFirstChunk ) {
174+ isFirstChunk = false ;
175+ const json = JSON . parse ( chunkStr ) ;
176+ expect ( json . schema ) . toEqual ( [
177+ {
178+ name : 'orderDate' ,
179+ column_type : 'Timestamp' ,
180+ } ,
181+ ] ) ;
182+ schemaReceived = true ;
183+ } else {
184+ data += chunkStr ;
185+ const json = JSON . parse ( chunkStr ) ;
186+ if ( json . data && Array . isArray ( json . data ) && json . data . length === 0 ) {
187+ emptyDataReceived = true ;
188+ }
189+ }
190+ } ) ;
191+ reader . on ( 'data' , onData ) ;
192+
193+ const onError = jest . fn ( ( ) => reject ( new Error ( 'Stream error' ) ) ) ;
194+ reader . on ( 'error' , onError ) ;
195+
196+ const onEnd = jest . fn ( ( ) => {
197+ resolve ( ) ;
198+ } ) ;
199+
200+ reader . on ( 'end' , onEnd ) ;
201+ } ) ;
202+
203+ await execute ( ) ;
204+
205+ // Verify schema was sent first
206+ expect ( schemaReceived ) . toBe ( true ) ;
207+
208+ // Verify empty data was sent
209+ expect ( emptyDataReceived ) . toBe ( true ) ;
210+
211+ // Verify no actual rows were returned
212+ const dataLines = data . split ( '\n' ) . filter ( ( it ) => it . trim ( ) ) ;
213+ if ( dataLines . length > 0 ) {
214+ const rows = dataLines
215+ . map ( ( it ) => JSON . parse ( it ) . data ?. length || 0 )
216+ . reduce ( ( a , b ) => a + b , 0 ) ;
217+ expect ( rows ) . toBe ( 0 ) ;
218+ }
219+ } ) ;
220+
151221 describe ( 'sql4sql' , ( ) => {
152222 async function generateSql ( query : string , disablePostPprocessing : boolean = false ) {
153223 const response = await fetch ( `${ birdbox . configuration . apiUrl } /sql` , {
0 commit comments