@@ -198,26 +198,35 @@ function findPkColumn(columns) {
198198 return columns . find ( c => PK_COLUMN_NAMES . includes ( c . name ) ) ;
199199}
200200
201+ // Hash function for row objects
202+ function hashRow ( row ) {
203+ const str = Object . keys ( row ) . sort ( ) . map ( k => `${ k } :${ row [ k ] } ` ) . join ( '|' ) ;
204+ let hash = 0 ;
205+ for ( let i = 0 ; i < str . length ; i ++ ) {
206+ const char = str . charCodeAt ( i ) ;
207+ hash = ( ( hash << 5 ) - hash ) + char ;
208+ hash = hash & hash ;
209+ }
210+ return `hash_${ hash } ` ;
211+ }
212+
201213// Get unique row identifier using PK column or first column
202214function getRowIdentifier ( row , pkColumn , columns ) {
203215 if ( pkColumn ?. key && row [ pkColumn . key ] !== undefined ) {
204216 return row [ pkColumn . key ] ;
205217 }
206218 const firstKey = columns [ 0 ] ?. key ;
207- return firstKey && row [ firstKey ] !== undefined ? row [ firstKey ] : JSON . stringify ( row ) ;
208- }
209-
210- // Create Set of row identifiers
211- function createIdentifierSet ( rowData , pkColumn , columns ) {
212- return new Set ( rowData . map ( row => getRowIdentifier ( row , pkColumn , columns ) ) ) ;
219+ if ( firstKey && row [ firstKey ] !== undefined ) {
220+ return row [ firstKey ] ;
221+ }
222+ return hashRow ( row ) ;
213223}
214224
215225// Match rows from previous selection to current rows
216- function matchRowSelection ( prevRowData , currentRows , pkColumn , columns ) {
217- if ( prevRowData . length === 0 ) return [ ] ;
226+ function matchRowSelection ( prevIdentifiers , currentRows , pkColumn , columns ) {
227+ if ( prevIdentifiers . size === 0 ) return [ ] ;
218228
219- const prevIdSet = createIdentifierSet ( prevRowData , pkColumn , columns ) ;
220- return currentRows . filter ( row => prevIdSet . has ( getRowIdentifier ( row , pkColumn , columns ) ) ) ;
229+ return currentRows . filter ( row => prevIdentifiers . has ( getRowIdentifier ( row , pkColumn , columns ) ) ) ;
221230}
222231
223232function PopupTable ( { data} ) {
@@ -492,7 +501,7 @@ export function GeometryViewer({rows, columns, column}) {
492501 const prevStateRef = React . useRef ( {
493502 columnKey : null ,
494503 columnNames : null ,
495- selectedRowData : [ ] ,
504+ selectedRowIdentifiers : new Set ( ) ,
496505 } ) ;
497506
498507 const [ mapKey , setMapKey ] = React . useState ( 0 ) ;
@@ -513,7 +522,7 @@ export function GeometryViewer({rows, columns, column}) {
513522 prevStateRef . current = {
514523 columnKey : null ,
515524 columnNames : null ,
516- selectedRowData : [ ] ,
525+ selectedRowIdentifiers : new Set ( ) ,
517526 } ;
518527 return ;
519528 }
@@ -524,32 +533,46 @@ export function GeometryViewer({rows, columns, column}) {
524533 prevStateRef . current = {
525534 columnKey : currentColumnKey ,
526535 columnNames : currentColumnNames ,
527- selectedRowData : rows ,
536+ selectedRowIdentifiers : new Set ( rows . map ( r => getRowIdentifier ( r , pkColumn , columns ) ) ) ,
528537 } ;
529538 return ;
530539 }
531540
532541 if ( currentColumnKey === prevState . columnKey &&
533542 currentColumnNames === prevState . columnNames &&
534543 rows . length > 0 ) {
535- prevStateRef . current . selectedRowData = displayRows ;
544+ prevStateRef . current . selectedRowIdentifiers = new Set (
545+ displayRows . map ( r => getRowIdentifier ( r , pkColumn , columns ) )
546+ ) ;
536547 }
537548 } , [ currentColumnKey , currentColumnNames , rows , pkColumn , columns ] ) ;
538549
539550 // Get rows to display based on selection
540551 const displayRows = React . useMemo ( ( ) => {
552+ // No geometry column selected or no rows available - nothing to display
541553 if ( ! currentColumnKey || rows . length === 0 ) return [ ] ;
542554 const prevState = prevStateRef . current ;
555+
556+ // Column context changed (different geometry column or different query schema)
557+ // Show all new rows since previous selection is no longer valid
543558 if ( currentColumnKey !== prevState . columnKey || currentColumnNames !== prevState . columnNames ) {
544559 return rows ;
545560 }
546561
547- const prevSelected = prevState . selectedRowData ;
548- if ( prevSelected . length === 0 ) return rows ;
549- if ( prevSelected . length < rows . length ) {
550- const matched = matchRowSelection ( prevSelected , rows , pkColumn , columns ) ;
562+ const prevIdentifiers = prevState . selectedRowIdentifiers ;
563+ // No previous selection recorded - show all rows
564+ if ( prevIdentifiers . size === 0 ) return rows ;
565+
566+ // Previous selection was a subset of total rows, meaning user had specific rows selected.
567+ // Try to match those previously selected rows in the new result set using stable
568+ // row identifiers (PK value, first column value, or hash fallback).
569+ // This handles the case where same query reruns with more/fewer rows
570+ if ( prevIdentifiers . size < rows . length ) {
571+ const matched = matchRowSelection ( prevIdentifiers , rows , pkColumn , columns ) ;
572+ // If matched rows found, show only those; otherwise fall back to all rows
551573 return matched . length > 0 ? matched : rows ;
552574 }
575+ // Previous selection covered all rows (or same count) - show all current rows
553576 return rows ;
554577 } , [ rows , currentColumnKey , currentColumnNames , pkColumn , columns ] ) ;
555578
0 commit comments