tranfi 0.1.2 → 0.2.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 (132) hide show
  1. package/LICENSE +177 -0
  2. package/NOTICE +8 -0
  3. package/README.md +272 -40
  4. package/app/assets/{index-pDFMluyz.js → index-BIAIKnrp.js} +1 -1
  5. package/app/index.html +1 -1
  6. package/binding.gyp +55 -3
  7. package/csrc/arena.c +7 -5
  8. package/csrc/batch.c +818 -71
  9. package/csrc/buffer.c +84 -8
  10. package/csrc/cJSON.c +262 -19
  11. package/csrc/cJSON.h +17 -1
  12. package/csrc/codec_csv.c +1074 -181
  13. package/csrc/codec_jsonl.c +830 -118
  14. package/csrc/codec_table.c +108 -78
  15. package/csrc/codec_text.c +286 -68
  16. package/csrc/compiler.c +31 -3
  17. package/csrc/config.h +21 -0
  18. package/csrc/dsl.c +4722 -485
  19. package/csrc/expr.c +363 -55
  20. package/csrc/expr.h +2 -0
  21. package/csrc/internal.h +316 -27
  22. package/csrc/ir.c +65 -18
  23. package/csrc/ir.h +41 -0
  24. package/csrc/ir_schema.c +20 -5
  25. package/csrc/ir_serialize.c +68 -6
  26. package/csrc/ir_sql.c +796 -185
  27. package/csrc/ir_validate.c +462 -6
  28. package/csrc/json_path.c +210 -0
  29. package/csrc/main.c +879 -30
  30. package/csrc/memory_estimate.c +477 -0
  31. package/csrc/op_acf.c +171 -21
  32. package/csrc/op_across.c +477 -0
  33. package/csrc/op_anomaly.c +167 -32
  34. package/csrc/op_assert.c +761 -0
  35. package/csrc/op_bin.c +168 -29
  36. package/csrc/op_cast.c +383 -55
  37. package/csrc/op_clip.c +30 -19
  38. package/csrc/op_date_trunc.c +208 -34
  39. package/csrc/op_datetime.c +259 -77
  40. package/csrc/op_derive.c +65 -97
  41. package/csrc/op_diff.c +146 -30
  42. package/csrc/op_ewma.c +149 -30
  43. package/csrc/op_explode.c +124 -26
  44. package/csrc/op_fill_down.c +125 -53
  45. package/csrc/op_fill_null.c +176 -31
  46. package/csrc/op_filter.c +89 -40
  47. package/csrc/op_frequency.c +571 -43
  48. package/csrc/op_grep.c +36 -18
  49. package/csrc/op_group_agg.c +1790 -119
  50. package/csrc/op_hash.c +48 -15
  51. package/csrc/op_head.c +21 -86
  52. package/csrc/op_interpolate.c +268 -62
  53. package/csrc/op_join.c +2700 -182
  54. package/csrc/op_json_extract.c +227 -0
  55. package/csrc/op_json_filter.c +384 -0
  56. package/csrc/op_json_flatten.c +293 -0
  57. package/csrc/op_json_schema.c +503 -0
  58. package/csrc/op_label_encode.c +328 -53
  59. package/csrc/op_lag.c +181 -0
  60. package/csrc/op_lead.c +141 -89
  61. package/csrc/op_normalize.c +363 -79
  62. package/csrc/op_onehot.c +345 -73
  63. package/csrc/op_pivot.c +1546 -162
  64. package/csrc/op_quarantine.c +189 -0
  65. package/csrc/op_registry.c +2062 -166
  66. package/csrc/op_rename.c +41 -50
  67. package/csrc/op_replace.c +270 -118
  68. package/csrc/op_rleid.c +297 -0
  69. package/csrc/op_rowid.c +559 -0
  70. package/csrc/op_sample.c +80 -23
  71. package/csrc/op_schema.c +1341 -0
  72. package/csrc/op_schema_infer.c +252 -0
  73. package/csrc/op_select.c +265 -65
  74. package/csrc/op_set.c +3449 -0
  75. package/csrc/op_skip.c +30 -87
  76. package/csrc/op_sort.c +670 -124
  77. package/csrc/op_source_name.c +120 -0
  78. package/csrc/op_split.c +65 -28
  79. package/csrc/op_split_data.c +41 -9
  80. package/csrc/op_stack.c +178 -222
  81. package/csrc/op_stats.c +206 -110
  82. package/csrc/op_step.c +217 -55
  83. package/csrc/op_tail.c +21 -12
  84. package/csrc/op_tee.c +338 -0
  85. package/csrc/op_top.c +260 -53
  86. package/csrc/op_trim.c +48 -19
  87. package/csrc/op_unique.c +1193 -150
  88. package/csrc/op_unpivot.c +100 -66
  89. package/csrc/op_validate.c +601 -24
  90. package/csrc/op_window.c +492 -51
  91. package/csrc/path_policy.c +85 -0
  92. package/csrc/pipeline.c +872 -99
  93. package/csrc/recipes.c +3 -1
  94. package/csrc/report.c +73 -30
  95. package/csrc/selector.c +1097 -0
  96. package/csrc/size_utils.c +348 -0
  97. package/csrc/spill.c +317 -0
  98. package/csrc/spill.h +21 -0
  99. package/csrc/tranfi.h +169 -1
  100. package/csrc/transform.h +209 -0
  101. package/csrc/transform_api.c +2237 -0
  102. package/csrc/transform_categorical.c +923 -0
  103. package/csrc/transform_internal.h +472 -0
  104. package/csrc/transform_json.c +3812 -0
  105. package/csrc/transform_numeric.c +1966 -0
  106. package/csrc/transform_sha256.c +154 -0
  107. package/csrc/transform_wasm.h +162 -0
  108. package/csrc/transform_wasm_api.c +1373 -0
  109. package/csrc/wasm_api.c +70 -9
  110. package/napi_api.c +219 -11
  111. package/napi_transform.c +1648 -0
  112. package/napi_transform.h +8 -0
  113. package/package.json +27 -11
  114. package/scripts/install-native.js +76 -0
  115. package/scripts/prepack.js +64 -0
  116. package/scripts/sync-csrc.js +23 -0
  117. package/src/cli.js +8 -11
  118. package/src/engines/duckdb.js +45 -12
  119. package/src/index.js +661 -42
  120. package/src/memory_policy.js +411 -0
  121. package/src/native.js +1 -5
  122. package/src/pipeline.js +454 -31
  123. package/src/recipe_json.js +80 -0
  124. package/src/server.js +10 -8
  125. package/src/transform.js +403 -0
  126. package/src/transform_error.js +10 -0
  127. package/src/wasm.js +6 -4
  128. package/wasm/index.js +498 -10
  129. package/wasm/tranfi_core.js +0 -0
  130. package/wasm/transform.js +1156 -0
  131. package/wasm/worker.js +786 -0
  132. package/csrc/plan.c +0 -206
