tranfi 0.0.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 (151) hide show
  1. package/LICENSE +177 -21
  2. package/NOTICE +8 -0
  3. package/README.md +627 -0
  4. package/app/assets/index-6quYZ5Ap.css +5 -0
  5. package/app/assets/index-BIAIKnrp.js +160 -0
  6. package/app/assets/materialdesignicons-webfont-B7mPwVP_.ttf +0 -0
  7. package/app/assets/materialdesignicons-webfont-CSr8KVlo.eot +0 -0
  8. package/app/assets/materialdesignicons-webfont-Dp5v-WZN.woff2 +0 -0
  9. package/app/assets/materialdesignicons-webfont-PXm3-2wK.woff +0 -0
  10. package/app/index.html +13 -0
  11. package/binding.gyp +121 -0
  12. package/csrc/arena.c +93 -0
  13. package/csrc/batch.c +976 -0
  14. package/csrc/buffer.c +154 -0
  15. package/csrc/cJSON.c +3386 -0
  16. package/csrc/cJSON.h +316 -0
  17. package/csrc/codec_csv.c +1951 -0
  18. package/csrc/codec_jsonl.c +1086 -0
  19. package/csrc/codec_table.c +248 -0
  20. package/csrc/codec_text.c +447 -0
  21. package/csrc/compiler.c +130 -0
  22. package/csrc/config.h +21 -0
  23. package/csrc/date_utils.h +94 -0
  24. package/csrc/dsl.c +5417 -0
  25. package/csrc/dsl.h +22 -0
  26. package/csrc/expr.c +1553 -0
  27. package/csrc/expr.h +58 -0
  28. package/csrc/internal.h +539 -0
  29. package/csrc/ir.c +166 -0
  30. package/csrc/ir.h +208 -0
  31. package/csrc/ir_schema.c +75 -0
  32. package/csrc/ir_serialize.c +166 -0
  33. package/csrc/ir_sql.c +1822 -0
  34. package/csrc/ir_validate.c +576 -0
  35. package/csrc/json_path.c +210 -0
  36. package/csrc/main.c +1241 -0
  37. package/csrc/memory_estimate.c +477 -0
  38. package/csrc/op_acf.c +283 -0
  39. package/csrc/op_across.c +477 -0
  40. package/csrc/op_anomaly.c +255 -0
  41. package/csrc/op_assert.c +761 -0
  42. package/csrc/op_bin.c +248 -0
  43. package/csrc/op_cast.c +523 -0
  44. package/csrc/op_clip.c +99 -0
  45. package/csrc/op_date_trunc.c +355 -0
  46. package/csrc/op_datetime.c +394 -0
  47. package/csrc/op_derive.c +216 -0
  48. package/csrc/op_diff.c +250 -0
  49. package/csrc/op_ewma.c +222 -0
  50. package/csrc/op_explode.c +206 -0
  51. package/csrc/op_fill_down.c +235 -0
  52. package/csrc/op_fill_null.c +268 -0
  53. package/csrc/op_filter.c +181 -0
  54. package/csrc/op_frequency.c +721 -0
  55. package/csrc/op_grep.c +181 -0
  56. package/csrc/op_group_agg.c +1956 -0
  57. package/csrc/op_hash.c +159 -0
  58. package/csrc/op_head.c +84 -0
  59. package/csrc/op_interpolate.c +445 -0
  60. package/csrc/op_join.c +2902 -0
  61. package/csrc/op_json_extract.c +227 -0
  62. package/csrc/op_json_filter.c +384 -0
  63. package/csrc/op_json_flatten.c +293 -0
  64. package/csrc/op_json_schema.c +503 -0
  65. package/csrc/op_label_encode.c +419 -0
  66. package/csrc/op_lag.c +181 -0
  67. package/csrc/op_lead.c +242 -0
  68. package/csrc/op_normalize.c +510 -0
  69. package/csrc/op_onehot.c +457 -0
  70. package/csrc/op_pivot.c +1754 -0
  71. package/csrc/op_quarantine.c +189 -0
  72. package/csrc/op_registry.c +3044 -0
  73. package/csrc/op_rename.c +129 -0
  74. package/csrc/op_replace.c +354 -0
  75. package/csrc/op_rleid.c +297 -0
  76. package/csrc/op_rowid.c +559 -0
  77. package/csrc/op_sample.c +158 -0
  78. package/csrc/op_schema.c +1341 -0
  79. package/csrc/op_schema_infer.c +252 -0
  80. package/csrc/op_select.c +340 -0
  81. package/csrc/op_set.c +3449 -0
  82. package/csrc/op_skip.c +95 -0
  83. package/csrc/op_sort.c +819 -0
  84. package/csrc/op_source_name.c +120 -0
  85. package/csrc/op_split.c +151 -0
  86. package/csrc/op_split_data.c +119 -0
  87. package/csrc/op_stack.c +271 -0
  88. package/csrc/op_stats.c +875 -0
  89. package/csrc/op_step.c +333 -0
  90. package/csrc/op_tail.c +105 -0
  91. package/csrc/op_tee.c +338 -0
  92. package/csrc/op_top.c +357 -0
  93. package/csrc/op_trim.c +138 -0
  94. package/csrc/op_unique.c +1343 -0
  95. package/csrc/op_unpivot.c +193 -0
  96. package/csrc/op_validate.c +648 -0
  97. package/csrc/op_window.c +591 -0
  98. package/csrc/path_policy.c +85 -0
  99. package/csrc/pipeline.c +1088 -0
  100. package/csrc/recipes.c +104 -0
  101. package/csrc/recipes.h +27 -0
  102. package/csrc/report.c +506 -0
  103. package/csrc/report.h +22 -0
  104. package/csrc/selector.c +1097 -0
  105. package/csrc/size_utils.c +348 -0
  106. package/csrc/spill.c +317 -0
  107. package/csrc/spill.h +21 -0
  108. package/csrc/tranfi.h +291 -0
  109. package/csrc/transform.h +209 -0
  110. package/csrc/transform_api.c +2237 -0
  111. package/csrc/transform_categorical.c +923 -0
  112. package/csrc/transform_internal.h +472 -0
  113. package/csrc/transform_json.c +3812 -0
  114. package/csrc/transform_numeric.c +1966 -0
  115. package/csrc/transform_sha256.c +154 -0
  116. package/csrc/transform_wasm.h +162 -0
  117. package/csrc/transform_wasm_api.c +1373 -0
  118. package/csrc/wasm_api.c +218 -0
  119. package/napi_api.c +534 -0
  120. package/napi_transform.c +1648 -0
  121. package/napi_transform.h +8 -0
  122. package/package.json +64 -59
  123. package/scripts/install-native.js +76 -0
  124. package/scripts/prepack.js +64 -0
  125. package/scripts/sync-csrc.js +23 -0
  126. package/src/cli.js +190 -0
  127. package/src/engines/duckdb.js +142 -0
  128. package/src/index.js +925 -0
  129. package/src/memory_policy.js +411 -0
  130. package/src/native.js +18 -0
  131. package/src/pipeline.js +709 -0
  132. package/src/recipe_json.js +80 -0
  133. package/src/server.js +279 -0
  134. package/src/transform.js +403 -0
  135. package/src/transform_error.js +10 -0
  136. package/src/wasm.js +21 -0
  137. package/wasm/index.js +732 -0
  138. package/wasm/package.json +1 -0
  139. package/wasm/tranfi_core.js +0 -0
  140. package/wasm/transform.js +1156 -0
  141. package/wasm/worker.js +786 -0
  142. package/dist/bundle.js +0 -1
  143. package/index.html +0 -18
  144. package/src/app.css +0 -169
  145. package/src/app.js +0 -203
  146. package/src/app.vue +0 -250
  147. package/src/bulma-input.vue +0 -110
  148. package/src/common-inputs.js +0 -28
  149. package/src/main.js +0 -20
  150. package/src/transforms.js +0 -166
  151. package/webpack.config.js +0 -108
