@platforma-sdk/model 1.68.5 → 1.68.7

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.
Files changed (52) hide show
  1. package/dist/columns/column_collection_builder.cjs +8 -2
  2. package/dist/columns/column_collection_builder.cjs.map +1 -1
  3. package/dist/columns/column_collection_builder.d.ts +14 -3
  4. package/dist/columns/column_collection_builder.d.ts.map +1 -1
  5. package/dist/columns/column_collection_builder.js +8 -2
  6. package/dist/columns/column_collection_builder.js.map +1 -1
  7. package/dist/columns/ctx_column_sources.d.ts +1 -1
  8. package/dist/columns/index.d.ts +1 -1
  9. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs +50 -50
  10. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs.map +1 -1
  11. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.d.ts +5 -10
  12. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.d.ts.map +1 -1
  13. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js +50 -50
  14. package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js.map +1 -1
  15. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs +16 -17
  16. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.cjs.map +1 -1
  17. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.d.ts +4 -4
  18. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.d.ts.map +1 -1
  19. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js +16 -17
  20. package/dist/components/PlDataTable/createPlDataTable/discoverColumns.js.map +1 -1
  21. package/dist/components/PlDataTable/createPlDataTable/utils.cjs +8 -2
  22. package/dist/components/PlDataTable/createPlDataTable/utils.cjs.map +1 -1
  23. package/dist/components/PlDataTable/createPlDataTable/utils.js +8 -2
  24. package/dist/components/PlDataTable/createPlDataTable/utils.js.map +1 -1
  25. package/dist/components/PlDatasetSelector/filter_discovery.d.ts +1 -1
  26. package/dist/index.d.ts +6 -6
  27. package/dist/labels/derive_distinct_labels.cjs +121 -50
  28. package/dist/labels/derive_distinct_labels.cjs.map +1 -1
  29. package/dist/labels/derive_distinct_labels.d.ts +30 -14
  30. package/dist/labels/derive_distinct_labels.d.ts.map +1 -1
  31. package/dist/labels/derive_distinct_labels.js +121 -50
  32. package/dist/labels/derive_distinct_labels.js.map +1 -1
  33. package/dist/labels/derive_distinct_tooltips.cjs +0 -10
  34. package/dist/labels/derive_distinct_tooltips.cjs.map +1 -1
  35. package/dist/labels/derive_distinct_tooltips.d.ts +2 -3
  36. package/dist/labels/derive_distinct_tooltips.d.ts.map +1 -1
  37. package/dist/labels/derive_distinct_tooltips.js +0 -10
  38. package/dist/labels/derive_distinct_tooltips.js.map +1 -1
  39. package/dist/labels/index.d.ts +1 -1
  40. package/dist/package.cjs +1 -1
  41. package/dist/package.js +1 -1
  42. package/package.json +4 -4
  43. package/src/columns/column_collection_builder.test.ts +0 -2
  44. package/src/columns/column_collection_builder.ts +26 -3
  45. package/src/components/PlDataTable/createPlDataTable/createPlDataTableV3.ts +90 -75
  46. package/src/components/PlDataTable/createPlDataTable/discoverColumns.ts +31 -34
  47. package/src/components/PlDataTable/createPlDataTable/utils.test.ts +1 -1
  48. package/src/components/PlDataTable/createPlDataTable/utils.ts +11 -4
  49. package/src/labels/derive_distinct_labels.test.ts +396 -52
  50. package/src/labels/derive_distinct_labels.ts +205 -103
  51. package/src/labels/derive_distinct_tooltips.test.ts +1 -22
  52. package/src/labels/derive_distinct_tooltips.ts +1 -18
@@ -20,13 +20,7 @@ import { isEmpty } from "es-toolkit/compat";
20
20
  import type { PlDataTableFilters, PlDataTableFilterSpecLeaf, PlDataTableModel } from "../typesV5";
21
21
  import { upgradePlDataTableStateV2 } from "../state-migration";
