@candidstartup/simple-spreadsheet-data 0.11.0 → 0.12.0

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.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { SpreadsheetData, ItemOffsetMapping, CellValue, Result, SpreadsheetDataError, ValidationError, LogEntry, EventLog, SequenceId, ResultAsync, AddEntryError, LogMetadata, MetadataError, QueryValue, QueryError, TruncateError } from '@candidstartup/infinisheet-types';
1
+ import { SpreadsheetData, Result, StorageError, ItemOffsetMapping, CellValue, ResultAsync, SpreadsheetDataError, ValidationError, LogEntry, EventLog, SequenceId, AddEntryError, LogMetadata, MetadataError, QueryValue, QueryError, TruncateError } from '@candidstartup/infinisheet-types';
2
2
 
3
3
  /**
4
4
  * Branding Enum. Used by {@link SimpleSnapshot} to ensure that
@@ -27,18 +27,21 @@ interface SimpleSnapshot {
27
27
  * for simple sample apps. Simplest possible implementation, no attempt at optimization.
28
28
  */
29
29
  declare class SimpleSpreadsheetData implements SpreadsheetData<SimpleSnapshot> {
30
- #private;
31
30
  constructor();
32
31
  subscribe(onDataChange: () => void): () => void;
33
32
  getSnapshot(): SimpleSnapshot;
33
+ getLoadStatus(_snapshot: SimpleSnapshot): Result<boolean, StorageError>;
34
34
  getRowCount(snapshot: SimpleSnapshot): number;
35
35
  getRowItemOffsetMapping(_snapshot: SimpleSnapshot): ItemOffsetMapping;
36
36
  getColumnCount(snapshot: SimpleSnapshot): number;
37
37
  getColumnItemOffsetMapping(_snapshot: SimpleSnapshot): ItemOffsetMapping;
38
38
  getCellValue(snapshot: SimpleSnapshot, row: number, column: number): CellValue;
39
39
  getCellFormat(snapshot: SimpleSnapshot, row: number, column: number): string | undefined;
40
- setCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): Result<void, SpreadsheetDataError>;
40
+ setCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): ResultAsync<void, SpreadsheetDataError>;
41
41
  isValidCellValueAndFormat(_row: number, _column: number, _value: CellValue, _format: string | undefined): Result<void, ValidationError>;
42
+ private notifyListeners;
43
+ private listeners;
44
+ private content;
42
45
  }
43
46
 
44
47
  /**
@@ -76,7 +79,6 @@ type SnapshotType<T> = T extends SpreadsheetData<infer TResult> ? TResult : neve
76
79
  * @typeParam EditSnapshot - Type of snapshot used by `EditData`. By default, inferred from `EditData`.
77
80
  */
