pond-ts 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +104 -1
  2. package/dist/batch/aggregate-columns.d.ts +29 -0
  3. package/dist/batch/aggregate-columns.d.ts.map +1 -1
  4. package/dist/batch/aggregate-columns.js +63 -0
  5. package/dist/batch/aggregate-columns.js.map +1 -1
  6. package/dist/batch/operators/collapse.d.ts +42 -0
  7. package/dist/batch/operators/collapse.d.ts.map +1 -0
  8. package/dist/batch/operators/collapse.js +83 -0
  9. package/dist/batch/operators/collapse.js.map +1 -0
  10. package/dist/batch/operators/cumulative.d.ts +40 -0
  11. package/dist/batch/operators/cumulative.d.ts.map +1 -0
  12. package/dist/batch/operators/cumulative.js +74 -0
  13. package/dist/batch/operators/cumulative.js.map +1 -0
  14. package/dist/batch/operators/diff-rate.d.ts +52 -0
  15. package/dist/batch/operators/diff-rate.d.ts.map +1 -0
  16. package/dist/batch/operators/diff-rate.js +99 -0
  17. package/dist/batch/operators/diff-rate.js.map +1 -0
  18. package/dist/batch/operators/fill.d.ts +66 -0
  19. package/dist/batch/operators/fill.d.ts.map +1 -0
  20. package/dist/batch/operators/fill.js +219 -0
  21. package/dist/batch/operators/fill.js.map +1 -0
  22. package/dist/batch/operators/map.d.ts +56 -0
  23. package/dist/batch/operators/map.d.ts.map +1 -0
  24. package/dist/batch/operators/map.js +109 -0
  25. package/dist/batch/operators/map.js.map +1 -0
  26. package/dist/batch/operators/shift.d.ts +31 -0
  27. package/dist/batch/operators/shift.d.ts.map +1 -0
  28. package/dist/batch/operators/shift.js +56 -0
  29. package/dist/batch/operators/shift.js.map +1 -0
  30. package/dist/batch/time-series.d.ts +36 -5
  31. package/dist/batch/time-series.d.ts.map +1 -1
  32. package/dist/batch/time-series.js +244 -387
  33. package/dist/batch/time-series.js.map +1 -1
  34. package/dist/columnar/index.d.ts +1 -1
  35. package/dist/columnar/index.d.ts.map +1 -1
  36. package/dist/columnar/index.js +1 -1
  37. package/dist/columnar/index.js.map +1 -1
  38. package/dist/columnar/view.d.ts +57 -1
  39. package/dist/columnar/view.d.ts.map +1 -1
  40. package/dist/columnar/view.js +88 -0
  41. package/dist/columnar/view.js.map +1 -1
  42. package/dist/reducers/stdev.d.ts.map +1 -1
  43. package/dist/reducers/stdev.js +81 -59
  44. package/dist/reducers/stdev.js.map +1 -1
  45. package/package.json +1 -1
