@@ -9,12 +9,13 @@ import { type IMetadataSource, type Metadata } from 'packages/core/src/metadata/
99import { MetadataSubscription } from 'packages/core/src/metadata/MetadataSubscription' ;
1010import { type BindTargetDeclaration } from 'packages/core/src/parsers/bindTargetParser/BindTargetDeclaration' ;
1111import { type Signal } from 'packages/core/src/utils/Signal' ;
12- import { areArraysEqual , arrayStartsWith } from 'packages/core/src/utils/Utils' ;
1312import {
1413 ErrorLevel ,
1514 MetaBindBindTargetError ,
1615 MetaBindInternalError ,
1716} from 'packages/core/src/utils/errors/MetaBindErrors' ;
17+ import { PropUtils } from 'packages/core/src/utils/prop/PropUtils' ;
18+ import { type PropPath } from 'packages/core/src/utils/prop/PropPath' ;
1819
1920export const METADATA_CACHE_UPDATE_CYCLE_THRESHOLD = 5 ; // {syncInterval (200)} * 5 = 1s
2021export const METADATA_CACHE_INACTIVE_CYCLE_THRESHOLD = 5 * 60 ; // {syncInterval (200)} * 5 * 60 = 1 minute
@@ -40,34 +41,40 @@ export function hasUpdateOverlap(a: BindTargetDeclaration | undefined, b: BindTa
4041 return false ;
4142 }
4243
43- return metadataPathHasUpdateOverlap (
44- a . storageProp . toStringArray ( ) ,
45- b . storageProp . toStringArray ( ) ,
46- b . listenToChildren ,
47- ) ;
44+ // TODO: this can be faster, no need to create new arrays
45+ return metadataPathHasUpdateOverlap ( a . storageProp , b . storageProp , b . listenToChildren ) ;
4846}
4947
5048/**
5149 * Checks if path `b` should receive an update when path `a` changes.
5250 * The rules are as follows:
53- * - if they are equal
54- * - if `b` starts with `a` (`a = foo.bar` and `b = foo.bar.baz`)
55- * - if `b` has `listenToChildren` and `a` starts with `b` (`a = foo.bar.baz` and `b = foo.bar`)
51+ *
52+ * - b = foo.bar.baz
53+ * - a = foo.bar -> true
54+ * - a = foo.bar.baz -> true
55+ * - a = foo.bar.baz.baz -> true
56+ * - a = foo.bar.foo -> false
57+ * - a = foo.foo -> false
5658 *
5759 * @param a
5860 * @param b
5961 * @param listenToChildren whether b listens to updates in children
6062 */
61- export function metadataPathHasUpdateOverlap ( a : string [ ] , b : string [ ] , listenToChildren : boolean ) : boolean {
62- if ( areArraysEqual ( a , b ) ) {
63- return true ;
63+ export function metadataPathHasUpdateOverlap ( a : PropPath , b : PropPath , listenToChildren : boolean ) : boolean {
64+ const aPath = a . path ;
65+ const bPath = b . path ;
66+
67+ for ( let i = 0 ; i < Math . min ( aPath . length , bPath . length ) ; i ++ ) {
68+ if ( aPath [ i ] . type !== bPath [ i ] . type || aPath [ i ] . prop !== bPath [ i ] . prop ) {
69+ return false ;
70+ }
6471 }
6572
66- if ( arrayStartsWith ( b , a ) ) {
73+ if ( aPath . length > bPath . length ) {
74+ return listenToChildren ;
75+ } else {
6776 return true ;
6877 }
69-
70- return listenToChildren && arrayStartsWith ( a , b ) ;
7178}
7279
7380export function bindTargetToString ( a : BindTargetDeclaration | undefined ) : string {
@@ -359,12 +366,12 @@ export class MetadataManager {
359366 if ( source === undefined ) {
360367 throw new MetaBindInternalError ( {
361368 errorLevel : ErrorLevel . ERROR ,
362- effect : 'can not update metadata ' ,
369+ effect : 'can not write to cache ' ,
363370 cause : `Source "${ bindTarget . storageType } " does not exist` ,
364371 } ) ;
365372 }
366373
367- const cacheItem = source . updateCache ( value , bindTarget ) ;
374+ const cacheItem = source . writeCache ( value , bindTarget ) ;
368375 cacheItem . pendingInternalChange = true ;
369376 cacheItem . cyclesSinceInternalChange = 0 ;
370377 this . notifyListeners ( bindTarget , updateSourceUuid ) ;
@@ -431,8 +438,8 @@ export class MetadataManager {
431438
432439 if (
433440 metadataPathHasUpdateOverlap (
434- bindTarget . storageProp . toStringArray ( ) ,
435- cacheSubscription . bindTarget . storageProp . toStringArray ( ) ,
441+ bindTarget . storageProp ,
442+ cacheSubscription . bindTarget . storageProp ,
436443 cacheSubscription . bindTarget . listenToChildren ,
437444 )
438445 ) {
@@ -501,8 +508,24 @@ export class MetadataManager {
501508 return ;
502509 }
503510
504- source . updateEntireCache ( value , cacheItem ) ;
505- this . notifyAllListeners ( source , cacheItem ) ;
511+ const oldValue = source . readEntireCacheItem ( cacheItem ) ;
512+
513+ source . writeEntireCache ( value , cacheItem ) ;
514+
515+ for ( const subscription of cacheItem . subscriptions ) {
516+ if ( subscription . bindTarget === undefined ) {
517+ continue ;
518+ }
519+
520+ const propPath = subscription . bindTarget . storageProp ;
521+
522+ const newBoundValue = PropUtils . tryGet ( value , propPath ) ;
523+ const oldBoundValue = PropUtils . tryGet ( oldValue , propPath ) ;
524+
525+ if ( newBoundValue !== oldBoundValue ) {
526+ subscription . notify ( newBoundValue ) ;
527+ }
528+ }
506529 }
507530
508531 /**
0 commit comments