@milaboratories/pl-model-common 1.24.1 → 1.24.2

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.
@@ -0,0 +1,791 @@
1
+ import type { PObjectId } from '../../../pool';
2
+ import type { JsonDataInfo } from '../data_info';
3
+ import type { AxisValueType, ColumnValueType } from '../spec';
4
+ /**
5
+ * Specification of column/frame structure.
6
+ *
7
+ * Defines the shape of data: which axes (dimensions) the data has
8
+ * and what value types are stored in columns.
9
+ */
10
+ export type TypeSpec = {
11
+ /** List of axis value types defining the dimensions of the data */
12
+ axes: AxisValueType[];
13
+ /** List of column value types defining the data stored */
14
+ columns: ColumnValueType[];
15
+ };
16
+ /**
17
+ * Unary mathematical operation kinds.
18
+ *
19
+ * These operations take a single numeric input and produce a numeric output.
20
+ * **Null handling**: If input is null, result is null.
21
+ *
22
+ * Operations:
23
+ * - `abs` - Absolute value: |x|
24
+ * - `ceil` - Round up to nearest integer
25
+ * - `floor` - Round down to nearest integer
26
+ * - `round` - Round to nearest integer (banker's rounding)
27
+ * - `sqrt` - Square root (returns NaN for negative inputs)
28
+ * - `log` - Natural logarithm (ln)
29
+ * - `log2` - Base-2 logarithm
30
+ * - `log10` - Base-10 logarithm
31
+ * - `exp` - Exponential function (e^x)
32
+ * - `negate` - Negation (-x)
33
+ */
34
+ export type NumericUnaryOperand = 'abs' | 'ceil' | 'floor' | 'round' | 'sqrt' | 'log' | 'log2' | 'log10' | 'exp' | 'negate';
35
+ /**
36
+ * Binary mathematical operation kinds.
37
+ *
38
+ * These operations take two numeric inputs and produce a numeric result.
39
+ * **Null handling**: If either operand is null, result is null.
40
+ *
41
+ * Operations:
42
+ * - `add` - Addition: left + right
43
+ * - `sub` - Subtraction: left - right
44
+ * - `mul` - Multiplication: left * right
45
+ * - `div` - Division: left / right (division by zero returns Infinity or NaN)
46
+ * - `mod` - Modulo: left % right
47
+ */
48
+ export type NumericBinaryOperand = 'add' | 'sub' | 'mul' | 'div' | 'mod';
49
+ /**
50
+ * Numeric comparison operation kinds.
51
+ *
52
+ * These operations compare two numeric inputs and produce a boolean result.
53
+ * **Null handling**: If either operand is null, result is null.
54
+ *
55
+ * Operations:
56
+ * - `eq` - Equal: left == right
57
+ * - `ne` - Not equal: left != right
58
+ * - `lt` - Less than: left < right
59
+ * - `le` - Less or equal: left <= right
60
+ * - `gt` - Greater than: left > right
61
+ * - `ge` - Greater or equal: left >= right
62
+ */
63
+ export type NumericComparisonOperand = 'eq' | 'ne' | 'lt' | 'le' | 'gt' | 'ge';
64
+ /**
65
+ * 2D point coordinates.
66
+ *
67
+ * Used for geometric operations like point-in-polygon tests.
68
+ * Common use case: flow cytometry gating where points are tested
69
+ * against user-defined polygon regions.
70
+ */
71
+ export type Point2D = {
72
+ x: number;
73
+ y: number;
74
+ };
75
+ /**
76
+ * Constant value expression.
77
+ *
78
+ * Represents a literal constant value in an expression tree.
79
+ * The value can be a string, number, or boolean.
80
+ *
81
+ * @example
82
+ * // Constant number
83
+ * { type: 'constant', value: 42 }
84
+ *
85
+ * // Constant string
86
+ * { type: 'constant', value: 'hello' }
87
+ *
88
+ * // Constant boolean
89
+ * { type: 'constant', value: true }
90
+ */
91
+ export type ExprConstant = {
92
+ type: 'constant';
93
+ value: string | number | boolean;
94
+ };
95
+ /**
96
+ * Unary mathematical expression.
97
+ *
98
+ * Applies a unary mathematical function to a single input expression.
99
+ * **Input**: One expression that evaluates to a numeric value.
100
+ * **Output**: Numeric value.
101
+ * **Null handling**: If input is null, result is null.
102
+ *
103
+ * @template I - The expression type (for recursion)
104
+ *
105
+ * @example
106
+ * // Absolute value of column "value"
107
+ * { type: 'unaryMath', operand: 'abs', input: columnRef }
108
+ *
109
+ * // Natural log of expression
110
+ * { type: 'unaryMath', operand: 'log', input: someExpr }
111
+ *
112
+ * @see NumericUnaryOperand for available operations
113
+ */
114
+ export interface ExprNumericUnary<I> {
115
+ type: 'numericUnary';
116
+ /** The mathematical operation to apply */
117
+ operand: NumericUnaryOperand;
118
+ /** Input expression (must evaluate to numeric) */
119
+ input: I;
120
+ }
121
+ /**
122
+ * Binary mathematical expression.
123
+ *
124
+ * Applies a binary arithmetic operation to two input expressions.
125
+ * **Input**: Two expressions that evaluate to numeric values.
126
+ * **Output**: Numeric value.
127
+ * **Null handling**: If either operand is null, result is null.
128
+ *
129
+ * @template I - The expression type (for recursion)
130
+ *
131
+ * @example
132
+ * // Addition: col_a + col_b
133
+ * { type: 'binaryMath', operand: 'add', left: colA, right: colB }
134
+ *
135
+ * // Division: col_a / 2
136
+ * { type: 'binaryMath', operand: 'div', left: colA, right: { type: 'constant', value: 2 } }
137
+ *
138
+ * @see NumericBinaryOperand for available operations
139
+ */
140
+ export interface ExprNumericBinary<I> {
141
+ type: 'numericBinary';
142
+ /** The arithmetic operation to apply */
143
+ operand: NumericBinaryOperand;
144
+ /** Left operand expression */
145
+ left: I;
146
+ /** Right operand expression */
147
+ right: I;
148
+ }
149
+ /**
150
+ * Numeric comparison expression.
151
+ *
152
+ * Compares two numeric expressions and produces a boolean result.
153
+ * **Input**: Two expressions that evaluate to numeric values.
154
+ * **Output**: Boolean.
155
+ * **Null handling**: If either operand is null, result is null.
156
+ *
157
+ * @template I - The expression type (for recursion)
158
+ *
159
+ * @example
160
+ * // Greater than: col_a > 10
161
+ * { type: 'numericComparison', operand: 'gt', left: colA, right: { type: 'constant', value: 10 } }
162
+ *
163
+ * // Equality: col_a == col_b
164
+ * { type: 'numericComparison', operand: 'eq', left: colA, right: colB }
165
+ *
166
+ * // Range check (combine with logical AND): 0 <= x && x < 100
167
+ * // { type: 'logical', operand: 'and', input: [
168
+ * // { type: 'numericComparison', operand: 'ge', left: colX, right: { type: 'constant', value: 0 } },
169
+ * // { type: 'numericComparison', operand: 'lt', left: colX, right: { type: 'constant', value: 100 } }
170
+ * // ]}
171
+ *
172
+ * @see NumericComparisonOperand for available operations
173
+ */
174
+ export interface ExprNumericComparison<I> {
175
+ type: 'numericComparison';
176
+ /** The comparison operation to apply */
177
+ operand: NumericComparisonOperand;
178
+ /** Left operand expression */
179
+ left: I;
180
+ /** Right operand expression */
181
+ right: I;
182
+ }
183
+ /**
184
+ * String equality check.
185
+ *
186
+ * Compares input string to a reference value.
187
+ * **Input**: Expression evaluating to a string.
188
+ * **Output**: Boolean.
189
+ * **Null handling**: Returns false if input is null.
190
+ *
191
+ * @template I - The expression type (for recursion)
192
+ *
193
+ * @example
194
+ * // Check if name equals "John" (case-sensitive)
195
+ * // Matches only: "John"
196
+ * { type: 'stringEquals', input: nameColumn, value: 'John' }
197
+ *
198
+ * @example
199
+ * // Check if name equals "John" (case-insensitive)
200
+ * // Matches: "john", "JOHN", "John", "jOhN"
201
+ * { type: 'stringEquals', input: nameColumn, value: 'John', caseInsensitive: true }
202
+ */
203
+ export interface ExprStringEquals<I> {
204
+ type: 'stringEquals';
205
+ /** Input expression (must evaluate to string) */
206
+ input: I;
207
+ /** Reference string to compare against */
208
+ value: string;
209
+ /** If true, comparison ignores case */
210
+ caseInsensitive: boolean;
211
+ }
212
+ /**
213
+ * Regular expression match check.
214
+ *
215
+ * Tests if input string matches a regular expression pattern.
216
+ * **Input**: Expression evaluating to a string.
217
+ * **Output**: Boolean (true if pattern matches).
218
+ * **Null handling**: Returns false if input is null.
219
+ *
220
+ * @template I - The expression type (for recursion)
221
+ *
222
+ * @example
223
+ * // Check if value matches email pattern
224
+ * { type: 'stringRegex', input: emailColumn, value: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$' }
225
+ *
226
+ * // Check if starts with "prefix"
227
+ * { type: 'stringRegex', input: valueColumn, value: '^prefix' }
228
+ *
229
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions | MDN Regular Expressions Guide}
230
+ */
231
+ export interface ExprStringRegex<I> {
232
+ type: 'stringRegex';
233
+ /** Input expression (must evaluate to string) */
234
+ input: I;
235
+ /** Regular expression pattern */
236
+ value: string;
237
+ }
238
+ /**
239
+ * Substring containment check.
240
+ *
241
+ * Tests if input string contains a specified substring.
242
+ * **Input**: Expression evaluating to a string.
243
+ * **Output**: Boolean (true if substring is found).
244
+ * **Null handling**: Returns false if input is null.
245
+ *
246
+ * @template I - The expression type (for recursion)
247
+ *
248
+ * @example
249
+ * // Case-sensitive contains
250
+ * { type: 'stringContains', input: descColumn, value: 'error', caseInsensitive: false }
251
+ *
252
+ * // Case-insensitive contains
253
+ * { type: 'stringContains', input: descColumn, value: 'ERROR', caseInsensitive: true }
254
+ */
255
+ export interface ExprStringContains<I> {
256
+ type: 'stringContains';
257
+ /** Input expression (must evaluate to string) */
258
+ input: I;
259
+ /** Substring to search for */
260
+ value: string;
261
+ /** If true, comparison ignores case */
262
+ caseInsensitive: boolean;
263
+ }
264
+ /**
265
+ * Fuzzy string containment check with edit distance.
266
+ *
267
+ * Tests if input string approximately matches a pattern within a specified edit distance.
268
+ * Uses Levenshtein distance (or substitution-only distance) for fuzzy matching.
269
+ * **Input**: Expression evaluating to a string.
270
+ * **Output**: Boolean (true if approximate match found within maxEdits).
271
+ * **Null handling**: Returns false if input is null.
272
+ *
273
+ * @template I - The expression type (for recursion)
274
+ *
275
+ * @example
276
+ * // Match "color" with up to 1 edit (catches "colour", "colr", etc.)
277
+ * {
278
+ * type: 'stringContainsFuzzy',
279
+ * input: textColumn,
280
+ * value: 'color',
281
+ * maxEdits: 1,
282
+ * caseInsensitive: true,
283
+ * substitutionsOnly: false,
284
+ * wildcard: null
285
+ * }
286
+ *
287
+ * // Match with wildcard (? matches any single character)
288
+ * {
289
+ * type: 'stringContainsFuzzy',
290
+ * input: textColumn,
291
+ * value: 'te?t',
292
+ * maxEdits: 0,
293
+ * caseInsensitive: false,
294
+ * substitutionsOnly: false,
295
+ * wildcard: '?'
296
+ * }
297
+ */
298
+ export interface ExprStringContainsFuzzy<I> {
299
+ type: 'stringContainsFuzzy';
300
+ /** Input expression (must evaluate to string) */
301
+ input: I;
302
+ /** Pattern to match against */
303
+ value: string;
304
+ /**
305
+ * Maximum edit distance (Levenshtein distance).
306
+ * 0 = exact match only, 1 = one edit allowed, etc.
307
+ */
308
+ maxEdits: number;
309
+ /** If true, comparison ignores case */
310
+ caseInsensitive: boolean;
311
+ /**
312
+ * If true, only substitutions count as edits (no insertions/deletions).
313
+ * Useful when you want to match strings of same length with typos.
314
+ */
315
+ substitutionsOnly: boolean;
316
+ /**
317
+ * Optional wildcard character that matches any single character.
318
+ * Example: '?' in "te?t" matches "test", "text", "tent", etc.
319
+ * Set to null to disable wildcard matching.
320
+ */
321
+ wildcard: null | string;
322
+ }
323
+ /**
324
+ * Logical NOT expression.
325
+ *
326
+ * Negates a boolean expression.
327
+ * **Input**: Expression evaluating to boolean.
328
+ * **Output**: Boolean (inverted).
329
+ * **Null handling**: NOT null = null.
330
+ *
331
+ * @template I - The expression type (for recursion)
332
+ *
333
+ * @example
334
+ * // NOT (value > 10)
335
+ * { type: 'not', input: comparisonExpr }
336
+ */
337
+ export interface ExprLogicalUnary<I> {
338
+ type: 'not';
339
+ /** Input boolean expression to negate */
340
+ input: I;
341
+ }
342
+ /**
343
+ * Logical AND/OR expression.
344
+ *
345
+ * Combines multiple boolean expressions using AND or OR logic.
346
+ * **Input**: Array of expressions evaluating to boolean (minimum 2).
347
+ * **Output**: Boolean.
348
+ *
349
+ * **Null handling**
350
+ * - AND: null AND true = null, null AND false = false
351
+ * - OR: null OR true = true, null OR false = null
352
+ *
353
+ * @template I - The expression type (for recursion)
354
+ *
355
+ * @example
356
+ * // (a > 0) AND (b < 100)
357
+ * { type: 'and', input: [exprA, exprB] }
358
+ *
359
+ * // (status == 'active') OR (status == 'pending')
360
+ * { type: 'or', input: [statusActive, statusPending] }
361
+ */
362
+ export interface ExprLogicalVariadic<I> {
363
+ /** Logical operation: 'and' or 'or' */
364
+ type: 'and' | 'or';
365
+ /** Array of boolean expressions to combine (minimum 2 elements) */
366
+ input: I[];
367
+ }
368
+ /**
369
+ * Set membership check expression.
370
+ *
371
+ * Tests if a value is present in a predefined set of values.
372
+ * **Input**: Expression evaluating to string or number.
373
+ * **Output**: Boolean.
374
+ * **Null handling**: Returns false if input is null.
375
+ *
376
+ * @template I - The expression type (for recursion)
377
+ * @template T - The type of set elements (string or number)
378
+ *
379
+ * @example
380
+ * // Check if status is in ['active', 'pending', 'review']
381
+ * {
382
+ * type: 'isIn',
383
+ * input: statusColumn,
384
+ * set: ['active', 'pending', 'review']
385
+ * }
386
+ */
387
+ export interface ExprIsIn<I, T extends string | number> {
388
+ type: 'isIn';
389
+ /** Input expression to test */
390
+ input: I;
391
+ /** Set of allowed values */
392
+ set: T[];
393
+ }
394
+ /**
395
+ * Axis reference expression.
396
+ *
397
+ * References an axis value for use in expressions (filtering, sorting, etc.).
398
+ * The axis identifier type varies by context (spec vs data layer).
399
+ *
400
+ * @template A - Axis identifier type (e.g., SingleAxisSelector for spec, number for data)
401
+ *
402
+ * @example
403
+ * // Reference axis by selector (spec layer)
404
+ * { type: 'axisRef', value: { name: 'sample' } }
405
+ *
406
+ * // Reference axis by index (data layer)
407
+ * { type: 'axisRef', value: 0 }
408
+ */
409
+ export interface ExprAxisRef<A> {
410
+ type: 'axisRef';
411
+ /** Axis identifier (selector or index depending on context) */
412
+ value: A;
413
+ }
414
+ /**
415
+ * Column reference expression.
416
+ *
417
+ * References a column value for use in expressions (filtering, arithmetic, etc.).
418
+ * The column identifier type varies by context (spec vs data layer).
419
+ *
420
+ * @template C - Column identifier type (e.g., PObjectId for spec, number for data)
421
+ *
422
+ * @example
423
+ * // Reference column by ID (spec layer)
424
+ * { type: 'columnRef', value: 'col_abc123' }
425
+ *
426
+ * // Reference column by index (data layer)
427
+ * { type: 'columnRef', value: 0 }
428
+ */
429
+ export interface ExprColumnRef<C> {
430
+ type: 'columnRef';
431
+ /** Column identifier (ID or index depending on context) */
432
+ value: C;
433
+ }
434
+ export type InferBooleanExpressionUnion<E> = [
435
+ E extends ExprNumericComparison<unknown> ? Extract<E, {
436
+ type: 'numericComparison';
437
+ }> : never,
438
+ E extends ExprStringEquals<unknown> ? Extract<E, {
439
+ type: 'stringEquals';
440
+ }> : never,
441
+ E extends ExprStringContains<unknown> ? Extract<E, {
442
+ type: 'stringContains';
443
+ }> : never,
444
+ E extends ExprStringContainsFuzzy<unknown> ? Extract<E, {
445
+ type: 'stringContainsFuzzy';
446
+ }> : never,
447
+ E extends ExprStringRegex<unknown> ? Extract<E, {
448
+ type: 'stringRegex';
449
+ }> : never,
450
+ E extends ExprLogicalUnary<unknown> ? Extract<E, {
451
+ type: 'not';
452
+ }> : never,
453
+ E extends ExprLogicalVariadic<unknown> ? Extract<E, {
454
+ type: 'and' | 'or';
455
+ }> : never,
456
+ E extends ExprIsIn<unknown, string | number> ? Extract<E, {
457
+ type: 'isIn';
458
+ }> : never
459
+ ][number];
460
+ /**
461
+ * Selector for referencing an axis in queries.
462
+ *
463
+ * Used to identify a specific axis dimension in operations like:
464
+ * - Sorting by axis values
465
+ * - Partitioning for window functions
466
+ * - Filtering/slicing axes
467
+ *
468
+ * @template A - Axis identifier type (typically string name or numeric index)
469
+ *
470
+ * @example
471
+ * // Select axis by name
472
+ * { type: 'axis', id: 'sample' }
473
+ *
474
+ * // Select axis by index
475
+ * { type: 'axis', id: 0 }
476
+ */
477
+ export interface QueryAxisSelector<A> {
478
+ type: 'axis';
479
+ /** Axis identifier (name or index depending on context) */
480
+ id: A;
481
+ }
482
+ /**
483
+ * Selector for referencing a column in queries.
484
+ *
485
+ * Used to identify a specific column in operations like:
486
+ * - Sorting by column values
487
+ * - Partitioning for window functions
488
+ * - Aggregation expressions
489
+ *
490
+ * @template C - Column identifier type (typically string name or numeric index)
491
+ *
492
+ * @example
493
+ * // Select column by name
494
+ * { type: 'column', id: 'expression_value' }
495
+ *
496
+ * // Select column by index
497
+ * { type: 'column', id: 0 }
498
+ */
499
+ export interface QueryColumnSelector<C> {
500
+ type: 'column';
501
+ /** Column identifier (name or index depending on context) */
502
+ id: C;
503
+ }
504
+ /**
505
+ * Left outer join query operation.
506
+ *
507
+ * Joins a primary query with one or more secondary queries using left outer join semantics.
508
+ * All records from the primary are preserved; matching records from secondaries are joined,
509
+ * non-matching positions are filled with nulls.
510
+ *
511
+ * **Join behavior**:
512
+ * - All records from `primary` are preserved
513
+ * - For each secondary, matching records (by axis keys) are joined
514
+ * - Missing matches from secondaries are filled with null values
515
+ * - Empty `secondary` array acts as identity (returns primary unchanged)
516
+ *
517
+ * **Null handling**: Null join keys don't match; positions without matches get null values.
518
+ *
519
+ * @template JE - Join entry type
520
+ *
521
+ * @example
522
+ * // Left join samples with optional annotations
523
+ * {
524
+ * type: 'outerJoin',
525
+ * primary: samplesQuery,
526
+ * secondary: [annotationsQuery, metadataQuery]
527
+ * }
528
+ * // Result has all samples; annotations/metadata are null where not available
529
+ */
530
+ export interface QueryOuterJoin<JE extends QueryJoinEntry<unknown>> {
531
+ type: 'outerJoin';
532
+ /** Primary query - all its records are preserved */
533
+ primary: JE;
534
+ /** Secondary queries - joined where keys match, null where they don't */
535
+ secondary: JE[];
536
+ }
537
+ /**
538
+ * Axis slicing query operation.
539
+ *
540
+ * Filters data by fixing one or more axes to specific constant values.
541
+ * Each filtered axis is removed from the resulting data shape (reduces dimensionality).
542
+ *
543
+ * **Behavior**:
544
+ * - Each axis filter selects records where that axis equals the constant
545
+ * - Filtered axes are removed from the output spec
546
+ * - Multiple filters apply conjunctively (AND)
547
+ *
548
+ * @template Q - Input query type
549
+ * @template A - Axis selector type
550
+ *
551
+ * @example
552
+ * // Slice 3D data [sample, gene, condition] to 1D [gene]
553
+ * {
554
+ * type: 'sliceAxes',
555
+ * input: fullDataQuery,
556
+ * axisFilters: [
557
+ * { type: 'constant', axisSelector: { type: 'axis', id: 'sample' }, constant: 'Sample1' },
558
+ * { type: 'constant', axisSelector: { type: 'axis', id: 'condition' }, constant: 'Treatment' }
559
+ * ]
560
+ * }
561
+ */
562
+ export interface QuerySliceAxes<Q, A extends QueryAxisSelector<unknown>> {
563
+ type: 'sliceAxes';
564
+ /** Input query to slice */
565
+ input: Q;
566
+ /** List of axis filters to apply (at least one required) */
567
+ axisFilters: {
568
+ /** Selector identifying which axis to filter */
569
+ axisSelector: A;
570
+ /** The constant value to filter the axis to */
571
+ constant: string | number;
572
+ }[];
573
+ }
574
+ /**
575
+ * Sort query operation.
576
+ *
577
+ * Reorders records by one or more axes or columns.
578
+ * Does not change data shape or values, only record order.
579
+ *
580
+ * **Behavior**:
581
+ * - Sort entries are applied in priority order (first entry = primary sort key)
582
+ * - Ties in first sort key are broken by second, etc.
583
+ * - All axes and columns pass through unchanged
584
+ * - Only the physical ordering of records changes
585
+ *
586
+ * @template Q - Input query type
587
+ * @template SE - Sort entry type
588
+ *
589
+ * @example
590
+ * // Sort by score descending, then by name ascending for ties
591
+ * {
592
+ * type: 'sort',
593
+ * input: dataQuery,
594
+ * sortBy: [
595
+ * { axisOrColumn: { type: 'column', id: 'score' }, ascending: false, nullsFirst: null },
596
+ * { axisOrColumn: { type: 'axis', id: 'name' }, ascending: true, nullsFirst: null }
597
+ * ]
598
+ * }
599
+ */
600
+ export interface QuerySort<Q, E> {
601
+ type: 'sort';
602
+ /** Input query to sort */
603
+ input: Q;
604
+ /** Sort criteria in priority order (at least one required) */
605
+ sortBy: {
606
+ data: E;
607
+ /** If true, sort ascending (A-Z, 0-9); if false, descending */
608
+ ascending: boolean;
609
+ /**
610
+ * Null placement control:
611
+ * - true: nulls sort before non-null values
612
+ * - false: nulls sort after non-null values
613
+ * - null: use default behavior (typically nulls last)
614
+ */
615
+ nullsFirst: null | boolean;
616
+ }[];
617
+ }
618
+ /**
619
+ * Filter query operation.
620
+ *
621
+ * Filters records based on a boolean predicate expression.
622
+ * Only records where predicate evaluates to true are kept.
623
+ *
624
+ * **Behavior**:
625
+ * - Evaluates predicate for each record
626
+ * - Keeps records where predicate is true
627
+ * - Discards records where predicate is false or null
628
+ * - Data shape (axes, columns) is preserved
629
+ *
630
+ * **Null handling**: Records with null predicate result are excluded (null ≠ true).
631
+ *
632
+ * @template Q - Input query type
633
+ * @template E - Expression type
634
+ *
635
+ * @example
636
+ * // Filter to records where value > 10 AND status == 'active'
637
+ * {
638
+ * type: 'filter',
639
+ * input: dataQuery,
640
+ * predicate: {
641
+ * type: 'logical',
642
+ * operand: 'and',
643
+ * input: [
644
+ * { type: 'numericComparison', operand: 'gt', left: valueRef, right: { type: 'constant', value: 10 } },
645
+ * { type: 'stringEquals', input: statusRef, value: 'active' }
646
+ * ]
647
+ * }
648
+ * }
649
+ */
650
+ export interface QueryFilter<Q, E> {
651
+ type: 'filter';
652
+ /** Input query to filter */
653
+ input: Q;
654
+ /** Boolean predicate expression - only true records pass */
655
+ predicate: E;
656
+ }
657
+ /**
658
+ * Column reference query (leaf node).
659
+ *
660
+ * References an existing column by its unique identifier.
661
+ * This is a leaf node in the query tree that retrieves actual data.
662
+ *
663
+ * The column must exist in the dataset and its spec (axes, value type)
664
+ * becomes the output spec of this query node.
665
+ *
666
+ * @example
667
+ * // Reference column by ID
668
+ * { type: 'column', columnId: 'col_abc123' }
669
+ */
670
+ export interface QueryColumn {
671
+ type: 'column';
672
+ /** Unique identifier of the column to reference */
673
+ columnId: PObjectId;
674
+ }
675
+ /**
676
+ * Inline column query (leaf node).
677
+ *
678
+ * Creates a column with inline/embedded data and type specification.
679
+ * Useful for creating constant columns or injecting computed data.
680
+ *
681
+ * The data is provided via dataInfo which contains the actual values
682
+ * or reference to where data is stored.
683
+ *
684
+ * @template T - Type spec type
685
+ *
686
+ * @example
687
+ * // Create inline column with constant values
688
+ * {
689
+ * type: 'inlineColumn',
690
+ * spec: { axes: ['sample'], columns: ['Int'] },
691
+ * dataInfo: { ... } // JsonDataInfo object
692
+ * }
693
+ */
694
+ export interface QueryInlineColumn<T> {
695
+ type: 'inlineColumn';
696
+ /** Type specification defining axes and column types */
697
+ spec: T;
698
+ /** Data information containing or referencing the actual values */
699
+ dataInfo: JsonDataInfo;
700
+ }
701
+ /**
702
+ * Sparse to dense column query operation.
703
+ *
704
+ * Expands a column across additional axes using Cartesian product.
705
+ * Creates all combinations of existing axis values with new axis values.
706
+ *
707
+ * **Use case**: When you need to repeat/broadcast a column across
708
+ * new dimensions that it doesn't originally have.
709
+ *
710
+ * **Behavior**:
711
+ * - Takes an existing column
712
+ * - Expands it across specified axes indices
713
+ * - Result has Cartesian product of original axes × new axes
714
+ *
715
+ * @template SO - Spec override type
716
+ *
717
+ * @example
718
+ * // Expand column across axes at indices 0 and 2
719
+ * {
720
+ * type: 'sparseToDenseColumn',
721
+ * columnId: 'col_abc123',
722
+ * axesIndices: [0, 2],
723
+ * specOverride: { ... } // optional spec modifications
724
+ * }
725
+ */
726
+ export interface QuerySparseToDenseColumn<SO> {
727
+ type: 'sparseToDenseColumn';
728
+ /** ID of the column to cross-join */
729
+ columnId: PObjectId;
730
+ /** Optional override for the column specification */
731
+ specOverride?: SO;
732
+ /** Indices of axes to expand across */
733
+ axesIndices: number[];
734
+ }
735
+ /**
736
+ * Symmetric join query operation (inner join or full outer join).
737
+ *
738
+ * Joins multiple queries symmetrically (order doesn't affect result semantics).
739
+ *
740
+ * **Inner Join** (`type: 'innerJoin'`):
741
+ * - Returns only records that exist in ALL entries
742
+ * - Null join keys don't match, so records with null keys are excluded
743
+ * - Result contains intersection of all entries by axis keys
744
+ *
745
+ * **Full Join** (`type: 'fullJoin'`):
746
+ * - Returns all records from ALL entries
747
+ * - Missing values are filled with nulls
748
+ * - Null join keys create separate groups
749
+ * - Result contains union of all entries by axis keys
750
+ *
751
+ * **Single entry**: Acts as identity (returns entry unchanged).
752
+ *
753
+ * @template JE - Join entry type
754
+ *
755
+ * @example
756
+ * // Inner join: only records present in all queries
757
+ * {
758
+ * type: 'innerJoin',
759
+ * entries: [query1Entry, query2Entry, query3Entry]
760
+ * }
761
+ *
762
+ * // Full join: all records from all queries, nulls for missing
763
+ * {
764
+ * type: 'fullJoin',
765
+ * entries: [query1Entry, query2Entry]
766
+ * }
767
+ */
768
+ export interface QuerySymmetricJoin<JE extends QueryJoinEntry<unknown>> {
769
+ /** 'innerJoin' for intersection, 'fullJoin' for union with nulls */
770
+ type: 'innerJoin' | 'fullJoin';
771
+ /** Queries to join (at least one required) */
772
+ entries: JE[];
773
+ }
774
+ /**
775
+ * Join entry wrapper.
776
+ *
777
+ * Wraps a query to be used as an entry in join operations.
778
+ * The wrapper allows for additional metadata or configuration
779
+ * on each joined query (e.g., specifying join keys, aliases).
780
+ *
781
+ * @template Q - Query type
782
+ *
783
+ * @example
784
+ * // Wrap a query for use in join
785
+ * { entry: someQuery }
786
+ */
787
+ export interface QueryJoinEntry<Q> {
788
+ /** The query to be joined */
789
+ entry: Q;
790
+ }
791
+ //# sourceMappingURL=query_common.d.ts.map