tranfi 0.1.2 → 0.2.1

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 +443 -51
  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 +352 -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 +81 -41
  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_filter.c CHANGED
@@ -10,13 +10,48 @@
10
10
  #include <stdlib.h>
11
11
  #include <string.h>
12
12
  #include <stdio.h>
13
+ #include <stdbool.h>
13
14
 
14
15
  typedef struct {
15
16
  tf_expr *expr;
17
+ char *expr_text;
16
18
  size_t rows_in;
17
19
  size_t rows_out;
20
+ size_t row_index;
21
+ size_t audit_limit;
22
+ size_t audit_emitted;
23
+ int audit;
24
+ tf_audit_options audit_opts;
18
25
  } filter_state;
19
26
 
27
+ static int filter_emit_drop_audit(filter_state *st, const tf_batch *b, size_t row,
28
+ tf_side_channels *side, const char *reason) {
29
+ if (!st->audit || st->audit_emitted >= st->audit_limit || !side || !side->stats) return TF_OK;
30
+ cJSON *obj = cJSON_CreateObject();
31
+ if (!obj) return TF_ERROR;
32
+ int rc = TF_ERROR;
33
+ if (tf_json_add_string(obj, "type", "audit") != TF_OK ||
34
+ tf_json_add_string(obj, "op", "filter") != TF_OK ||
35
+ tf_json_add_string(obj, "event", "row_dropped") != TF_OK ||
36
+ tf_json_add_string(obj, "reason", reason ? reason : "predicate_false") != TF_OK ||
37
+ tf_json_add_string(obj, "channel", "audit") != TF_OK ||
38
+ tf_json_add_string(obj, "expr", st->expr_text ? st->expr_text : "") != TF_OK ||
39
+ tf_json_add_number(obj, "row", (double)st->row_index) != TF_OK) {
40
+ goto done;
41
+ }
42
+ cJSON *data = tf_audit_row_to_json(b, row, &st->audit_opts);
43
+ if (data) {
44
+ if (tf_json_add_item(obj, "data", data) != TF_OK) goto done;
45
+ } else if (st->audit_opts.include_row) {
46
+ goto done;
47
+ }
48
+ rc = tf_buffer_write_json_line(side->stats, obj);
49
+ done:
50
+ cJSON_Delete(obj);
51
+ if (rc == TF_OK) st->audit_emitted++;
52
+ return rc;
53
+ }
54
+
20
55
  static int filter_process(tf_step *self, tf_batch *in, tf_batch **out,
21
56
  tf_side_channels *side) {
22
57
  filter_state *st = self->state;
@@ -25,55 +60,36 @@ static int filter_process(tf_step *self, tf_batch *in, tf_batch **out,
25
60
  /* Create output batch with same schema */
26
61
  tf_batch *ob = tf_batch_create(in->n_cols, in->n_rows);
27
62
  if (!ob) return TF_ERROR;
28
- for (size_t i = 0; i < in->n_cols; i++) {
29
- tf_batch_set_schema(ob, i, in->col_names[i], in->col_types[i]);
63
+ if (tf_batch_clone_schema(ob, in) != TF_OK) {
64
+ tf_batch_free(ob);
65
+ return TF_ERROR;
30
66
  }
31
67
 
32
68
  /* Filter rows */
33
69
  size_t out_row = 0;
34
70
  for (size_t r = 0; r < in->n_rows; r++) {
71
+ st->row_index++;
35
72
  bool keep = false;
36
- if (tf_expr_eval(st->expr, in, r, &keep) != TF_OK) continue;
37
- if (!keep) continue;
73
+ int eval_ok = tf_expr_eval(st->expr, in, r, &keep) == TF_OK;
74
+ if (!eval_ok || !keep) {
75
+ if (filter_emit_drop_audit(st, in, r, side,
76
+ eval_ok ? "predicate_false" : "predicate_error") != TF_OK) {
77
+ tf_batch_free(ob);
78
+ return TF_ERROR;
79
+ }
80
+ continue;
81
+ }
38
82
 
39
- if (tf_batch_ensure_capacity(ob, out_row + 1) != TF_OK) {
83
+ if (tf_batch_copy_row(ob, out_row, in, r) != TF_OK) {
40
84
  tf_batch_free(ob);
41
85
  return TF_ERROR;
42
86
  }
43
-
44
- /* Copy row */
45
- for (size_t c = 0; c < in->n_cols; c++) {
46
- if (tf_batch_is_null(in, r, c)) {
47
- tf_batch_set_null(ob, out_row, c);
48
- continue;
49
- }
50
- switch (in->col_types[c]) {
51
- case TF_TYPE_BOOL:
52
- tf_batch_set_bool(ob, out_row, c, tf_batch_get_bool(in, r, c));
53
- break;
54
- case TF_TYPE_INT64:
55
- tf_batch_set_int64(ob, out_row, c, tf_batch_get_int64(in, r, c));
56
- break;
57
- case TF_TYPE_FLOAT64:
58
- tf_batch_set_float64(ob, out_row, c, tf_batch_get_float64(in, r, c));
59
- break;
60
- case TF_TYPE_STRING:
61
- tf_batch_set_string(ob, out_row, c, tf_batch_get_string(in, r, c));
62
- break;
63
- case TF_TYPE_DATE:
64
- tf_batch_set_date(ob, out_row, c, tf_batch_get_date(in, r, c));
65
- break;
66
- case TF_TYPE_TIMESTAMP:
67
- tf_batch_set_timestamp(ob, out_row, c, tf_batch_get_timestamp(in, r, c));
68
- break;
69
- default:
70
- tf_batch_set_null(ob, out_row, c);
71
- break;
72
- }
87
+ if (tf_batch_expose_row(ob, out_row) != TF_OK) {
88
+ tf_batch_free(ob);
89
+ return TF_ERROR;
73
90
  }
74
91
  out_row++;
75
92
  }
76
- ob->n_rows = out_row;
77
93
 
78
94
  st->rows_in += in->n_rows;
79
95
  st->rows_out += out_row;
@@ -82,9 +98,12 @@ static int filter_process(tf_step *self, tf_batch *in, tf_batch **out,
82
98
  if (side && side->stats) {
83
99
  char stats_buf[128];
84
100
  snprintf(stats_buf, sizeof(stats_buf),
85
- "{\"op\":\"filter\",\"rows_in\":%zu,\"rows_out\":%zu}\n",
101
+ "{\"op\":\"filter\",\"rows_in\":%zu,\"rows_out\":%zu}",
86
102
  in->n_rows, out_row);
87
- tf_buffer_write_str(side->stats, stats_buf);
103
+ if (tf_buffer_write_line(side->stats, stats_buf) != TF_OK) {
104
+ tf_batch_free(ob);
105
+ return TF_ERROR;
106
+ }
88
107
  }
89
108
 
90
109
  if (out_row > 0) {
@@ -105,6 +124,8 @@ static void filter_destroy(tf_step *self) {
105
124
  filter_state *st = self->state;
106
125
  if (st) {
107
126
  tf_expr_free(st->expr);
127
+ free(st->expr_text);
128
+ tf_audit_options_free(&st->audit_opts);
108
129
  free(st);
109
130
  }
110
131
  free(self);
@@ -121,9 +142,37 @@ tf_step *tf_filter_create(const cJSON *args) {
121
142
  filter_state *st = calloc(1, sizeof(filter_state));
122
143
  if (!st) { tf_expr_free(expr); return NULL; }
123
144
  st->expr = expr;
145
+ st->expr_text = strdup(expr_json->valuestring);
146
+ st->audit_limit = 1000;
147
+ tf_audit_options_init(&st->audit_opts, 1);
148
+ cJSON *audit_json = cJSON_GetObjectItemCaseSensitive(args, "audit");
149
+ st->audit = cJSON_IsTrue(audit_json) ? 1 : 0;
150
+ cJSON *audit_limit_json = cJSON_GetObjectItemCaseSensitive(args, "audit_limit");
151
+ if (!audit_limit_json) audit_limit_json = cJSON_GetObjectItemCaseSensitive(args, "auditLimit");
152
+ if (audit_limit_json) {
153
+ size_t parsed_limit = 0;
154
+ if (tf_json_get_size_arg_any(args, "audit_limit", "auditLimit",
155
+ 1, TF_MAX_AUDIT_RECORDS,
156
+ &parsed_limit, "filter") < 0) {
157
+ tf_expr_free(expr);
158
+ free(st->expr_text);
159
+ tf_audit_options_free(&st->audit_opts);
160
+ free(st);
161
+ return NULL;
162
+ }
163
+ st->audit_limit = parsed_limit;
164
+ }
165
+ if (tf_audit_options_parse(&st->audit_opts, args, "filter") != TF_OK) {
166
+ tf_expr_free(expr);
167
+ free(st->expr_text);
168
+ tf_audit_options_free(&st->audit_opts);
169
+ free(st);
170
+ return NULL;
171
+ }
172
+ if (!st->expr_text) { tf_expr_free(expr); tf_audit_options_free(&st->audit_opts); free(st); return NULL; }
124
173
 
125
- tf_step *step = malloc(sizeof(tf_step));
126
- if (!step) { tf_expr_free(expr); free(st); return NULL; }
174
+ tf_step *step = calloc(1, sizeof(tf_step));
175
+ if (!step) { tf_expr_free(expr); free(st->expr_text); tf_audit_options_free(&st->audit_opts); free(st); return NULL; }
127
176
  step->process = filter_process;
128
177
  step->flush = filter_flush;
129
178
  step->destroy = filter_destroy;