@@ -256,6 +256,45 @@ class Haro {
256256 /* node:coverage ignore */ return JSON . parse ( JSON . stringify ( arg ) ) ;
257257 }
258258
259+ /**
260+ * Freezes a result when immutable mode is enabled.
261+ * @param {Array|Object } result - Value to freeze
262+ * @returns {Array|Object } Frozen or unchanged result
263+ */
264+ #freezeResult( result ) {
265+ if ( this . #immutable) {
266+ if ( Array . isArray ( result ) ) {
267+ for ( let i = 0 , len = result . length ; i < len ; i ++ ) {
268+ Object . freeze ( result [ i ] ) ;
269+ }
270+ Object . freeze ( result ) ;
271+ } else {
272+ Object . freeze ( result ) ;
273+ }
274+ }
275+ return result ;
276+ }
277+
278+ /**
279+ * Returns a cached result, cloned or frozen based on immutable mode.
280+ * @param {* } cached - Cached value
281+ * @returns {* } Cloned (non-immutable) or frozen (immutable) result
282+ */
283+ #fromCache( cached ) {
284+ return this . #immutable ? Object . freeze ( cached ) : this . #clone( cached ) ;
285+ }
286+
287+ /**
288+ * Stores results in cache if enabled.
289+ * @param {* } cacheKey - Cache key
290+ * @param {Array } records - Result records to cache
291+ */
292+ #toCache( cacheKey , records ) {
293+ if ( this . #cacheEnabled) {
294+ this . #cache. set ( cacheKey , records ) ;
295+ }
296+ }
297+
259298 /**
260299 * Deletes a record and removes it from all indexes.
261300 * @param {string } [key=STRING_EMPTY] - Key to delete
@@ -368,7 +407,7 @@ class Haro {
368407 const idx = this . #indexes. get ( i ) ;
369408 if ( ! idx ) return ;
370409 const values = i . includes ( this . #delimiter)
371- ? this . #getIndexKeys ( i , this . #delimiter , data )
410+ ? this . #getIndexKeysFrom ( i , data , ( f , s ) => this . #getNestedValue ( s , f ) )
372411 : Array . isArray ( this . #getNestedValue( data , i ) )
373412 ? this . #getNestedValue( data , i )
374413 : [ this . #getNestedValue( data , i ) ] ;
@@ -415,58 +454,20 @@ class Haro {
415454 }
416455
417456 /**
418- * Generates index keys for composite indexes from data object .
457+ * Generates index keys from source object using a value getter function .
419458 * @param {string } arg - Composite index field names
420459 * @param {string } delimiter - Field delimiter
421- * @param {Object } data - Data object
460+ * @param {Object } source - Source object (data or where clause)
461+ * @param {Function } getValueFn - Function(field, source) => value
422462 * @returns {string[] } Index keys
423463 */
424- #getIndexKeys ( arg , delimiter , data ) {
464+ #getIndexKeysFrom ( arg , source , getValueFn ) {
425465 const fields = arg . split ( this . #delimiter) . sort ( this . #sortKeys) ;
426466 const result = [ STRING_EMPTY ] ;
427467 const fieldsLen = fields . length ;
428468 for ( let i = 0 ; i < fieldsLen ; i ++ ) {
429469 const field = fields [ i ] ;
430- const fieldValue = this . #getNestedValue( data , field ) ;
431- const values = Array . isArray ( fieldValue ) ? fieldValue : [ fieldValue ] ;
432- const newResult = [ ] ;
433- const resultLen = result . length ;
434- const valuesLen = values . length ;
435- for ( let j = 0 ; j < resultLen ; j ++ ) {
436- const existing = result [ j ] ;
437- for ( let k = 0 ; k < valuesLen ; k ++ ) {
438- const value = values [ k ] ;
439- const newKey = i === 0 ? value : `${ existing } ${ this . #delimiter} ${ value } ` ;
440- newResult . push ( newKey ) ;
441- }
442- }
443- result . length = 0 ;
444- result . push ( ...newResult ) ;
445- }
446- return result ;
447- }
448-
449- /**
450- * Generates index keys for where object (handles both dot notation and direct access).
451- * @param {string } arg - Composite index field names
452- * @param {string } delimiter - Field delimiter
453- * @param {Object } where - Where object
454- * @returns {string[] } Index keys
455- */
456- #getIndexKeysForWhere( arg , delimiter , where ) {
457- const fields = arg . split ( this . #delimiter) . sort ( this . #sortKeys) ;
458- const result = [ STRING_EMPTY ] ;
459- const fieldsLen = fields . length ;
460- for ( let i = 0 ; i < fieldsLen ; i ++ ) {
461- const field = fields [ i ] ;
462- // Check if field exists directly in where object first (for dot notation keys)
463- let fieldValue ;
464- if ( field in where ) {
465- fieldValue = where [ field ] ;
466- /* node:coverage ignore next 4 */
467- } else {
468- fieldValue = this . #getNestedValue( where , field ) ;
469- }
470+ const fieldValue = getValueFn ( field , source ) ;
470471 const values = Array . isArray ( fieldValue ) ? fieldValue : [ fieldValue ] ;
471472 const newResult = [ ] ;
472473 const resultLen = result . length ;
@@ -512,7 +513,9 @@ class Haro {
512513
513514 const index = this . #indexes. get ( compositeKey ) ;
514515 if ( index ) {
515- const keys = this . #getIndexKeysForWhere( compositeKey , this . #delimiter, where ) ;
516+ const keys = this . #getIndexKeysFrom( compositeKey , where , ( f , s ) =>
517+ f in s ? s [ f ] : this . #getNestedValue( s , f ) ,
518+ ) ;
516519 const keysLen = keys . length ;
517520 for ( let i = 0 ; i < keysLen ; i ++ ) {
518521 const v = keys [ i ] ;
@@ -525,11 +528,7 @@ class Haro {
525528 }
526529 }
527530
528- const records = Array . from ( result , ( i ) => this . get ( i ) ) ;
529- if ( this . #immutable) {
530- return Object . freeze ( records ) ;
531- }
532- return records ;
531+ return this . #freezeResult( Array . from ( result , ( i ) => this . get ( i ) ) ) ;
533532 }
534533
535534 /**
@@ -550,10 +549,7 @@ class Haro {
550549 result . push ( value ) ;
551550 }
552551 } ) ;
553- if ( this . #immutable) {
554- return Object . freeze ( result ) ;
555- }
556- return result ;
552+ return this . #freezeResult( result ) ;
557553 }
558554
559555 /**
@@ -587,10 +583,7 @@ class Haro {
587583 if ( result === undefined ) {
588584 return null ;
589585 }
590- if ( this . #immutable) {
591- return Object . freeze ( result ) ;
592- }
593- return result ;
586+ return this . #freezeResult( result ) ;
594587 }
595588
596589 /**
@@ -629,12 +622,7 @@ class Haro {
629622 if ( typeof max !== STRING_NUMBER ) {
630623 throw new Error ( STRING_ERROR_LIMIT_MAX_TYPE ) ;
631624 }
632- let result = this . registry . slice ( offset , offset + max ) . map ( ( i ) => this . get ( i ) ) ;
633- if ( this . #immutable) {
634- result = Object . freeze ( result ) ;
635- }
636-
637- return result ;
625+ return this . #freezeResult( this . registry . slice ( offset , offset + max ) . map ( ( i ) => this . get ( i ) ) ) ;
638626 }
639627
640628 /**
@@ -651,11 +639,7 @@ class Haro {
651639 }
652640 let result = [ ] ;
653641 this . forEach ( ( value , key ) => result . push ( fn ( value , key ) ) ) ;
654- if ( this . #immutable) {
655- result = Object . freeze ( result ) ;
656- }
657-
658- return result ;
642+ return this . #freezeResult( result ) ;
659643 }
660644
661645 /**
@@ -762,7 +746,7 @@ class Haro {
762746 cacheKey = await this . #getCacheKey( STRING_CACHE_DOMAIN_SEARCH , value , index ) ;
763747 const cached = this . #cache. get ( cacheKey ) ;
764748 if ( cached !== undefined ) {
765- return this . #immutable ? Object . freeze ( cached ) : this . #clone ( cached ) ;
749+ return this . #fromCache ( cached ) ;
766750 }
767751 }
768752
@@ -799,14 +783,8 @@ class Haro {
799783 }
800784 const records = Array . from ( result , ( key ) => this . get ( key ) ) ;
801785
802- if ( this . #cacheEnabled) {
803- this . #cache. set ( cacheKey , records ) ;
804- }
805-
806- if ( this . #immutable) {
807- return Object . freeze ( records ) ;
808- }
809- return records ;
786+ this . #toCache( cacheKey , records ) ;
787+ return this . #freezeResult( records ) ;
810788 }
811789
812790 /**
@@ -876,7 +854,7 @@ class Haro {
876854 this . #indexes. set ( field , idx ) ;
877855 }
878856 const values = field . includes ( this . #delimiter)
879- ? this . #getIndexKeys ( field , this . #delimiter , data )
857+ ? this . #getIndexKeysFrom ( field , data , ( f , s ) => this . #getNestedValue ( s , f ) )
880858 : Array . isArray ( this . #getNestedValue( data , field ) )
881859 ? this . #getNestedValue( data , field )
882860 : [ this . #getNestedValue( data , field ) ] ;
@@ -959,10 +937,7 @@ class Haro {
959937 return mapped ;
960938 } ) ;
961939
962- if ( this . #immutable) {
963- return Object . freeze ( result ) ;
964- }
965- return result ;
940+ return this . #freezeResult( result ) ;
966941 }
967942
968943 /**
@@ -974,11 +949,7 @@ class Haro {
974949 toArray ( ) {
975950 const result = Array . from ( this . #data. values ( ) ) ;
976951 if ( this . #immutable) {
977- const resultLen = result . length ;
978- for ( let i = 0 ; i < resultLen ; i ++ ) {
979- Object . freeze ( result [ i ] ) ;
980- }
981- Object . freeze ( result ) ;
952+ return this . #freezeResult( result ) ;
982953 }
983954
984955 return result ;
@@ -1058,7 +1029,7 @@ class Haro {
10581029 cacheKey = await this . #getCacheKey( STRING_CACHE_DOMAIN_WHERE , predicate , op ) ;
10591030 const cached = this . #cache. get ( cacheKey ) ;
10601031 if ( cached !== undefined ) {
1061- return this . #immutable ? Object . freeze ( cached ) : this . #clone ( cached ) ;
1032+ return this . #fromCache ( cached ) ;
10621033 }
10631034 }
10641035
@@ -1130,14 +1101,8 @@ class Haro {
11301101 }
11311102 }
11321103
1133- if ( this . #cacheEnabled) {
1134- this . #cache. set ( cacheKey , results ) ;
1135- }
1136-
1137- if ( this . #immutable) {
1138- return Object . freeze ( results ) ;
1139- }
1140- return results ;
1104+ this . #toCache( cacheKey , results ) ;
1105+ return this . #freezeResult( results ) ;
11411106 }
11421107 }
11431108}
0 commit comments