@@ -0,0 +1,99 @@
1
+ import { float64ColumnFromArray, withColumnReplaced, withRowRange, } from '../../columnar/index.js';
2
+ /**
3
+ * **Step 4 — column-native `diff` / `rate` / `pctChange` (extracted
4
+ * operator).** Successive differences per target column, computed
5
+ * straight off the columnar store: read each target's cells
6
+ * (storage-agnostic `read(i)`), fold the per-row difference, replace
7
+ * the column — no `series.events` materialization, no per-row
8
+ * `Event`. Non-target columns + the key axis pass through untouched
9
+ * (`withColumnReplaced` references the unchanged columns + keys
10
+ * zero-copy).
11
+ *
12
+ * Matches the row path's semantics exactly:
13
+ * - Row 0 has no predecessor, so each target is `undefined` there.
14
+ * - Row `i ≥ 1`: with both `prev` and `curr` defined numbers,
15
+ * `delta = curr - prev`; `diff` emits `delta`, `rate` emits
16
+ * `delta / dt` (`dt` = `(begin[i] − begin[i−1]) / 1000` seconds,
17
+ * `undefined` when `dt === 0`), `pctChange` emits `delta / prev`
18
+ * (`undefined` when `prev === 0`). If either side is missing /
19
+ * non-numeric, the output is `undefined`. A stored `NaN` is a
20
+ * defined number (`typeof raw === 'number'`), so it participates.
21
+ *
22
+ * **`drop`.** `drop: false` (default) keeps the predecessor-less
23
+ * first row (its targets `undefined`, its other columns + key
24
+ * intact). `drop: true` removes that row entirely — every column
25
+ * **and** the key slice to `[1, n)` via `withRowRange`, the row-range
26
+ * substrate built for exactly this. The full-length result is built
27
+ * first (the `drop: false` shape); `drop: true` just appends the
28
+ * trailing one-row slice, so the two paths share all the fold logic.
29
+ *
30
+ * Returns the reshaped store + the output schema (targets widened to
31
+ * optional `number`). The result-schema cast is the single trust
32
+ * boundary; the `TimeSeries` method wraps the store via
33
+ * `#fromTrustedStore`.
34
+ *
35
+ * A non-numeric target name is unreachable through the typed surface
36
+ * (`NumericColumnNameForSchema<S>`); defeating that constraint makes
37
+ * the all-`undefined` replacement column `kind: 'number'`, so
38
+ * `withColumnReplaced`'s kind guard throws a `RangeError` naming the
39
+ * column — fail-fast over the old path's silent all-`undefined`.
40
+ */
41
+ export function diffRateOp(store, schema, mode, cols, drop) {
42
+ if (cols.length === 0) {
43
+ throw new Error(`${mode}() requires at least one column name`);
44
+ }
45
+ const targetSet = new Set(cols);
46
+ const outSchema = Object.freeze(schema.map((col, i) => i === 0 || !targetSet.has(col.name)
47
+ ? col
48
+ : { ...col, kind: 'number', required: false }));
49
+ const n = store.length;
50
+ // For `rate`, the elapsed-seconds divisor depends only on the row
51
+ // index, not the target — precompute it once rather than per
52
+ // (target, row). dt[0] is unused (row 0 has no predecessor).
53
+ let dt;
54
+ if (mode === 'rate' && n > 0) {
55
+ dt = new Float64Array(n);
56
+ for (let i = 1; i < n; i += 1) {
57
+ dt[i] = (store.beginAt(i) - store.beginAt(i - 1)) / 1000;
58
+ }
59
+ }
60
+ let result = store;
61
+ for (const name of cols) {
62
+ const col = store.columns.get(name);
63
+ const out = new Array(n);
64
+ if (n > 0)
65
+ out[0] = undefined; // first row: no predecessor
66
+ for (let i = 1; i < n; i += 1) {
67
+ const prev = col.read(i - 1);
68
+ const curr = col.read(i);
69
+ if (typeof curr === 'number' && typeof prev === 'number') {
70
+ const delta = curr - prev;
71
+ if (mode === 'pctChange') {
72
+ out[i] = prev !== 0 ? delta / prev : undefined;
73
+ }
74
+ else if (mode === 'rate') {
75
+ const d = dt[i];
76
+ out[i] = d !== 0 ? delta / d : undefined;
77
+ }
78
+ else {
79
+ out[i] = delta;
80
+ }
81
+ }
82
+ else {
83
+ out[i] = undefined;
84
+ }
85
+ }
86
+ result = withColumnReplaced(result, name, float64ColumnFromArray(out));
87
+ }
88
+ // drop:true removes the predecessor-less first row from every column
89
+ // + the key. (n === 0 has no row to drop; the guard keeps the empty
90
+ // store untouched rather than slicing [1, 0).)
91
+ if (drop && n > 0) {
92
+ result = withRowRange(result, 1, n);
93
+ }
94
+ return {
95
+ store: result,
96
+ schema: outSchema,
97
+ };
98
+ }
99
+ //# sourceMappingURL=diff-rate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-rate.js","sourceRoot":"","sources":["../../../src/batch/operators/diff-rate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { type ColumnarStore } from '../../columnar/index.js';
2
+ import type { FillStrategy } from '../../schema/reshape.js';
3
+ import type { ScalarValue, SeriesSchema } from '../../schema/index.js';
4
+ /**
5
+ * A fill strategy resolved to its operator-ready form: a built-in
6
+ * strategy keyword, or a literal value to place in every gap cell.
7
+ * (The method resolves the public `FillStrategy | FillMapping` input
8
+ * into a per-column map of these before delegating.)
9
+ */
10
+ export type ResolvedFillSpec = {
11
+ mode: FillStrategy;
12
+ } | {
13
+ mode: 'literal';
14
+ value: ScalarValue;
15
+ };
16
+ /**
17
+ * **Step 4 — column-native `fill` (extracted operator).** Gap-fills
18
+ * value columns straight off the columnar store: read each target's
19
+ * cells (storage-agnostic `read(i)`), walk contiguous `undefined`
20
+ * runs, apply the per-column strategy, and replace only the columns
21
+ * that actually changed — no `series.events` materialization, no
22
+ * per-row `Event`. Untouched columns + the key axis pass through by
23
+ * reference.
24
+ *
25
+ * Matches the row path's semantics exactly:
26
+ * - **Gap walk.** Each maximal run of `undefined` cells is one gap.
27
+ * `linear` needs both neighbors, `hold` needs a left neighbor,
28
+ * `bfill` needs a right neighbor; `zero` / `literal` need none. A
29
+ * gap missing its required neighbor is left unfilled.
30
+ * - **`limit` / `maxGap`** are all-or-nothing per gap: a gap longer
31
+ * than `limit` cells, or whose temporal span exceeds `maxGap` ms,
32
+ * is skipped entirely. The span uses both neighbors for interior
33
+ * gaps, the available neighbor + the gap edge for edge gaps.
34
+ * - **Strategies.** `hold` carries the left value, `bfill` the right;
35
+ * `zero` writes 0; `literal` writes the supplied value; `linear`
36
+ * interpolates by time (`tspan === 0` ⇒ the left value). `zero` and
37
+ * `linear` are **numeric-only** — on a non-numeric column they
38
+ * silently skip (the column is left untouched, not rebuilt).
39
+ *
40
+ * Unlike the numeric folds (`cumulative`, `diff`), `fill` preserves
41
+ * each column's **kind** — `hold` / `bfill` / `literal` apply to any
42
+ * kind — so a changed column is rebuilt with the kind-appropriate
43
+ * builder (`buildFilledColumn`). A `literal` whose runtime type
44
+ * doesn't match the column kind throws a `RangeError` naming the
45
+ * column when it would be placed (gap-dependent).
46
+ *
47
+ * **This throw is a deliberate behavior change, not parity.** The old
48
+ * events path did NOT throw on a kind-mismatched literal: it stored
49
+ * the literal in the event cache *and* coerced it into the numeric
50
+ * buffer, yielding an internally-inconsistent series (`.get()`
51
+ * returned the string, `.column().sum()` returned `NaN`). Column-
52
+ * native has a single representation, so that dual-view inconsistency
53
+ * is unreproducible — failing fast on the nonsensical input (a kind-
54
+ * mismatched literal is only writable because `FillMapping` values
55
+ * are the broad `FillStrategy | ScalarValue`) is the principled
56
+ * replacement.
57
+ *
58
+ * The schema is unchanged (fill never widens or drops); the cast is
59
+ * the single trust boundary, and the `TimeSeries.fill` method wraps
60
+ * the store via `#fromTrustedStore`.
61
+ */
62
+ export declare function fillOp<S extends SeriesSchema>(store: ColumnarStore<S>, schema: S, specs: ReadonlyMap<string, ResolvedFillSpec>, limit: number | undefined, maxGapMs: number | undefined): {
63
+ store: ColumnarStore<S>;
64
+ schema: S;
65
+ };
66
+ //# sourceMappingURL=fill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fill.d.ts","sourceRoot":"","sources":["../../../src/batch/operators/fill.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAOnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAAC;AAmC5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,YAAY,EAC3C,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,EAC5C,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B;IAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAAC,MAAM,EAAE,CAAC,CAAA;CAAE,CA6IxC"}
@@ -0,0 +1,219 @@
1
+ import { arrayColumnFromArray, booleanColumnFromArray, float64ColumnFromArray, stringColumnFromArray, withColumnReplaced, } from '../../columnar/index.js';
2
+ /** Does `value`'s runtime type match the column's declared kind? */
3
+ function valueMatchesKind(value, kind) {
4
+ switch (kind) {
5
+ case 'number':
6
+ return typeof value === 'number';
7
+ case 'string':
8
+ return typeof value === 'string';
9
+ case 'boolean':
10
+ return typeof value === 'boolean';
11
+ case 'array':
12
+ return Array.isArray(value);
13
+ default:
14
+ return false;
15
+ }
16
+ }
17
+ /** Rebuilds a filled value array into a column of the given kind. */
18
+ function buildFilledColumn(kind, values) {
19
+ switch (kind) {
20
+ case 'number':
21
+ return float64ColumnFromArray(values);
22
+ case 'string':
23
+ return stringColumnFromArray(values);
24
+ case 'boolean':
25
+ return booleanColumnFromArray(values);
26
+ case 'array':
27
+ // ArrayValue cells; the cast is the kind dispatch's trust point.
28
+ return arrayColumnFromArray(values);
29
+ default:
30
+ throw new TypeError(`fill: unsupported column kind '${kind}'`);
31
+ }
32
+ }
33
+ /**
34
+ * **Step 4 — column-native `fill` (extracted operator).** Gap-fills
35
+ * value columns straight off the columnar store: read each target's
36
+ * cells (storage-agnostic `read(i)`), walk contiguous `undefined`
37
+ * runs, apply the per-column strategy, and replace only the columns
38
+ * that actually changed — no `series.events` materialization, no
39
+ * per-row `Event`. Untouched columns + the key axis pass through by
40
+ * reference.
41
+ *
42
+ * Matches the row path's semantics exactly:
43
+ * - **Gap walk.** Each maximal run of `undefined` cells is one gap.
44
+ * `linear` needs both neighbors, `hold` needs a left neighbor,
45
+ * `bfill` needs a right neighbor; `zero` / `literal` need none. A
46
+ * gap missing its required neighbor is left unfilled.
47
+ * - **`limit` / `maxGap`** are all-or-nothing per gap: a gap longer
48
+ * than `limit` cells, or whose temporal span exceeds `maxGap` ms,
49
+ * is skipped entirely. The span uses both neighbors for interior
50
+ * gaps, the available neighbor + the gap edge for edge gaps.
51
+ * - **Strategies.** `hold` carries the left value, `bfill` the right;
52
+ * `zero` writes 0; `literal` writes the supplied value; `linear`
53
+ * interpolates by time (`tspan === 0` ⇒ the left value). `zero` and
54
+ * `linear` are **numeric-only** — on a non-numeric column they
55
+ * silently skip (the column is left untouched, not rebuilt).
56
+ *
57
+ * Unlike the numeric folds (`cumulative`, `diff`), `fill` preserves
58
+ * each column's **kind** — `hold` / `bfill` / `literal` apply to any
59
+ * kind — so a changed column is rebuilt with the kind-appropriate
60
+ * builder (`buildFilledColumn`). A `literal` whose runtime type
61
+ * doesn't match the column kind throws a `RangeError` naming the
62
+ * column when it would be placed (gap-dependent).
63
+ *
64
+ * **This throw is a deliberate behavior change, not parity.** The old
65
+ * events path did NOT throw on a kind-mismatched literal: it stored
66
+ * the literal in the event cache *and* coerced it into the numeric
67
+ * buffer, yielding an internally-inconsistent series (`.get()`
68
+ * returned the string, `.column().sum()` returned `NaN`). Column-
69
+ * native has a single representation, so that dual-view inconsistency
70
+ * is unreproducible — failing fast on the nonsensical input (a kind-
71
+ * mismatched literal is only writable because `FillMapping` values
72
+ * are the broad `FillStrategy | ScalarValue`) is the principled
73
+ * replacement.
74
+ *
75
+ * The schema is unchanged (fill never widens or drops); the cast is
76
+ * the single trust boundary, and the `TimeSeries.fill` method wraps
77
+ * the store via `#fromTrustedStore`.
78
+ */
79
+ export function fillOp(store, schema, specs, limit, maxGapMs) {
80
+ const n = store.length;
81
+ if (n === 0 || specs.size === 0) {
82
+ return { store, schema };
83
+ }
84
+ const colKind = new Map();
85
+ for (let i = 1; i < schema.length; i += 1) {
86
+ colKind.set(schema[i].name, schema[i].kind);
87
+ }
88
+ // Times are needed only for `linear` and `maxGap`; build once, lazily.
89
+ let times;
90
+ const getTimes = () => {
91
+ if (times === undefined) {
92
+ times = new Array(n);
93
+ for (let i = 0; i < n; i += 1)
94
+ times[i] = store.beginAt(i);
95
+ }
96
+ return times;
97
+ };
98
+ let result = store;
99
+ for (const [name, spec] of specs) {
100
+ const col = store.columns.get(name);
101
+ if (col === undefined)
102
+ continue;
103
+ const kind = colKind.get(name);
104
+ // `zero` / `linear` are numeric-only: skip non-numeric columns
105
+ // entirely (leave the original column, no rebuild).
106
+ if ((spec.mode === 'zero' || spec.mode === 'linear') && kind !== 'number') {
107
+ continue;
108
+ }
109
+ const values = new Array(n);
110
+ for (let i = 0; i < n; i += 1)
111
+ values[i] = col.read(i);
112
+ let changed = false;
113
+ let i = 0;
114
+ while (i < n) {
115
+ if (values[i] !== undefined) {
116
+ i += 1;
117
+ continue;
118
+ }
119
+ const start = i;
120
+ while (i < n && values[i] === undefined)
121
+ i += 1;
122
+ const end = i; // exclusive
123
+ const length = end - start;
124
+ const hasPrev = start > 0;
125
+ const hasNext = end < n;
126
+ let strategyOk;
127
+ switch (spec.mode) {
128
+ case 'linear':
129
+ strategyOk = hasPrev && hasNext;
130
+ break;
131
+ case 'hold':
132
+ strategyOk = hasPrev;
133
+ break;
134
+ case 'bfill':
135
+ strategyOk = hasNext;
136
+ break;
137
+ default:
138
+ strategyOk = true; // zero, literal
139
+ }
140
+ if (!strategyOk)
141
+ continue;
142
+ if (limit !== undefined && length > limit)
143
+ continue;
144
+ if (maxGapMs !== undefined) {
145
+ const t = getTimes();
146
+ let span;
147
+ if (hasPrev && hasNext) {
148
+ span = t[end] - t[start - 1];
149
+ }
150
+ else if (hasPrev) {
151
+ span = t[end - 1] - t[start - 1];
152
+ }
153
+ else if (hasNext) {
154
+ span = t[end] - t[start];
155
+ }
156
+ else {
157
+ span = 0;
158
+ }
159
+ if (span > maxGapMs)
160
+ continue;
161
+ }
162
+ switch (spec.mode) {
163
+ case 'hold': {
164
+ const v = values[start - 1];
165
+ for (let j = start; j < end; j += 1)
166
+ values[j] = v;
167
+ changed = true;
168
+ break;
169
+ }
170
+ case 'bfill': {
171
+ const v = values[end];
172
+ for (let j = start; j < end; j += 1)
173
+ values[j] = v;
174
+ changed = true;
175
+ break;
176
+ }
177
+ case 'zero': {
178
+ for (let j = start; j < end; j += 1)
179
+ values[j] = 0;
180
+ changed = true;
181
+ break;
182
+ }
183
+ case 'literal': {
184
+ // Gap-dependent kind check: throws exactly when a kind-broken
185
+ // literal would be placed (matching the old SeriesStore-intake
186
+ // error), with a clearer column-named message.
187
+ if (!valueMatchesKind(spec.value, kind)) {
188
+ throw new RangeError(`fill: literal value ${JSON.stringify(spec.value)} for column '${name}' does not match its kind '${kind}'`);
189
+ }
190
+ for (let j = start; j < end; j += 1)
191
+ values[j] = spec.value;
192
+ changed = true;
193
+ break;
194
+ }
195
+ case 'linear': {
196
+ const before = values[start - 1];
197
+ const after = values[end];
198
+ const t = getTimes();
199
+ const t0 = t[start - 1];
200
+ const t1 = t[end];
201
+ const tspan = t1 - t0;
202
+ for (let j = start; j < end; j += 1) {
203
+ values[j] =
204
+ tspan === 0
205
+ ? before
206
+ : before + (after - before) * ((t[j] - t0) / tspan);
207
+ }
208
+ changed = true;
209
+ break;
210
+ }
211
+ }
212
+ }
213
+ if (changed) {
214
+ result = withColumnReplaced(result, name, buildFilledColumn(kind, values));
215
+ }
216
+ }
217
+ return { store: result, schema };
218
+ }
219
+ //# sourceMappingURL=fill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fill.js","sourceRoot":"","sources":["../../../src/batch/operators/fill.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import { type ColumnarStore } from '../../columnar/index.js';
2
+ import type { SeriesSchema } from '../../schema/index.js';
3
+ /**
4
+ * A per-cell value transform: `(value) => newValue`, where the output
5
+ * is the **same kind** as the input (number→number, string→string,
6
+ * …). The `TimeSeries.mapColumns` method types each column's mapper
7
+ * against that column's value type; the operator erases to
8
+ * `(value: unknown) => unknown` at the trust boundary.
9
+ */
10
+ export type ColumnMapper = (value: unknown) => unknown;
11
+ /**
12
+ * **Step 4 — column-native `mapColumns` (extracted operator).** Applies
13
+ * a per-cell value transform to one or more columns, straight off the
14
+ * columnar store: read each target's cells (storage-agnostic
15
+ * `read(i)`), apply the mapper to each **defined** value, rebuild the
16
+ * column — no `series.events` materialization, no per-row `Event`.
17
+ * Non-mapped columns + the key axis pass through by reference.
18
+ *
19
+ * Semantics:
20
+ * - **Missing cells carry.** The mapper is called only on defined
21
+ * values; a missing (`undefined`) cell stays missing (the mapper is
22
+ * not invoked).
23
+ * - **Numeric results must be finite.** For a `number` column, a mapper
24
+ * result of `NaN` or `±Infinity` throws a `RangeError` at write —
25
+ * matching construction intake (`assertCellKind`), which rejects
26
+ * non-finite numbers. This keeps packed numeric columns NaN-free, so
27
+ * the columnar fast-path and the row-path reducers can never diverge
28
+ * on the same bucket (the bug audit v2 §1.3 reproduced). A stored
29
+ * `NaN` *is* a defined value, so the mapper is still invoked on it —
30
+ * use that to clean it (map `NaN` to a finite number, or to
31
+ * `undefined` for a missing cell). (Array columns are not
32
+ * element-checked here; they don't feed the numeric reducers.)
33
+ * - **Same kind, schema-stable.** The mapper returns the column's own
34
+ * kind (the method's type enforces `(value: T) => T`), so the output
35
+ * column keeps its kind and the schema is unchanged. The result is
36
+ * rebuilt with the kind-appropriate builder.
37
+ *
38
+ * The schema is returned unchanged; the cast is the single trust
39
+ * boundary, and the `TimeSeries.mapColumns` method wraps the store via
40
+ * `#fromTrustedStore`.
41
+ *
42
+ * A mapper that — only by defeating the `(value: T) => T` type —
43
+ * returns `undefined`, or a value of the wrong kind (e.g. a string
44
+ * from a numeric mapper via an `as` cast), produces a cell the
45
+ * same-kind builder can't store: `columnFromValuesByKind` coerces it
46
+ * to missing, so the cell reads back as a gap the declared schema may
47
+ * not advertise. Both are type-illegal inputs, not handled specially.
48
+ * (A non-finite *number* from a numeric mapper is the one same-kind
49
+ * case that throws rather than coerces — it would corrupt the packed
50
+ * column, not read back as a gap.)
51
+ */
52
+ export declare function mapOp<S extends SeriesSchema>(store: ColumnarStore<S>, schema: S, spec: ReadonlyMap<string, ColumnMapper>): {
53
+ store: ColumnarStore<S>;
54
+ schema: S;
55
+ };
56
+ //# sourceMappingURL=map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"map.d.ts","sourceRoot":"","sources":["../../../src/batch/operators/map.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAOnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;AAyBvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,YAAY,EAC1C,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,MAAM,EAAE,CAAC,EACT,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,GACtC;IAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAAC,MAAM,EAAE,CAAC,CAAA;CAAE,CAqDxC"}
@@ -0,0 +1,109 @@
1
+ import { arrayColumnFromArray, booleanColumnFromArray, float64ColumnFromArray, stringColumnFromArray, withColumnReplaced, } from '../../columnar/index.js';
2
+ /**
3
+ * Rebuilds a mapped value array into a column of the given kind.
4
+ *
5
+ * NB: this is the same kind→builder dispatch as `fillOp`'s
6
+ * `buildFilledColumn`. Two callers now (fill + map) — a candidate for
7
+ * a shared `columnFromValuesByKind` helper in a follow-up; kept local
8
+ * here to keep this PR focused on the new operator.
9
+ */
10
+ function columnFromValuesByKind(kind, values) {
11
+ switch (kind) {
12
+ case 'number':
13
+ return float64ColumnFromArray(values);
14
+ case 'string':
15
+ return stringColumnFromArray(values);
16
+ case 'boolean':
17
+ return booleanColumnFromArray(values);
18
+ case 'array':
19
+ return arrayColumnFromArray(values);
20
+ default:
21
+ throw new TypeError(`mapColumns: unsupported column kind '${kind}'`);
22
+ }
23
+ }
24
+ /**
25
+ * **Step 4 — column-native `mapColumns` (extracted operator).** Applies
26
+ * a per-cell value transform to one or more columns, straight off the
27
+ * columnar store: read each target's cells (storage-agnostic
28
+ * `read(i)`), apply the mapper to each **defined** value, rebuild the
29
+ * column — no `series.events` materialization, no per-row `Event`.
30
+ * Non-mapped columns + the key axis pass through by reference.
31
+ *
32
+ * Semantics:
33
+ * - **Missing cells carry.** The mapper is called only on defined
34
+ * values; a missing (`undefined`) cell stays missing (the mapper is
35
+ * not invoked).
36
+ * - **Numeric results must be finite.** For a `number` column, a mapper
37
+ * result of `NaN` or `±Infinity` throws a `RangeError` at write —
38
+ * matching construction intake (`assertCellKind`), which rejects
39
+ * non-finite numbers. This keeps packed numeric columns NaN-free, so
40
+ * the columnar fast-path and the row-path reducers can never diverge
41
+ * on the same bucket (the bug audit v2 §1.3 reproduced). A stored
42
+ * `NaN` *is* a defined value, so the mapper is still invoked on it —
43
+ * use that to clean it (map `NaN` to a finite number, or to
44
+ * `undefined` for a missing cell). (Array columns are not
45
+ * element-checked here; they don't feed the numeric reducers.)
46
+ * - **Same kind, schema-stable.** The mapper returns the column's own
47
+ * kind (the method's type enforces `(value: T) => T`), so the output
48
+ * column keeps its kind and the schema is unchanged. The result is
49
+ * rebuilt with the kind-appropriate builder.
50
+ *
51
+ * The schema is returned unchanged; the cast is the single trust
52
+ * boundary, and the `TimeSeries.mapColumns` method wraps the store via
53
+ * `#fromTrustedStore`.
54
+ *
55
+ * A mapper that — only by defeating the `(value: T) => T` type —
56
+ * returns `undefined`, or a value of the wrong kind (e.g. a string
57
+ * from a numeric mapper via an `as` cast), produces a cell the
58
+ * same-kind builder can't store: `columnFromValuesByKind` coerces it
59
+ * to missing, so the cell reads back as a gap the declared schema may
60
+ * not advertise. Both are type-illegal inputs, not handled specially.
61
+ * (A non-finite *number* from a numeric mapper is the one same-kind
62
+ * case that throws rather than coerces — it would corrupt the packed
63
+ * column, not read back as a gap.)
64
+ */
65
+ export function mapOp(store, schema, spec) {
66
+ const n = store.length;
67
+ if (n === 0 || spec.size === 0) {
68
+ return { store, schema };
69
+ }
70
+ const colKind = new Map();
71
+ for (let i = 1; i < schema.length; i += 1) {
72
+ colKind.set(schema[i].name, schema[i].kind);
73
+ }
74
+ let result = store;
75
+ for (const [name, fn] of spec) {
76
+ const col = store.columns.get(name);
77
+ if (col === undefined)
78
+ continue;
79
+ const kind = colKind.get(name);
80
+ // Numeric columns reject a non-finite (NaN / ±Infinity) mapper result at
81
+ // write, matching construction intake (assertCellKind). A packed NaN would
82
+ // otherwise be unreachable-by-assumption for the reduce kernels and diverge
83
+ // the fast path from the row path (audit v2 §1.3). Hoisted out of the loop
84
+ // so non-numeric columns pay nothing.
85
+ const rejectNonFinite = kind === 'number';
86
+ const out = new Array(n);
87
+ for (let i = 0; i < n; i += 1) {
88
+ const v = col.read(i);
89
+ if (v === undefined) {
90
+ out[i] = undefined;
91
+ continue;
92
+ }
93
+ const mapped = fn(v);
94
+ if (rejectNonFinite &&
95
+ typeof mapped === 'number' &&
96
+ !Number.isFinite(mapped)) {
97
+ throw new RangeError(`mapColumns: the mapper for column '${name}' returned a non-finite ` +
98
+ `number (${mapped}) at row ${i}. Numeric columns reject NaN and ` +
99
+ `±Infinity at write, consistent with intake — a packed NaN would ` +
100
+ `diverge the fast-path and row-path reducers on the same data. ` +
101
+ `Map to a finite number, or to undefined for a missing cell.`);
102
+ }
103
+ out[i] = mapped;
104
+ }
105
+ result = withColumnReplaced(result, name, columnFromValuesByKind(kind, out));
106
+ }
107
+ return { store: result, schema };
108
+ }
109
+ //# sourceMappingURL=map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"map.js","sourceRoot":"","sources":["../../../src/batch/operators/map.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { type ColumnarStore } from '../../columnar/index.js';
2
+ import type { SeriesSchema } from '../../schema/index.js';
3
+ /**
4
+ * **Step 4 — column-native `shift` (extracted operator).** Shifts each
5
+ * target numeric column's values by `n` rows, straight off the
6
+ * columnar store: row `i` takes the value at row `i − n` (storage-
7
+ * agnostic `col.read`), or `undefined` when that source row is out of
8
+ * range — no `series.events` materialization, no per-row `Event`.
9
+ * Non-target columns + the key axis pass through by reference.
10
+ *
11
+ * `n > 0` shifts forward (a lag: the first `n` rows pad to
12
+ * `undefined`); `n < 0` shifts backward (a lead: the last `|n|` rows
13
+ * pad); `n === 0` is identity. `n` beyond the row count pads the whole
14
+ * column. The padding is why targets widen to optional `number` in the
15
+ * output schema.
16
+ *
17
+ * Returns the reshaped store + the output schema; the result-schema
18
+ * cast is the single trust boundary, and the `TimeSeries.shift` method
19
+ * wraps the store via `#fromTrustedStore`.
20
+ *
21
+ * A non-numeric target is unreachable through the typed surface
22
+ * (`NumericColumnNameForSchema<S>`); defeating that constraint makes the
23
+ * `Float64Column` replacement collide with the existing column's kind, so
24
+ * `withColumnReplaced`'s kind guard throws a `RangeError` naming the column
25
+ * — fail-fast, matching `cumulativeOp` / `diffRateOp`.
26
+ */
27
+ export declare function shiftOp<S extends SeriesSchema, OutSchema extends SeriesSchema>(store: ColumnarStore<S>, schema: S, cols: readonly string[], n: number): {
28
+ store: ColumnarStore<OutSchema>;
29
+ schema: OutSchema;
30
+ };
31
+ //# sourceMappingURL=shift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shift.d.ts","sourceRoot":"","sources":["../../../src/batch/operators/shift.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAInB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,YAAY,EAAE,SAAS,SAAS,YAAY,EAC5E,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,MAAM,EAAE,CAAC,EACT,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,CAAC,EAAE,MAAM,GACR;IAAE,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,CAmCxD"}