@@ -179,6 +179,22 @@ interface EmscriptenModule {
179179 ccall : ( name : string , returnType : string , argTypes : string [ ] , args : unknown [ ] ) => unknown ;
180180}
181181
182+ /** Structured error information from Rayforce */
183+ interface ErrorInfo {
184+ code : string ;
185+ message ?: string ;
186+ expected ?: string ;
187+ got ?: string ;
188+ need ?: number ;
189+ have ?: number ;
190+ index ?: number ;
191+ bound ?: number ;
192+ name ?: string ;
193+ type ?: string ;
194+ limit ?: number ;
195+ raw ?: string ;
196+ }
197+
182198interface RayObject {
183199 ptr : number ;
184200 type : number ;
@@ -192,6 +208,11 @@ interface RayObject {
192208 drop ( ) : void ;
193209}
194210
211+ interface RayError extends RayObject {
212+ info : ErrorInfo ;
213+ message : string ;
214+ }
215+
195216interface Vector extends RayObject {
196217 typedArray : ArrayBufferView ;
197218 at ( idx : number ) : unknown ;
@@ -747,26 +768,40 @@ export class RayforceClient {
747768 throw new Error ( 'SDK not loaded' ) ;
748769 }
749770
750- logInfo ( 'Rayforce' , `Loading CSV into table '${ name } ' (${ content . length } bytes)` ) ;
771+ logInfo ( 'Rayforce' , `Loading CSV into table '${ name } ' (${ content . length } bytes, ${ ( content . length / ( 1024 * 1024 ) ) . toFixed ( 1 ) } MB )` ) ;
751772
752773 // 1. Parse CSV into Table object
753774 // Note: read_csv returns a Table object associated with the WASM heap
754775 const table = this . sdk . read_csv ( content ) ;
776+
777+ logDebug ( 'Rayforce' , `read_csv returned: type=${ table . type } , isNull=${ table . isNull } , isError=${ table . isError } , ptr=${ table . ptr } ` ) ;
755778
756779 if ( table . isError ) {
757- const err = table . toString ( ) ;
780+ // Use structured error info for clean display
781+ const errObj = table as unknown as RayError ;
782+ const errMsg = errObj . message || table . toString ( ) ;
783+ logError ( 'Rayforce' , `CSV parse error: ${ errMsg } ` ) ;
758784 table . drop ( ) ;
759- throw new Error ( `CSV parse error: ${ err } ` ) ;
785+ throw new Error ( errMsg ) ;
786+ }
787+
788+ if ( table . isNull ) {
789+ logError ( 'Rayforce' , `read_csv returned null` ) ;
790+ throw new Error ( 'CSV parse returned null' ) ;
760791 }
761792
793+ // Get table info before setting
794+ const rowCount = ( table as Table ) . rowCount ;
795+ const columns = ( table as Table ) . columnNames ( ) ;
796+ logInfo ( 'Rayforce' , `Parsed table: ${ rowCount } rows, ${ columns . length } columns (${ columns . join ( ', ' ) } )` ) ;
797+
762798 // 2. Register table as a variable
763799 // This allows SQL/queries to reference it by name
764800 this . sdk . set ( name , table ) ;
801+ logDebug ( 'Rayforce' , `Called set('${ name } ', table)` ) ;
765802
766803 // 3. Drop our reference (the variable 'name' now holds a reference)
767- // Actually, set() might copy or increment ref count.
768- // Usually SDK.set takes ownership or we should drop our handle if we don't need it.
769- // Based on typical Rayforce pattern, we should drop the local handle.
804+ // binary_set clones the value, so dropping our reference is safe
770805 table . drop ( ) ;
771806
772807 logInfo ( 'Rayforce' , `CSV loaded successfully as '${ name } '` ) ;
@@ -1299,7 +1334,10 @@ export class RayforceClient {
12991334 }
13001335
13011336 if ( obj . isError ) {
1302- return { type : 'error' , data : obj . toString ( ) } ;
1337+ // Use structured error info for clean display
1338+ const errObj = obj as unknown as RayError ;
1339+ const errMsg = errObj . message || obj . toString ( ) ;
1340+ return { type : 'error' , data : errMsg } ;
13031341 }
13041342
13051343 const type = Math . abs ( obj . type ) ;
@@ -1309,10 +1347,43 @@ export class RayforceClient {
13091347 const table = obj as Table ;
13101348 const columns = table . columnNames ( ) ;
13111349 const rowCount = table . rowCount ;
1350+
1351+ logDebug ( 'Rayforce' , `wrapRayObject TABLE: columns=${ columns . length } , rowCount=${ rowCount } ` ) ;
1352+
1353+ // For display, only convert first N rows (large tables would be too slow)
1354+ const MAX_DISPLAY_ROWS = 1000 ;
1355+ let rows : Record < string , unknown > [ ] = [ ] ;
1356+
1357+ if ( rowCount <= MAX_DISPLAY_ROWS ) {
1358+ // Small table - convert all rows
1359+ try {
1360+ const startTime = performance . now ( ) ;
1361+ rows = table . toRows ( ) ;
1362+ logDebug ( 'Rayforce' , `toRows() returned ${ rows . length } rows in ${ ( performance . now ( ) - startTime ) . toFixed ( 1 ) } ms` ) ;
1363+ } catch ( err ) {
1364+ logError ( 'Rayforce' , `toRows() failed: ${ err } ` ) ;
1365+ }
1366+ } else {
1367+ // Large table - only get first N rows for display
1368+ logDebug ( 'Rayforce' , `Large table (${ rowCount } rows), showing first ${ MAX_DISPLAY_ROWS } for display` ) ;
1369+ try {
1370+ const startTime = performance . now ( ) ;
1371+ for ( let i = 0 ; i < MAX_DISPLAY_ROWS && i < rowCount ; i ++ ) {
1372+ const rowObj = table . row ( i ) ;
1373+ if ( rowObj && ! rowObj . isNull ) {
1374+ rows . push ( rowObj . toJS ( ) as Record < string , unknown > ) ;
1375+ }
1376+ }
1377+ logDebug ( 'Rayforce' , `Extracted ${ rows . length } display rows in ${ ( performance . now ( ) - startTime ) . toFixed ( 1 ) } ms` ) ;
1378+ } catch ( err ) {
1379+ logError ( 'Rayforce' , `Row extraction failed: ${ err } ` ) ;
1380+ }
1381+ }
13121382
13131383 return {
13141384 type : 'table' ,
13151385 rayObject : obj ,
1386+ data : rows ,
13161387 columns,
13171388 rowCount,
13181389 // Zero-copy column access
@@ -1321,7 +1392,7 @@ export class RayforceClient {
13211392 if ( ! col ) return null ;
13221393 return col . typedArray || null ;
13231394 } ,
1324- // Lazy JS conversion
1395+ // Full conversion - use with caution for large tables
13251396 toJS : ( ) => table . toRows ( ) ,
13261397 } ;
13271398 }
0 commit comments