@@ -522,6 +522,16 @@ const EmptySet: IndexSet = {
522522 [ Symbol . iterator ] : function * ( ) { } ,
523523} ;
524524
525+ const LenIndexSet : ( len : number ) => IndexSet = ( len ) => ( {
526+ has : ( index ) => index < len ,
527+ size : len ,
528+ [ Symbol . iterator ] : function * ( ) {
529+ for ( let i = 0 ; i < len ; i ++ ) {
530+ yield i ;
531+ }
532+ } ,
533+ } ) ;
534+
525535/**
526536 * Converts a sorted array of numbers into an IndexSet data structure.
527537 * sortedArr shouldn't have duplicate elements.
@@ -662,19 +672,6 @@ export class InvertedIndexMap<R extends Record<keyof R, unknown>> {
662672 return this . data . length ;
663673 }
664674
665- private allIndexSet ( ) : IndexSet {
666- const data = this . data ;
667- return {
668- has : ( index ) => index < data . length ,
669- size : data . length ,
670- [ Symbol . iterator ] : function * ( ) {
671- for ( let i = 0 ; i < data . length ; i ++ ) {
672- yield i ;
673- }
674- } ,
675- } ;
676- }
677-
678675 private updateFieldOrder ( ) {
679676 if ( ! this . fieldOrderStale ) {
680677 return ;
@@ -691,36 +688,43 @@ export class InvertedIndexMap<R extends Record<keyof R, unknown>> {
691688 const key = this . keyfn ( record ) ;
692689 let i = this . primaryIdx . get ( key ) ;
693690 if ( i != null ) {
694- // For updates, remove the old posting for each field.
695691 const exstRecord = this . data [ i ] ;
692+ // Only update indices where values have changed
696693 for ( const { field } of this . fieldOrder ) {
697- const v = exstRecord [ field ] ;
694+ const oldVal = exstRecord [ field ] ;
695+ const newVal = record [ field ] ;
696+ if ( oldVal === newVal ) {
697+ continue ;
698+ }
698699 const idx = this . invIdxes [ field ] ! ;
699- const posting = idx . get ( v ) ;
700+ // Remove old posting
701+ const posting = idx . get ( oldVal ) ;
700702 if ( posting ) {
701- // Remove i from the sorted array (linear scan)
702703 const pos = posting . indexOf ( i ) ;
703704 if ( pos !== - 1 ) {
704705 posting . splice ( pos , 1 ) ;
705706 }
706707 }
708+ // Add new posting
709+ if ( ! idx . has ( newVal ) ) {
710+ idx . set ( newVal , [ ] ) ;
711+ }
712+ idx . get ( newVal ) ! . push ( i ) ;
707713 }
708714 } else {
709715 i = this . data . length ;
710716 this . primaryIdx . set ( key , i ) ;
711- }
712- this . data [ i ] = record ;
713- // For each indexed field, add the new index.
714- for ( const { field } of this . fieldOrder ) {
715- const v = record [ field ] ;
716- const idx = this . invIdxes [ field ] ! ;
717- if ( ! idx . has ( v ) ) {
718- // For new posting lists, initialize with an empty array.
719- idx . set ( v , [ ] ) ;
717+ // For new records, just add to indices
718+ for ( const { field } of this . fieldOrder ) {
719+ const v = record [ field ] ;
720+ const idx = this . invIdxes [ field ] ! ;
721+ if ( ! idx . has ( v ) ) {
722+ idx . set ( v , [ ] ) ;
723+ }
724+ idx . get ( v ) ! . push ( i ) ;
720725 }
721- // Because indices only increase, push preserves sorted order.
722- idx . get ( v ) ! . push ( i ) ;
723726 }
727+ this . data [ i ] = record ;
724728 this . fieldOrderStale = true ;
725729 }
726730
@@ -755,14 +759,14 @@ export class InvertedIndexMap<R extends Record<keyof R, unknown>> {
755759 queryIndexSet ( q : Partial < R > ) : IndexSet {
756760 const qfields = Object . keys ( q ) as ( keyof R ) [ ] ;
757761 if ( qfields . length === 0 ) {
758- return this . allIndexSet ( ) ;
762+ return LenIndexSet ( this . data . length ) ;
759763 }
760764 if ( qfields . length === 1 ) {
761765 const qfield = qfields [ 0 ] ;
762766 const idx = this . invIdxes [ qfield ] ;
763767 const qv = q [ qfield ] ;
764768 if ( ! idx || qv === undefined ) {
765- return this . allIndexSet ( ) ;
769+ return LenIndexSet ( this . data . length ) ;
766770 }
767771 const posting = idx . get ( qv ) ;
768772 return posting ? sortedArrToIndexSet ( posting ) : EmptySet ;
0 commit comments