@@ -75,6 +75,48 @@ test.describe("Arrow", function () {
7575 } ) ;
7676
7777 test . describe ( "regressions" , ( ) => {
78+ // https://github.com/perspective-dev/perspective/issues/3169
79+ test ( "null values are preserved across multi-batch Arrow IPC streams" , async function ( ) {
80+ function row (
81+ identifier : string ,
82+ value : number | null ,
83+ date : Date | null ,
84+ ) {
85+ return arrow . tableFromArrays ( {
86+ Identifier : arrow . vectorFromArray (
87+ [ identifier ] ,
88+ new arrow . Utf8 ( ) ,
89+ ) ,
90+ Value : arrow . vectorFromArray ( [ value ] , new arrow . Float64 ( ) ) ,
91+ Date : arrow . vectorFromArray ( [ date ] , new arrow . DateDay ( ) ) ,
92+ } ) ;
93+ }
94+
95+ const t1 = row ( "A" , null , null ) ;
96+ const t2 = row ( "B" , 5 , null ) ;
97+ const t3 = row ( "C" , null , new Date ( Date . UTC ( 2025 , 5 , 15 ) ) ) ;
98+
99+ const multiBatchTable = new arrow . Table ( [
100+ ...t1 . batches ,
101+ ...t2 . batches ,
102+ ...t3 . batches ,
103+ ] ) ;
104+ expect ( multiBatchTable . batches . length ) . toEqual ( 3 ) ;
105+
106+ const ipc = arrow . tableToIPC ( multiBatchTable , "stream" ) ;
107+ const table = await perspective . table ( ipc . buffer as ArrayBuffer ) ;
108+ const view = await table . view ( ) ;
109+ const json = await view . to_json ( ) ;
110+ await view . delete ( ) ;
111+ await table . delete ( ) ;
112+
113+ expect ( json ) . toStrictEqual ( [
114+ { Identifier : "A" , Value : null , Date : null } ,
115+ { Identifier : "B" , Value : 5 , Date : null } ,
116+ { Identifier : "C" , Value : null , Date : 1749945600000 } ,
117+ ] ) ;
118+ } ) ;
119+
78120 test ( "null equality works correctly in updates" , async function ( ) {
79121 async function write_to_json (
80122 buffer : ArrayBuffer ,
0 commit comments