78
81
  declare class LayeredSpreadsheetData<BaseData extends SpreadsheetData<BaseSnapshot>, EditData extends SpreadsheetData<EditSnapshot>, BaseSnapshot = SnapshotType<BaseData>, EditSnapshot = SnapshotType<EditData>> implements SpreadsheetData<LayeredSnapshot<BaseSnapshot, EditSnapshot>> {
79
- #private;
80
82
  /**
81
83
  * Creates a `LayeredSpreadsheetData` instance from two existing `SpreadsheetData` instances.
82
84
  *
@@ -88,24 +90,55 @@ declare class LayeredSpreadsheetData<BaseData extends SpreadsheetData<BaseSnapsh
88
90
  constructor(base: BaseData, edit: EditData);
89
91
  subscribe(onDataChange: () => void): () => void;
90
92
  getSnapshot(): LayeredSnapshot<BaseSnapshot, EditSnapshot>;
93
+ getLoadStatus(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): Result<boolean, StorageError>;
91
94
  getRowCount(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): number;
92
95
  getRowItemOffsetMapping(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): ItemOffsetMapping;
93
96
  getColumnCount(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): number;
94
97
  getColumnItemOffsetMapping(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): ItemOffsetMapping;
95
98
  getCellValue(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>, row: number, column: number): CellValue;
96
99
  getCellFormat(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>, row: number, column: number): string | undefined;
97
- setCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): Result<void, SpreadsheetDataError>;
100
+ setCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): ResultAsync<void, SpreadsheetDataError>;
98
101
  isValidCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): Result<void, ValidationError>;
102
+ private base;
103
+ private edit;
104
+ private content;
99
105
  }
100
106
 
107
+ /**
108
+ * Reference implementation of {@link EventLog}
109
+ *
110
+ * In-memory event log
111
+ *
112
+ * Intended for use as a mock, to compare with an optimized implementation when testing and
113
+ * for simple sample apps. Simplest possible implementation, no attempt at optimization.
114
+ */
101
115
  declare class SimpleEventLog<T extends LogEntry> implements EventLog<T> {
102
- #private;
103
116
  constructor();
104
117
  addEntry(entry: T, sequenceId: SequenceId): ResultAsync<void, AddEntryError>;
105
118
  setMetadata(sequenceId: SequenceId, metadata: LogMetadata): ResultAsync<void, MetadataError>;
106
119
  query(start: SequenceId | 'snapshot' | 'start', end: SequenceId | 'end'): ResultAsync<QueryValue<T>, QueryError>;
107
120
  truncate(start: SequenceId): ResultAsync<void, TruncateError>;
108
121
  private findSnapshotIndex;
122
+ private startSequenceId;
123
+ private endSequenceId;
124
+ private entries;
125
+ }
126
+
127
+ /**
128
+ * Wrapper around an {@link EventLog} that injects latency
129
+ *
130
+ * Intended for use when simulating the effects of latency in a real implementation
131
+ */
132
+ declare class DelayEventLog<T extends LogEntry> implements EventLog<T> {
133
+ constructor(base: EventLog<T>, delay?: number);
134
+ /** Delay in milliseconds to add to response from each API call */
135
+ delay: number;
136
+ addEntry(entry: T, sequenceId: SequenceId): ResultAsync<void, AddEntryError>;
137
+ setMetadata(sequenceId: SequenceId, metadata: LogMetadata): ResultAsync<void, MetadataError>;
138
+ query(start: SequenceId | 'snapshot' | 'start', end: SequenceId | 'end'): ResultAsync<QueryValue<T>, QueryError>;
139
+ truncate(start: SequenceId): ResultAsync<void, TruncateError>;
140
+ private base;
109
141
  }
110
142
 
111
- export { type LayeredSnapshot, LayeredSpreadsheetData, SimpleEventLog, type SimpleSnapshot, SimpleSpreadsheetData, type SnapshotType, _LayeredSnapshotBrand, _SimpleSnapshotBrand };
143
+ export { DelayEventLog, LayeredSpreadsheetData, SimpleEventLog, SimpleSpreadsheetData, _LayeredSnapshotBrand, _SimpleSnapshotBrand };
144
+ export type { LayeredSnapshot, SimpleSnapshot, SnapshotType };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { FixedSizeItemOffsetMapping, rowColCoordsToRef, ok, errAsync, conflictError, okAsync, infinisheetRangeError } from '@candidstartup/infinisheet-types';
1
+ import { FixedSizeItemOffsetMapping, ok, rowColCoordsToRef, okAsync, errAsync, conflictError, infinisheetRangeError, ResultAsync } from '@candidstartup/infinisheet-types';
2
2
 
3
3
  /**
4
4
  * Branding Enum. Used by {@link SimpleSnapshot} to ensure that
@@ -29,21 +29,24 @@ function asSnapshot$1(snapshot) {
29
29
  */
30
30
  class SimpleSpreadsheetData {
31
31
  constructor() {
32
- this.#listeners = [];
33
- this.#content = {
32
+ this.listeners = [];
33
+ this.content = {
34
34
  values: {},
35
35
  rowCount: 0,
36
36
  colCount: 0
37
37
  };
38
38
  }
39
39
  subscribe(onDataChange) {
40
- this.#listeners = [...this.#listeners, onDataChange];
40
+ this.listeners = [...this.listeners, onDataChange];
41
41
  return () => {
42
- this.#listeners = this.#listeners.filter(l => l !== onDataChange);
42
+ this.listeners = this.listeners.filter(l => l !== onDataChange);
43
43
  };
44
44
  }
45
45
  getSnapshot() {
46
- return asSnapshot$1(this.#content);
46
+ return asSnapshot$1(this.content);
47
+ }
48
+ getLoadStatus(_snapshot) {
49
+ return ok(true);
47
50
  }
48
51
  getRowCount(snapshot) {
49
52
  return asContent$1(snapshot).rowCount;
@@ -66,29 +69,28 @@ class SimpleSpreadsheetData {
66
69
  return asContent$1(snapshot).values[ref]?.format;
67
70
  }
68
71
  setCellValueAndFormat(row, column, value, format) {
69
- const curr = this.#content;
72
+ const curr = this.content;
70
73
  const ref = rowColCoordsToRef(row, column);
71
74
  // Snapshot semantics preserved by treating SimpleSnapshot as an immutable data structure which is
72
75
  // replaced with a modified copy on every update. Yes, this is horribly inefficient.
73
76
  // For simplicity, setting a value to undefined stores it explicitly rather than removing it. Functional
74
77
  // behavior is the same.
75
- this.#content = {
78
+ this.content = {
76
79
  values: { ...curr.values, [ref]: { value, format } },
77
80
  rowCount: Math.max(curr.rowCount, row + 1),
78
81
  colCount: Math.max(curr.colCount, column + 1)
79
82
  };
80
- this.#notifyListeners();
81
- return ok();
83
+ return okAsync().andTee(() => this.notifyListeners());
82
84
  }
83
85
  isValidCellValueAndFormat(_row, _column, _value, _format) {
84
86
  return ok();
85
87
  }
86
- #notifyListeners() {
87
- for (const listener of this.#listeners)
88
+ notifyListeners() {
89
+ for (const listener of this.listeners)
88
90
  listener();
89
91
  }
90
- #listeners;
91
- #content;
92
+ listeners;
93
+ content;
92
94
  }
93
95
 
94
96
  /**
@@ -130,84 +132,96 @@ class LayeredSpreadsheetData {
130
132
  * @param edit - `SpreadsheetData` instance to use for the edit layer
131
133
  */
132
134
  constructor(base, edit) {
133
- this.#base = base;
134
- this.#edit = edit;
135
+ this.base = base;
136
+ this.edit = edit;
135
137
  }
136
138
  subscribe(onDataChange) {
137
- const unsubscribeBase = this.#base.subscribe(onDataChange);
138
- const unsubscribeEdit = this.#edit.subscribe(onDataChange);
139
+ const unsubscribeBase = this.base.subscribe(onDataChange);
140
+ const unsubscribeEdit = this.edit.subscribe(onDataChange);
139
141
  return () => {
140
142
  unsubscribeBase();
141
143
  unsubscribeEdit();
142
144
  };
143
145
  }
144
146
  getSnapshot() {
145
- const baseSnapshot = this.#base.getSnapshot();
146
- const editSnapshot = this.#edit.getSnapshot();
147
- if (!this.#content || this.#content.base != baseSnapshot || this.#content.edit != editSnapshot) {
148
- this.#content = { base: baseSnapshot, edit: editSnapshot };
147
+ const baseSnapshot = this.base.getSnapshot();
148
+ const editSnapshot = this.edit.getSnapshot();
149
+ if (!this.content || this.content.base != baseSnapshot || this.content.edit != editSnapshot) {
150
+ this.content = { base: baseSnapshot, edit: editSnapshot };
149
151
  }
150
- return asSnapshot(this.#content);
152
+ return asSnapshot(this.content);
153
+ }
154
+ getLoadStatus(snapshot) {
155
+ const content = asContent(snapshot);
156
+ return this.base.getLoadStatus(content.base).andThen((t1) => this.edit.getLoadStatus(content.edit).map((t2) => t1 && t2));
151
157
  }
152
158
  getRowCount(snapshot) {
153
159
  const content = asContent(snapshot);
154
- return Math.max(this.#base.getRowCount(content.base), this.#edit.getRowCount(content.edit));
160
+ return Math.max(this.base.getRowCount(content.base), this.edit.getRowCount(content.edit));
155
161
  }
156
162
  getRowItemOffsetMapping(snapshot) {
157
- return this.#base.getRowItemOffsetMapping(asContent(snapshot).base);
163
+ return this.base.getRowItemOffsetMapping(asContent(snapshot).base);
158
164
  }
159
165
  getColumnCount(snapshot) {
160
166
  const content = asContent(snapshot);
161
- return Math.max(this.#base.getColumnCount(content.base), this.#edit.getColumnCount(content.edit));
167
+ return Math.max(this.base.getColumnCount(content.base), this.edit.getColumnCount(content.edit));
162
168
  }
163
169
  getColumnItemOffsetMapping(snapshot) {
164
- return this.#base.getColumnItemOffsetMapping(asContent(snapshot).base);
170
+ return this.base.getColumnItemOffsetMapping(asContent(snapshot).base);
165
171
  }
166
172
  getCellValue(snapshot, row, column) {
167
173
  const content = asContent(snapshot);
168
- const editValue = this.#edit.getCellValue(content.edit, row, column);
174
+ const editValue = this.edit.getCellValue(content.edit, row, column);
169
175
  if (editValue !== undefined)
170
176
  return editValue;
171
- return this.#base.getCellValue(content.base, row, column);
177
+ return this.base.getCellValue(content.base, row, column);
172
178
  }
173
179
  getCellFormat(snapshot, row, column) {
174
180
  const content = asContent(snapshot);
175
- const editValue = this.#edit.getCellValue(content.edit, row, column);
176
- return (editValue === undefined) ? this.#base.getCellFormat(content.base, row, column) : this.#edit.getCellFormat(content.edit, row, column);
181
+ const editValue = this.edit.getCellValue(content.edit, row, column);
182
+ return (editValue === undefined) ? this.base.getCellFormat(content.base, row, column) : this.edit.getCellFormat(content.edit, row, column);
177
183
  }
178
184
  setCellValueAndFormat(row, column, value, format) {
179
- const result = this.#base.isValidCellValueAndFormat(row, column, value, format);
180
- return result.andThen(() => this.#edit.setCellValueAndFormat(row, column, value, format));
185
+ const result = this.base.isValidCellValueAndFormat(row, column, value, format);
186
+ return result.asyncAndThen(() => this.edit.setCellValueAndFormat(row, column, value, format));
181
187
  }
182
188
  // Must be valid for both layers
183
189
  isValidCellValueAndFormat(row, column, value, format) {
184
- const result = this.#base.isValidCellValueAndFormat(row, column, value, format);
185
- return result.andThen(() => this.#edit.isValidCellValueAndFormat(row, column, value, format));
190
+ const result = this.base.isValidCellValueAndFormat(row, column, value, format);
191
+ return result.andThen(() => this.edit.isValidCellValueAndFormat(row, column, value, format));
186
192
  }
187
- #base;
188
- #edit;
189
- #content;
193
+ base;
194
+ edit;
195
+ content;
190
196
  }
191
197
 
192
198
  const QUERY_PAGE_SIZE = 10;
199
+ /**
200
+ * Reference implementation of {@link EventLog}
201
+ *
202
+ * In-memory event log
203
+ *
204
+ * Intended for use as a mock, to compare with an optimized implementation when testing and
205
+ * for simple sample apps. Simplest possible implementation, no attempt at optimization.
206
+ */
193
207
  class SimpleEventLog {
194
208
  constructor() {
195
- this.#startSequenceId = 0n;
196
- this.#endSequenceId = 0n;
197
- this.#entries = [];
209
+ this.startSequenceId = 0n;
210
+ this.endSequenceId = 0n;
211
+ this.entries = [];
198
212
  }
199
213
  addEntry(entry, sequenceId) {
200
- if (sequenceId !== this.#endSequenceId)
201
- return errAsync(conflictError("sequenceId is not next sequence id", this.#endSequenceId));
202
- this.#entries.push(entry);
203
- this.#endSequenceId++;
214
+ if (sequenceId !== this.endSequenceId)
215
+ return errAsync(conflictError("sequenceId is not next sequence id", this.endSequenceId));
216
+ this.entries.push(entry);
217
+ this.endSequenceId++;
204
218
  return okAsync();
205
219
  }
206
220
  setMetadata(sequenceId, metadata) {
207
- if (sequenceId < this.#startSequenceId || sequenceId >= this.#endSequenceId)
221
+ if (sequenceId < this.startSequenceId || sequenceId >= this.endSequenceId)
208
222
  return errAsync(infinisheetRangeError(`Log entry with sequenceId ${sequenceId} does not exist`));
209
- const index = Number(sequenceId - this.#startSequenceId);
210
- const entry = this.#entries[index];
223
+ const index = Number(sequenceId - this.startSequenceId);
224
+ const entry = this.entries[index];
211
225
  if ("snapshot" in metadata)
212
226
  entry.snapshot = metadata.snapshot;
213
227
  if ("history" in metadata)
@@ -218,58 +232,94 @@ class SimpleEventLog {
218
232
  }
219
233
  query(start, end) {
220
234
  if (start === 'start')
221
- start = this.#startSequenceId;
235
+ start = this.startSequenceId;
222
236
  else if (start === 'snapshot')
223
- start = this.#startSequenceId + BigInt(this.findSnapshotIndex());
224
- else if (start < this.#startSequenceId || start > this.#endSequenceId)
237
+ start = this.startSequenceId + BigInt(this.findSnapshotIndex());
238
+ else if (start < this.startSequenceId || start > this.endSequenceId)
225
239
  return errAsync(infinisheetRangeError("start index out of range"));
226
240
  if (end === 'end')
227
- end = this.#endSequenceId;
241
+ end = this.endSequenceId;
228
242
  const num = end - start;
229
243
  const isComplete = num <= BigInt(QUERY_PAGE_SIZE);
230
244
  let numToReturn = isComplete ? Number(num) : QUERY_PAGE_SIZE;
231
- const firstIndex = Number(start - this.#startSequenceId);
232
- if (firstIndex + numToReturn > this.#entries.length)
233
- numToReturn = this.#entries.length - firstIndex;
245
+ const firstIndex = Number(start - this.startSequenceId);
246
+ if (firstIndex + numToReturn > this.entries.length)
247
+ numToReturn = this.entries.length - firstIndex;
234
248
  const value = {
235
249
  startSequenceId: start,
236
250
  endSequenceId: start + BigInt(numToReturn),
237
251
  isComplete,
238
- entries: this.#entries.slice(firstIndex, firstIndex + numToReturn)
252
+ entries: this.entries.slice(firstIndex, firstIndex + numToReturn)
239
253
  };
240
254
  return okAsync(value);
241
255
  }
242
256
  truncate(start) {
243
- if (start < this.#startSequenceId)
257
+ if (start < this.startSequenceId)
244
258
  return errAsync(infinisheetRangeError("start before start entry in the log"));
245
- if (start === this.#startSequenceId)
259
+ if (start === this.startSequenceId)
246
260
  return okAsync();
247
- if (start === this.#endSequenceId) {
248
- this.#startSequenceId = start;
249
- this.#endSequenceId = start;
250
- this.#entries = [];
261
+ if (start === this.endSequenceId) {
262
+ this.startSequenceId = start;
263
+ this.endSequenceId = start;
264
+ this.entries = [];
251
265
  return okAsync();
252
266
  }
253
- if (start > this.#endSequenceId)
267
+ if (start > this.endSequenceId)
254
268
  return errAsync(infinisheetRangeError("start after end entry in the log"));
255
- const numToRemove = start - this.#startSequenceId;
256
- this.#startSequenceId = start;
257
- this.#entries.splice(0, Number(numToRemove));
269
+ const numToRemove = start - this.startSequenceId;
270
+ this.startSequenceId = start;
271
+ this.entries.splice(0, Number(numToRemove));
258
272
  return okAsync();
259
273
  }
260
274
  findSnapshotIndex() {
261
- for (let i = this.#entries.length - 1; i > 0; i--) {
262
- const entry = this.#entries[i];
275
+ for (let i = this.entries.length - 1; i > 0; i--) {
276
+ const entry = this.entries[i];
263
277
  if (entry.snapshot)
264
278
  return i;
265
279
  }
266
280
  // If no other entry has a snapshot use the first (whether it has a snapshot or not)
267
281
  return 0;
268
282
  }
269
- #startSequenceId;
270
- #endSequenceId;
271
- #entries;
283
+ startSequenceId;
284
+ endSequenceId;
285
+ entries;
286
+ }
287
+
288
+ function delayPromise(value, delay) {
289
+ return new Promise((resolve) => {
290
+ setTimeout(() => resolve(value), delay);
291
+ });
292
+ }
293
+ function delayResult(result, delay) {
294
+ const promiseLike = result.then((r) => delayPromise(r, delay));
295
+ return new ResultAsync(Promise.resolve(promiseLike));
296
+ }
297
+ /**
298
+ * Wrapper around an {@link EventLog} that injects latency
299
+ *
300
+ * Intended for use when simulating the effects of latency in a real implementation
301
+ */
302
+ class DelayEventLog {
303
+ constructor(base, delay = 0) {
304
+ this.base = base;
305
+ this.delay = delay;
306
+ }
307
+ /** Delay in milliseconds to add to response from each API call */
308
+ delay;
309
+ addEntry(entry, sequenceId) {
310
+ return delayResult(this.base.addEntry(entry, sequenceId), this.delay);
311
+ }
312
+ setMetadata(sequenceId, metadata) {
313
+ return delayResult(this.base.setMetadata(sequenceId, metadata), this.delay);
314
+ }
315
+ query(start, end) {
316
+ return delayResult(this.base.query(start, end), this.delay);
317
+ }
318
+ truncate(start) {
319
+ return delayResult(this.base.truncate(start), this.delay);
320
+ }
321
+ base;
272
322
  }
273
323
 
274
- export { LayeredSpreadsheetData, SimpleEventLog, SimpleSpreadsheetData, _LayeredSnapshotBrand, _SimpleSnapshotBrand };
324
+ export { DelayEventLog, LayeredSpreadsheetData, SimpleEventLog, SimpleSpreadsheetData, _LayeredSnapshotBrand, _SimpleSnapshotBrand };
275
325
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/SimpleSpreadsheetData.ts","../src/LayeredSpreadsheetData.ts","../src/SimpleEventLog.ts"],"sourcesContent":["import type { CellValue, SpreadsheetData, RowColRef, ItemOffsetMapping, Result, \n SpreadsheetDataError, ValidationError } from \"@candidstartup/infinisheet-types\";\nimport { FixedSizeItemOffsetMapping, rowColCoordsToRef, ok } from \"@candidstartup/infinisheet-types\";\n\ninterface CellContent {\n value: CellValue;\n format: string|undefined;\n}\n\ninterface SimpleSnapshotContent {\n values: Record<RowColRef,CellContent>;\n rowCount: number;\n colCount: number;\n}\n\n/** \n * Branding Enum. Used by {@link SimpleSnapshot} to ensure that\n * you'll get a type error if you pass some random object where a `SimpleSnapshot`\n * is expected.\n * @internal\n */\nexport enum _SimpleSnapshotBrand { _DO_NOT_USE=\"\" };\n\n/**\n * Opaque type representing a {@link SimpleSpreadsheetData} snapshot. All the\n * internal implementation details are hidden from the exported API.\n */\nexport interface SimpleSnapshot {\n /** @internal */\n _brand: _SimpleSnapshotBrand;\n}\n\nconst rowItemOffsetMapping = new FixedSizeItemOffsetMapping(30);\nconst columnItemOffsetMapping = new FixedSizeItemOffsetMapping(100);\n\nfunction asContent(snapshot: SimpleSnapshot) {\n return snapshot as unknown as SimpleSnapshotContent;\n}\n\nfunction asSnapshot(snapshot: SimpleSnapshotContent) {\n return snapshot as unknown as SimpleSnapshot;\n}\n\n/**\n * Reference implementation of {@link SpreadsheetData}\n * \n * Editable in-memory spreadsheet data container. Starts out empty. Use the API to fill\n * with data!\n * \n * Intended for use as a mock, to compare with an optimized implementation when testing and\n * for simple sample apps. Simplest possible implementation, no attempt at optimization.\n */\nexport class SimpleSpreadsheetData implements SpreadsheetData<SimpleSnapshot> {\n constructor () {\n this.#listeners = [];\n this.#content = {\n values: {},\n rowCount: 0,\n colCount: 0\n }\n }\n\n subscribe(onDataChange: () => void): () => void {\n this.#listeners = [...this.#listeners, onDataChange];\n return () => {\n this.#listeners = this.#listeners.filter(l => l !== onDataChange);\n }\n }\n\n getSnapshot(): SimpleSnapshot {\n return asSnapshot(this.#content);\n }\n\n getRowCount(snapshot: SimpleSnapshot): number {\n return asContent(snapshot).rowCount;\n }\n\n getRowItemOffsetMapping(_snapshot: SimpleSnapshot): ItemOffsetMapping {\n return rowItemOffsetMapping;\n }\n\n getColumnCount(snapshot: SimpleSnapshot): number {\n return asContent(snapshot).colCount;\n }\n\n getColumnItemOffsetMapping(_snapshot: SimpleSnapshot): ItemOffsetMapping {\n return columnItemOffsetMapping\n }\n\n getCellValue(snapshot: SimpleSnapshot, row: number, column: number): CellValue {\n const ref = rowColCoordsToRef(row, column);\n return asContent(snapshot).values[ref]?.value;\n }\n\n getCellFormat(snapshot: SimpleSnapshot, row: number, column: number): string | undefined {\n const ref = rowColCoordsToRef(row, column);\n return asContent(snapshot).values[ref]?.format;\n }\n\n setCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): Result<void,SpreadsheetDataError> {\n const curr = this.#content;\n const ref = rowColCoordsToRef(row, column);\n\n // Snapshot semantics preserved by treating SimpleSnapshot as an immutable data structure which is \n // replaced with a modified copy on every update. Yes, this is horribly inefficient. \n // For simplicity, setting a value to undefined stores it explicitly rather than removing it. Functional\n // behavior is the same.\n this.#content = {\n values: { ...curr.values, [ref]: { value, format }},\n rowCount: Math.max(curr.rowCount, row+1),\n colCount: Math.max(curr.colCount, column+1)\n }\n this.#notifyListeners();\n\n return ok();\n }\n\n isValidCellValueAndFormat(_row: number, _column: number, _value: CellValue, _format: string | undefined): Result<void,ValidationError> {\n return ok(); \n }\n\n #notifyListeners() {\n for (const listener of this.#listeners)\n listener();\n }\n\n #listeners: (() => void)[];\n #content: SimpleSnapshotContent;\n}\n","import type { CellValue, SpreadsheetData, ItemOffsetMapping, Result, \n SpreadsheetDataError, ValidationError } from \"@candidstartup/infinisheet-types\";\n\ninterface LayeredSnapshotContent<BaseSnapshot, EditSnapshot> {\n base: BaseSnapshot,\n edit: EditSnapshot\n}\n\n/** \n * Branding Enum. Used by {@link LayeredSnapshot} to ensure that\n * you'll get a type error if you pass some random object where a `LayeredSnapshot`\n * is expected.\n * @internal\n */\nexport enum _LayeredSnapshotBrand { _DO_NOT_USE=\"\" };\n\n/**\n * Opaque type representing a {@link LayeredSpreadsheetData} snapshot. All the\n * internal implementation details are hidden from the exported API.\n */\nexport interface LayeredSnapshot<BaseSnapshot,EditSnapshot> {\n /** @internal */\n _brand: [ _LayeredSnapshotBrand, BaseSnapshot, EditSnapshot ]\n}\n\nfunction asContent<Base,Edit>(snapshot: LayeredSnapshot<Base,Edit>) {\n return snapshot as unknown as LayeredSnapshotContent<Base,Edit>;\n}\n\nfunction asSnapshot<Base,Edit>(snapshot: LayeredSnapshotContent<Base,Edit>) {\n return snapshot as unknown as LayeredSnapshot<Base,Edit>;\n}\n\n/**\n * Extracts the snapshot type from a {@link SpreadsheetData} instance\n */\nexport type SnapshotType<T> = T extends SpreadsheetData<infer TResult> ? TResult : never;\n\n/**\n * Implementation of {@link SpreadsheetData} that layers two other `SpreadsheetData` instances on top of each other.\n * \n * There's an \"edit\" layer on top where any changes are stored, with a \"base\" layer underneath. If a value is `undefined` in the edit layer, \n * the corresponding value is returned from the base layer instead.\n * \n * Common use case is a read only reference data source as the base layer with an initially empty edit layer that accepts changes.\n * \n * @typeParam BaseData - Type of base layer `SpreadsheetData` instance\n * @typeParam EditData - Type of edit layer `SpreadsheetData` instance\n * @typeParam BaseSnapshot - Type of snapshot used by `BaseData`. By default, inferred from `BaseData`.\n * @typeParam EditSnapshot - Type of snapshot used by `EditData`. By default, inferred from `EditData`.\n */\nexport class LayeredSpreadsheetData<BaseData extends SpreadsheetData<BaseSnapshot>, \n EditData extends SpreadsheetData<EditSnapshot>, BaseSnapshot = SnapshotType<BaseData>, EditSnapshot = SnapshotType<EditData>>\n implements SpreadsheetData<LayeredSnapshot<BaseSnapshot, EditSnapshot>> {\n\n /**\n * Creates a `LayeredSpreadsheetData` instance from two existing `SpreadsheetData` instances.\n * \n * All type parameters can be inferred from the constructor arguments.\n * \n * @param base - `SpreadsheetData` instance to use for the base layer\n * @param edit - `SpreadsheetData` instance to use for the edit layer\n */\n constructor(base: BaseData, edit: EditData) {\n this.#base = base;\n this.#edit = edit;\n }\n\n subscribe(onDataChange: () => void): () => void {\n const unsubscribeBase = this.#base.subscribe(onDataChange);\n const unsubscribeEdit = this.#edit.subscribe(onDataChange);\n return () => {\n unsubscribeBase();\n unsubscribeEdit();\n }\n }\n\n getSnapshot(): LayeredSnapshot<BaseSnapshot, EditSnapshot> {\n const baseSnapshot = this.#base.getSnapshot();\n const editSnapshot = this.#edit.getSnapshot();\n\n if (!this.#content || this.#content.base != baseSnapshot || this.#content.edit != editSnapshot) {\n this.#content = { base: baseSnapshot, edit: editSnapshot } ;\n }\n\n return asSnapshot(this.#content);\n }\n\n getRowCount(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): number {\n const content = asContent(snapshot);\n return Math.max(this.#base.getRowCount(content.base), this.#edit.getRowCount(content.edit));\n }\n\n getRowItemOffsetMapping(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): ItemOffsetMapping {\n return this.#base.getRowItemOffsetMapping(asContent(snapshot).base);\n }\n\n getColumnCount(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): number {\n const content = asContent(snapshot);\n return Math.max(this.#base.getColumnCount(content.base), this.#edit.getColumnCount(content.edit));\n }\n\n getColumnItemOffsetMapping(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): ItemOffsetMapping {\n return this.#base.getColumnItemOffsetMapping(asContent(snapshot).base);\n }\n\n getCellValue(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>, row: number, column: number): CellValue {\n const content = asContent(snapshot);\n const editValue = this.#edit.getCellValue(content.edit, row, column);\n if (editValue !== undefined)\n return editValue;\n\n return this.#base.getCellValue(content.base, row, column);\n }\n\n getCellFormat(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>, row: number, column: number): string | undefined {\n const content = asContent(snapshot);\n const editValue = this.#edit.getCellValue(content.edit, row, column);\n return (editValue === undefined) ? this.#base.getCellFormat(content.base, row, column) : this.#edit.getCellFormat(content.edit, row, column);\n }\n\n setCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): Result<void,SpreadsheetDataError> {\n const result = this.#base.isValidCellValueAndFormat(row, column, value, format);\n return result.andThen(() => this.#edit.setCellValueAndFormat(row, column, value, format));\n }\n\n // Must be valid for both layers\n isValidCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): Result<void,ValidationError> {\n const result = this.#base.isValidCellValueAndFormat(row, column, value, format);\n return result.andThen(() => this.#edit.isValidCellValueAndFormat(row,column,value,format));\n }\n\n #base: BaseData;\n #edit: EditData;\n #content: LayeredSnapshotContent<BaseSnapshot, EditSnapshot> | undefined;\n}\n","import type { EventLog, LogEntry, LogMetadata, SequenceId, ResultAsync, QueryValue, \n AddEntryError, QueryError, TruncateError, MetadataError } from \"@candidstartup/infinisheet-types\";\nimport { okAsync, errAsync, conflictError, infinisheetRangeError } from \"@candidstartup/infinisheet-types\";\n\nconst QUERY_PAGE_SIZE = 10;\n\nexport class SimpleEventLog<T extends LogEntry> implements EventLog<T> {\n constructor() {\n this.#startSequenceId = 0n;\n this.#endSequenceId = 0n;\n this.#entries = [];\n }\n\n addEntry(entry: T, sequenceId: SequenceId): ResultAsync<void,AddEntryError> {\n if (sequenceId !== this.#endSequenceId)\n return errAsync(conflictError(\"sequenceId is not next sequence id\", this.#endSequenceId));\n\n this.#entries.push(entry);\n this.#endSequenceId ++;\n return okAsync();\n }\n\n setMetadata(sequenceId: SequenceId, metadata: LogMetadata): ResultAsync<void,MetadataError> {\n if (sequenceId < this.#startSequenceId || sequenceId >= this.#endSequenceId)\n return errAsync(infinisheetRangeError(`Log entry with sequenceId ${sequenceId} does not exist`));\n\n const index = Number(sequenceId - this.#startSequenceId);\n const entry = this.#entries[index]!;\n if (\"snapshot\" in metadata)\n entry.snapshot = metadata.snapshot;\n if (\"history\" in metadata)\n entry.history = metadata.history;\n if (\"pending\" in metadata)\n entry.pending = metadata.pending;\n\n return okAsync();\n }\n\n query(start: SequenceId | 'snapshot' | 'start', end: SequenceId | 'end'): ResultAsync<QueryValue<T>,QueryError> {\n if (start === 'start')\n start = this.#startSequenceId;\n else if (start === 'snapshot')\n start = this.#startSequenceId + BigInt(this.findSnapshotIndex());\n else if (start < this.#startSequenceId || start > this.#endSequenceId)\n return errAsync(infinisheetRangeError(\"start index out of range\"));\n\n if (end === 'end')\n end = this.#endSequenceId;\n\n const num = end - start;\n const isComplete = num <= BigInt(QUERY_PAGE_SIZE);\n let numToReturn = isComplete ? Number(num) : QUERY_PAGE_SIZE;\n const firstIndex = Number(start - this.#startSequenceId);\n if (firstIndex + numToReturn > this.#entries.length)\n numToReturn = this.#entries.length - firstIndex;\n\n const value: QueryValue<T> = {\n startSequenceId: start,\n endSequenceId: start + BigInt(numToReturn),\n isComplete,\n entries: this.#entries.slice(firstIndex, firstIndex + numToReturn)\n }\n\n return okAsync(value);\n }\n\n truncate(start: SequenceId): ResultAsync<void,TruncateError> {\n if (start < this.#startSequenceId)\n return errAsync(infinisheetRangeError(\"start before start entry in the log\"));\n\n if (start === this.#startSequenceId)\n return okAsync();\n \n if (start === this.#endSequenceId) {\n this.#startSequenceId = start;\n this.#endSequenceId = start;\n this.#entries = [];\n return okAsync();\n }\n\n if (start > this.#endSequenceId)\n return errAsync(infinisheetRangeError(\"start after end entry in the log\"));\n\n const numToRemove = start - this.#startSequenceId;\n this.#startSequenceId = start;\n this.#entries.splice(0, Number(numToRemove));\n return okAsync();\n }\n\n private findSnapshotIndex(): number {\n for (let i = this.#entries.length - 1; i > 0; i--) {\n const entry = this.#entries[i]!;\n if (entry.snapshot)\n return i;\n }\n\n // If no other entry has a snapshot use the first (whether it has a snapshot or not)\n return 0;\n }\n\n #startSequenceId: SequenceId;\n #endSequenceId: SequenceId;\n #entries: T[];\n}"],"names":["asContent","asSnapshot"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/SimpleSpreadsheetData.ts","../src/LayeredSpreadsheetData.ts","../src/SimpleEventLog.ts","../src/DelayEventLog.ts"],"sourcesContent":["import type { CellValue, SpreadsheetData, RowColRef, ItemOffsetMapping, Result, ResultAsync,\n SpreadsheetDataError, ValidationError, StorageError } from \"@candidstartup/infinisheet-types\";\nimport { FixedSizeItemOffsetMapping, rowColCoordsToRef, ok, okAsync } from \"@candidstartup/infinisheet-types\";\n\ninterface CellContent {\n value: CellValue;\n format: string|undefined;\n}\n\ninterface SimpleSnapshotContent {\n values: Record<RowColRef,CellContent>;\n rowCount: number;\n colCount: number;\n}\n\n/** \n * Branding Enum. Used by {@link SimpleSnapshot} to ensure that\n * you'll get a type error if you pass some random object where a `SimpleSnapshot`\n * is expected.\n * @internal\n */\nexport enum _SimpleSnapshotBrand { _DO_NOT_USE=\"\" };\n\n/**\n * Opaque type representing a {@link SimpleSpreadsheetData} snapshot. All the\n * internal implementation details are hidden from the exported API.\n */\nexport interface SimpleSnapshot {\n /** @internal */\n _brand: _SimpleSnapshotBrand;\n}\n\nconst rowItemOffsetMapping = new FixedSizeItemOffsetMapping(30);\nconst columnItemOffsetMapping = new FixedSizeItemOffsetMapping(100);\n\nfunction asContent(snapshot: SimpleSnapshot) {\n return snapshot as unknown as SimpleSnapshotContent;\n}\n\nfunction asSnapshot(snapshot: SimpleSnapshotContent) {\n return snapshot as unknown as SimpleSnapshot;\n}\n\n/**\n * Reference implementation of {@link SpreadsheetData}\n * \n * Editable in-memory spreadsheet data container. Starts out empty. Use the API to fill\n * with data!\n * \n * Intended for use as a mock, to compare with an optimized implementation when testing and\n * for simple sample apps. Simplest possible implementation, no attempt at optimization.\n */\nexport class SimpleSpreadsheetData implements SpreadsheetData<SimpleSnapshot> {\n constructor () {\n this.listeners = [];\n this.content = {\n values: {},\n rowCount: 0,\n colCount: 0\n }\n }\n\n subscribe(onDataChange: () => void): () => void {\n this.listeners = [...this.listeners, onDataChange];\n return () => {\n this.listeners = this.listeners.filter(l => l !== onDataChange);\n }\n }\n\n getSnapshot(): SimpleSnapshot {\n return asSnapshot(this.content);\n }\n\n getLoadStatus(_snapshot: SimpleSnapshot): Result<boolean,StorageError> {\n return ok(true);\n }\n\n getRowCount(snapshot: SimpleSnapshot): number {\n return asContent(snapshot).rowCount;\n }\n\n getRowItemOffsetMapping(_snapshot: SimpleSnapshot): ItemOffsetMapping {\n return rowItemOffsetMapping;\n }\n\n getColumnCount(snapshot: SimpleSnapshot): number {\n return asContent(snapshot).colCount;\n }\n\n getColumnItemOffsetMapping(_snapshot: SimpleSnapshot): ItemOffsetMapping {\n return columnItemOffsetMapping\n }\n\n getCellValue(snapshot: SimpleSnapshot, row: number, column: number): CellValue {\n const ref = rowColCoordsToRef(row, column);\n return asContent(snapshot).values[ref]?.value;\n }\n\n getCellFormat(snapshot: SimpleSnapshot, row: number, column: number): string | undefined {\n const ref = rowColCoordsToRef(row, column);\n return asContent(snapshot).values[ref]?.format;\n }\n\n setCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): ResultAsync<void,SpreadsheetDataError> {\n const curr = this.content;\n const ref = rowColCoordsToRef(row, column);\n\n // Snapshot semantics preserved by treating SimpleSnapshot as an immutable data structure which is \n // replaced with a modified copy on every update. Yes, this is horribly inefficient. \n // For simplicity, setting a value to undefined stores it explicitly rather than removing it. Functional\n // behavior is the same.\n this.content = {\n values: { ...curr.values, [ref]: { value, format }},\n rowCount: Math.max(curr.rowCount, row+1),\n colCount: Math.max(curr.colCount, column+1)\n }\n\n return okAsync().andTee(() => this.notifyListeners());\n }\n\n isValidCellValueAndFormat(_row: number, _column: number, _value: CellValue, _format: string | undefined): Result<void,ValidationError> {\n return ok(); \n }\n\n private notifyListeners() {\n for (const listener of this.listeners)\n listener();\n }\n\n private listeners: (() => void)[];\n private content: SimpleSnapshotContent;\n}\n","import type { CellValue, SpreadsheetData, ItemOffsetMapping, Result, ResultAsync,\n SpreadsheetDataError, ValidationError, StorageError } from \"@candidstartup/infinisheet-types\";\n\ninterface LayeredSnapshotContent<BaseSnapshot, EditSnapshot> {\n base: BaseSnapshot,\n edit: EditSnapshot\n}\n\n/** \n * Branding Enum. Used by {@link LayeredSnapshot} to ensure that\n * you'll get a type error if you pass some random object where a `LayeredSnapshot`\n * is expected.\n * @internal\n */\nexport enum _LayeredSnapshotBrand { _DO_NOT_USE=\"\" };\n\n/**\n * Opaque type representing a {@link LayeredSpreadsheetData} snapshot. All the\n * internal implementation details are hidden from the exported API.\n */\nexport interface LayeredSnapshot<BaseSnapshot,EditSnapshot> {\n /** @internal */\n _brand: [ _LayeredSnapshotBrand, BaseSnapshot, EditSnapshot ]\n}\n\nfunction asContent<Base,Edit>(snapshot: LayeredSnapshot<Base,Edit>) {\n return snapshot as unknown as LayeredSnapshotContent<Base,Edit>;\n}\n\nfunction asSnapshot<Base,Edit>(snapshot: LayeredSnapshotContent<Base,Edit>) {\n return snapshot as unknown as LayeredSnapshot<Base,Edit>;\n}\n\n/**\n * Extracts the snapshot type from a {@link SpreadsheetData} instance\n */\nexport type SnapshotType<T> = T extends SpreadsheetData<infer TResult> ? TResult : never;\n\n/**\n * Implementation of {@link SpreadsheetData} that layers two other `SpreadsheetData` instances on top of each other.\n * \n * There's an \"edit\" layer on top where any changes are stored, with a \"base\" layer underneath. If a value is `undefined` in the edit layer, \n * the corresponding value is returned from the base layer instead.\n * \n * Common use case is a read only reference data source as the base layer with an initially empty edit layer that accepts changes.\n * \n * @typeParam BaseData - Type of base layer `SpreadsheetData` instance\n * @typeParam EditData - Type of edit layer `SpreadsheetData` instance\n * @typeParam BaseSnapshot - Type of snapshot used by `BaseData`. By default, inferred from `BaseData`.\n * @typeParam EditSnapshot - Type of snapshot used by `EditData`. By default, inferred from `EditData`.\n */\nexport class LayeredSpreadsheetData<BaseData extends SpreadsheetData<BaseSnapshot>, \n EditData extends SpreadsheetData<EditSnapshot>, BaseSnapshot = SnapshotType<BaseData>, EditSnapshot = SnapshotType<EditData>>\n implements SpreadsheetData<LayeredSnapshot<BaseSnapshot, EditSnapshot>> {\n\n /**\n * Creates a `LayeredSpreadsheetData` instance from two existing `SpreadsheetData` instances.\n * \n * All type parameters can be inferred from the constructor arguments.\n * \n * @param base - `SpreadsheetData` instance to use for the base layer\n * @param edit - `SpreadsheetData` instance to use for the edit layer\n */\n constructor(base: BaseData, edit: EditData) {\n this.base = base;\n this.edit = edit;\n }\n\n subscribe(onDataChange: () => void): () => void {\n const unsubscribeBase = this.base.subscribe(onDataChange);\n const unsubscribeEdit = this.edit.subscribe(onDataChange);\n return () => {\n unsubscribeBase();\n unsubscribeEdit();\n }\n }\n\n getSnapshot(): LayeredSnapshot<BaseSnapshot, EditSnapshot> {\n const baseSnapshot = this.base.getSnapshot();\n const editSnapshot = this.edit.getSnapshot();\n\n if (!this.content || this.content.base != baseSnapshot || this.content.edit != editSnapshot) {\n this.content = { base: baseSnapshot, edit: editSnapshot } ;\n }\n\n return asSnapshot(this.content);\n }\n\n getLoadStatus(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): Result<boolean,StorageError> {\n const content = asContent(snapshot);\n return this.base.getLoadStatus(content.base).andThen((t1) => this.edit.getLoadStatus(content.edit).map((t2) => t1 && t2));\n }\n\n getRowCount(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): number {\n const content = asContent(snapshot);\n return Math.max(this.base.getRowCount(content.base), this.edit.getRowCount(content.edit));\n }\n\n getRowItemOffsetMapping(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): ItemOffsetMapping {\n return this.base.getRowItemOffsetMapping(asContent(snapshot).base);\n }\n\n getColumnCount(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): number {\n const content = asContent(snapshot);\n return Math.max(this.base.getColumnCount(content.base), this.edit.getColumnCount(content.edit));\n }\n\n getColumnItemOffsetMapping(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>): ItemOffsetMapping {\n return this.base.getColumnItemOffsetMapping(asContent(snapshot).base);\n }\n\n getCellValue(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>, row: number, column: number): CellValue {\n const content = asContent(snapshot);\n const editValue = this.edit.getCellValue(content.edit, row, column);\n if (editValue !== undefined)\n return editValue;\n\n return this.base.getCellValue(content.base, row, column);\n }\n\n getCellFormat(snapshot: LayeredSnapshot<BaseSnapshot, EditSnapshot>, row: number, column: number): string | undefined {\n const content = asContent(snapshot);\n const editValue = this.edit.getCellValue(content.edit, row, column);\n return (editValue === undefined) ? this.base.getCellFormat(content.base, row, column) : this.edit.getCellFormat(content.edit, row, column);\n }\n\n setCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): ResultAsync<void,SpreadsheetDataError> {\n const result = this.base.isValidCellValueAndFormat(row, column, value, format);\n return result.asyncAndThen(() => this.edit.setCellValueAndFormat(row, column, value, format));\n }\n\n // Must be valid for both layers\n isValidCellValueAndFormat(row: number, column: number, value: CellValue, format: string | undefined): Result<void,ValidationError> {\n const result = this.base.isValidCellValueAndFormat(row, column, value, format);\n return result.andThen(() => this.edit.isValidCellValueAndFormat(row,column,value,format));\n }\n\n private base: BaseData;\n private edit: EditData;\n private content: LayeredSnapshotContent<BaseSnapshot, EditSnapshot> | undefined;\n}\n","import type { EventLog, LogEntry, LogMetadata, SequenceId, ResultAsync, QueryValue, \n AddEntryError, QueryError, TruncateError, MetadataError } from \"@candidstartup/infinisheet-types\";\nimport { okAsync, errAsync, conflictError, infinisheetRangeError } from \"@candidstartup/infinisheet-types\";\n\nconst QUERY_PAGE_SIZE = 10;\n\n/**\n * Reference implementation of {@link EventLog}\n * \n * In-memory event log\n * \n * Intended for use as a mock, to compare with an optimized implementation when testing and\n * for simple sample apps. Simplest possible implementation, no attempt at optimization.\n */\nexport class SimpleEventLog<T extends LogEntry> implements EventLog<T> {\n constructor() {\n this.startSequenceId = 0n;\n this.endSequenceId = 0n;\n this.entries = [];\n }\n\n addEntry(entry: T, sequenceId: SequenceId): ResultAsync<void,AddEntryError> {\n if (sequenceId !== this.endSequenceId)\n return errAsync(conflictError(\"sequenceId is not next sequence id\", this.endSequenceId));\n\n this.entries.push(entry);\n this.endSequenceId ++;\n return okAsync();\n }\n\n setMetadata(sequenceId: SequenceId, metadata: LogMetadata): ResultAsync<void,MetadataError> {\n if (sequenceId < this.startSequenceId || sequenceId >= this.endSequenceId)\n return errAsync(infinisheetRangeError(`Log entry with sequenceId ${sequenceId} does not exist`));\n\n const index = Number(sequenceId - this.startSequenceId);\n const entry = this.entries[index]!;\n if (\"snapshot\" in metadata)\n entry.snapshot = metadata.snapshot;\n if (\"history\" in metadata)\n entry.history = metadata.history;\n if (\"pending\" in metadata)\n entry.pending = metadata.pending;\n\n return okAsync();\n }\n\n query(start: SequenceId | 'snapshot' | 'start', end: SequenceId | 'end'): ResultAsync<QueryValue<T>,QueryError> {\n if (start === 'start')\n start = this.startSequenceId;\n else if (start === 'snapshot')\n start = this.startSequenceId + BigInt(this.findSnapshotIndex());\n else if (start < this.startSequenceId || start > this.endSequenceId)\n return errAsync(infinisheetRangeError(\"start index out of range\"));\n\n if (end === 'end')\n end = this.endSequenceId;\n\n const num = end - start;\n const isComplete = num <= BigInt(QUERY_PAGE_SIZE);\n let numToReturn = isComplete ? Number(num) : QUERY_PAGE_SIZE;\n const firstIndex = Number(start - this.startSequenceId);\n if (firstIndex + numToReturn > this.entries.length)\n numToReturn = this.entries.length - firstIndex;\n\n const value: QueryValue<T> = {\n startSequenceId: start,\n endSequenceId: start + BigInt(numToReturn),\n isComplete,\n entries: this.entries.slice(firstIndex, firstIndex + numToReturn)\n }\n\n return okAsync(value);\n }\n\n truncate(start: SequenceId): ResultAsync<void,TruncateError> {\n if (start < this.startSequenceId)\n return errAsync(infinisheetRangeError(\"start before start entry in the log\"));\n\n if (start === this.startSequenceId)\n return okAsync();\n \n if (start === this.endSequenceId) {\n this.startSequenceId = start;\n this.endSequenceId = start;\n this.entries = [];\n return okAsync();\n }\n\n if (start > this.endSequenceId)\n return errAsync(infinisheetRangeError(\"start after end entry in the log\"));\n\n const numToRemove = start - this.startSequenceId;\n this.startSequenceId = start;\n this.entries.splice(0, Number(numToRemove));\n return okAsync();\n }\n\n private findSnapshotIndex(): number {\n for (let i = this.entries.length - 1; i > 0; i--) {\n const entry = this.entries[i]!;\n if (entry.snapshot)\n return i;\n }\n\n // If no other entry has a snapshot use the first (whether it has a snapshot or not)\n return 0;\n }\n\n private startSequenceId: SequenceId;\n private endSequenceId: SequenceId;\n private entries: T[];\n}","import type { EventLog, LogEntry, LogMetadata, SequenceId, Result, QueryValue, \n AddEntryError, QueryError, TruncateError, MetadataError } from \"@candidstartup/infinisheet-types\";\nimport { ResultAsync } from \"@candidstartup/infinisheet-types\";\n\nfunction delayPromise<T>(value: T, delay: number): Promise<T> {\n return new Promise<T>((resolve) => {\n setTimeout(() => resolve(value), delay);\n })\n}\n\nfunction delayResult<T,E>(result: ResultAsync<T,E>, delay: number): ResultAsync<T,E> {\n const promiseLike = result.then<Result<T,E>,never>((r) => delayPromise(r, delay));\n return new ResultAsync(Promise.resolve(promiseLike));\n}\n\n/**\n * Wrapper around an {@link EventLog} that injects latency\n * \n * Intended for use when simulating the effects of latency in a real implementation\n */\nexport class DelayEventLog<T extends LogEntry> implements EventLog<T> {\n constructor(base: EventLog<T>, delay: number=0) {\n this.base = base;\n this.delay = delay;\n }\n\n /** Delay in milliseconds to add to response from each API call */\n delay: number;\n\n addEntry(entry: T, sequenceId: SequenceId): ResultAsync<void,AddEntryError> {\n return delayResult(this.base.addEntry(entry, sequenceId), this.delay);\n }\n\n setMetadata(sequenceId: SequenceId, metadata: LogMetadata): ResultAsync<void,MetadataError> {\n return delayResult(this.base.setMetadata(sequenceId, metadata), this.delay);\n }\n\n query(start: SequenceId | 'snapshot' | 'start', end: SequenceId | 'end'): ResultAsync<QueryValue<T>,QueryError> {\n return delayResult(this.base.query(start, end), this.delay);\n }\n\n truncate(start: SequenceId): ResultAsync<void,TruncateError> {\n return delayResult(this.base.truncate(start), this.delay);\n }\n\n private base: EventLog<T>;\n}"],"names":["asContent","asSnapshot"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@candidstartup/simple-spreadsheet-data",
3
3
  "private": false,
4
- "version": "0.11.0",
4
+ "version": "0.12.0",
5
5
  "description": "Reference implementations of SpreadsheetData",
6
6
  "author": "Tim Wiegand <tim.wiegand@thecandidstartup.org>",
7
7
  "license": "BSD-3-Clause",
@@ -49,7 +49,7 @@
49
49
  "test": "vitest"
50
50
  },
51
51
  "dependencies": {
52
- "@candidstartup/infinisheet-types": "^0.11.0"
52
+ "@candidstartup/infinisheet-types": "^0.12.0"
53
53
  },
54
- "gitHead": "0c72d04996502cb84f8720972bfda453e4989106"
54
+ "gitHead": "03b639807d367f0c167dc5b6653b3935412cbde8"
55
55
  }