package/csrc/op_sample.c CHANGED
@@ -1,11 +1,12 @@
1
1
  /*
2
- * op_sample.c — Reservoir sampling (Algorithm R). Bounded memory.
2
+ * op_sample.c -- Reservoir sampling (Algorithm R). Bounded memory.
3
3
  *
4
- * Config: {"n": 100}
4
+ * Config: {"n": 100, "seed": 123} or {"n": 100, "seed": "random"}
5
5
  */
6
6
 
7
7
  #include "internal.h"
8
8
  #include "cJSON.h"
9
+ #include <stdint.h>
9
10
  #include <stdlib.h>
10
11
  #include <string.h>
11
12
  #include <time.h>
@@ -15,9 +16,33 @@ typedef struct {
15
16
  tf_batch *buf;
16
17
  size_t seen; /* total rows seen */
17
18
  int has_schema;
18
- unsigned seed;
19
+ uint64_t rng;
19
20
  } sample_state;
20
21
 
22
+ static uint64_t sample_random_seed(void) {
23
+ uintptr_t stack_marker = 0;
24
+ uintptr_t stack_addr = (uintptr_t)&stack_marker;
25
+ return ((uint64_t)time(NULL) << 32) ^ (uint64_t)clock() ^ (uint64_t)stack_addr;
26
+ }
27
+
28
+ static uint64_t sample_next_u64(sample_state *st) {
29
+ st->rng += UINT64_C(0x9E3779B97F4A7C15);
30
+ uint64_t z = st->rng;
31
+ z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9);
32
+ z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB);
33
+ return z ^ (z >> 31);
34
+ }
35
+
36
+ static size_t sample_bounded(sample_state *st, size_t bound) {
37
+ if (bound <= 1) return 0;
38
+ uint64_t b = (uint64_t)bound;
39
+ uint64_t threshold = (uint64_t)(-b) % b;
40
+ for (;;) {
41
+ uint64_t r = sample_next_u64(st);
42
+ if (r >= threshold) return (size_t)(r % b);
43
+ }
44
+ }
45
+
21
46
  static int sample_process(tf_step *self, tf_batch *in, tf_batch **out,
22
47
  tf_side_channels *side) {
23
48
  (void)side;
@@ -27,22 +52,22 @@ static int sample_process(tf_step *self, tf_batch *in, tf_batch **out,
27
52
  if (!st->has_schema) {
28
53
  st->buf = tf_batch_create(in->n_cols, st->n);
29
54
  if (!st->buf) return TF_ERROR;
30
- for (size_t c = 0; c < in->n_cols; c++)
31
- tf_batch_set_schema(st->buf, c, in->col_names[c], in->col_types[c]);
55
+ if (tf_batch_clone_schema(st->buf, in) != TF_OK) return TF_ERROR;
32
56
  st->has_schema = 1;
33
57
  }
34
58
 
35
59
  for (size_t r = 0; r < in->n_rows; r++) {
60
+ if (st->seen == SIZE_MAX) {
61
+ tf_set_last_error("sample: row count overflow");
62
+ return TF_ERROR;
63
+ }
36
64
  if (st->seen < st->n) {
37
- /* Fill reservoir */
38
- tf_batch_copy_row(st->buf, st->seen, in, r);
39
- st->buf->n_rows = st->seen + 1;
65
+ if (tf_batch_copy_row(st->buf, st->seen, in, r) != TF_OK) return TF_ERROR;
66
+ if (tf_batch_expose_row(st->buf, st->seen) != TF_OK) return TF_ERROR;
40
67
  } else {
41
- /* Replace with probability n/seen */
42
- size_t j = (size_t)(rand_r(&st->seed) % (st->seen + 1));
43
- if (j < st->n) {
44
- tf_batch_copy_row(st->buf, j, in, r);
45
- }
68
+ size_t j = sample_bounded(st, st->seen + 1);
69
+ if (j < st->n && tf_batch_copy_row(st->buf, j, in, r) != TF_OK)
70
+ return TF_ERROR;
46
71
  }
47
72
  st->seen++;
48
73
  }
@@ -57,15 +82,22 @@ static int sample_flush(tf_step *self, tf_batch **out, tf_side_channels *side) {
57
82
 
58
83
  if (!st->buf || st->buf->n_rows == 0) return TF_OK;
59
84
 
60
- /* Copy buffer to output */
61
85
  size_t n = st->buf->n_rows;
62
86
  tf_batch *ob = tf_batch_create(st->buf->n_cols, n);
63
87
  if (!ob) return TF_ERROR;
64
- for (size_t c = 0; c < st->buf->n_cols; c++)
65
- tf_batch_set_schema(ob, c, st->buf->col_names[c], st->buf->col_types[c]);
88
+ if (tf_batch_clone_schema(ob, st->buf) != TF_OK) {
89
+ tf_batch_free(ob);
90
+ return TF_ERROR;
91
+ }
66
92
  for (size_t i = 0; i < n; i++) {
67
- tf_batch_copy_row(ob, i, st->buf, i);
68
- ob->n_rows = i + 1;
93
+ if (tf_batch_copy_row(ob, i, st->buf, i) != TF_OK) {
94
+ tf_batch_free(ob);
95
+ return TF_ERROR;
96
+ }
97
+ if (tf_batch_expose_row(ob, i) != TF_OK) {
98
+ tf_batch_free(ob);
99
+ return TF_ERROR;
100
+ }
69
101
  }
70
102
 
71
103
  *out = ob;
@@ -83,15 +115,40 @@ static void sample_destroy(tf_step *self) {
83
115
 
84
116
  tf_step *tf_sample_create(const cJSON *args) {
85
117
  if (!args) return NULL;
86
- cJSON *n_json = cJSON_GetObjectItemCaseSensitive(args, "n");
87
- if (!cJSON_IsNumber(n_json) || n_json->valueint <= 0) return NULL;
118
+ size_t n = 0;
119
+ int has_n = tf_json_get_size_arg(args, "n", 1, TF_MAX_OUTPUT_ROWS_PER_BATCH, &n, "sample");
120
+ if (has_n <= 0) return NULL;
88
121
 
89
122
  sample_state *st = calloc(1, sizeof(sample_state));
90
123
  if (!st) return NULL;
91
- st->n = (size_t)n_json->valueint;
92
- st->seed = (unsigned)time(NULL);
124
+ st->n = n;
125
+ st->rng = 0;
126
+
127
+ cJSON *seed_json = cJSON_GetObjectItemCaseSensitive(args, "seed");
128
+ if (seed_json) {
129
+ if (cJSON_IsString(seed_json)) {
130
+ if (strcmp(seed_json->valuestring, "random") != 0) {
131
+ tf_set_last_error("sample: seed must be an integer or 'random'");
132
+ free(st);
133
+ return NULL;
134
+ }
135
+ st->rng = sample_random_seed();
136
+ } else if (cJSON_IsNumber(seed_json) && seed_json->valuedouble >= 0.0) {
137
+ size_t parsed = 0;
138
+ if (tf_json_size_value(seed_json, "seed", 0, TF_MAX_SAFE_SIZE_ARG,
139
+ &parsed, "sample") < 0) {
140
+ free(st);
141
+ return NULL;
142
+ }
143
+ st->rng = (uint64_t)parsed;
144
+ } else {
145
+ tf_set_last_error("sample: seed must be an integer or 'random'");
146
+ free(st);
147
+ return NULL;
148
+ }
149
+ }
93
150
 
94
- tf_step *step = malloc(sizeof(tf_step));
151
+ tf_step *step = calloc(1, sizeof(tf_step));
95
152
  if (!step) { free(st); return NULL; }
96
153
  step->process = sample_process;
97
154
  step->flush = sample_flush;