Skip to content

Commit eb94121

Browse files
committed
Implement .compact() method for PathObject and Instance types for LiveObjects
Resolves PUB-2064
1 parent 113304e commit eb94121

File tree

5 files changed

+460
-24
lines changed

5 files changed

+460
-24
lines changed

ably.d.ts

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2457,6 +2457,28 @@ export type LiveObject = LiveMap | LiveCounter;
24572457
*/
24582458
export type Value = LiveObject | Primitive;
24592459

2460+
/**
2461+
* CompactedValue transforms LiveObject types into plain JavaScript equivalents.
2462+
* LiveMap becomes an object, LiveCounter becomes a number, primitives remain unchanged.
2463+
*/
2464+
export type CompactedValue<T extends Value> =
2465+
// LiveMap types
2466+
[T] extends [LiveMap<infer U>]
2467+
? { [K in keyof U]: CompactedValue<U[K]> }
2468+
: [T] extends [LiveMap<infer U> | undefined]
2469+
? { [K in keyof U]: CompactedValue<U[K]> } | undefined
2470+
: // LiveCounter types
2471+
[T] extends [LiveCounter]
2472+
? number
2473+
: [T] extends [LiveCounter | undefined]
2474+
? number | undefined
2475+
: // Primitive types
2476+
[T] extends [Primitive]
2477+
? T
2478+
: [T] extends [Primitive | undefined]
2479+
? T
2480+
: any;
2481+
24602482
/**
24612483
* PathObjectBase defines the set of common methods on a PathObject
24622484
* that are present regardless of the underlying type specified by the type parameter T.
@@ -2469,13 +2491,6 @@ interface PathObjectBase<_T extends Value> {
24692491
*/
24702492
path(): string;
24712493

2472-
/**
2473-
* Get a JavaScript object representation of the object at this path.
2474-
*
2475-
* @experimental
2476-
*/
2477-
compact(): any;
2478-
24792494
/**
24802495
* Registers a listener that is called each time the object or a primitive value at this path is updated.
24812496
*
@@ -2579,6 +2594,13 @@ export interface LiveMapPathObject<T extends Record<string, Value> = Record<stri
25792594
* @experimental
25802595
*/
25812596
instance(): LiveMapInstance<T> | undefined;
2597+
2598+
/**
2599+
* Get a JavaScript object representation of the map at this path.
2600+
*
2601+
* @experimental
2602+
*/
2603+
compact(): CompactedValue<LiveMap<T>>;
25822604
}
25832605

25842606
/**
@@ -2601,6 +2623,13 @@ export interface LiveCounterPathObject extends PathObjectBase<LiveCounter>, Live
26012623
* @experimental
26022624
*/
26032625
instance(): LiveCounterInstance | undefined;
2626+
2627+
/**
2628+
* Get a number representation of the counter at this path.
2629+
*
2630+
* @experimental
2631+
*/
2632+
compact(): CompactedValue<LiveCounter>;
26042633
}
26052634

26062635
/**
@@ -2614,6 +2643,13 @@ export interface PrimitivePathObject<T extends Primitive = Primitive> extends Pa
26142643
* @experimental
26152644
*/
26162645
value(): T | undefined;
2646+
2647+
/**
2648+
* Get a JavaScript object representation of the primitive value at this path.
2649+
*
2650+
* @experimental
2651+
*/
2652+
compact(): CompactedValue<T>;
26172653
}
26182654

26192655
/**
@@ -2692,6 +2728,13 @@ export interface AnyPathObject<T extends Value = Value>
26922728
* @experimental
26932729
*/
26942730
instance<T extends Value = Value>(): Instance<T> | undefined;
2731+
2732+
/**
2733+
* Get a JavaScript object representation of the object at this path.
2734+
*
2735+
* @experimental
2736+
*/
2737+
compact<T extends Value = Value>(): CompactedValue<T> | undefined;
26952738
}
26962739

26972740
/**
@@ -2701,8 +2744,8 @@ export interface AnyPathObject<T extends Value = Value>
27012744
*
27022745
* @experimental
27032746
*/
2704-
export type PathObject<T extends Value = Value> = [T] extends [LiveMap<infer T>]
2705-
? LiveMapPathObject<T>
2747+
export type PathObject<T extends Value = Value> = [T] extends [LiveMap<infer U>]
2748+
? LiveMapPathObject<U>
27062749
: [T] extends [LiveCounter]
27072750
? LiveCounterPathObject
27082751
: [T] extends [Primitive]
@@ -2862,13 +2905,6 @@ interface InstanceBase<T extends Value> {
28622905
*/
28632906
id(): string;
28642907

2865-
/**
2866-
* Get a JavaScript object representation of the instance.
2867-
*
2868-
* @experimental
2869-
*/
2870-
compact(): any;
2871-
28722908
/**
28732909
* Registers a listener that is called each time this instance is updated.
28742910
*
@@ -2943,6 +2979,13 @@ export interface LiveMapInstance<T extends Record<string, Value> = Record<string
29432979
* @experimental
29442980
*/
29452981
get<K extends keyof T & string>(key: K): Instance<T[K]> | undefined;
2982+
2983+
/**
2984+
* Get a JavaScript object representation of the map instance.
2985+
*
2986+
* @experimental
2987+
*/
2988+
compact(): CompactedValue<LiveMap<T>>;
29462989
}
29472990

29482991
/**
@@ -2955,6 +2998,13 @@ export interface LiveCounterInstance extends InstanceBase<LiveCounter>, LiveCoun
29552998
* @experimental
29562999
*/
29573000
value(): number;
3001+
3002+
/**
3003+
* Get a number representation of the counter instance.
3004+
*
3005+
* @experimental
3006+
*/
3007+
compact(): CompactedValue<LiveCounter>;
29583008
}
29593009

