polfan-server-js-client 0.2.86 → 0.2.87

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -30,6 +30,7 @@ export declare abstract class TraversableRemoteCollection<ItemT, EventMapT exten
30
30
  current: WindowState;
31
31
  ongoing?: WindowState;
32
32
  limit: number | null;
33
+ retainRatio: number;
33
34
  fetchLimit: number;
34
35
  lastFetchCount: number;
35
36
  oldestId: string | null;
@@ -43,15 +44,23 @@ export declare abstract class TraversableRemoteCollection<ItemT, EventMapT exten
43
44
  */
44
45
  set fetchLimit(value: number);
45
46
  /**
46
- * Maximum numer of items stored in window.
47
+ * Maximum number of items stored in window (High Watermark).
47
48
  * Null for unlimited.
48
49
  */
49
50
  get limit(): number | null;
50
51
  /**
51
- * Maximum numer of items stored in window.
52
+ * Maximum number of items stored in window (High Watermark).
52
53
  * Null for unlimited.
53
54
  */
54
55
  set limit(value: number | null);
56
+ /**
57
+ * Percentage of limit to keep when trimming.
58
+ */
59
+ get retainRatio(): number;
60
+ /**
61
+ * Percentage of limit to keep when trimming.
62
+ */
63
+ set retainRatio(value: number);
55
64
  get hasLatest(): boolean;
56
65
  get hasOldest(): boolean;
57
66
  abstract createMirror(): TraversableRemoteCollection<ItemT, EventMapT>;
@@ -65,7 +74,7 @@ export declare abstract class TraversableRemoteCollection<ItemT, EventMapT exten
65
74
  protected refreshFetchedState(): Promise<void>;
66
75
  protected addItems(newItems: ItemT[], to: 'head' | 'tail'): void;
67
76
  /**
68
- * Return array with messages of count that matching limit.
77
+ * Return array with messages trimmed using High/Low Watermark strategy.
69
78
  */
70
79
  private trimItemsArrayToLimit;
71
80
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polfan-server-js-client",
3
- "version": "0.2.86",
3
+ "version": "0.2.87",
4
4
  "description": "JavaScript client library for handling communication with Polfan chat server.",
5
5
  "author": "Jarosław Żak",
6
6
  "license": "MIT",
@@ -40,14 +40,16 @@ export abstract class TraversableRemoteCollection<
40
40
  protected internalState: {
41
41
  current: WindowState,
42
42
  ongoing?: WindowState,
43
- limit: number | null,
43
+ limit: number | null, // Acts as High Watermark
44
+ retainRatio: number, // Percentage of limit to keep when trimming
44
45
  fetchLimit: number,
45
46
  lastFetchCount: number,
46
47
  oldestId: string | null,
47
48
  } = {
48
49
  current: WindowState.LIVE,
49
50
  ongoing: undefined,
50
- limit: 50,
51
+ limit: 1000,
52
+ retainRatio: 1,
51
53
  fetchLimit: 50,
52
54
  lastFetchCount: 0,
53
55
  oldestId: null,
@@ -68,7 +70,7 @@ export abstract class TraversableRemoteCollection<
68
70
  }
69
71
 
70
72
  /**
71
- * Maximum numer of items stored in window.
73
+ * Maximum number of items stored in window (High Watermark).
72
74
  * Null for unlimited.
73
75
  */
74
76
  public get limit(): number | null {
@@ -76,13 +78,27 @@ export abstract class TraversableRemoteCollection<
76
78
  }
77
79
 
78
80
  /**
79
- * Maximum numer of items stored in window.
81
+ * Maximum number of items stored in window (High Watermark).
80
82
  * Null for unlimited.
81
83
  */
82
84
  public set limit(value: number | null) {
83
85
  this.internalState.limit = value;
84
86
  }
85
87
 
88
+ /**
89
+ * Percentage of limit to keep when trimming.
90
+ */
91
+ public get retainRatio(): number {
92
+ return this.internalState.retainRatio;
93
+ }
94
+
95
+ /**
96
+ * Percentage of limit to keep when trimming.
97
+ */
98
+ public set retainRatio(value: number) {
99
+ this.internalState.retainRatio = value;
100
+ }
101
+
86
102
  public get hasLatest(): boolean {
87
103
  return [WindowState.LATEST, WindowState.LIVE].includes(this.state);
88
104
  }
