@@ -402,6 +402,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
402402
403403 /**
404404 * @internal
405+ * @spec RTLM15, RTLM15a
405406 */
406407 applyOperation ( op : ObjectOperation < ObjectData > , msg : ObjectMessage ) : void {
407408 if ( op . objectId !== this . getObjectId ( ) ) {
@@ -415,6 +416,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
415416 const opSerial = msg . serial ! ;
416417 const opSiteCode = msg . siteCode ! ;
417418 if ( ! this . _canApplyOperation ( opSerial , opSiteCode ) ) {
419+ // RTLM15b
418420 this . _client . Logger . logAction (
419421 this . _client . logger ,
420422 this . _client . Logger . LOG_MICRO ,
@@ -425,17 +427,18 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
425427 }
426428 // should update stored site serial immediately. doesn't matter if we successfully apply the op,
427429 // as it's important to mark that the op was processed by the object
428- this . _siteTimeserials [ opSiteCode ] = opSerial ;
430+ this . _siteTimeserials [ opSiteCode ] = opSerial ; // RTLM15c
429431
430432 if ( this . isTombstoned ( ) ) {
431433 // this object is tombstoned so the operation cannot be applied
432434 return ;
433435 }
434436
435437 let update : LiveMapUpdate < T > | LiveObjectUpdateNoop ;
438+ // RTLM15d
436439 switch ( op . action ) {
437440 case ObjectOperationAction . MAP_CREATE :
438- update = this . _applyMapCreate ( op ) ;
441+ update = this . _applyMapCreate ( op ) ; // RTLM15d1
439442 break ;
440443
441444 case ObjectOperationAction . MAP_SET :
@@ -444,7 +447,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
444447 // leave an explicit return here, so that TS knows that update object is always set after the switch statement.
445448 return ;
446449 } else {
447- update = this . _applyMapSet ( op . mapOp , opSerial ) ;
450+ update = this . _applyMapSet ( op . mapOp , opSerial ) ; // RTLM15d2
448451 }
449452 break ;
450453
@@ -454,7 +457,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
454457 // leave an explicit return here, so that TS knows that update object is always set after the switch statement.
455458 return ;
456459 } else {
457- update = this . _applyMapRemove ( op . mapOp , opSerial , msg . serialTimestamp ) ;
460+ update = this . _applyMapRemove ( op . mapOp , opSerial , msg . serialTimestamp ) ; // RTLM15d3
458461 }
459462 break ;
460463
@@ -463,6 +466,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
463466 break ;
464467
465468 default :
469+ // RTLM15d4
466470 throw new this . _client . ErrorInfo (
467471 `Invalid ${ op . action } op for LiveMap objectId=${ this . getObjectId ( ) } ` ,
468472 92000 ,
@@ -543,9 +547,8 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
543547 // override data for this object with data from the object state
544548 this . _createOperationIsMerged = false ; // RTLM6b
545549 this . _dataRef = this . _liveMapDataFromMapEntries ( objectState . map ?. entries ?? { } ) ; // RTLM6c
546- // RTLM6d
547550 if ( ! this . _client . Utils . isNil ( objectState . createOp ) ) {
548- this . _mergeInitialDataFromCreateOperation ( objectState . createOp ) ;
551+ this . _mergeInitialDataFromCreateOperation ( objectState . createOp ) ; // RTLM6d
549552 }
550553 }
551554
@@ -631,6 +634,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
631634 return update ;
632635 }
633636
637+ /** @spec RTLM17 */
634638 protected _mergeInitialDataFromCreateOperation ( objectOperation : ObjectOperation < ObjectData > ) : LiveMapUpdate < T > {
635639 if ( this . _client . Utils . isNil ( objectOperation . map ) ) {
636640 // if a map object is missing for the MAP_CREATE op, the initial value is implicitly an empty map.
@@ -639,18 +643,18 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
639643 }
640644
641645 const aggregatedUpdate : LiveMapUpdate < T > = { update : { } } ;
642- // RTLM6d1
646+ // RTLM17a
643647 // in order to apply MAP_CREATE op for an existing map, we should merge their underlying entries keys.
644648 // 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.
645649 Object . entries ( objectOperation . map . entries ?? { } ) . forEach ( ( [ key , entry ] ) => {
646650 // for a MAP_CREATE operation we must use the serial value available on an entry, instead of a serial on a message
647651 const opSerial = entry . timeserial ;
648652 let update : LiveMapUpdate < T > | LiveObjectUpdateNoop ;
649653 if ( entry . tombstone === true ) {
650- // RTLM6d1b - entry in MAP_CREATE op is removed, try to apply MAP_REMOVE op
654+ // RTLM17a2 - entry in MAP_CREATE op is removed, try to apply MAP_REMOVE op
651655 update = this . _applyMapRemove ( { key } , opSerial , entry . serialTimestamp ) ;
652656 } else {
653- // RTLM6d1a - entry in MAP_CREATE op is not removed, try to set it via MAP_SET op
657+ // RTLM17a1 - entry in MAP_CREATE op is not removed, try to set it via MAP_SET op
654658 update = this . _applyMapSet ( { key, data : entry . data } , opSerial ) ;
655659 }
656660
@@ -663,7 +667,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
663667 Object . assign ( aggregatedUpdate . update , update . update ) ;
664668 } ) ;
665669
666- this . _createOperationIsMerged = true ; // RTLM6d2
670+ this . _createOperationIsMerged = true ; // RTLM17b
667671
668672 return aggregatedUpdate ;
669673 }
@@ -676,8 +680,10 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
676680 ) ;
677681 }
678682
683+ /** @spec RTLM16 */
679684 private _applyMapCreate ( op : ObjectOperation < ObjectData > ) : LiveMapUpdate < T > | LiveObjectUpdateNoop {
680685 if ( this . _createOperationIsMerged ) {
686+ // RTLM16b
681687 // There can't be two different create operation for the same object id, because the object id
682688 // fully encodes that operation. This means we can safely ignore any new incoming create operations
683689 // if we already merged it once.
@@ -691,20 +697,21 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
691697 }
692698
693699 if ( this . _semantics !== op . map ?. semantics ) {
700+ // RTLM16c
694701 throw new this . _client . ErrorInfo (
695702 `Cannot apply MAP_CREATE op on LiveMap objectId=${ this . getObjectId ( ) } ; map's semantics=${ this . _semantics } , but op expected ${ op . map ?. semantics } ` ,
696703 92000 ,
697704 500 ,
698705 ) ;
699706 }
700707
701- return this . _mergeInitialDataFromCreateOperation ( op ) ;
708+ return this . _mergeInitialDataFromCreateOperation ( op ) ; // RTLM16d
702709 }
703710
704711 /** @spec RTLM7 */
705712 private _applyMapSet (
706- op : ObjectsMapOp < ObjectData > ,
707- opSerial : string | undefined ,
713+ op : ObjectsMapOp < ObjectData > , // RTLM7d1
714+ opSerial : string | undefined , // RTLM7d2
708715 ) : LiveMapUpdate < T > | LiveObjectUpdateNoop {
709716 const { ErrorInfo, Utils } = this . _client ;
710717
@@ -781,8 +788,8 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
781788
782789 /** @spec RTLM8 */
783790 private _applyMapRemove (
784- op : ObjectsMapOp < ObjectData > ,
785- opSerial : string | undefined ,
791+ op : ObjectsMapOp < ObjectData > , // RTLM8c1
792+ opSerial : string | undefined , // RTLM8c2
786793 opTimestamp : number | undefined ,
787794 ) : LiveMapUpdate < T > | LiveObjectUpdateNoop {
788795 const existingEntry = this . _dataRef . data . get ( op . key ) ;
@@ -937,17 +944,21 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
937944
938945 // RTLM5d2f - otherwise, it has an objectId reference, and we should get the actual object from the pool
939946 const objectId = ( data as ObjectIdObjectData ) . objectId ;
940- const refObject : LiveObject | undefined = this . _objects . getPool ( ) . get ( objectId ) ;
941- if ( ! refObject ) {
942- return undefined ; // RTLM5d2f1
943- }
947+ if ( objectId != null ) {
948+ const refObject : LiveObject | undefined = this . _objects . getPool ( ) . get ( objectId ) ;
949+ if ( ! refObject ) {
950+ return undefined ; // RTLM5d2f1
951+ }
952+
953+ if ( refObject . isTombstoned ( ) ) {
954+ // tombstoned objects must not be surfaced to the end users
955+ return undefined ;
956+ }
944957
945- if ( refObject . isTombstoned ( ) ) {
946- // tombstoned objects must not be surfaced to the end users
947- return undefined ;
958+ return refObject ; // RTLM5d2f2
948959 }
949960
950- return refObject ; // RTLM5d2f2
961+ return undefined ; // RTLM5d2g
951962 }
952963
953964 /** @spec RTLM14 */
0 commit comments