22
22
  import type { PlDataTableStateV2 } from "../state-migration";
23
- import type {
24
- ColumnSelector,
25
- ColumnSnapshot,
26
- MatchingMode,
27
- MatchQualifications,
28
- MatchVariant,
29
- } from "../../../columns";
23
+ import type { ColumnSelector, ColumnSnapshot, ColumnVariant, MatchingMode } from "../../../columns";
30
24
  import { getAllLabelColumns, getMatchingLabelColumns } from "../labels";
31
25
  import type { DeriveLabelsOptions } from "../../../labels/derive_distinct_labels";
32
26
  import {
@@ -44,11 +38,12 @@ import type { PrimaryEntry, SecondaryGroup } from "./createPTableDefV3";
44
38
  import { createPTableDefV3 } from "./createPTableDefV3";
45
39
  import { discoverTableColumnSnaphots, type DiscoverTableColumnOptions } from "./discoverColumns";
46
40
  import { isNil, isPlainObject, throwError, type Nil } from "@milaboratories/helpers";
41
+ import { flow } from "es-toolkit";
47
42
 
48
43
  export type createPlDataTableOptionsV3 = {
49
44
  tableState?: PlDataTableStateV2;
50
45
 
51
- columns: Nil | DiscoverTableColumnOptions | TableColumnSnapshot[];
46
+ columns: Nil | DiscoverTableColumnOptions | TableColumnVariant[];
52
47
  filters?: PlDataTableFilters;
53
48
  sorting?: PTableSorting[];
54
49
  primaryJoinType?: "inner" | "full";
@@ -103,15 +98,16 @@ export function createPlDataTableV3<A, U>(
103
98
  const splited = splitDiscoveredColumns(discovered);
104
99
 
105
100
  const labelColumns = getMatchingLabelColumns(
106
- [...splited.direct, ...splited.linked],
101
+ [...splited.direct, ...splited.linked].map((v) => v.column),
107
102
  getAllLabelColumns(ctx),
108
103
  );
109
104
 
110
105
  const derivedLabels = deriveAllLabels({
111
106
  columns: discovered.map((dc) => ({
112
- id: dc.id,
113
- spec: dc.spec,
114
- linkerPath: dc.linkerPath?.map((lp) => ({ spec: lp.linker.spec })),
107
+ id: dc.column.id,
108
+ spec: dc.column.spec,
109
+ linkerPath: dc.path,
110
+ qualifications: dc.qualifications,
115
111
  })),
116
112
  labelColumns,
117
113
  deriveLabelsOptions: {
@@ -122,12 +118,11 @@ export function createPlDataTableV3<A, U>(
122
118
 
123
119
  const derivedTooltips = deriveAllTooltips({
124
120
  columns: discovered.map((dc) => ({
125
- id: dc.id,
121
+ id: dc.column.id,
126
122
  originalId: dc.originalId,
127
- spec: dc.spec,
128
- linkerPath: dc.linkerPath,
123
+ spec: dc.column.spec,
124
+ linkerPath: dc.path,
129
125
  qualifications: dc.qualifications,
130
- distinctiveQualifications: dc.distinctiveQualifications,
131
126
  })),
132
127
  });
133
128
 
@@ -146,8 +141,8 @@ export function createPlDataTableV3<A, U>(
146
141
  if (primarySnapshots.length === 0) return undefined;
147
142
 
148
143
  const columnIsAvailable = createColumnValidationById([
149
- ...annotated.direct,
150
- ...annotated.linked.flatMap((lc) => [...(lc.linkerPath ?? []).map((s) => s.linker), lc]),
144
+ ...annotated.direct.map((v) => v.column),
145
+ ...annotated.linked.flatMap((lc) => [...lc.path.map((s) => s.linker), lc.column]),
151
146
  ...annotated.labels,
152
147
  ]);
153
148
 
@@ -165,7 +160,7 @@ export function createPlDataTableV3<A, U>(
165
160
  validateSorting(sorting, columnIsAvailable);
166
161
 
167
162
  const primaryEntries: PrimaryEntry<undefined | PColumnDataUniversal>[] = primarySnapshots.map(
168
- (snap) => ({ column: resolveSnapshot(snap) }),
163
+ (v) => ({ column: resolveSnapshot(v.column) }),
169
164
  );
170
165
  const secondaryGroups: SecondaryGroup<undefined | PColumnDataUniversal>[] = buildSecondaryGroups(
171
166
  secondarySnapshots,
@@ -184,15 +179,15 @@ export function createPlDataTableV3<A, U>(
184
179
  // TODO: is workaround for dropdown suggestions.
185
180
  // Pframe have not equivalent data for columns relativly to Ptable
186
181
  const pframeHandle = ctx.createPFrame([
187
- ...annotated.direct.map(resolveSnapshot),
188
- ...annotated.linked.map(resolveSnapshot),
182
+ ...annotated.direct.map((v) => resolveSnapshot(v.column)),
183
+ ...annotated.linked.map((v) => resolveSnapshot(v.column)),
189
184
  ...annotated.labels,
190
185
  ...collectLinkerSnapshots(annotated.linked).map(resolveSnapshot),
191
186
  ]);
192
187
 
193
188
  const hiddenSpecs = state.pTableParams.hiddenColIds;
194
189
  const hiddenColumnIds = computeHiddenColumns(
195
- [...annotated.direct, ...annotated.linked],
190
+ [...annotated.direct, ...annotated.linked].map((v) => v.column),
196
191
  sorting,
197
192
  filters,
198
193
  hiddenSpecs,
@@ -221,43 +216,39 @@ export function createPlDataTableV3<A, U>(
221
216
  } satisfies PlDataTableModel;
222
217
  }
223
218
 
224
- /** A single column discovered from sources — normalized from raw ColumnSnapshot/ColumnMatch. */
225
- export type TableColumnSnapshot = ColumnSnapshot<DiscoveredPColumnId> & {
219
+ export type TableColumnVariant = ColumnVariant<DiscoveredPColumnId> & {
226
220
  readonly originalId: PObjectId;
227
221
  readonly isPrimary?: boolean;
228
- readonly linkerPath?: MatchVariant["path"];
229
- readonly qualifications?: MatchQualifications;
230
- readonly distinctiveQualifications?: MatchQualifications;
231
222
  };
232
223
 
233
224
  type SplitDiscoveredColumns = {
234
- readonly direct: TableColumnSnapshot[];
235
- readonly linked: TableColumnSnapshot[];
225
+ readonly direct: TableColumnVariant[];
226
+ readonly linked: TableColumnVariant[];
236
227
  };
237
228
 
238
229
  type AnnotatedColumnGroups = {
239
- readonly direct: TableColumnSnapshot[];
240
- readonly linked: TableColumnSnapshot[];
230
+ readonly direct: TableColumnVariant[];
231
+ readonly linked: TableColumnVariant[];
241
232
  readonly labels: PColumn<PColumnDataUniversal>[];
242
233
  };
243
234
 
244
235
  type VisibleColumns = {
245
- readonly direct: TableColumnSnapshot[];
246
- readonly linked: TableColumnSnapshot[];
236
+ readonly direct: TableColumnVariant[];
237
+ readonly linked: TableColumnVariant[];
247
238
  readonly labels: PColumn<PColumnDataUniversal>[];
248
239
  };
249
240
 
250
241
  /** Split discovered columns into direct (no linker path) and linked (with linker path). */
251
- function splitDiscoveredColumns(columns: TableColumnSnapshot[]): SplitDiscoveredColumns {
252
- const direct = columns.filter((dc) => isNil(dc.linkerPath) || dc.linkerPath.length === 0);
253
- const linked = columns.filter((dc) => !isNil(dc.linkerPath) && dc.linkerPath.length > 0);
242
+ function splitDiscoveredColumns(columns: TableColumnVariant[]): SplitDiscoveredColumns {
243
+ const direct = columns.filter((dc) => dc.path.length === 0);
244
+ const linked = columns.filter((dc) => dc.path.length > 0);
254
245
  return { direct, linked };
255
246
  }
256
247
 
257
248
  /** All linker snapshots across the given linked columns, deduped by id. */
258
- function collectLinkerSnapshots(linked: TableColumnSnapshot[]): ColumnSnapshot<PObjectId>[] {
249
+ function collectLinkerSnapshots(linked: TableColumnVariant[]): ColumnSnapshot<PObjectId>[] {
259
250
  return uniqueBy(
260
- linked.flatMap((lc) => (lc.linkerPath ?? []).map((s) => s.linker)),
251
+ linked.flatMap((lc) => lc.path.map((s) => s.linker)),
261
252
  (c) => c.id,
262
253
  );
263
254
  }
@@ -269,8 +260,8 @@ function collectLinkerSnapshots(linked: TableColumnSnapshot[]): ColumnSnapshot<P
269
260
  * column annotations via `withTableVisualAnnotations`.
270
261
  */
271
262
  function annotateColumnGroups(params: {
272
- direct: TableColumnSnapshot[];
273
- linked: TableColumnSnapshot[];
263
+ direct: TableColumnVariant[];
264
+ linked: TableColumnVariant[];
274
265
  labelColumns: PColumn<PColumnDataUniversal>[];
275
266
  derivedLabels: Record<string, string>;
276
267
  derivedTooltips: Record<string, string>;
@@ -288,8 +279,8 @@ function annotateColumnGroups(params: {
288
279
  } = params;
289
280
 
290
281
  const allColumnsForRules = [
291
- ...direct,
292
- ...linked,
282
+ ...direct.map((v) => v.column),
283
+ ...linked.map((v) => v.column),
293
284
  ...labelColumns,
294
285
  ...collectLinkerSnapshots(linked),
295
286
  ];
@@ -304,22 +295,29 @@ function annotateColumnGroups(params: {
304
295
  pframeSpec,
305
296
  );
306
297
 
307
- const directAnnotated = [
308
- withLabelAnnotations.bind(null, derivedLabels),
309
- withInfoAnnotations.bind(null, derivedTooltips),
310
- withTableVisualAnnotations.bind(null, visibilityByColId, orderByColId),
311
- ].reduce((cols, fn) => fn(cols) as TableColumnSnapshot[], direct);
298
+ const directAnnotated = liftToVariantColumns(
299
+ direct,
300
+ flow(
301
+ (cols) => withLabelAnnotations(derivedLabels, cols),
302
+ (cols) => withInfoAnnotations(derivedTooltips, cols),
303
+ (cols) => withTableVisualAnnotations(visibilityByColId, orderByColId, cols),
304
+ ),
305
+ );
312
306
 
313
- const linkedAnnotated = [
314
- withLabelAnnotations.bind(null, derivedLabels),
315
- withInfoAnnotations.bind(null, derivedTooltips),
316
- withHidenAxesAnnotations.bind(null),
317
- withTableVisualAnnotations.bind(null, visibilityByColId, orderByColId),
318
- (cols: TableColumnSnapshot[]) =>
319
- cols.map((lc) => ({ ...lc, linkerPath: annotateLinkerPath(derivedLabels, lc.linkerPath) })),
320
- ].reduce((cols, fn) => fn(cols) as TableColumnSnapshot[], linked);
307
+ const linkedAnnotated = liftToVariantColumns(
308
+ linked,
309
+ flow(
310
+ (cols) => withHidenAxesAnnotations(cols),
311
+ (cols) => withLabelAnnotations(derivedLabels, cols),
312
+ (cols) => withInfoAnnotations(derivedTooltips, cols),
313
+ (cols) => withTableVisualAnnotations(visibilityByColId, orderByColId, cols),
314
+ ),
315
+ ).map((lc) => ({ ...lc, path: annotateLinkerPath(derivedLabels, lc.path) }));
321
316
 
322
- const labelColumnsAnnotated = withLabelAnnotations(derivedLabels, labelColumns);
317
+ const labelColumnsAnnotated = flow(
318
+ (cols: PColumn<PColumnDataUniversal>[]) => withHidenAxesAnnotations(cols),
319
+ (cols) => withLabelAnnotations(derivedLabels, cols),
320
+ )(labelColumns);
323
321
 
324
322
  return {
325
323
  direct: directAnnotated,
@@ -327,11 +325,25 @@ function annotateColumnGroups(params: {
327
325
  labels: labelColumnsAnnotated,
328
326
  };
329
327
  }
328
+
329
+ /** Lift a snapshot-array transform so it runs on the inner `column` of each variant. */
330
+ function liftToVariantColumns<V extends { readonly column: ColumnSnapshot<DiscoveredPColumnId> }>(
331
+ variants: V[],
332
+ fn: (cols: ColumnSnapshot<DiscoveredPColumnId>[]) => ColumnSnapshot<DiscoveredPColumnId>[],
333
+ ): V[] {
334
+ const cols = fn(variants.map((v) => v.column));
335
+ if (cols.length !== variants.length)
336
+ throw new Error(
337
+ `liftToVariantColumns: fn must preserve array length (got ${cols.length}, expected ${variants.length})`,
338
+ );
339
+ return variants.map((v, i) => ({ ...v, column: cols[i] }));
340
+ }
341
+
330
342
  function annotateLinkerPath(
331
343
  derivedLabels: Record<string, string>,
332
- path: TableColumnSnapshot["linkerPath"],
333
- ): TableColumnSnapshot["linkerPath"] {
334
- if (isNil(path) || path.length === 0) return path;
344
+ path: TableColumnVariant["path"],
345
+ ): TableColumnVariant["path"] {
346
+ if (path.length === 0) return path;
335
347
  const annotatedLinkers = withHidenAxesAnnotations(
336
348
  withLabelAnnotations(
337
349
  derivedLabels,
@@ -408,27 +420,27 @@ function validateSorting(sorting: PTableSorting[], isValidColumnId: (id: string)
408
420
  }
409
421
 
410
422
  function buildSecondaryGroups(
411
- direct: TableColumnSnapshot[],
412
- linked: TableColumnSnapshot[],
423
+ direct: TableColumnVariant[],
424
+ linked: TableColumnVariant[],
413
425
  labels: PColumn<PColumnDataUniversal>[],
414
426
  ): SecondaryGroup<undefined | PColumnDataUniversal>[] {
415
427
  return [
416
428
  ...direct.map(
417
429
  (c): SecondaryGroup<undefined | PColumnDataUniversal> => ({
418
- entries: [{ column: resolveSnapshot(c), qualifications: c.qualifications?.forHit }],
419
- primaryQualifications: c.qualifications?.forQueries,
430
+ entries: [{ column: resolveSnapshot(c.column), qualifications: c.qualifications.forHit }],
431
+ primaryQualifications: c.qualifications.forQueries,
420
432
  }),
421
433
  ),
422
434
  ...linked.map(
423
435
  (lc): SecondaryGroup<undefined | PColumnDataUniversal> => ({
424
436
  entries: [
425
- ...(lc.linkerPath ?? []).map((s) => ({
437
+ ...lc.path.map((s) => ({
426
438
  column: resolveSnapshot(s.linker),
427
439
  qualifications: s.qualifications,
428
440
  })),
429
- { column: resolveSnapshot(lc), qualifications: lc.qualifications?.forHit },
441
+ { column: resolveSnapshot(lc.column), qualifications: lc.qualifications.forHit },
430
442
  ],
431
- primaryQualifications: lc.qualifications?.forQueries,
443
+ primaryQualifications: lc.qualifications.forQueries,
432
444
  }),
433
445
  ),
434
446
  ...labels.map(
@@ -480,9 +492,12 @@ function buildVisibleColumns(
480
492
  hiddenColumns: Set<PObjectId>,
481
493
  originalLabelColumns: PColumn<PColumnDataUniversal>[],
482
494
  ): VisibleColumns {
483
- const direct = annotated.direct.filter((c) => !hiddenColumns.has(c.id));
484
- const linked = annotated.linked.filter((c) => !hiddenColumns.has(c.id));
485
- const labels = getMatchingLabelColumns([...direct, ...linked], originalLabelColumns);
495
+ const direct = annotated.direct.filter((c) => !hiddenColumns.has(c.column.id));
496
+ const linked = annotated.linked.filter((c) => !hiddenColumns.has(c.column.id));
497
+ const labels = getMatchingLabelColumns(
498
+ [...direct, ...linked].map((v) => v.column),
499
+ originalLabelColumns,
500
+ );
486
501
  return { direct, linked, labels };
487
502
  }
488
503
 
@@ -496,21 +511,21 @@ function resolveSnapshot(
496
511
  /** Remap column references in sorting entries. */
497
512
  function remapSortingColumnIds(
498
513
  sorting: Nil | PTableSorting[],
499
- columns: TableColumnSnapshot[],
514
+ columns: TableColumnVariant[],
500
515
  ): Nil | PTableSorting[] {
501
516
  return sorting?.map((s) => {
502
517
  if (s.column.type === "axis") return s; // Axis references are unaffected by column ID remapping
503
518
 
504
519
  const id = s.column.id;
505
520
  const column =
506
- columns.find((c) => (c.originalId ?? c.id) === id) ??
521
+ columns.find((c) => (c.originalId ?? c.column.id) === id) ??
507
522
  throwError(`Column ID "${id}" in sorting does not match any discovered column`);
508
523
 
509
524
  return {
510
525
  ...s,
511
526
  column: {
512
527
  type: "column",
513
- id: column.id,
528
+ id: column.column.id,
514
529
  },
515
530
  };
516
531
  });
@@ -521,7 +536,7 @@ type PlDataTableFilterNode = FilterSpecNode<PlDataTableFilterSpecLeaf>;
521
536
  /** Remap column references in a filter tree. */
522
537
  function remapFilterColumnIds(
523
538
  filters: Nil | PlDataTableFilters,
524
- columns: TableColumnSnapshot[],
539
+ columns: TableColumnVariant[],
525
540
  ): Nil | PlDataTableFilters {
526
541
  if (isNil(filters)) return filters;
527
542
 
@@ -533,12 +548,12 @@ function remapFilterColumnIds(
533
548
 
534
549
  const originalId = parsed.id;
535
550
  const column =
536
- columns.find((c) => (c.originalId ?? c.id) === originalId) ??
551
+ columns.find((c) => (c.originalId ?? c.column.id) === originalId) ??
537
552
  throwError(`Column ID "${parsed.id}" in filters does not match any discovered column`);
538
553
 
539
554
  return canonicalizeJson<PTableColumnId>({
540
555
  type: "column",
541
- id: column.id,
556
+ id: column.column.id,
542
557
  });
543
558
  };
544
559
 
@@ -3,7 +3,7 @@ import { createDiscoveredPColumnId, isPlRef } from "@milaboratories/pl-model-com
3
3
  import type { RenderCtxBase } from "../../../render";
4
4
  import type {
5
5
  ColumnSource,
6
- ColumnMatch,
6
+ ColumnVariant,
7
7
  RelaxedColumnSelector,
8
8
  ColumnSnapshotProvider,
9
9
  ColumnSnapshot,
@@ -12,7 +12,7 @@ import { ColumnCollectionBuilder } from "../../../columns";
12
12
  import { toColumnSnapshotProvider } from "../../../columns/column_snapshot_provider";
13
13
  import { collectCtxColumnSnapshotProviders } from "../../../columns/ctx_column_sources";
14
14
  import { throwError } from "@milaboratories/helpers";
15
- import type { ColumnsSelectorConfig, TableColumnSnapshot } from "./createPlDataTableV3";
15
+ import type { ColumnsSelectorConfig, TableColumnVariant } from "./createPlDataTableV3";
16
16
  import { isNil } from "es-toolkit";
17
17
 
18
18
  export type DiscoverTableColumnOptions = {
@@ -21,11 +21,11 @@ export type DiscoverTableColumnOptions = {
21
21
  selector: ColumnsSelectorConfig;
22
22
  };
23
23
 
24
- /** Discover columns from sources/anchors and normalize into a flat DiscoveredColumn list. */
24
+ /** Discover columns from sources/anchors and normalize into a flat TableColumnVariant list. */
25
25
  export function discoverTableColumnSnaphots(
26
26
  ctx: RenderCtxBase,
27
27
  options: DiscoverTableColumnOptions,
28
- ): TableColumnSnapshot[] | undefined {
28
+ ): TableColumnVariant[] | undefined {
29
29
  // Resolve PlRef anchors to PColumnSpec
30
30
  const resolvedOptions = {
31
31
  ...options,
@@ -43,7 +43,7 @@ export function discoverTableColumnSnaphots(
43
43
  if (collection === undefined) return undefined;
44
44
 
45
45
  try {
46
- const columns = collection.findColumns({
46
+ const variants = collection.findColumnVariants({
47
47
  ...(resolvedOptions.selector ?? {}),
48
48
  exclude: [
49
49
  ...(Array.isArray(resolvedOptions.selector?.exclude)
@@ -55,7 +55,7 @@ export function discoverTableColumnSnaphots(
55
55
  ],
56
56
  });
57
57
  const anchors = collection.getAnchors();
58
- return mapToDiscoveredColumns(columns, anchors);
58
+ return mapToTableColumnVariants(variants, anchors);
59
59
  } finally {
60
60
  collection.dispose();
61
61
  }
@@ -93,43 +93,40 @@ function resolveProviders(
93
93
  : collectCtxColumnSnapshotProviders(ctx);
94
94
  }
95
95
 
96
- /** Map matched columns into a flat DiscoveredColumn list with deduped IDs. */
97
- function mapToDiscoveredColumns(
98
- matched: readonly ColumnMatch[],
96
+ /** Map column variants into TableColumnVariant list with anchor-derived isPrimary flag. */
97
+ function mapToTableColumnVariants(
98
+ variants: readonly ColumnVariant[],
99
99
  anchors: Map<string, ColumnSnapshot<PObjectId>>,
100
- ): TableColumnSnapshot[] {
100
+ ): TableColumnVariant[] {
101
101
  const columnIdToAnchorName = new Map<PObjectId, string>(
102
102
  Array.from(anchors.entries(), ([key, { id }]) => [id, key] as const),
103
103
  );
104
104
 
105
- return matched.flatMap((match) => {
106
- const snap = match.column;
107
- const isPrimary = columnIdToAnchorName.get(match.column.id) !== undefined;
105
+ return variants.map((variant): TableColumnVariant => {
106
+ const snap = variant.column;
107
+ const isPrimary = columnIdToAnchorName.get(snap.id) !== undefined;
108
108
 
109
- return match.variants.map((variant): TableColumnSnapshot => {
110
- const discoveredId = createDiscoveredPColumnId({
111
- column: snap.id,
112
- path: variant.path.map((p) => ({
113
- type: "linker",
114
- column: p.linker.id,
115
- qualifications: p.qualifications,
116
- })),
117
- columnQualifications: variant.qualifications.forHit,
118
- queriesQualifications: variant.qualifications.forQueries,
119
- });
120
- return {
109
+ const discoveredId = createDiscoveredPColumnId({
110
+ column: snap.id,
111
+ path: variant.path.map((p) => ({
112
+ type: "linker",
113
+ column: p.linker.id,
114
+ qualifications: p.qualifications,
115
+ })),
116
+ columnQualifications: variant.qualifications.forHit,
117
+ queriesQualifications: variant.qualifications.forQueries,
118
+ });
119
+ return {
120
+ column: {
121
121
  id: discoveredId,
122
- isPrimary,
123
-
124
- originalId: snap.id,
125
122
  spec: snap.spec,
126
123
  data: snap.data,
127
124
  dataStatus: snap.dataStatus,
128
-
129
- linkerPath: variant.path,
130
- qualifications: variant.qualifications,
131
- distinctiveQualifications: variant.distinctiveQualifications,
132
- };
133
- });
125
+ },
126
+ path: variant.path,
127
+ qualifications: variant.qualifications,
128
+ originalId: snap.id,
129
+ isPrimary,
130
+ };
134
131
  });
135
132
  }
@@ -239,7 +239,7 @@ describe("deriveAxisLabels via deriveAllLabels", () => {
239
239
  makeLabelableColumn(
240
240
  "c1",
241
241
  { name: "shared", annotations: { [Annotation.Label]: "Cluster size" } },
242
- [{ spec: linkerSpec }],
242
+ [{ linker: { id: "lk" as PObjectId, spec: linkerSpec } as never, qualifications: [] }],
243
243
  ),
244
244
  makeLabelableColumn("c2", {
245
245
  name: "shared",
@@ -229,7 +229,8 @@ export function withHidenAxesAnnotations<T extends { readonly spec: PColumnSpec
229
229
  export type LabelableColumn = {
230
230
  readonly id: PObjectId;
231
231
  readonly spec: PColumnSpec;
232
- readonly linkerPath?: { spec: PColumnSpec }[];
232
+ readonly linkerPath?: MatchVariant["path"];
233
+ readonly qualifications?: MatchQualifications;
233
234
  };
234
235
 
235
236
  /** Derive labels for all table elements: columns via deriveDistinctLabels, axes from label columns. */
@@ -240,7 +241,15 @@ export function deriveAllLabels(options: {
240
241
  }): Record<string, string> {
241
242
  const { columns, labelColumns, deriveLabelsOptions } = options;
242
243
  const axisLabels = deriveAxisLabels(columns, labelColumns);
243
- const columnLabels = deriveDistinctLabels(columns, deriveLabelsOptions).reduce(
244
+ const entries = columns.map((c) => ({
245
+ spec: c.spec,
246
+ linkerPath: c.linkerPath?.map((step) => ({
247
+ spec: step.linker.spec,
248
+ qualifications: step.qualifications,
249
+ })),
250
+ qualifications: c.qualifications,
251
+ }));
252
+ const columnLabels = deriveDistinctLabels(entries, deriveLabelsOptions).reduce(
244
253
  (acc, label, index) => ((acc[columns[index].id] = label), acc),
245
254
  {} as Record<string, string>,
246
255
  );
@@ -273,7 +282,6 @@ export type TooltipableColumn = {
273
282
  readonly originalId: PObjectId;
274
283
  readonly linkerPath?: MatchVariant["path"];
275
284
  readonly qualifications?: MatchQualifications;
276
- readonly distinctiveQualifications?: MatchQualifications;
277
285
  };
278
286
 
279
287
  /** Derive origin tooltips for columns whose qualifications or linker path carry info. */
@@ -297,7 +305,6 @@ export function deriveAllTooltips(options: {
297
305
  spec: c.spec,
298
306
  linkerPath: c.linkerPath,
299
307
  qualifications: c.qualifications,
300
- distinctiveQualifications: c.distinctiveQualifications,
301
308
  variantIndex,
302
309
  variantCount,
303
310
  });