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