@@ -0,0 +1,293 @@
1
+ /*
2
+ * op_json_flatten.c -- Append declared JSON path fields as columns per row.
3
+ *
4
+ * Config: {"column":"_line", "fields":[{"path":"/user/id", "name":"user_id", "type":"int"}]}
5
+ * This is a bounded row-local flatten: output columns must be declared up front.
6
+ */
7
+
8
+ #include "internal.h"
9
+ #include "cJSON.h"
10
+ #include <ctype.h>
11
+ #include <errno.h>
12
+ #include <stdlib.h>
13
+ #include <string.h>
14
+
15
+ typedef struct {
16
+ char *path;
17
+ char *name;
18
+ tf_type type;
19
+ } json_flatten_field;
20
+
21
+ typedef struct {
22
+ char *column;
23
+ json_flatten_field *fields;
24
+ size_t n_fields;
25
+ } json_flatten_state;
26
+
27
+ static tf_type parse_output_type(const char *s) {
28
+ if (!s || strcmp(s, "string") == 0 || strcmp(s, "str") == 0 || strcmp(s, "json") == 0)
29
+ return TF_TYPE_STRING;
30
+ if (strcmp(s, "int") == 0 || strcmp(s, "int64") == 0)
31
+ return TF_TYPE_INT64;
32
+ if (strcmp(s, "float") == 0 || strcmp(s, "float64") == 0 || strcmp(s, "number") == 0)
33
+ return TF_TYPE_FLOAT64;
34
+ if (strcmp(s, "bool") == 0 || strcmp(s, "boolean") == 0)
35
+ return TF_TYPE_BOOL;
36
+ return TF_TYPE_NULL;
37
+ }
38
+
39
+ static int parse_strict_int64(const char *s, int64_t *out) {
40
+ if (!s) return 0;
41
+ errno = 0;
42
+ char *end = NULL;
43
+ long long v = strtoll(s, &end, 10);
44
+ if (errno != 0 || end == s) return 0;
45
+ while (*end && isspace((unsigned char)*end)) end++;
46
+ if (*end != '\0') return 0;
47
+ *out = (int64_t)v;
48
+ return 1;
49
+ }
50
+
51
+ static int parse_strict_double(const char *s, double *out) {
52
+ if (!s) return 0;
53
+ errno = 0;
54
+ char *end = NULL;
55
+ double v = strtod(s, &end);
56
+ if (errno != 0 || end == s) return 0;
57
+ while (*end && isspace((unsigned char)*end)) end++;
58
+ if (*end != '\0') return 0;
59
+ *out = v;
60
+ return 1;
61
+ }
62
+
63
+ static int str_eq_ci(const char *a, const char *b) {
64
+ while (*a && *b) {
65
+ if (tolower((unsigned char)*a) != tolower((unsigned char)*b)) return 0;
66
+ a++; b++;
67
+ }
68
+ return *a == '\0' && *b == '\0';
69
+ }
70
+
71
+ static int parse_bool_string(const char *s, int *out) {
72
+ if (!s) return 0;
73
+ if (str_eq_ci(s, "true") || strcmp(s, "1") == 0) { *out = 1; return 1; }
74
+ if (str_eq_ci(s, "false") || strcmp(s, "0") == 0) { *out = 0; return 1; }
75
+ return 0;
76
+ }
77
+
78
+ static int set_flattened_value(tf_batch *ob, size_t row, size_t col,
79
+ tf_type type, const cJSON *val) {
80
+ if (!val || cJSON_IsNull(val)) {
81
+ return tf_batch_set_null(ob, row, col);
82
+ }
83
+
84
+ switch (type) {
85
+ case TF_TYPE_STRING: {
86
+ if (cJSON_IsString(val)) {
87
+ return tf_batch_set_string(ob, row, col, val->valuestring ? val->valuestring : "");
88
+ }
89
+ char *printed = cJSON_PrintUnformatted((cJSON *)val);
90
+ if (!printed) return tf_batch_set_null(ob, row, col);
91
+ int rc = tf_batch_set_string(ob, row, col, printed);
92
+ free(printed);
93
+ return rc;
94
+ }
95
+ case TF_TYPE_INT64: {
96
+ int64_t out = 0;
97
+ if (cJSON_IsNumber(val)) return tf_batch_set_int64(ob, row, col, (int64_t)val->valuedouble);
98
+ if (cJSON_IsBool(val)) return tf_batch_set_int64(ob, row, col, cJSON_IsTrue(val) ? 1 : 0);
99
+ if (cJSON_IsString(val) && parse_strict_int64(val->valuestring, &out)) return tf_batch_set_int64(ob, row, col, out);
100
+ return tf_batch_set_null(ob, row, col);
101
+ }
102
+ case TF_TYPE_FLOAT64: {
103
+ double out = 0.0;
104
+ if (cJSON_IsNumber(val)) return tf_batch_set_float64(ob, row, col, val->valuedouble);
105
+ if (cJSON_IsBool(val)) return tf_batch_set_float64(ob, row, col, cJSON_IsTrue(val) ? 1.0 : 0.0);
106
+ if (cJSON_IsString(val) && parse_strict_double(val->valuestring, &out)) return tf_batch_set_float64(ob, row, col, out);
107
+ return tf_batch_set_null(ob, row, col);
108
+ }
109
+ case TF_TYPE_BOOL: {
110
+ int out = 0;
111
+ if (cJSON_IsBool(val)) return tf_batch_set_bool(ob, row, col, cJSON_IsTrue(val));
112
+ if (cJSON_IsNumber(val)) return tf_batch_set_bool(ob, row, col, val->valuedouble != 0.0);
113
+ if (cJSON_IsString(val) && parse_bool_string(val->valuestring, &out)) return tf_batch_set_bool(ob, row, col, out != 0);
114
+ return tf_batch_set_null(ob, row, col);
115
+ }
116
+ default:
117
+ return tf_batch_set_null(ob, row, col);
118
+ }
119
+ }
120
+
121
+ static int json_flatten_process(tf_step *self, tf_batch *in, tf_batch **out,
122
+ tf_side_channels *side) {
123
+ (void)side;
124
+ json_flatten_state *st = self->state;
125
+ *out = NULL;
126
+
127
+ const char **extra_names = NULL;
128
+ tf_type *extra_types = NULL;
129
+ if (st->n_fields > 0) {
130
+ extra_names = malloc(st->n_fields * sizeof(char *));
131
+ extra_types = malloc(st->n_fields * sizeof(tf_type));
132
+ if (!extra_names || !extra_types) {
133
+ free(extra_names);
134
+ free(extra_types);
135
+ return TF_ERROR;
136
+ }
137
+ for (size_t i = 0; i < st->n_fields; i++) {
138
+ extra_names[i] = st->fields[i].name;
139
+ extra_types[i] = st->fields[i].type;
140
+ }
141
+ }
142
+
143
+ tf_batch *ob = tf_batch_create(in->n_cols + st->n_fields, in->n_rows > 0 ? in->n_rows : 1);
144
+ if (!ob) { free(extra_names); free(extra_types); return TF_ERROR; }
145
+ if (tf_batch_clone_with_extra_cols(ob, in, extra_names, extra_types, st->n_fields) != TF_OK) {
146
+ tf_batch_free(ob);
147
+ free(extra_names);
148
+ free(extra_types);
149
+ return TF_ERROR;
150
+ }
151
+ free(extra_names);
152
+ free(extra_types);
153
+
154
+ int ci = tf_batch_col_index(in, st->column);
155
+ int can_parse = ci >= 0 && in->col_types[(size_t)ci] == TF_TYPE_STRING;
156
+
157
+ for (size_t r = 0; r < in->n_rows; r++) {
158
+ if (tf_batch_copy_row(ob, r, in, r) != TF_OK) goto fail;
159
+ for (size_t i = 0; i < st->n_fields; i++) {
160
+ if (tf_batch_set_null(ob, r, in->n_cols + i) != TF_OK) goto fail;
161
+ }
162
+
163
+ cJSON *root = NULL;
164
+ if (can_parse && !tf_batch_is_null(in, r, (size_t)ci)) {
165
+ const char *json = tf_batch_get_string(in, r, (size_t)ci);
166
+ if (json && json[0] != '\0') root = cJSON_Parse(json);
167
+ if (!root && cJSON_ParseHadAllocationFailure()) goto fail;
168
+ }
169
+ if (root) {
170
+ for (size_t i = 0; i < st->n_fields; i++) {
171
+ const cJSON *val = tf_json_path_resolve(root, st->fields[i].path);
172
+ if (set_flattened_value(ob, r, in->n_cols + i, st->fields[i].type, val) != TF_OK) {
173
+ cJSON_Delete(root);
174
+ goto fail;
175
+ }
176
+ }
177
+ cJSON_Delete(root);
178
+ }
179
+ if (tf_batch_expose_row(ob, r) != TF_OK) goto fail;
180
+ }
181
+
182
+ if (ob->n_rows > 0) *out = ob;
183
+ else tf_batch_free(ob);
184
+ return TF_OK;
185
+
186
+ fail:
187
+ tf_batch_free(ob);
188
+ return TF_ERROR;
189
+ }
190
+
191
+ static int json_flatten_flush(tf_step *self, tf_batch **out, tf_side_channels *side) {
192
+ (void)self; (void)side; *out = NULL; return TF_OK;
193
+ }
194
+
195
+ static void json_flatten_field_free(json_flatten_field *f) {
196
+ if (!f) return;
197
+ free(f->path);
198
+ free(f->name);
199
+ }
200
+
201
+ static void json_flatten_state_free(json_flatten_state *st) {
202
+ if (!st) return;
203
+ free(st->column);
204
+ for (size_t i = 0; i < st->n_fields; i++) json_flatten_field_free(&st->fields[i]);
205
+ free(st->fields);
206
+ free(st);
207
+ }
208
+
209
+ static void json_flatten_destroy(tf_step *self) {
210
+ json_flatten_state_free(self ? self->state : NULL);
211
+ free(self);
212
+ }
213
+
214
+ static int parse_field_spec(const char *spec, char **path, char **name, tf_type *type) {
215
+ if (!spec) return 0;
216
+ char *copy = strdup(spec);
217
+ if (!copy) return 0;
218
+ char *first = strchr(copy, ':');
219
+ if (!first) { free(copy); return 0; }
220
+ *first = '\0';
221
+ char *second = strchr(first + 1, ':');
222
+ if (second) *second = '\0';
223
+ const char *type_s = second ? second + 1 : "string";
224
+ tf_type parsed = parse_output_type(type_s);
225
+ if (copy[0] == '\0' || first[1] == '\0' || parsed == TF_TYPE_NULL) {
226
+ free(copy);
227
+ return 0;
228
+ }
229
+ if (tf_json_path_validate(copy) != TF_OK) {
230
+ free(copy);
231
+ return 0;
232
+ }
233
+ *path = strdup(copy);
234
+ *name = strdup(first + 1);
235
+ *type = parsed;
236
+ free(copy);
237
+ return *path && *name;
238
+ }
239
+
240
+ static int init_field_from_json(const cJSON *item, json_flatten_field *field) {
241
+ memset(field, 0, sizeof(*field));
242
+ if (cJSON_IsString(item)) {
243
+ return parse_field_spec(item->valuestring, &field->path, &field->name, &field->type);
244
+ }
245
+ if (!cJSON_IsObject(item)) return 0;
246
+ cJSON *path_j = cJSON_GetObjectItemCaseSensitive(item, "path");
247
+ cJSON *name_j = cJSON_GetObjectItemCaseSensitive(item, "name");
248
+ if (!cJSON_IsString(name_j)) name_j = cJSON_GetObjectItemCaseSensitive(item, "result");
249
+ cJSON *type_j = cJSON_GetObjectItemCaseSensitive(item, "type");
250
+ tf_type type = parse_output_type(cJSON_IsString(type_j) ? type_j->valuestring : "string");
251
+ if (!cJSON_IsString(path_j) || !cJSON_IsString(name_j) ||
252
+ path_j->valuestring[0] == '\0' || name_j->valuestring[0] == '\0' ||
253
+ type == TF_TYPE_NULL) return 0;
254
+ if (tf_json_path_validate(path_j->valuestring) != TF_OK) return 0;
255
+ field->path = strdup(path_j->valuestring);
256
+ field->name = strdup(name_j->valuestring);
257
+ field->type = type;
258
+ return field->path && field->name;
259
+ }
260
+
261
+ tf_step *tf_json_flatten_create(const cJSON *args) {
262
+ if (!args) return NULL;
263
+ cJSON *fields_j = cJSON_GetObjectItemCaseSensitive(args, "fields");
264
+ if (!cJSON_IsArray(fields_j) || cJSON_GetArraySize(fields_j) <= 0) return NULL;
265
+
266
+ cJSON *column_j = cJSON_GetObjectItemCaseSensitive(args, "column");
267
+ const char *column = cJSON_IsString(column_j) && column_j->valuestring[0] != '\0'
268
+ ? column_j->valuestring : "_line";
269
+
270
+ int n_fields = cJSON_GetArraySize(fields_j);
271
+ json_flatten_state *st = calloc(1, sizeof(json_flatten_state));
272
+ if (!st) return NULL;
273
+ st->column = strdup(column);
274
+ st->fields = calloc((size_t)n_fields, sizeof(json_flatten_field));
275
+ st->n_fields = (size_t)n_fields;
276
+ if (!st->column || !st->fields) { json_flatten_state_free(st); return NULL; }
277
+
278
+ for (int i = 0; i < n_fields; i++) {
279
+ cJSON *item = cJSON_GetArrayItem(fields_j, i);
280
+ if (!init_field_from_json(item, &st->fields[i])) {
281
+ json_flatten_state_free(st);
282
+ return NULL;
283
+ }
284
+ }
285
+
286
+ tf_step *step = calloc(1, sizeof(tf_step));
287
+ if (!step) { json_flatten_state_free(st); return NULL; }
288
+ step->process = json_flatten_process;
289
+ step->flush = json_flatten_flush;
290
+ step->destroy = json_flatten_destroy;
291
+ step->state = st;
292
+ return step;
293
+ }