29603010
/**
@@ -2967,6 +3017,13 @@ export interface PrimitiveInstance<T extends Primitive = Primitive> {
29673017
* @experimental
29683018
*/
29693019
value(): T;
3020+
3021+
/**
3022+
* Get a JavaScript object representation of the primitive value.
3023+
*
3024+
* @experimental
3025+
*/
3026+
compact(): CompactedValue<T>;
29703027
}
29713028

29723029
/**
@@ -3033,6 +3090,13 @@ export interface AnyInstance<T extends Value> extends InstanceBase<T>, AnyInstan
30333090
* @experimental
30343091
*/
30353092
value<T extends number | Primitive = number | Primitive>(): T | undefined;
3093+
3094+
/**
3095+
* Get a JavaScript object representation of the object instance.
3096+
*
3097+
* @experimental
3098+
*/
3099+
compact<T extends Value = Value>(): CompactedValue<T> | undefined;
30363100
}
30373101

30383102
/**
@@ -3042,8 +3106,8 @@ export interface AnyInstance<T extends Value> extends InstanceBase<T>, AnyInstan
30423106
*
30433107
* @experimental
30443108
*/
3045-
export type Instance<T extends Value> = [T] extends [LiveMap<infer T>]
3046-
? LiveMapInstance<T>
3109+
export type Instance<T extends Value> = [T] extends [LiveMap<infer U>]
3110+
? LiveMapInstance<U>
30473111
: [T] extends [LiveCounter]
30483112
? LiveCounterInstance
30493113
: [T] extends [Primitive]

src/plugins/objects/instance.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import type BaseClient from 'common/lib/client/baseclient';
2-
import type { AnyInstance, EventCallback, Instance, InstanceSubscriptionEvent, Primitive, Value } from '../../../ably';
2+
import type {
3+
AnyInstance,
4+
CompactedValue,
5+
EventCallback,
6+
Instance,
7+
InstanceSubscriptionEvent,
8+
Primitive,
9+
Value,
10+
} from '../../../ably';
311
import { LiveCounter } from './livecounter';
412
import { LiveMap } from './livemap';
513
import { LiveObject, LiveObjectUpdate, SubscribeResponse } from './liveobject';
@@ -30,8 +38,12 @@ export class DefaultInstance<T extends Value> implements AnyInstance<T> {
3038
return this._value.getObjectId();
3139
}
3240

33-
compact(): any {
34-
throw new Error('Not implemented');
41+
compact<U extends Value = Value>(): CompactedValue<U> | undefined {
42+
if (this._value instanceof LiveMap) {
43+
return this._value.compact() as CompactedValue<U>;
44+
}
45+
46+
return this.value() as CompactedValue<U>;
3547
}
3648

3749
get<U extends Value = Value>(key: string): Instance<U> | undefined {

src/plugins/objects/livemap.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { dequal } from 'dequal';
22

33
import type { Bufferlike } from 'common/platform';
44
import type * as API from '../../../ably';
5+
import { LiveCounter } from './livecounter';
56
import { LiveCounterValueType } from './livecountervaluetype';
67
import { LiveMapValueType } from './livemapvaluetype';
78
import { LiveObject, LiveObjectData, LiveObjectUpdate, LiveObjectUpdateNoop } from './liveobject';
@@ -640,6 +641,34 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
640641
return super.clearData();
641642
}
642643

644+
/**
645+
* Returns a plain JavaScript object representation of this LiveMap.
646+
* LiveMap values are recursively compacted using their own compact methods.
647+
*
648+
* @internal
649+
*/
650+
compact(): { [K in keyof T]: any } {
651+
const result: Record<keyof T, any> = {} as Record<keyof T, any>;
652+
653+
// Use public entries() method to ensure we only include publicly exposed properties
654+
for (const [key, value] of this.entries()) {
655+
if (value instanceof LiveMap) {
656+
result[key] = value.compact();
657+
continue;
658+
}
659+
660+
if (value instanceof LiveCounter) {
661+
result[key] = value.value();
662+
continue;
663+
}
664+
665+
// Other values return as is
666+
result[key] = value;
667+
}
668+
669+
return result;
670+
}
671+
643672
/** @spec RTLM4 */
644673
protected _getZeroValueData(): LiveMapData {
645674
return { data: new Map<string, LiveMapEntry>() };

src/plugins/objects/pathobject.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type BaseClient from 'common/lib/client/baseclient';
22
import type * as API from '../../../ably';
33
import type {
44
AnyPathObject,
5+
CompactedValue,
56
EventCallback,
67
Instance,
78
PathObject,
@@ -44,10 +45,25 @@ export class DefaultPathObject<T extends Value = Value> implements AnyPathObject
4445
}
4546

4647
/**
47-
* Returns a compact representation of the object at this path
48+
* Returns a JavaScript object representation of the object at this path
4849
*/
49-
compact(): any {
50-
throw new Error('Not implemented');
50+
compact<U extends Value = Value>(): CompactedValue<U> | undefined {
51+
try {
52+
const resolved = this._resolvePath(this._path);
53+
54+
if (resolved instanceof LiveMap) {
55+
return resolved.compact() as CompactedValue<U>;
56+
}
57+
58+
return this.value() as CompactedValue<U>;
59+
} catch (error) {
60+
if (this._client.Utils.isErrorInfoOrPartialErrorInfo(error)) {
61+
// ignore ErrorInfos indicating path resolution failure and return undefined
62+
return undefined;
63+
}
64+
// otherwise rethrow unexpected errors
65+
throw error;
66+
}
5167
}
5268

5369
/**

0 commit comments

Comments
 (0)