@@ -374,6 +374,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
374374
375375 /**
376376 * @internal
377+ * @spec RTLM15, RTLM15a
377378 */
378379 applyOperation ( op : ObjectOperation < ObjectData > , msg : ObjectMessage ) : void {
379380 if ( op . objectId !== this . getObjectId ( ) ) {
@@ -387,6 +388,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
387388 const opSerial = msg . serial ! ;
388389 const opSiteCode = msg . siteCode ! ;
389390 if ( ! this . _canApplyOperation ( opSerial , opSiteCode ) ) {
391+ // RTLM15b
390392 this . _client . Logger . logAction (
391393 this . _client . logger ,
392394 this . _client . Logger . LOG_MICRO ,
@@ -397,17 +399,18 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
397399 }
398400 // should update stored site serial immediately. doesn't matter if we successfully apply the op,
399401 // as it's important to mark that the op was processed by the object
400- this . _siteTimeserials [ opSiteCode ] = opSerial ;
402+ this . _siteTimeserials [ opSiteCode ] = opSerial ; // RTLM15c
401403
402404 if ( this . isTombstoned ( ) ) {
403405 // this object is tombstoned so the operation cannot be applied
404406 return ;
405407 }
406408
407409 let update : LiveMapUpdate < T > | LiveObjectUpdateNoop ;
410+ // RTLM15d
408411 switch ( op . action ) {
409412 case ObjectOperationAction . MAP_CREATE :
410- update = this . _applyMapCreate ( op ) ;
413+ update = this . _applyMapCreate ( op ) ; // RTLM15d1
411414 break ;
412415
413416 case ObjectOperationAction . MAP_SET :
@@ -416,7 +419,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
416419 // leave an explicit return here, so that TS knows that update object is always set after the switch statement.
417420 return ;
418421 } else {
419- update = this . _applyMapSet ( op . mapOp , opSerial ) ;
422+ update = this . _applyMapSet ( op . mapOp , opSerial ) ; // RTLM15d2
420423 }
421424 break ;
422425
@@ -426,7 +429,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
426429 // leave an explicit return here, so that TS knows that update object is always set after the switch statement.
427430 return ;
428431 } else {
429- update = this . _applyMapRemove ( op . mapOp , opSerial , msg . serialTimestamp ) ;
432+ update = this . _applyMapRemove ( op . mapOp , opSerial , msg . serialTimestamp ) ; // RTLM15d3
430433 }
431434 break ;
432435
@@ -435,6 +438,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
435438 break ;
436439
437440 default :
441+ // RTLM15d4
438442 throw new this . _client . ErrorInfo (
439443 `Invalid ${ op . action } op for LiveMap objectId=${ this . getObjectId ( ) } ` ,
440444 92000 ,
@@ -515,9 +519,8 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
515519 // override data for this object with data from the object state
516520 this . _createOperationIsMerged = false ; // RTLM6b
517521 this . _dataRef = this . _liveMapDataFromMapEntries ( objectState . map ?. entries ?? { } ) ; // RTLM6c
518- // RTLM6d
519522 if ( ! this . _client . Utils . isNil ( objectState . createOp ) ) {
520- this . _mergeInitialDataFromCreateOperation ( objectState . createOp ) ;
523+ this . _mergeInitialDataFromCreateOperation ( objectState . createOp ) ; // RTLM6d
521524 }
522525 }
523526
@@ -603,6 +606,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
603606 return update ;
604607 }
605608
609+ /** @spec RTLM17 */
606610 protected _mergeInitialDataFromCreateOperation ( objectOperation : ObjectOperation < ObjectData > ) : LiveMapUpdate < T > {
607611 if ( this . _client . Utils . isNil ( objectOperation . map ) ) {
608612 // if a map object is missing for the MAP_CREATE op, the initial value is implicitly an empty map.
@@ -611,18 +615,18 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
611615 }
612616
613617 const aggregatedUpdate : LiveMapUpdate < T > = { update : { } } ;
614- // RTLM6d1
618+ // RTLM17a
615619 // in order to apply MAP_CREATE op for an existing map, we should merge their underlying entries keys.
616620 // we can do this by iterating over entries from MAP_CREATE op and apply changes on per-key basis as if we had MAP_SET, MAP_REMOVE operations.
617621 Object . entries ( objectOperation . map . entries ?? { } ) . forEach ( ( [ key , entry ] ) => {
618622 // for a MAP_CREATE operation we must use the serial value available on an entry, instead of a serial on a message
619623 const opSerial = entry . timeserial ;
620624 let update : LiveMapUpdate < T > | LiveObjectUpdateNoop ;
621625 if ( entry . tombstone === true ) {
622- // RTLM6d1b - entry in MAP_CREATE op is removed, try to apply MAP_REMOVE op
626+ // RTLM17a2 - entry in MAP_CREATE op is removed, try to apply MAP_REMOVE op
623627 update = this . _applyMapRemove ( { key } , opSerial , entry . serialTimestamp ) ;
624628 } else {
625- // RTLM6d1a - entry in MAP_CREATE op is not removed, try to set it via MAP_SET op
629+ // RTLM17a1 - entry in MAP_CREATE op is not removed, try to set it via MAP_SET op
626630 update = this . _applyMapSet ( { key, data : entry . data } , opSerial ) ;
627631 }
628632
@@ -635,7 +639,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
635639 Object . assign ( aggregatedUpdate . update , update . update ) ;
636640 } ) ;
637641
638- this . _createOperationIsMerged = true ; // RTLM6d2
642+ this . _createOperationIsMerged = true ; // RTLM17b
639643
640644 return aggregatedUpdate ;
641645 }
@@ -648,8 +652,10 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
648652 ) ;
649653 }
650654
655+ /** @spec RTLM16 */
651656 private _applyMapCreate ( op : ObjectOperation < ObjectData > ) : LiveMapUpdate < T > | LiveObjectUpdateNoop {
652657 if ( this . _createOperationIsMerged ) {
658+ // RTLM16b
653659 // There can't be two different create operation for the same object id, because the object id
654660 // fully encodes that operation. This means we can safely ignore any new incoming create operations
655661 // if we already merged it once.
@@ -663,20 +669,21 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
663669 }
664670
665671 if ( this . _semantics !== op . map ?. semantics ) {
672+ // RTLM16c
666673 throw new this . _client . ErrorInfo (
667674 `Cannot apply MAP_CREATE op on LiveMap objectId=${ this . getObjectId ( ) } ; map's semantics=${ this . _semantics } , but op expected ${ op . map ?. semantics } ` ,
668675 92000 ,
669676 500 ,
670677 ) ;
671678 }
672679
673- return this . _mergeInitialDataFromCreateOperation ( op ) ;
680+ return this . _mergeInitialDataFromCreateOperation ( op ) ; // RTLM16d
674681 }
675682
676683 /** @spec RTLM7 */
677684 private _applyMapSet (
678- op : ObjectsMapOp < ObjectData > ,
679- opSerial : string | undefined ,
685+ op : ObjectsMapOp < ObjectData > , // RTLM7d1
686+ opSerial : string | undefined , // RTLM7d2
680687 ) : LiveMapUpdate < T > | LiveObjectUpdateNoop {
681688 const { ErrorInfo, Utils } = this . _client ;
682689
@@ -740,8 +747,8 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
740747
741748 /** @spec RTLM8 */
742749 private _applyMapRemove (
743- op : ObjectsMapOp < ObjectData > ,
744- opSerial : string | undefined ,
750+ op : ObjectsMapOp < ObjectData > , // RTLM8c1
751+ opSerial : string | undefined , // RTLM8c2
745752 opTimestamp : number | undefined ,
746753 ) : LiveMapUpdate < T > | LiveObjectUpdateNoop {
747754 const existingEntry = this . _dataRef . data . get ( op . key ) ;
@@ -881,17 +888,21 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
881888
882889 // RTLM5d2f - otherwise, it has an objectId reference, and we should get the actual object from the pool
883890 const objectId = ( data as ObjectIdObjectData ) . objectId ;
884- const refObject : LiveObject | undefined = this . _objects . getPool ( ) . get ( objectId ) ;
885- if ( ! refObject ) {
886- return undefined ; // RTLM5d2f1
887- }
891+ if ( objectId != null ) {
892+ const refObject : LiveObject | undefined = this . _objects . getPool ( ) . get ( objectId ) ;
893+ if ( ! refObject ) {
894+ return undefined ; // RTLM5d2f1
895+ }
896+
897+ if ( refObject . isTombstoned ( ) ) {
898+ // tombstoned objects must not be surfaced to the end users
899+ return undefined ;
900+ }
888901
889- if ( refObject . isTombstoned ( ) ) {
890- // tombstoned objects must not be surfaced to the end users
891- return undefined ;
902+ return refObject ; // RTLM5d2f2
892903 }
893904
894- return refObject ; // RTLM5d2f2
905+ return undefined ; // RTLM5d2g
895906 }
896907
897908 /** @spec RTLM14 */
0 commit comments