@orkestrel/table 0.0.3 → 0.0.5
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/README.md +13 -15
- package/dist/src/core/index.cjs +286 -199
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +364 -429
- package/dist/src/core/index.d.ts +364 -429
- package/dist/src/core/index.js +284 -194
- package/dist/src/core/index.js.map +1 -1
- package/package.json +17 -14
package/dist/src/core/index.cjs
CHANGED
|
@@ -2,35 +2,40 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
let _orkestrel_contract = require("@orkestrel/contract");
|
|
3
3
|
let _orkestrel_emitter = require("@orkestrel/emitter");
|
|
4
4
|
//#region src/core/constants.ts
|
|
5
|
-
/**
|
|
5
|
+
/** Lists every column cell, in the order declared by the public contract. */
|
|
6
6
|
var COLUMN_CELLS = Object.freeze([
|
|
7
7
|
"text",
|
|
8
8
|
"number",
|
|
9
9
|
"flag",
|
|
10
10
|
"choice"
|
|
11
11
|
]);
|
|
12
|
-
/**
|
|
12
|
+
/** Names the maximum number of columns one schema may declare: 256. */
|
|
13
13
|
var COLUMN_LIMIT = 256;
|
|
14
|
-
/**
|
|
14
|
+
/** Names the maximum number of choices one `choice` column may offer: 1024. */
|
|
15
15
|
var CHOICE_LIMIT = 1024;
|
|
16
|
-
/**
|
|
16
|
+
/** Names the maximum length of a schema name or column key: 128 UTF-16 code units. */
|
|
17
17
|
var NAME_LIMIT = 128;
|
|
18
|
-
/**
|
|
18
|
+
/** Names the maximum length of any single retained string: 65536 UTF-16 code units. */
|
|
19
19
|
var STRING_LIMIT = 65536;
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Names the maximum total length of every string one schema retains: 1048576 UTF-16 code units.
|
|
22
|
+
*/
|
|
21
23
|
var TEXT_LIMIT = 1048576;
|
|
22
|
-
/**
|
|
24
|
+
/** Names the maximum total number of records, arrays, and leaves one schema retains: 16384. */
|
|
23
25
|
var NODE_LIMIT = 16384;
|
|
24
26
|
//#endregion
|
|
25
27
|
//#region src/core/errors.ts
|
|
26
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Represents an error raised by the table domain — a machine-readable `code` and optional
|
|
30
|
+
* structured `context`.
|
|
31
|
+
*/
|
|
27
32
|
var TableError = class extends Error {
|
|
28
|
-
/**
|
|
33
|
+
/** Holds the machine-readable reason for this failure. */
|
|
29
34
|
code;
|
|
30
|
-
/**
|
|
35
|
+
/** Holds structured values that locate or explain this failure. */
|
|
31
36
|
context;
|
|
32
37
|
/**
|
|
33
|
-
*
|
|
38
|
+
* Creates a table error.
|
|
34
39
|
*
|
|
35
40
|
* @param code - The machine-readable reason.
|
|
36
41
|
* @param message - The human-readable failure text.
|
|
@@ -44,10 +49,11 @@ var TableError = class extends Error {
|
|
|
44
49
|
}
|
|
45
50
|
};
|
|
46
51
|
/**
|
|
47
|
-
*
|
|
52
|
+
* Determines whether a caught value is a table error, so a `catch` branches on `code` without an
|
|
53
|
+
* assertion.
|
|
48
54
|
*
|
|
49
55
|
* @param input - The value to inspect.
|
|
50
|
-
* @returns
|
|
56
|
+
* @returns True if the value is a {@link TableError} instance; false otherwise.
|
|
51
57
|
*/
|
|
52
58
|
function isTableError(input) {
|
|
53
59
|
return input instanceof TableError;
|
|
@@ -55,7 +61,7 @@ function isTableError(input) {
|
|
|
55
61
|
//#endregion
|
|
56
62
|
//#region src/core/helpers.ts
|
|
57
63
|
/**
|
|
58
|
-
*
|
|
64
|
+
* Finds one column by key; `undefined` when the schema declares no such column.
|
|
59
65
|
*
|
|
60
66
|
* @param schema - The schema whose columns to search.
|
|
61
67
|
* @param key - The column key to find.
|
|
@@ -65,7 +71,8 @@ function extractColumn(schema, key) {
|
|
|
65
71
|
return schema.columns.find((column) => column.key === key);
|
|
66
72
|
}
|
|
67
73
|
/**
|
|
68
|
-
*
|
|
74
|
+
* Reads one row's declared identity; `undefined` when its key cell is missing, empty, or not a
|
|
75
|
+
* string.
|
|
69
76
|
*
|
|
70
77
|
* @param schema - The schema that names the identity column.
|
|
71
78
|
* @param row - The row whose identity to read.
|
|
@@ -77,7 +84,8 @@ function extractKey(schema, row) {
|
|
|
77
84
|
return (0, _orkestrel_contract.isString)(key) && key.length > 0 ? key : void 0;
|
|
78
85
|
}
|
|
79
86
|
/**
|
|
80
|
-
*
|
|
87
|
+
* Computes one atomic 0/1/N membership change over the keys a caller may address — the engine
|
|
88
|
+
* selection and expansion share.
|
|
81
89
|
*
|
|
82
90
|
* @param known - Every key the caller may change.
|
|
83
91
|
* @param current - The current key set.
|
|
@@ -96,11 +104,59 @@ function computeKeys(known, current, input, include) {
|
|
|
96
104
|
return next.size !== current.size || [...next].some((key) => !current.has(key)) ? next : current;
|
|
97
105
|
}
|
|
98
106
|
/**
|
|
99
|
-
*
|
|
107
|
+
* Merges lens terms into a column-keyed list, replacing the entry that names the same column —
|
|
108
|
+
* the `set` write.
|
|
109
|
+
*
|
|
110
|
+
* @param current - The list as it stands.
|
|
111
|
+
* @param requested - The terms to write, in the order they are written.
|
|
112
|
+
* @returns A frozen list holding one owned entry per column, in the order the columns first
|
|
113
|
+
* appeared.
|
|
114
|
+
*/
|
|
115
|
+
function mergeTerms(current, requested) {
|
|
116
|
+
const next = [...current];
|
|
117
|
+
for (const term of requested) {
|
|
118
|
+
const owned = Object.freeze({ ...term });
|
|
119
|
+
const index = next.findIndex((candidate) => candidate.column === term.column);
|
|
120
|
+
if (index === -1) next.push(owned);
|
|
121
|
+
else next[index] = owned;
|
|
122
|
+
}
|
|
123
|
+
return Object.freeze(next);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Removes every lens term naming one of the given columns — the drop `sort.remove` and
|
|
127
|
+
* `filter.remove` share.
|
|
128
|
+
*
|
|
129
|
+
* @param current - The list as it stands.
|
|
130
|
+
* @param columns - The column keys to drop.
|
|
131
|
+
* @returns A frozen list holding the entries no named column matched, in their original order.
|
|
132
|
+
*/
|
|
133
|
+
function removeTerms(current, columns) {
|
|
134
|
+
const removed = new Set(columns);
|
|
135
|
+
return Object.freeze(current.filter((term) => !removed.has(term.column)));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Checks whether two lens lists hold the same terms in the same order, with the supplied test
|
|
139
|
+
* deciding the operands.
|
|
140
|
+
*
|
|
141
|
+
* @param left - The first list.
|
|
142
|
+
* @param right - The second list.
|
|
143
|
+
* @param equal - Decide whether two terms naming one column carry the same operands.
|
|
144
|
+
* @returns True if the lists are the same length and every position names the same column and
|
|
145
|
+
* carries the same operands; false otherwise.
|
|
146
|
+
*/
|
|
147
|
+
function matchesTerms(left, right, equal) {
|
|
148
|
+
return left.length === right.length && left.every((term, index) => {
|
|
149
|
+
const other = right[index];
|
|
150
|
+
return other !== void 0 && term.column === other.column && equal(term, other);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Checks whether one column can hold a value — the shape gate every write and every seed passes
|
|
155
|
+
* through.
|
|
100
156
|
*
|
|
101
157
|
* @param column - The column that owns the cell.
|
|
102
158
|
* @param value - The unknown value to inspect.
|
|
103
|
-
* @returns
|
|
159
|
+
* @returns True if the column can hold the value; false otherwise.
|
|
104
160
|
*/
|
|
105
161
|
function matchesCell(column, value) {
|
|
106
162
|
if ((0, _orkestrel_contract.isString)(value) && value.length > 65536) return false;
|
|
@@ -112,7 +168,7 @@ function matchesCell(column, value) {
|
|
|
112
168
|
}
|
|
113
169
|
}
|
|
114
170
|
/**
|
|
115
|
-
*
|
|
171
|
+
* Compares two of one column's cells the way its `cell` fixes, describing ascending order.
|
|
116
172
|
*
|
|
117
173
|
* @param column - The column that fixes the comparison.
|
|
118
174
|
* @param left - The first cell, or absence.
|
|
@@ -138,11 +194,12 @@ function compareCells(column, left, right) {
|
|
|
138
194
|
}
|
|
139
195
|
}
|
|
140
196
|
/**
|
|
141
|
-
*
|
|
197
|
+
* Checks whether one column admits a filter and every operand it carries — the gate `filter.set`
|
|
198
|
+
* and {@link matchesFilter} share.
|
|
142
199
|
*
|
|
143
200
|
* @param column - The column that fixes the accepted operators and cell shapes.
|
|
144
201
|
* @param filter - The filter to inspect.
|
|
145
|
-
* @returns
|
|
202
|
+
* @returns True if the filter belongs to the column and the column can apply it; false otherwise.
|
|
146
203
|
*/
|
|
147
204
|
function admitsFilter(column, filter) {
|
|
148
205
|
if (filter.column !== column.key) return false;
|
|
@@ -153,12 +210,12 @@ function admitsFilter(column, filter) {
|
|
|
153
210
|
}
|
|
154
211
|
}
|
|
155
212
|
/**
|
|
156
|
-
*
|
|
213
|
+
* Tests one of a column's cells against one filter the way its `cell` fixes.
|
|
157
214
|
*
|
|
158
215
|
* @param column - The column that fixes the accepted operators.
|
|
159
216
|
* @param cell - The cell to test, or absence.
|
|
160
217
|
* @param filter - The filter to apply.
|
|
161
|
-
* @returns
|
|
218
|
+
* @returns True if the filter accepts the cell; false otherwise.
|
|
162
219
|
*/
|
|
163
220
|
function matchesFilter(column, cell, filter) {
|
|
164
221
|
if (cell === void 0 || !admitsFilter(column, filter) || !matchesCell(column, cell)) return false;
|
|
@@ -169,7 +226,8 @@ function matchesFilter(column, cell, filter) {
|
|
|
169
226
|
}
|
|
170
227
|
}
|
|
171
228
|
/**
|
|
172
|
-
*
|
|
229
|
+
* Keeps the rows every filter accepts, in the order given; a supplied {@link CellMatcher}
|
|
230
|
+
* replaces the default per column.
|
|
173
231
|
*
|
|
174
232
|
* @param schema - The schema that declares the filtered columns.
|
|
175
233
|
* @param rows - The rows to filter.
|
|
@@ -187,7 +245,8 @@ function filterRows(schema, rows, filters, matchers) {
|
|
|
187
245
|
})));
|
|
188
246
|
}
|
|
189
247
|
/**
|
|
190
|
-
*
|
|
248
|
+
* Orders rows by the terms given, stably; a supplied {@link CellComparator} replaces the default
|
|
249
|
+
* per column.
|
|
191
250
|
*
|
|
192
251
|
* @param schema - The schema that declares the sorted columns.
|
|
193
252
|
* @param rows - The rows to order.
|
|
@@ -215,7 +274,8 @@ function sortRows(schema, rows, orders, comparators) {
|
|
|
215
274
|
return Object.freeze(indexed.map((entry) => entry.row));
|
|
216
275
|
}
|
|
217
276
|
/**
|
|
218
|
-
*
|
|
277
|
+
* Audits a structurally valid schema for domain faults and budget breaches, returning human
|
|
278
|
+
* diagnostics.
|
|
219
279
|
*
|
|
220
280
|
* @param schema - The table schema to audit.
|
|
221
281
|
* @returns Frozen human-readable diagnostics, or an empty list when the schema is sound.
|
|
@@ -314,7 +374,8 @@ function auditTable(schema) {
|
|
|
314
374
|
return Object.freeze(faults);
|
|
315
375
|
}
|
|
316
376
|
/**
|
|
317
|
-
*
|
|
377
|
+
* Projects a schema into JSON in declaration order, dropping every absent member; raises `SCHEMA`
|
|
378
|
+
* for a `meta` it cannot own.
|
|
318
379
|
*
|
|
319
380
|
* @param schema - The schema to project.
|
|
320
381
|
* @returns A deeply owned JSON record with absent members omitted.
|
|
@@ -353,7 +414,8 @@ function serializeTable(schema) {
|
|
|
353
414
|
}
|
|
354
415
|
}
|
|
355
416
|
/**
|
|
356
|
-
*
|
|
417
|
+
* Projects rows into JSON with each row's cells in the schema's column order, dropping every
|
|
418
|
+
* absent cell.
|
|
357
419
|
*
|
|
358
420
|
* @param schema - The schema that fixes cell order.
|
|
359
421
|
* @param rows - The rows to project.
|
|
@@ -381,19 +443,21 @@ function serializeRows(schema, rows) {
|
|
|
381
443
|
//#endregion
|
|
382
444
|
//#region src/core/validators.ts
|
|
383
445
|
/**
|
|
384
|
-
*
|
|
446
|
+
* Determines whether an unknown value has a table cell shape — a string, a finite number, or a
|
|
447
|
+
* boolean.
|
|
385
448
|
*
|
|
386
449
|
* @param input - The value to inspect.
|
|
387
|
-
* @returns
|
|
450
|
+
* @returns True if the value is a string, finite number, or boolean; false otherwise.
|
|
388
451
|
*/
|
|
389
452
|
function isTableCell(input) {
|
|
390
453
|
return (0, _orkestrel_contract.unionOf)(_orkestrel_contract.isString, _orkestrel_contract.isFiniteNumber, _orkestrel_contract.isBoolean)(input);
|
|
391
454
|
}
|
|
392
455
|
/**
|
|
393
|
-
*
|
|
456
|
+
* Determines whether an unknown value is a record whose every own key is a string and every value
|
|
457
|
+
* a {@link TableCell}.
|
|
394
458
|
*
|
|
395
459
|
* @param input - The value to inspect.
|
|
396
|
-
* @returns
|
|
460
|
+
* @returns True if every own key is a string and every value is a table cell; false otherwise.
|
|
397
461
|
*/
|
|
398
462
|
function isTableRow(input) {
|
|
399
463
|
const outcome = (0, _orkestrel_contract.attempt)(() => {
|
|
@@ -403,19 +467,20 @@ function isTableRow(input) {
|
|
|
403
467
|
return outcome.success && outcome.value;
|
|
404
468
|
}
|
|
405
469
|
/**
|
|
406
|
-
*
|
|
470
|
+
* Determines whether an unknown value is a declared column cell.
|
|
407
471
|
*
|
|
408
472
|
* @param input - The value to inspect.
|
|
409
|
-
* @returns
|
|
473
|
+
* @returns True if the value is a declared column cell; false otherwise.
|
|
410
474
|
*/
|
|
411
475
|
function isColumnCell(input) {
|
|
412
476
|
return COLUMN_CELLS.some((cell) => cell === input);
|
|
413
477
|
}
|
|
414
478
|
/**
|
|
415
|
-
*
|
|
479
|
+
* Determines whether an unknown value is one exact {@link ColumnChoice} record; an unknown member
|
|
480
|
+
* refuses it.
|
|
416
481
|
*
|
|
417
482
|
* @param input - The value to inspect.
|
|
418
|
-
* @returns
|
|
483
|
+
* @returns True if the value is a column choice; false otherwise.
|
|
419
484
|
*/
|
|
420
485
|
function isColumnChoice(input) {
|
|
421
486
|
const outcome = (0, _orkestrel_contract.attempt)(() => {
|
|
@@ -429,10 +494,11 @@ function isColumnChoice(input) {
|
|
|
429
494
|
return outcome.success && outcome.value;
|
|
430
495
|
}
|
|
431
496
|
/**
|
|
432
|
-
*
|
|
497
|
+
* Determines whether an unknown value is one exact discriminated {@link TableColumn}, checked
|
|
498
|
+
* against its cell's own options.
|
|
433
499
|
*
|
|
434
500
|
* @param input - The value to inspect.
|
|
435
|
-
* @returns
|
|
501
|
+
* @returns True if the value is a structurally valid table column; false otherwise.
|
|
436
502
|
*/
|
|
437
503
|
function isTableColumn(input) {
|
|
438
504
|
const outcome = (0, _orkestrel_contract.attempt)(() => {
|
|
@@ -471,10 +537,11 @@ function isTableColumn(input) {
|
|
|
471
537
|
return outcome.success && outcome.value;
|
|
472
538
|
}
|
|
473
539
|
/**
|
|
474
|
-
*
|
|
540
|
+
* Determines whether an unknown value has the exact shape of a {@link TableSchema} — the shape
|
|
541
|
+
* alone, with no domain check.
|
|
475
542
|
*
|
|
476
543
|
* @param input - The value to inspect.
|
|
477
|
-
* @returns
|
|
544
|
+
* @returns True if the value has the exact structure of a table schema; false otherwise.
|
|
478
545
|
*/
|
|
479
546
|
function isStructuralTableSchema(input) {
|
|
480
547
|
const outcome = (0, _orkestrel_contract.attempt)(() => {
|
|
@@ -494,10 +561,12 @@ function isStructuralTableSchema(input) {
|
|
|
494
561
|
return outcome.success && outcome.value;
|
|
495
562
|
}
|
|
496
563
|
/**
|
|
497
|
-
*
|
|
564
|
+
* Determines whether an unknown value is a {@link TableSchema} a table can be opened against —
|
|
565
|
+
* the exact shape, and an audit that finds nothing.
|
|
498
566
|
*
|
|
499
567
|
* @param input - The value to inspect.
|
|
500
|
-
* @returns
|
|
568
|
+
* @returns True if the value has valid structure, domain relationships, and
|
|
569
|
+
* budgets; false otherwise.
|
|
501
570
|
*/
|
|
502
571
|
function isTableSchema(input) {
|
|
503
572
|
const outcome = (0, _orkestrel_contract.attempt)(() => isStructuralTableSchema(input) && auditTable(input).length === 0);
|
|
@@ -506,7 +575,7 @@ function isTableSchema(input) {
|
|
|
506
575
|
//#endregion
|
|
507
576
|
//#region src/core/cloners.ts
|
|
508
577
|
/**
|
|
509
|
-
*
|
|
578
|
+
* Clones one row into an owned frozen snapshot.
|
|
510
579
|
*
|
|
511
580
|
* @param row - The row to own.
|
|
512
581
|
* @returns A frozen copy of the row's cells.
|
|
@@ -515,7 +584,8 @@ function cloneRow(row) {
|
|
|
515
584
|
return Object.freeze({ ...row });
|
|
516
585
|
}
|
|
517
586
|
/**
|
|
518
|
-
*
|
|
587
|
+
* Clones a whole schema into an owned frozen snapshot, freezing every nested column, choice list,
|
|
588
|
+
* choice, and `meta`; raises `SCHEMA` for a `meta` it cannot own.
|
|
519
589
|
*
|
|
520
590
|
* @param schema - The schema to own.
|
|
521
591
|
* @returns A frozen schema with every nested column, choice, list, and metadata record owned.
|
|
@@ -546,7 +616,7 @@ function cloneSchema(schema) {
|
|
|
546
616
|
//#endregion
|
|
547
617
|
//#region src/core/parsers.ts
|
|
548
618
|
/**
|
|
549
|
-
*
|
|
619
|
+
* Parses unknown wire data into an owned, structurally valid, semantically sound table schema.
|
|
550
620
|
*
|
|
551
621
|
* @param input - The unknown schema value to parse.
|
|
552
622
|
* @returns An owned table schema, or `undefined` on refusal.
|
|
@@ -560,7 +630,8 @@ function parseTable(input) {
|
|
|
560
630
|
return outcome.success ? outcome.value : void 0;
|
|
561
631
|
}
|
|
562
632
|
/**
|
|
563
|
-
*
|
|
633
|
+
* Parses unknown wire data into owned rows against one table schema, coercing a numeric string
|
|
634
|
+
* and `'true'` / `'false'`.
|
|
564
635
|
*
|
|
565
636
|
* @param schema - The schema that declares the accepted keys and cell shapes.
|
|
566
637
|
* @param input - The unknown row-list value to parse.
|
|
@@ -606,63 +677,94 @@ function parseRows(schema, input) {
|
|
|
606
677
|
return outcome.success ? outcome.value : void 0;
|
|
607
678
|
}
|
|
608
679
|
//#endregion
|
|
609
|
-
//#region src/core/tables/
|
|
610
|
-
/**
|
|
611
|
-
var
|
|
680
|
+
//#region src/core/tables/KeyManager.ts
|
|
681
|
+
/** Manages the key set one table axis holds, and the event it announces when that set moves. */
|
|
682
|
+
var KeyManager = class {
|
|
612
683
|
#emitter;
|
|
684
|
+
#event;
|
|
613
685
|
#gate;
|
|
614
686
|
#rows;
|
|
615
687
|
#read;
|
|
616
688
|
#write;
|
|
617
689
|
/**
|
|
618
|
-
*
|
|
690
|
+
* Creates a key-set shell over one table's private store.
|
|
619
691
|
*
|
|
620
692
|
* @param emitter - The table's event emitter.
|
|
693
|
+
* @param event - The event this axis announces when its key set moves.
|
|
621
694
|
* @param gate - The table lifecycle gate.
|
|
622
695
|
* @param rows - A read of every row key.
|
|
623
|
-
* @param read - A read of the
|
|
624
|
-
* @param write - The
|
|
696
|
+
* @param read - A read of the held keys.
|
|
697
|
+
* @param write - The held-key commit boundary.
|
|
625
698
|
*/
|
|
626
|
-
constructor(emitter, gate, rows, read, write) {
|
|
699
|
+
constructor(emitter, event, gate, rows, read, write) {
|
|
627
700
|
this.#emitter = emitter;
|
|
701
|
+
this.#event = event;
|
|
628
702
|
this.#gate = gate;
|
|
629
703
|
this.#rows = rows;
|
|
630
704
|
this.#read = read;
|
|
631
705
|
this.#write = write;
|
|
632
706
|
}
|
|
633
|
-
/**
|
|
707
|
+
/** Returns the keys held right now. */
|
|
634
708
|
get keys() {
|
|
635
709
|
return new Set(this.#read());
|
|
636
710
|
}
|
|
637
|
-
/**
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
}
|
|
647
|
-
/** Turn one or more rows around independently. */
|
|
648
|
-
toggle(input) {
|
|
711
|
+
/**
|
|
712
|
+
* Applies one atomic 0/1/N membership change, announcing it only when the set moves.
|
|
713
|
+
*
|
|
714
|
+
* @param input - Every known key, one key, or a key list.
|
|
715
|
+
* @param include - Decides the next membership from each key's membership at that step.
|
|
716
|
+
* @returns `undefined` for the no-argument form, `false` when any requested key names no row
|
|
717
|
+
* the table holds, and `true` otherwise.
|
|
718
|
+
*/
|
|
719
|
+
change(input, include) {
|
|
649
720
|
this.#gate();
|
|
650
|
-
return this.#change(input, (included) => !included) === true;
|
|
651
|
-
}
|
|
652
|
-
#change(input, include) {
|
|
653
721
|
const previous = this.#read();
|
|
654
722
|
const next = computeKeys(this.#rows(), previous, input, include);
|
|
655
723
|
if (next === void 0) return false;
|
|
656
724
|
if (next !== previous) {
|
|
657
725
|
this.#write(next);
|
|
658
|
-
this.#emitter.emit(
|
|
726
|
+
this.#emitter.emit(this.#event, new Set(next));
|
|
659
727
|
}
|
|
660
728
|
return input === void 0 ? void 0 : true;
|
|
661
729
|
}
|
|
662
730
|
};
|
|
663
731
|
//#endregion
|
|
732
|
+
//#region src/core/tables/ExpansionManager.ts
|
|
733
|
+
/** Manages the keys of the rows somebody has opened. */
|
|
734
|
+
var ExpansionManager = class {
|
|
735
|
+
#keys;
|
|
736
|
+
/**
|
|
737
|
+
* Creates an expansion manager over one table's private stores.
|
|
738
|
+
*
|
|
739
|
+
* @param emitter - The table's event emitter.
|
|
740
|
+
* @param gate - The table lifecycle gate.
|
|
741
|
+
* @param rows - A read of every row key.
|
|
742
|
+
* @param read - A read of the expanded keys.
|
|
743
|
+
* @param write - The expanded-key commit boundary.
|
|
744
|
+
*/
|
|
745
|
+
constructor(emitter, gate, rows, read, write) {
|
|
746
|
+
this.#keys = new KeyManager(emitter, "expand", gate, rows, read, write);
|
|
747
|
+
}
|
|
748
|
+
/** Returns the keys of the rows opened right now. */
|
|
749
|
+
get keys() {
|
|
750
|
+
return this.#keys.keys;
|
|
751
|
+
}
|
|
752
|
+
/** Opens one or more rows. */
|
|
753
|
+
expand(input) {
|
|
754
|
+
return this.#keys.change(input, () => true);
|
|
755
|
+
}
|
|
756
|
+
/** Closes one or more rows. */
|
|
757
|
+
clear(input) {
|
|
758
|
+
return this.#keys.change(input, () => false);
|
|
759
|
+
}
|
|
760
|
+
/** Turns one or more rows around independently. */
|
|
761
|
+
toggle(input) {
|
|
762
|
+
return this.#keys.change(input, (included) => !included) === true;
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
//#endregion
|
|
664
766
|
//#region src/core/tables/FilterManager.ts
|
|
665
|
-
/**
|
|
767
|
+
/** Manages the filters one table applies with and-only composition. */
|
|
666
768
|
var FilterManager = class {
|
|
667
769
|
#schema;
|
|
668
770
|
#emitter;
|
|
@@ -671,7 +773,7 @@ var FilterManager = class {
|
|
|
671
773
|
#write;
|
|
672
774
|
#clamp;
|
|
673
775
|
/**
|
|
674
|
-
*
|
|
776
|
+
* Creates a filter manager over one table's private filter store.
|
|
675
777
|
*
|
|
676
778
|
* @param schema - The table schema.
|
|
677
779
|
* @param emitter - The table's event emitter.
|
|
@@ -688,42 +790,35 @@ var FilterManager = class {
|
|
|
688
790
|
this.#write = write;
|
|
689
791
|
this.#clamp = clamp;
|
|
690
792
|
}
|
|
691
|
-
/**
|
|
793
|
+
/** Finds one column's filter. */
|
|
692
794
|
filter(column) {
|
|
693
795
|
const filter = this.#read().find((candidate) => candidate.column === column);
|
|
694
796
|
return filter === void 0 ? void 0 : Object.freeze({ ...filter });
|
|
695
797
|
}
|
|
696
|
-
/**
|
|
798
|
+
/** Reads every filter as an owned frozen snapshot. */
|
|
697
799
|
filters() {
|
|
698
800
|
return Object.freeze(this.#read().map((filter) => Object.freeze({ ...filter })));
|
|
699
801
|
}
|
|
700
|
-
/**
|
|
802
|
+
/** Filters one column or several. */
|
|
701
803
|
set(input) {
|
|
702
804
|
this.#gate();
|
|
703
805
|
const requested = Array.isArray(input) ? input : [input];
|
|
704
806
|
for (const filter of requested) this.#validate(filter);
|
|
705
|
-
const next =
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
const index = next.findIndex((candidate) => candidate.column === filter.column);
|
|
709
|
-
if (index === -1) next.push(owned);
|
|
710
|
-
else next[index] = owned;
|
|
711
|
-
}
|
|
712
|
-
if (this.#same(next, this.#read())) return;
|
|
713
|
-
this.#write(Object.freeze(next));
|
|
807
|
+
const next = mergeTerms(this.#read(), requested);
|
|
808
|
+
if (matchesTerms(next, this.#read(), (filter, other) => this.#operands(filter, other))) return;
|
|
809
|
+
this.#write(next);
|
|
714
810
|
const page = this.#clamp();
|
|
715
811
|
this.#emitter.emit("filter", this.filters());
|
|
716
812
|
if (page !== void 0) this.#emitter.emit("paginate", page);
|
|
717
813
|
}
|
|
718
|
-
/**
|
|
814
|
+
/** Stops filtering by one or more columns. */
|
|
719
815
|
remove(input) {
|
|
720
816
|
this.#gate();
|
|
721
817
|
const columns = input === void 0 ? this.#schema.columns.map((column) => column.key) : Array.isArray(input) ? input : [input];
|
|
722
818
|
for (const column of columns) if (extractColumn(this.#schema, column) === void 0) return false;
|
|
723
|
-
const
|
|
724
|
-
const next = this.#read().filter((filter) => !removed.has(filter.column));
|
|
819
|
+
const next = removeTerms(this.#read(), columns);
|
|
725
820
|
if (next.length !== this.#read().length) {
|
|
726
|
-
this.#write(
|
|
821
|
+
this.#write(next);
|
|
727
822
|
const page = this.#clamp();
|
|
728
823
|
this.#emitter.emit("filter", this.filters());
|
|
729
824
|
if (page !== void 0) this.#emitter.emit("paginate", page);
|
|
@@ -735,19 +830,16 @@ var FilterManager = class {
|
|
|
735
830
|
if (column === void 0) throw new TableError("COLUMN", `The schema declares no column named "${filter.column}"`, { column: filter.column });
|
|
736
831
|
if (!admitsFilter(column, filter)) throw new TableError("CELL", `Column "${filter.column}" cannot apply that filter`, { column: filter.column });
|
|
737
832
|
}
|
|
738
|
-
#
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
if (filter.operator === "between" && other.operator === "between") return filter.minimum === other.minimum && filter.maximum === other.maximum;
|
|
744
|
-
return filter.operator === "equals" && other.operator === "equals" && filter.value === other.value;
|
|
745
|
-
});
|
|
833
|
+
#operands(left, right) {
|
|
834
|
+
if (left.operator !== right.operator) return false;
|
|
835
|
+
if (left.operator === "contains" && right.operator === "contains") return left.text === right.text;
|
|
836
|
+
if (left.operator === "between" && right.operator === "between") return left.minimum === right.minimum && left.maximum === right.maximum;
|
|
837
|
+
return left.operator === "equals" && right.operator === "equals" && left.value === right.value;
|
|
746
838
|
}
|
|
747
839
|
};
|
|
748
840
|
//#endregion
|
|
749
841
|
//#region src/core/tables/PaginationManager.ts
|
|
750
|
-
/**
|
|
842
|
+
/** Manages the page arithmetic over one table's filtered rows. */
|
|
751
843
|
var PaginationManager = class {
|
|
752
844
|
#emitter;
|
|
753
845
|
#gate;
|
|
@@ -757,7 +849,7 @@ var PaginationManager = class {
|
|
|
757
849
|
#readLimit;
|
|
758
850
|
#writeLimit;
|
|
759
851
|
/**
|
|
760
|
-
*
|
|
852
|
+
* Creates a pagination manager over one table's private stores.
|
|
761
853
|
*
|
|
762
854
|
* @param emitter - The table's event emitter.
|
|
763
855
|
* @param gate - The table lifecycle gate.
|
|
@@ -778,33 +870,33 @@ var PaginationManager = class {
|
|
|
778
870
|
const limit = this.#readLimit();
|
|
779
871
|
if (limit !== void 0) this.#writeLimit(this.#normalize(limit));
|
|
780
872
|
}
|
|
781
|
-
/**
|
|
873
|
+
/** Returns the page shown, counted from one. */
|
|
782
874
|
get page() {
|
|
783
875
|
return this.#readLimit() === void 0 ? 1 : this.#readPage();
|
|
784
876
|
}
|
|
785
|
-
/**
|
|
877
|
+
/** Returns the number of rows one page holds. */
|
|
786
878
|
get limit() {
|
|
787
879
|
return this.#readLimit();
|
|
788
880
|
}
|
|
789
|
-
/**
|
|
881
|
+
/** Returns the number of filtered rows skipped before this page. */
|
|
790
882
|
get offset() {
|
|
791
883
|
const limit = this.#readLimit();
|
|
792
884
|
return limit === void 0 ? 0 : (this.#readPage() - 1) * limit;
|
|
793
885
|
}
|
|
794
|
-
/**
|
|
886
|
+
/** Returns the number of pages filled by the filtered rows. */
|
|
795
887
|
get count() {
|
|
796
888
|
const limit = this.#readLimit();
|
|
797
889
|
return limit === void 0 ? 1 : Math.max(1, Math.ceil(this.#rows() / limit));
|
|
798
890
|
}
|
|
799
|
-
/**
|
|
891
|
+
/** Shows another page, clamped to the pages that exist. */
|
|
800
892
|
move(page) {
|
|
801
893
|
this.#gate();
|
|
802
|
-
const next = this.#readLimit() === void 0 ? 1 : Math.min(this.count,
|
|
894
|
+
const next = this.#readLimit() === void 0 || Number.isNaN(page) ? 1 : Math.min(this.count, Math.max(1, Math.trunc(page)));
|
|
803
895
|
if (next === this.#readPage()) return;
|
|
804
896
|
this.#writePage(next);
|
|
805
897
|
this.#emitter.emit("paginate", next);
|
|
806
898
|
}
|
|
807
|
-
/**
|
|
899
|
+
/** Changes the page size while keeping the first row previously shown. */
|
|
808
900
|
resize(limit) {
|
|
809
901
|
this.#gate();
|
|
810
902
|
const previous = this.#readLimit();
|
|
@@ -822,7 +914,7 @@ var PaginationManager = class {
|
|
|
822
914
|
};
|
|
823
915
|
//#endregion
|
|
824
916
|
//#region src/core/tables/RowManager.ts
|
|
825
|
-
/**
|
|
917
|
+
/** Manages the rows one table holds in its own order. */
|
|
826
918
|
var RowManager = class {
|
|
827
919
|
#schema;
|
|
828
920
|
#emitter;
|
|
@@ -831,7 +923,7 @@ var RowManager = class {
|
|
|
831
923
|
#write;
|
|
832
924
|
#settle;
|
|
833
925
|
/**
|
|
834
|
-
*
|
|
926
|
+
* Creates a row manager over one table's private row store.
|
|
835
927
|
*
|
|
836
928
|
* @param schema - The table schema.
|
|
837
929
|
* @param emitter - The table's event emitter.
|
|
@@ -851,16 +943,16 @@ var RowManager = class {
|
|
|
851
943
|
const seeded = this.#prepare(rows, /* @__PURE__ */ new Set());
|
|
852
944
|
if (seeded.length > 0) this.#write(Object.freeze(seeded));
|
|
853
945
|
}
|
|
854
|
-
/**
|
|
946
|
+
/** Finds one row by key as an owned frozen snapshot. */
|
|
855
947
|
row(key) {
|
|
856
948
|
const row = this.#read().find((candidate) => extractKey(this.#schema, candidate) === key);
|
|
857
949
|
return row === void 0 ? void 0 : cloneRow(row);
|
|
858
950
|
}
|
|
859
|
-
/**
|
|
951
|
+
/** Reads every row as owned frozen snapshots in table order. */
|
|
860
952
|
rows() {
|
|
861
953
|
return Object.freeze(this.#read().map((row) => cloneRow(row)));
|
|
862
954
|
}
|
|
863
|
-
/**
|
|
955
|
+
/** Appends one row or several. */
|
|
864
956
|
add(input) {
|
|
865
957
|
this.#gate();
|
|
866
958
|
const rows = Array.isArray(input) ? input : [input];
|
|
@@ -879,7 +971,7 @@ var RowManager = class {
|
|
|
879
971
|
}
|
|
880
972
|
});
|
|
881
973
|
}
|
|
882
|
-
/**
|
|
974
|
+
/** Merges one row or several into the rows their keys name. */
|
|
883
975
|
update(input) {
|
|
884
976
|
this.#gate();
|
|
885
977
|
const updates = (Array.isArray(input) ? input : [input]).map((row) => cloneRow(row));
|
|
@@ -918,13 +1010,13 @@ var RowManager = class {
|
|
|
918
1010
|
});
|
|
919
1011
|
return true;
|
|
920
1012
|
}
|
|
921
|
-
/**
|
|
1013
|
+
/** Moves one row to a clamped index in table order. */
|
|
922
1014
|
move(key, index) {
|
|
923
1015
|
this.#gate();
|
|
924
1016
|
const current = this.#read();
|
|
925
1017
|
const origin = current.findIndex((row) => extractKey(this.#schema, row) === key);
|
|
926
1018
|
if (origin === -1) return false;
|
|
927
|
-
const target = Math.min(current.length - 1, Number.
|
|
1019
|
+
const target = Math.min(current.length - 1, Number.isNaN(index) ? 0 : Math.max(0, Math.trunc(index)));
|
|
928
1020
|
if (origin === target) return true;
|
|
929
1021
|
const row = current[origin];
|
|
930
1022
|
if (row === void 0) return false;
|
|
@@ -935,7 +1027,7 @@ var RowManager = class {
|
|
|
935
1027
|
this.#settle([], () => this.#emitter.emit("write", key));
|
|
936
1028
|
return true;
|
|
937
1029
|
}
|
|
938
|
-
/**
|
|
1030
|
+
/** Removes one or more rows. */
|
|
939
1031
|
remove(input) {
|
|
940
1032
|
this.#gate();
|
|
941
1033
|
const current = this.#read();
|
|
@@ -996,15 +1088,11 @@ var RowManager = class {
|
|
|
996
1088
|
};
|
|
997
1089
|
//#endregion
|
|
998
1090
|
//#region src/core/tables/SelectionManager.ts
|
|
999
|
-
/**
|
|
1091
|
+
/** Manages the keys of the rows somebody has picked. */
|
|
1000
1092
|
var SelectionManager = class {
|
|
1001
|
-
#
|
|
1002
|
-
#gate;
|
|
1003
|
-
#rows;
|
|
1004
|
-
#read;
|
|
1005
|
-
#write;
|
|
1093
|
+
#keys;
|
|
1006
1094
|
/**
|
|
1007
|
-
*
|
|
1095
|
+
* Creates a selection manager over one table's private stores.
|
|
1008
1096
|
*
|
|
1009
1097
|
* @param emitter - The table's event emitter.
|
|
1010
1098
|
* @param gate - The table lifecycle gate.
|
|
@@ -1013,45 +1101,28 @@ var SelectionManager = class {
|
|
|
1013
1101
|
* @param write - The selected-key commit boundary.
|
|
1014
1102
|
*/
|
|
1015
1103
|
constructor(emitter, gate, rows, read, write) {
|
|
1016
|
-
this.#
|
|
1017
|
-
this.#gate = gate;
|
|
1018
|
-
this.#rows = rows;
|
|
1019
|
-
this.#read = read;
|
|
1020
|
-
this.#write = write;
|
|
1104
|
+
this.#keys = new KeyManager(emitter, "select", gate, rows, read, write);
|
|
1021
1105
|
}
|
|
1022
|
-
/**
|
|
1106
|
+
/** Returns the keys of the rows picked right now. */
|
|
1023
1107
|
get keys() {
|
|
1024
|
-
return
|
|
1108
|
+
return this.#keys.keys;
|
|
1025
1109
|
}
|
|
1026
|
-
/**
|
|
1110
|
+
/** Picks one or more rows. */
|
|
1027
1111
|
select(input) {
|
|
1028
|
-
this.#
|
|
1029
|
-
return this.#change(input, () => true);
|
|
1112
|
+
return this.#keys.change(input, () => true);
|
|
1030
1113
|
}
|
|
1031
|
-
/**
|
|
1114
|
+
/** Drops one or more picks. */
|
|
1032
1115
|
clear(input) {
|
|
1033
|
-
this.#
|
|
1034
|
-
return this.#change(input, () => false);
|
|
1116
|
+
return this.#keys.change(input, () => false);
|
|
1035
1117
|
}
|
|
1036
|
-
/**
|
|
1118
|
+
/** Turns one or more rows around independently. */
|
|
1037
1119
|
toggle(input) {
|
|
1038
|
-
this.#
|
|
1039
|
-
return this.#change(input, (included) => !included) === true;
|
|
1040
|
-
}
|
|
1041
|
-
#change(input, include) {
|
|
1042
|
-
const previous = this.#read();
|
|
1043
|
-
const next = computeKeys(this.#rows(), previous, input, include);
|
|
1044
|
-
if (next === void 0) return false;
|
|
1045
|
-
if (next !== previous) {
|
|
1046
|
-
this.#write(next);
|
|
1047
|
-
this.#emitter.emit("select", new Set(next));
|
|
1048
|
-
}
|
|
1049
|
-
return input === void 0 ? void 0 : true;
|
|
1120
|
+
return this.#keys.change(input, (included) => !included) === true;
|
|
1050
1121
|
}
|
|
1051
1122
|
};
|
|
1052
1123
|
//#endregion
|
|
1053
1124
|
//#region src/core/tables/SortManager.ts
|
|
1054
|
-
/**
|
|
1125
|
+
/** Manages the ordered sort terms of one table. */
|
|
1055
1126
|
var SortManager = class {
|
|
1056
1127
|
#schema;
|
|
1057
1128
|
#emitter;
|
|
@@ -1059,7 +1130,7 @@ var SortManager = class {
|
|
|
1059
1130
|
#read;
|
|
1060
1131
|
#write;
|
|
1061
1132
|
/**
|
|
1062
|
-
*
|
|
1133
|
+
* Creates a sort manager over one table's private term store.
|
|
1063
1134
|
*
|
|
1064
1135
|
* @param schema - The table schema.
|
|
1065
1136
|
* @param emitter - The table's event emitter.
|
|
@@ -1074,41 +1145,33 @@ var SortManager = class {
|
|
|
1074
1145
|
this.#read = read;
|
|
1075
1146
|
this.#write = write;
|
|
1076
1147
|
}
|
|
1077
|
-
/**
|
|
1148
|
+
/** Finds one column's sort term. */
|
|
1078
1149
|
order(column) {
|
|
1079
1150
|
const order = this.#read().find((candidate) => candidate.column === column);
|
|
1080
1151
|
return order === void 0 ? void 0 : Object.freeze({ ...order });
|
|
1081
1152
|
}
|
|
1082
|
-
/**
|
|
1153
|
+
/** Reads every sort term as an owned frozen snapshot. */
|
|
1083
1154
|
orders() {
|
|
1084
1155
|
return Object.freeze(this.#read().map((order) => Object.freeze({ ...order })));
|
|
1085
1156
|
}
|
|
1086
|
-
/**
|
|
1157
|
+
/** Sorts by one column or several. */
|
|
1087
1158
|
set(input) {
|
|
1088
1159
|
this.#gate();
|
|
1089
1160
|
const requested = Array.isArray(input) ? input : [input];
|
|
1090
1161
|
for (const order of requested) this.#require(order.column);
|
|
1091
|
-
const next =
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
const index = next.findIndex((candidate) => candidate.column === order.column);
|
|
1095
|
-
if (index === -1) next.push(owned);
|
|
1096
|
-
else next[index] = owned;
|
|
1097
|
-
}
|
|
1098
|
-
if (this.#same(next, this.#read())) return;
|
|
1099
|
-
const committed = Object.freeze(next);
|
|
1100
|
-
this.#write(committed);
|
|
1162
|
+
const next = mergeTerms(this.#read(), requested);
|
|
1163
|
+
if (matchesTerms(next, this.#read(), (order, other) => order.direction === other.direction)) return;
|
|
1164
|
+
this.#write(next);
|
|
1101
1165
|
this.#emitter.emit("sort", this.orders());
|
|
1102
1166
|
}
|
|
1103
|
-
/**
|
|
1167
|
+
/** Stops sorting by one or more columns. */
|
|
1104
1168
|
remove(input) {
|
|
1105
1169
|
this.#gate();
|
|
1106
1170
|
const columns = input === void 0 ? this.#schema.columns.map((column) => column.key) : Array.isArray(input) ? input : [input];
|
|
1107
1171
|
for (const column of columns) if (extractColumn(this.#schema, column) === void 0) return false;
|
|
1108
|
-
const
|
|
1109
|
-
const next = this.#read().filter((order) => !removed.has(order.column));
|
|
1172
|
+
const next = removeTerms(this.#read(), columns);
|
|
1110
1173
|
if (next.length !== this.#read().length) {
|
|
1111
|
-
this.#write(
|
|
1174
|
+
this.#write(next);
|
|
1112
1175
|
this.#emitter.emit("sort", this.orders());
|
|
1113
1176
|
}
|
|
1114
1177
|
return input === void 0 ? void 0 : true;
|
|
@@ -1116,16 +1179,13 @@ var SortManager = class {
|
|
|
1116
1179
|
#require(column) {
|
|
1117
1180
|
if (extractColumn(this.#schema, column) === void 0) throw new TableError("COLUMN", `The schema declares no column named "${column}"`, { column });
|
|
1118
1181
|
}
|
|
1119
|
-
#same(left, right) {
|
|
1120
|
-
return left.length === right.length && left.every((order, index) => {
|
|
1121
|
-
const other = right[index];
|
|
1122
|
-
return other !== void 0 && order.column === other.column && order.direction === other.direction;
|
|
1123
|
-
});
|
|
1124
|
-
}
|
|
1125
1182
|
};
|
|
1126
1183
|
//#endregion
|
|
1127
1184
|
//#region src/core/Table.ts
|
|
1128
|
-
/**
|
|
1185
|
+
/**
|
|
1186
|
+
* Holds a schema, its rows, and the lens through which they are read, implementing
|
|
1187
|
+
* {@link TableInterface} exactly.
|
|
1188
|
+
*/
|
|
1129
1189
|
var Table = class {
|
|
1130
1190
|
#emitter;
|
|
1131
1191
|
#schema;
|
|
@@ -1147,7 +1207,7 @@ var Table = class {
|
|
|
1147
1207
|
#expansion;
|
|
1148
1208
|
#pagination;
|
|
1149
1209
|
/**
|
|
1150
|
-
*
|
|
1210
|
+
* Opens a table against a schema.
|
|
1151
1211
|
*
|
|
1152
1212
|
* @param schema - The table declaration to own.
|
|
1153
1213
|
* @param options - Initial rows, lens overrides, pagination, and emitter wiring.
|
|
@@ -1155,9 +1215,13 @@ var Table = class {
|
|
|
1155
1215
|
* identity is unusable or repeated, and `CELL` when a seeded cell is invalid.
|
|
1156
1216
|
*/
|
|
1157
1217
|
constructor(schema, options) {
|
|
1158
|
-
const
|
|
1218
|
+
const unusable = "The schema is not a table schema";
|
|
1219
|
+
const owned = isStructuralTableSchema(schema) ? (0, _orkestrel_contract.attempt)(() => cloneSchema(schema)) : void 0;
|
|
1220
|
+
if (owned !== void 0 && !owned.success && isTableError(owned.error)) throw owned.error;
|
|
1221
|
+
if (owned === void 0 || !owned.success) throw new TableError("SCHEMA", `The table schema is unusable: ${unusable}`, { problems: [unusable] });
|
|
1222
|
+
const problems = isStructuralTableSchema(owned.value) ? auditTable(owned.value) : [unusable];
|
|
1159
1223
|
if (problems.length > 0) throw new TableError("SCHEMA", `The table schema is unusable: ${problems.join("; ")}`, { problems: [...problems] });
|
|
1160
|
-
this.#schema =
|
|
1224
|
+
this.#schema = owned.value;
|
|
1161
1225
|
this.#comparators = options?.comparators === void 0 ? void 0 : Object.freeze({ ...options.comparators });
|
|
1162
1226
|
this.#matchers = options?.matchers === void 0 ? void 0 : Object.freeze({ ...options.matchers });
|
|
1163
1227
|
this.#limit = options?.limit;
|
|
@@ -1187,54 +1251,54 @@ var Table = class {
|
|
|
1187
1251
|
this.#rowStore = rows;
|
|
1188
1252
|
}, (removed, announce) => this.#settle(removed, announce), options?.rows);
|
|
1189
1253
|
}
|
|
1190
|
-
/**
|
|
1254
|
+
/** Holds the table's event emitter. */
|
|
1191
1255
|
get emitter() {
|
|
1192
1256
|
return this.#emitter;
|
|
1193
1257
|
}
|
|
1194
|
-
/**
|
|
1258
|
+
/** Holds the owned frozen schema. */
|
|
1195
1259
|
get schema() {
|
|
1196
1260
|
return this.#schema;
|
|
1197
1261
|
}
|
|
1198
|
-
/**
|
|
1262
|
+
/** Manages the rows the table holds. */
|
|
1199
1263
|
get rows() {
|
|
1200
1264
|
return this.#rows;
|
|
1201
1265
|
}
|
|
1202
|
-
/**
|
|
1266
|
+
/** Manages the ordered sort terms. */
|
|
1203
1267
|
get sort() {
|
|
1204
1268
|
return this.#sort;
|
|
1205
1269
|
}
|
|
1206
|
-
/**
|
|
1270
|
+
/** Manages the filters applied with and-only composition. */
|
|
1207
1271
|
get filter() {
|
|
1208
1272
|
return this.#filter;
|
|
1209
1273
|
}
|
|
1210
|
-
/**
|
|
1274
|
+
/** Manages the selected row keys. */
|
|
1211
1275
|
get selection() {
|
|
1212
1276
|
return this.#selection;
|
|
1213
1277
|
}
|
|
1214
|
-
/**
|
|
1278
|
+
/** Manages the expanded row keys. */
|
|
1215
1279
|
get expansion() {
|
|
1216
1280
|
return this.#expansion;
|
|
1217
1281
|
}
|
|
1218
|
-
/**
|
|
1282
|
+
/** Manages the page arithmetic. */
|
|
1219
1283
|
get pagination() {
|
|
1220
1284
|
return this.#pagination;
|
|
1221
1285
|
}
|
|
1222
|
-
/**
|
|
1286
|
+
/** Returns the filtered, sorted, and paged rows as owned frozen snapshots. */
|
|
1223
1287
|
get view() {
|
|
1224
1288
|
const ordered = sortRows(this.#schema, this.#filtered(), this.#orderStore, this.#comparators);
|
|
1225
1289
|
const limit = this.#limit;
|
|
1226
1290
|
const page = limit === void 0 ? ordered : ordered.slice(this.#pagination.offset, this.#pagination.offset + limit);
|
|
1227
1291
|
return Object.freeze(page.map((row) => cloneRow(row)));
|
|
1228
1292
|
}
|
|
1229
|
-
/**
|
|
1293
|
+
/** Returns the number of rows admitted by the filters. */
|
|
1230
1294
|
get count() {
|
|
1231
1295
|
return this.#filtered().length;
|
|
1232
1296
|
}
|
|
1233
|
-
/**
|
|
1297
|
+
/** Reports whether the table has been torn down. */
|
|
1234
1298
|
get destroyed() {
|
|
1235
1299
|
return this.#destroyed;
|
|
1236
1300
|
}
|
|
1237
|
-
/**
|
|
1301
|
+
/** Resets every moving axis to its opening state. */
|
|
1238
1302
|
clear() {
|
|
1239
1303
|
this.#gate();
|
|
1240
1304
|
if (!(this.#rowStore.length > 0 || this.#orderStore.length > 0 || this.#filterStore.length > 0 || this.#selected.size > 0 || this.#expanded.size > 0 || this.#page !== 1 || this.#limit !== this.#initialLimit)) return;
|
|
@@ -1247,7 +1311,7 @@ var Table = class {
|
|
|
1247
1311
|
this.#limit = this.#initialLimit;
|
|
1248
1312
|
this.#emitter.emit("clear");
|
|
1249
1313
|
}
|
|
1250
|
-
/**
|
|
1314
|
+
/** Tears the table down while leaving every getter readable. */
|
|
1251
1315
|
destroy() {
|
|
1252
1316
|
if (this.#destroyed) return;
|
|
1253
1317
|
this.#destroyed = true;
|
|
@@ -1289,17 +1353,43 @@ var Table = class {
|
|
|
1289
1353
|
//#endregion
|
|
1290
1354
|
//#region src/core/factories.ts
|
|
1291
1355
|
/**
|
|
1292
|
-
*
|
|
1356
|
+
* Opens a table against a schema. The schema is copied, and the copy is what the table declares.
|
|
1293
1357
|
*
|
|
1294
1358
|
* @param schema - The table declaration to own.
|
|
1295
1359
|
* @param options - Initial rows, lens overrides, pagination, and emitter wiring.
|
|
1296
1360
|
* @returns A live table interface.
|
|
1297
1361
|
* @throws A {@link TableError} coded `SCHEMA` when the schema is unusable, `KEY` when a seeded
|
|
1298
1362
|
* identity is unusable or repeated, and `CELL` when a seeded cell is invalid.
|
|
1299
|
-
* @example
|
|
1363
|
+
* @example Open a table
|
|
1300
1364
|
* ```ts
|
|
1301
|
-
*
|
|
1302
|
-
*
|
|
1365
|
+
* import { createTable } from '@orkestrel/table'
|
|
1366
|
+
*
|
|
1367
|
+
* const table = createTable(
|
|
1368
|
+
* {
|
|
1369
|
+
* label: 'People',
|
|
1370
|
+
* key: 'id',
|
|
1371
|
+
* columns: [
|
|
1372
|
+
* { cell: 'text', key: 'id', label: 'Reference' },
|
|
1373
|
+
* { cell: 'text', key: 'name', label: 'Name' },
|
|
1374
|
+
* { cell: 'number', key: 'age', label: 'Age' },
|
|
1375
|
+
* ],
|
|
1376
|
+
* },
|
|
1377
|
+
* {
|
|
1378
|
+
* rows: [
|
|
1379
|
+
* { id: '1', name: 'Ada', age: 36 },
|
|
1380
|
+
* { id: '2', name: 'Grace', age: 45 },
|
|
1381
|
+
* { id: '3', name: 'Alan', age: 41 },
|
|
1382
|
+
* ],
|
|
1383
|
+
* limit: 2,
|
|
1384
|
+
* },
|
|
1385
|
+
* )
|
|
1386
|
+
*
|
|
1387
|
+
* table.filter.set({ column: 'name', operator: 'contains', text: 'a' })
|
|
1388
|
+
* table.sort.set({ column: 'age', direction: 'descending' })
|
|
1389
|
+
*
|
|
1390
|
+
* table.count // 3 — every name holds a lowercase 'a'
|
|
1391
|
+
* table.pagination.count // 2 — two pages of two
|
|
1392
|
+
* table.view.map((row) => row.name) // ['Grace', 'Alan'] — page one, oldest first
|
|
1303
1393
|
* ```
|
|
1304
1394
|
*/
|
|
1305
1395
|
function createTable(schema, options) {
|
|
@@ -1309,15 +1399,9 @@ function createTable(schema, options) {
|
|
|
1309
1399
|
exports.CHOICE_LIMIT = CHOICE_LIMIT;
|
|
1310
1400
|
exports.COLUMN_CELLS = COLUMN_CELLS;
|
|
1311
1401
|
exports.COLUMN_LIMIT = COLUMN_LIMIT;
|
|
1312
|
-
exports.ExpansionManager = ExpansionManager;
|
|
1313
|
-
exports.FilterManager = FilterManager;
|
|
1314
1402
|
exports.NAME_LIMIT = NAME_LIMIT;
|
|
1315
1403
|
exports.NODE_LIMIT = NODE_LIMIT;
|
|
1316
|
-
exports.PaginationManager = PaginationManager;
|
|
1317
|
-
exports.RowManager = RowManager;
|
|
1318
1404
|
exports.STRING_LIMIT = STRING_LIMIT;
|
|
1319
|
-
exports.SelectionManager = SelectionManager;
|
|
1320
|
-
exports.SortManager = SortManager;
|
|
1321
1405
|
exports.TEXT_LIMIT = TEXT_LIMIT;
|
|
1322
1406
|
exports.Table = Table;
|
|
1323
1407
|
exports.TableError = TableError;
|
|
@@ -1341,8 +1425,11 @@ exports.isTableRow = isTableRow;
|
|
|
1341
1425
|
exports.isTableSchema = isTableSchema;
|
|
1342
1426
|
exports.matchesCell = matchesCell;
|
|
1343
1427
|
exports.matchesFilter = matchesFilter;
|
|
1428
|
+
exports.matchesTerms = matchesTerms;
|
|
1429
|
+
exports.mergeTerms = mergeTerms;
|
|
1344
1430
|
exports.parseRows = parseRows;
|
|
1345
1431
|
exports.parseTable = parseTable;
|
|
1432
|
+
exports.removeTerms = removeTerms;
|
|
1346
1433
|
exports.serializeRows = serializeRows;
|
|
1347
1434
|
exports.serializeTable = serializeTable;
|
|
1348
1435
|
exports.sortRows = sortRows;
|