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/recipes.c CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- * recipes.c — Built-in named recipes (20 common ETL pipelines).
2
+ * recipes.c — Built-in named recipes for common ETL pipelines.
3
3
  */
4
4
 
5
5
  #include "recipes.h"
@@ -20,6 +20,8 @@ static const recipe_entry recipes[] = {
20
20
  "Quick preview of first 10 rows"},
21
21
  {"schema", "csv | head 0 | csv",
22
22
  "Show column names only"},
23
+ {"sniff", "csv | schema infer rows=1000 | csv",
24
+ "Bounded-memory schema/type/nullability sniff (sample 1000 rows)"},
23
25
  {"summary", "csv | stats count,min,max,avg,stddev | csv",
24
26
  "Summary statistics"},
25
27
  {"count", "csv | stats count | csv",
package/csrc/report.c CHANGED
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  #include "report.h"
9
+ #include "internal.h"
9
10
  #include <stdlib.h>
10
11
  #include <string.h>
11
12
  #include <stdio.h>
@@ -27,41 +28,68 @@ typedef struct {
27
28
  char *data;
28
29
  size_t len;
29
30
  size_t cap;
31
+ int failed;
30
32
  } strbuf;
31
33
 
32
34
  static void sb_init(strbuf *sb) {
33
35
  sb->cap = 4096;
34
- sb->data = malloc(sb->cap);
35
36
  sb->len = 0;
36
- if (sb->data) sb->data[0] = '\0';
37
+ sb->failed = 0;
38
+ sb->data = tf_mallocarray_checked(sb->cap, sizeof(char));
39
+ if (sb->data) {
40
+ sb->data[0] = '\0';
41
+ } else {
42
+ sb->cap = 0;
43
+ sb->failed = 1;
44
+ }
37
45
  }
38
46
 
39
- static void sb_ensure(strbuf *sb, size_t extra) {
40
- if (sb->len + extra + 1 > sb->cap) {
41
- while (sb->len + extra + 1 > sb->cap) sb->cap *= 2;
42
- sb->data = realloc(sb->data, sb->cap);
47
+ static int sb_ensure(strbuf *sb, size_t extra) {
48
+ if (!sb || sb->failed) return -1;
49
+ size_t need;
50
+ if (tf_size_add(sb->len, extra, &need) != TF_OK ||
51
+ tf_size_add(need, 1, &need) != TF_OK) {
52
+ sb->failed = 1;
53
+ return -1;
54
+ }
55
+ if (need <= sb->cap) return 0;
56
+ size_t new_cap;
57
+ if (tf_size_grow_pow2(sb->cap, need, 4096, &new_cap) != TF_OK) {
58
+ sb->failed = 1;
59
+ return -1;
60
+ }
61
+ char *tmp = tf_reallocarray_checked(sb->data, new_cap, sizeof(char));
62
+ if (!tmp) {
63
+ sb->failed = 1;
64
+ return -1;
43
65
  }
66
+ sb->data = tmp;
67
+ sb->cap = new_cap;
68
+ return 0;
44
69
  }
45
70
 
46
71
  static void sb_append(strbuf *sb, const char *s) {
72
+ if (!sb || sb->failed || !s) return;
47
73
  size_t n = strlen(s);
48
- sb_ensure(sb, n);
74
+ if (sb_ensure(sb, n) != 0) return;
49
75
  memcpy(sb->data + sb->len, s, n);
50
76
  sb->len += n;
51
77
  sb->data[sb->len] = '\0';
52
78
  }
53
79
 
54
80
  static void sb_printf(strbuf *sb, const char *fmt, ...) {
81
+ if (!sb || sb->failed || !fmt) return;
55
82
  va_list ap;
56
83
  va_start(ap, fmt);
57
84
  int needed = vsnprintf(NULL, 0, fmt, ap);
58
85
  va_end(ap);
59
- if (needed < 0) return;
60
- sb_ensure(sb, (size_t)needed);
86
+ if (needed < 0) { sb->failed = 1; return; }
87
+ if (sb_ensure(sb, (size_t)needed) != 0) return;
61
88
  va_start(ap, fmt);
62
- vsnprintf(sb->data + sb->len, (size_t)needed + 1, fmt, ap);
89
+ int written = vsnprintf(sb->data + sb->len, (size_t)needed + 1, fmt, ap);
63
90
  va_end(ap);
64
- sb->len += (size_t)needed;
91
+ if (written < 0 || written > needed) { sb->failed = 1; return; }
92
+ sb->len += (size_t)written;
65
93
  }
66
94
 
67
95
  /* ---- Sparkline ---- */
@@ -90,6 +118,17 @@ typedef struct {
90
118
  size_t n_rows;
91
119
  } csv_table;
92
120
 
121
+ static void csv_free(csv_table *t);
122
+
123
+ static char *csv_field_copy(const char *start, size_t len) {
124
+ if (len > MAX_FIELD - 1) len = MAX_FIELD - 1;
125
+ char *field = tf_mallocarray_checked(len + 1, sizeof(char));
126
+ if (!field) return NULL;
127
+ if (len > 0) memcpy(field, start, len);
128
+ field[len] = '\0';
129
+ return field;
130
+ }
131
+
93
132
  /* Find column index by name, -1 if not found */
94
133
  static int csv_col(const csv_table *t, const char *name) {
95
134
  for (size_t i = 0; i < t->n_cols; i++) {
@@ -99,9 +138,9 @@ static int csv_col(const csv_table *t, const char *name) {
99
138
  return -1;
100
139
  }
101
140
 
102
- /* Parse a simple CSV (no quoted fields with embedded commas needed for stats) */
141
+ /* Parse the bounded stats CSV format, including quoted comma-containing fields. */
103
142
  static csv_table *csv_parse(const char *csv, size_t len) {
104
- csv_table *t = calloc(1, sizeof(csv_table));
143
+ csv_table *t = tf_callocarray_checked(1, sizeof(csv_table));
105
144
  if (!t) return NULL;
106
145
 
107
146
  const char *p = csv;
@@ -112,13 +151,13 @@ static csv_table *csv_parse(const char *csv, size_t len) {
112
151
  const char *start = p;
113
152
  while (p < end && *p != ',' && *p != '\n' && *p != '\r') p++;
114
153
  size_t flen = (size_t)(p - start);
115
- if (flen > MAX_FIELD - 1) flen = MAX_FIELD - 1;
116
154
  if (t->n_cols < MAX_COLS) {
117
- t->headers[t->n_cols] = malloc(flen + 1);
118
- if (t->headers[t->n_cols]) {
119
- memcpy(t->headers[t->n_cols], start, flen);
120
- t->headers[t->n_cols][flen] = '\0';
155
+ char *field = csv_field_copy(start, flen);
156
+ if (!field) {
157
+ csv_free(t);
158
+ return NULL;
121
159
  }
160
+ t->headers[t->n_cols] = field;
122
161
  t->n_cols++;
123
162
  }
124
163
  if (p < end && *p == ',') p++;
@@ -139,13 +178,13 @@ static csv_table *csv_parse(const char *csv, size_t len) {
139
178
  start = p;
140
179
  while (p < end && *p != '"') p++;
141
180
  size_t flen = (size_t)(p - start);
142
- if (flen > MAX_FIELD - 1) flen = MAX_FIELD - 1;
143
181
  if (ci < MAX_COLS) {
144
- t->cells[t->n_rows][ci] = malloc(flen + 1);
145
- if (t->cells[t->n_rows][ci]) {
146
- memcpy(t->cells[t->n_rows][ci], start, flen);
147
- t->cells[t->n_rows][ci][flen] = '\0';
182
+ char *field = csv_field_copy(start, flen);
183
+ if (!field) {
184
+ csv_free(t);
185
+ return NULL;
148
186
  }
187
+ t->cells[t->n_rows][ci] = field;
149
188
  }
150
189
  if (p < end && *p == '"') p++; /* skip closing quote */
151
190
  if (p < end && *p == ',') p++;
@@ -154,13 +193,13 @@ static csv_table *csv_parse(const char *csv, size_t len) {
154
193
  }
155
194
  while (p < end && *p != ',' && *p != '\n' && *p != '\r') p++;
156
195
  size_t flen = (size_t)(p - start);
157
- if (flen > MAX_FIELD - 1) flen = MAX_FIELD - 1;
158
196
  if (ci < MAX_COLS) {
159
- t->cells[t->n_rows][ci] = malloc(flen + 1);
160
- if (t->cells[t->n_rows][ci]) {
161
- memcpy(t->cells[t->n_rows][ci], start, flen);
162
- t->cells[t->n_rows][ci][flen] = '\0';
197
+ char *field = csv_field_copy(start, flen);
198
+ if (!field) {
199
+ csv_free(t);
200
+ return NULL;
163
201
  }
202
+ t->cells[t->n_rows][ci] = field;
164
203
  }
165
204
  if (p < end && *p == ',') p++;
166
205
  ci++;
@@ -176,7 +215,7 @@ static csv_table *csv_parse(const char *csv, size_t len) {
176
215
  static void csv_free(csv_table *t) {
177
216
  if (!t) return;
178
217
  for (size_t i = 0; i < t->n_cols; i++) free(t->headers[i]);
179
- for (size_t r = 0; r < t->n_rows; r++)
218
+ for (size_t r = 0; r < MAX_ROWS; r++)
180
219
  for (size_t c = 0; c < t->n_cols; c++)
181
220
  free(t->cells[r][c]);
182
221
  free(t);
@@ -293,7 +332,7 @@ char *tf_report_format(const char *stats_csv, size_t stats_len, int use_color) {
293
332
 
294
333
  strbuf sb;
295
334
  sb_init(&sb);
296
- if (!sb.data) { csv_free(t); return NULL; }
335
+ if (sb.failed) { csv_free(t); return NULL; }
297
336
 
298
337
  /* Header */
299
338
  long long total_count = 0;
@@ -459,5 +498,9 @@ char *tf_report_format(const char *stats_csv, size_t stats_len, int use_color) {
459
498
 
460
499
  csv_free(t);
461
500
 
501
+ if (sb.failed) {
502
+ free(sb.data);
503
+ return NULL;
504
+ }
462
505
  return sb.data;
463
506
  }