feat(liveobjects): implement remaining path-based API — parent references, event bubbling etc#1224
Draft
sacOO7 wants to merge 1 commit into
Conversation
…ubscriptions and event bubbling Completes the path-addressed LiveObjects API on top of the sync engine: - Bridge ResolvedValue (MapRef/CounterRef/Leaf) to the internal graph objects so path resolution returns live references - Replace the untyped ObjectUpdate with a sealed model (MapUpdate/CounterUpdate/NoOp) carrying the source objectMessage and tombstone flag (RTLO4b4, RTLM18, RTLC11) - Track parent references on every graph object and derive getFullPaths() for event bubbling (RTLO3f, RTLO4f-RTLO4h) - Implement RTPO3 path resolution and the read APIs: RealtimeObject#get (RTO23), PathObject value/exists/instance/compactJson (RTPO8, RTPO13/RTPO14) - Add creation value-type evaluation and the path write APIs - Add value-bound typed Instances and PathObject#instance (RTINS5, RTTS6/RTTS7) - Add path/instance subscriptions with depth windows and event bubbling via PathObjectSubscriptionRegister (RTO24, RTPO19) - RTO4c fix: always start a new sync sequence on ATTACHED regardless of the HAS_OBJECTS flag, matching current ably-js - Make stored path strings round-trip-safe by escaping backslashes as well as dots in PathSegments#join - Remove dead createMap/createCounter code paths and re-enable the UTS liveobjects test suites
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PathObject implementation from new API i.e. bubbling events and parentReferenesPath based API i.e. parentReferenes and bubbling events
Path based API i.e. parentReferenes and bubbling events
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Completes the path-based LiveObjects public API in the
liveobjectsKotlin module. The sync/CRDT engine and serialization layers landed earlier on the base branch; this PR fills in everything between them and the public interfaces: value resolution, reads, writes, identity-bound instances, parent references, and subscription event bubbling. ably-jsliveobjectsplugin is the source of truth throughout, with spec points (objects-features.md, plus the unmerged typed-SDK points from ably/specification#491) anchored inline as code comments.What was missing before
The module had a complete sync engine but the path/instance layers were skeletons:
ResolvedValuewrapped the wrong types (public blueprints instead of the internal CRDT objects), every read/write/subscribe method was aTODO(), and update events carried no source message, no tombstone signal and no path information.Changes
Internal graph bridge
ResolvedValueis now a sealed interface over the internal graph:MapRef(InternalLiveMap)/CounterRef(InternalLiveCounter)/Leaf(WireObjectData), resolved per call viaLiveMapEntry.getResolvedValue()(tombstone- and dangling-ref-aware, RTLM5d2).PathSegmentshandles dot-delimited path ↔ segment conversion with escape-aware parsing (RTPO4, RTPO6). Deviation from ably-js:joinescapes backslashes as well as dots, because here the joined string is the storage and gets re-parsed on every resolution (ably-js stores segment arrays and only renders the escaped string). Without this, a key ending in\collides with the escaped-dot separator and breaks lookups/subscriptions.Typed update model
ObjectUpdateis a sealed class (NoOp/MapUpdate/CounterUpdate) carrying the sourceWireObjectMessageand atombstoneflag (RTLO4b4). Both managers thread the message through every apply/merge/diff path (RTLM6h, RTLC6h, RTLM23c).Parent references & event bubbling
parentReferences, keyed by parent objectId per RTLO3f), maintained at all mutation points and rebuilt wholesale after sync (RTO5c10, ordered before the RTO5c7 notifications).getFullPaths()computes all simple paths from root with cycle safety (RTLO4f);notifyUpdatedfans out to instance listeners, then bubbles to path subscribers viaPathObjectSubscriptionRegister(RTO24: prefix + depth coverage, most-preferred candidate path, at-most-once per subscription, per-listener error isolation), then tears down instance listeners on tombstone (RTLO4b4c3).operation == null), and surfaced messages are converted once viatoPublicMessage(PAOM3).Reads, writes and instances
RealtimeObject#get()returns the rootLiveMapPathObjectafter attach + sync (RTO23), bridged from coroutines withsequentialScope.future {}.value()s, map iteration,compactJson()with cycle markers (RTPO13/14).LiveMapValueType/LiveCounterValueType, RTLMV4/RTLCV4): nested create messages first, ownMAP_CREATElast, published together with theMAP_SETin a single protocol message (RTLM20h1).Instancetypes are value-bound (RTINS2a): live map/counter instances delegate to the internal objects; primitives capture the extracted value (binary decoded once, defensively copied out).Fix found during cross-validation against ably-js history
handleStateChange(ATTACHED)now clears buffered operations (RTO4d) and starts a new sync unconditionally (RTO4c). The previous conditional was a port of pre-e280bff1ably-js code that upstream has since removed.Testing & validation
PathSegmentsTestcovers the stored-vs-supplied path invariants and the backslash round-trip regression.runUnitTests,runLiveObjectsUnitTests,checkWithCodenarc,checkstyleMain/Testall green; zeroTODOs remain in the module.objects-features.md/ spec PR README: add a note about the push example/test app #491; behavioral markers (boundary comparisons, error codes, skip predicates, message ordering) were cross-checked against ably-js.(Number)/(Map)) unchanged, existing keep rules remain valid.Notes for reviewers
uts/build.gradle.ktsbut failures there are pending triage in a follow-up — check the spec anchor before assuming an engine bug.entries()skips dangling references (RTLM11d3a) whilekeys()does not, and the backslash escaping described above.🤖 Generated with Claude Code