@@ -111,7 +127,7 @@ export abstract class TraversableRemoteCollection<
111
127
  this.internalState.ongoing = undefined;
112
128
  }
113
129
 
114
- this.deleteAll();
130
+ this._items.deleteAll(); // Directly call deleteAll to prevent event emit.
115
131
  this.addItems(result, 'tail');
116
132
  this.internalState.current = WindowState.LATEST;
117
133
  }
@@ -205,25 +221,31 @@ export abstract class TraversableRemoteCollection<
205
221
  result = this.trimItemsArrayToLimit([...this.items, ...newItems], 'head');
206
222
  }
207
223
 
208
- this.deleteAll();
224
+ this._items.deleteAll(); // Directly call deleteAll to prevent event emit.
209
225
  this.set(...result);
210
226
  }
211
227
 
212
228
  /**
213
- * Return array with messages of count that matching limit.
229
+ * Return array with messages trimmed using High/Low Watermark strategy.
214
230
  */
215
231
  private trimItemsArrayToLimit(items: ItemT[], from: 'head' | 'tail'): ItemT[] {
216
- if (this.limit === null) {
232
+ const highWatermark = this.limit;
233
+
234
+ if (highWatermark === null || items.length <= highWatermark) {
217
235
  return items;
218
236
  }
219
237
 
238
+ const lowWatermark = Math.floor(highWatermark * this.internalState.retainRatio);
239
+
220
240
  if (from === 'head') {
221
- return items.slice(-this.limit);
241
+ return items.slice(-lowWatermark);
222
242
  }
223
243
 
224
244
  if (from === 'tail') {
225
- return items.slice(0, this.limit);
245
+ return items.slice(0, lowWatermark);
226
246
  }
247
+
248
+ return items;
227
249
  }
228
250
  }
229
251
 
@@ -69,7 +69,8 @@ class TestableHistoryWindow extends TraversableRemoteCollection<SimpleMessage> {
69
69
  test('history window - fresh instance', async () => {
70
70
  const window = new TestableHistoryWindow();
71
71
  expect(window.items).toHaveLength(0);
72
- expect(window.limit).toEqual(50);
72
+ expect(window.limit).toEqual(1000);
73
+ expect(window.retainRatio).toEqual(1);
73
74
  });
74
75
 
75
76
  test('history window - states change', async () => {
@@ -251,3 +252,36 @@ test('history window - hasOldest false when in LATEST and length == fetchLimit',
251
252
  expect(window.fetchLimit).toEqual(3);
252
253
  expect(window.hasOldest).toBeFalsy();
253
254
  });
255
+
256
+ test('history window - high/low watermark limit (retainRatio)', async () => {
257
+ const window = new TestableHistoryWindow();
258
+ window.limit = 6; // High Watermark
259
+ window.retainRatio = 0.5; // Low Watermark target = 6 * 0.5 = 3
260
+ window.fetchLimit = 3;
261
+
262
+ await window.resetToLatest(); // [7, 8, 9]
263
+
264
+ expect(window.items).toHaveLength(3);
265
+
266
+ await window.fetchPrevious(); // [4, 5, 6] added to 'head' -> [4, 5, 6, 7, 8, 9]
267
+
268
+ expect(window.items).toHaveLength(6);
269
+ [4, 5, 6, 7, 8, 9].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
270
+
271
+ await window.fetchPrevious(); // [1, 2, 3] added to 'head' -> [1, 2, 3, 4, 5, 6, 7, 8, 9]
272
+
273
+ expect(window.items).toHaveLength(3);
274
+ [1, 2, 3].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
275
+ expect(window.state).toEqual(WindowState.PAST);
276
+
277
+ await window.fetchNext(); // [4, 5, 6] added to 'tail' -> [1, 2, 3, 4, 5, 6]
278
+
279
+ expect(window.items).toHaveLength(6);
280
+ [1, 2, 3, 4, 5, 6].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
281
+
282
+ await window.fetchNext(); // [7, 8, 9] added to 'tail' -> [1, 2, 3, 4, 5, 6, 7, 8, 9]
283
+
284
+ expect(window.items).toHaveLength(3);
285
+ [7, 8, 9].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
286
+ expect(window.state).toEqual(WindowState.LATEST);
287
+ });