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.
- package/LICENSE +177 -0
- package/NOTICE +8 -0
- package/README.md +272 -40
- package/app/assets/{index-pDFMluyz.js → index-BIAIKnrp.js} +1 -1
- package/app/index.html +1 -1
- package/binding.gyp +55 -3
- package/csrc/arena.c +7 -5
- package/csrc/batch.c +818 -71
- package/csrc/buffer.c +84 -8
- package/csrc/cJSON.c +262 -19
- package/csrc/cJSON.h +17 -1
- package/csrc/codec_csv.c +1074 -181
- package/csrc/codec_jsonl.c +830 -118
- package/csrc/codec_table.c +108 -78
- package/csrc/codec_text.c +286 -68
- package/csrc/compiler.c +31 -3
- package/csrc/config.h +21 -0
- package/csrc/dsl.c +4722 -485
- package/csrc/expr.c +363 -55
- package/csrc/expr.h +2 -0
- package/csrc/internal.h +316 -27
- package/csrc/ir.c +65 -18
- package/csrc/ir.h +41 -0
- package/csrc/ir_schema.c +20 -5
- package/csrc/ir_serialize.c +68 -6
- package/csrc/ir_sql.c +796 -185
- package/csrc/ir_validate.c +462 -6
- package/csrc/json_path.c +210 -0
- package/csrc/main.c +879 -30
- package/csrc/memory_estimate.c +477 -0
- package/csrc/op_acf.c +171 -21
- package/csrc/op_across.c +477 -0
- package/csrc/op_anomaly.c +167 -32
- package/csrc/op_assert.c +761 -0
- package/csrc/op_bin.c +168 -29
- package/csrc/op_cast.c +383 -55
- package/csrc/op_clip.c +30 -19
- package/csrc/op_date_trunc.c +208 -34
- package/csrc/op_datetime.c +259 -77
- package/csrc/op_derive.c +65 -97
- package/csrc/op_diff.c +146 -30
- package/csrc/op_ewma.c +149 -30
- package/csrc/op_explode.c +124 -26
- package/csrc/op_fill_down.c +125 -53
- package/csrc/op_fill_null.c +176 -31
- package/csrc/op_filter.c +89 -40
- package/csrc/op_frequency.c +571 -43
- package/csrc/op_grep.c +36 -18
- package/csrc/op_group_agg.c +1790 -119
- package/csrc/op_hash.c +48 -15
- package/csrc/op_head.c +21 -86
- package/csrc/op_interpolate.c +268 -62
- package/csrc/op_join.c +2700 -182
- package/csrc/op_json_extract.c +227 -0
- package/csrc/op_json_filter.c +384 -0
- package/csrc/op_json_flatten.c +293 -0
- package/csrc/op_json_schema.c +503 -0
- package/csrc/op_label_encode.c +328 -53
- package/csrc/op_lag.c +181 -0
- package/csrc/op_lead.c +141 -89
- package/csrc/op_normalize.c +363 -79
- package/csrc/op_onehot.c +345 -73
- package/csrc/op_pivot.c +1546 -162
- package/csrc/op_quarantine.c +189 -0
- package/csrc/op_registry.c +2062 -166
- package/csrc/op_rename.c +41 -50
- package/csrc/op_replace.c +270 -118
- package/csrc/op_rleid.c +297 -0
- package/csrc/op_rowid.c +559 -0
- package/csrc/op_sample.c +80 -23
- package/csrc/op_schema.c +1341 -0
- package/csrc/op_schema_infer.c +252 -0
- package/csrc/op_select.c +265 -65
- package/csrc/op_set.c +3449 -0
- package/csrc/op_skip.c +30 -87
- package/csrc/op_sort.c +670 -124
- package/csrc/op_source_name.c +120 -0
- package/csrc/op_split.c +65 -28
- package/csrc/op_split_data.c +41 -9
- package/csrc/op_stack.c +178 -222
- package/csrc/op_stats.c +206 -110
- package/csrc/op_step.c +217 -55
- package/csrc/op_tail.c +21 -12
- package/csrc/op_tee.c +338 -0
- package/csrc/op_top.c +260 -53
- package/csrc/op_trim.c +48 -19
- package/csrc/op_unique.c +1193 -150
- package/csrc/op_unpivot.c +100 -66
- package/csrc/op_validate.c +601 -24
- package/csrc/op_window.c +492 -51
- package/csrc/path_policy.c +85 -0
- package/csrc/pipeline.c +872 -99
- package/csrc/recipes.c +3 -1
- package/csrc/report.c +73 -30
- package/csrc/selector.c +1097 -0
- package/csrc/size_utils.c +348 -0
- package/csrc/spill.c +317 -0
- package/csrc/spill.h +21 -0
- package/csrc/tranfi.h +169 -1
- package/csrc/transform.h +209 -0
- package/csrc/transform_api.c +2237 -0
- package/csrc/transform_categorical.c +923 -0
- package/csrc/transform_internal.h +472 -0
- package/csrc/transform_json.c +3812 -0
- package/csrc/transform_numeric.c +1966 -0
- package/csrc/transform_sha256.c +154 -0
- package/csrc/transform_wasm.h +162 -0
- package/csrc/transform_wasm_api.c +1373 -0
- package/csrc/wasm_api.c +70 -9
- package/napi_api.c +219 -11
- package/napi_transform.c +1648 -0
- package/napi_transform.h +8 -0
- package/package.json +27 -11
- package/scripts/install-native.js +76 -0
- package/scripts/prepack.js +64 -0
- package/scripts/sync-csrc.js +23 -0
- package/src/cli.js +8 -11
- package/src/engines/duckdb.js +45 -12
- package/src/index.js +661 -42
- package/src/memory_policy.js +411 -0
- package/src/native.js +1 -5
- package/src/pipeline.js +454 -31
- package/src/recipe_json.js +80 -0
- package/src/server.js +10 -8
- package/src/transform.js +403 -0
- package/src/transform_error.js +10 -0
- package/src/wasm.js +6 -4
- package/wasm/index.js +498 -10
- package/wasm/tranfi_core.js +0 -0
- package/wasm/transform.js +1156 -0
- package/wasm/worker.js +786 -0
- package/csrc/plan.c +0 -206
package/csrc/op_bin.c
CHANGED
|
@@ -10,59 +10,173 @@
|
|
|
10
10
|
#include <stdlib.h>
|
|
11
11
|
#include <string.h>
|
|
12
12
|
#include <stdio.h>
|
|
13
|
+
#include <math.h>
|
|
14
|
+
|
|
15
|
+
typedef enum {
|
|
16
|
+
BIN_MISSING_ERROR,
|
|
17
|
+
BIN_MISSING_NULL,
|
|
18
|
+
BIN_MISSING_IGNORE,
|
|
19
|
+
} bin_missing_policy;
|
|
20
|
+
|
|
21
|
+
typedef enum {
|
|
22
|
+
BIN_TYPE_FAIL,
|
|
23
|
+
BIN_TYPE_NULL,
|
|
24
|
+
} bin_type_policy;
|
|
13
25
|
|
|
14
26
|
typedef struct {
|
|
15
27
|
char *column;
|
|
16
28
|
double *boundaries;
|
|
17
29
|
size_t n_boundaries;
|
|
30
|
+
bin_missing_policy missing;
|
|
31
|
+
bin_type_policy on_type_error;
|
|
18
32
|
} bin_state;
|
|
19
33
|
|
|
34
|
+
static int bin_is_numeric_type(tf_type type) {
|
|
35
|
+
return type == TF_TYPE_INT64 || type == TF_TYPE_FLOAT64;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static double bin_get_numeric(const tf_batch *b, size_t r, int ci) {
|
|
39
|
+
if (b->col_types[ci] == TF_TYPE_INT64) return (double)tf_batch_get_int64(b, r, ci);
|
|
40
|
+
return tf_batch_get_float64(b, r, ci);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static void bin_set_col_error(const char *column, const char *suffix) {
|
|
44
|
+
char msg[512];
|
|
45
|
+
snprintf(msg, sizeof(msg), "bin: column '%s' %s", column ? column : "", suffix);
|
|
46
|
+
tf_set_last_error(msg);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static int bin_parse_missing_policy(const cJSON *args, bin_missing_policy *out) {
|
|
50
|
+
*out = BIN_MISSING_ERROR;
|
|
51
|
+
const cJSON *j = cJSON_GetObjectItemCaseSensitive(args, "missing");
|
|
52
|
+
if (!j) return TF_OK;
|
|
53
|
+
if (!cJSON_IsString(j)) {
|
|
54
|
+
tf_set_last_error("bin: missing must be error, null, or ignore");
|
|
55
|
+
return TF_ERROR;
|
|
56
|
+
}
|
|
57
|
+
if (strcmp(j->valuestring, "error") == 0) *out = BIN_MISSING_ERROR;
|
|
58
|
+
else if (strcmp(j->valuestring, "null") == 0) *out = BIN_MISSING_NULL;
|
|
59
|
+
else if (strcmp(j->valuestring, "ignore") == 0) *out = BIN_MISSING_IGNORE;
|
|
60
|
+
else {
|
|
61
|
+
tf_set_last_error("bin: missing must be error, null, or ignore");
|
|
62
|
+
return TF_ERROR;
|
|
63
|
+
}
|
|
64
|
+
return TF_OK;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static int bin_parse_type_policy(const cJSON *args, bin_type_policy *out) {
|
|
68
|
+
*out = BIN_TYPE_FAIL;
|
|
69
|
+
const cJSON *j = cJSON_GetObjectItemCaseSensitive(args, "on_type_error");
|
|
70
|
+
if (!j) return TF_OK;
|
|
71
|
+
if (!cJSON_IsString(j)) {
|
|
72
|
+
tf_set_last_error("bin: on_type_error must be fail or null");
|
|
73
|
+
return TF_ERROR;
|
|
74
|
+
}
|
|
75
|
+
if (strcmp(j->valuestring, "fail") == 0) *out = BIN_TYPE_FAIL;
|
|
76
|
+
else if (strcmp(j->valuestring, "null") == 0) *out = BIN_TYPE_NULL;
|
|
77
|
+
else {
|
|
78
|
+
tf_set_last_error("bin: on_type_error must be fail or null");
|
|
79
|
+
return TF_ERROR;
|
|
80
|
+
}
|
|
81
|
+
return TF_OK;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static int bin_passthrough(tf_batch *in, tf_batch **out) {
|
|
85
|
+
tf_batch *ob = tf_batch_create(in->n_cols, in->n_rows);
|
|
86
|
+
if (!ob) return TF_ERROR;
|
|
87
|
+
if (tf_batch_clone_schema(ob, in) != TF_OK) {
|
|
88
|
+
tf_batch_free(ob);
|
|
89
|
+
return TF_ERROR;
|
|
90
|
+
}
|
|
91
|
+
for (size_t r = 0; r < in->n_rows; r++) {
|
|
92
|
+
if (tf_batch_copy_row(ob, r, in, r) != TF_OK) {
|
|
93
|
+
tf_batch_free(ob);
|
|
94
|
+
return TF_ERROR;
|
|
95
|
+
}
|
|
96
|
+
if (tf_batch_expose_row(ob, r) != TF_OK) {
|
|
97
|
+
tf_batch_free(ob);
|
|
98
|
+
return TF_ERROR;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
*out = ob;
|
|
102
|
+
return TF_OK;
|
|
103
|
+
}
|
|
104
|
+
|
|
20
105
|
static int bin_process(tf_step *self, tf_batch *in, tf_batch **out,
|
|
21
106
|
tf_side_channels *side) {
|
|
22
107
|
(void)side;
|
|
23
108
|
bin_state *st = self->state;
|
|
24
109
|
*out = NULL;
|
|
25
110
|
|
|
26
|
-
|
|
27
|
-
|
|
111
|
+
int ci = tf_batch_col_index(in, st->column);
|
|
112
|
+
int force_null = 0;
|
|
113
|
+
if (ci < 0) {
|
|
114
|
+
if (st->missing == BIN_MISSING_ERROR) {
|
|
115
|
+
bin_set_col_error(st->column, "not found");
|
|
116
|
+
return TF_ERROR;
|
|
117
|
+
}
|
|
118
|
+
if (st->missing == BIN_MISSING_IGNORE) return bin_passthrough(in, out);
|
|
119
|
+
force_null = 1;
|
|
120
|
+
} else if (!bin_is_numeric_type(in->col_types[ci])) {
|
|
121
|
+
if (st->on_type_error == BIN_TYPE_FAIL) {
|
|
122
|
+
bin_set_col_error(st->column, "must be numeric");
|
|
123
|
+
return TF_ERROR;
|
|
124
|
+
}
|
|
125
|
+
force_null = 1;
|
|
126
|
+
}
|
|
28
127
|
|
|
128
|
+
char *bin_col_name = tf_string_append_suffix_checked(st->column, "_bin");
|
|
129
|
+
if (!bin_col_name) return TF_ERROR;
|
|
130
|
+
const char *extra_names[1] = {bin_col_name};
|
|
131
|
+
tf_type extra_types[1] = {TF_TYPE_STRING};
|
|
29
132
|
tf_batch *ob = tf_batch_create(in->n_cols + 1, in->n_rows);
|
|
30
|
-
if (!ob)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
133
|
+
if (!ob) {
|
|
134
|
+
free(bin_col_name);
|
|
135
|
+
return TF_ERROR;
|
|
136
|
+
}
|
|
137
|
+
if (tf_batch_clone_with_extra_cols(ob, in, extra_names, extra_types, 1) != TF_OK) {
|
|
138
|
+
free(bin_col_name);
|
|
139
|
+
tf_batch_free(ob);
|
|
140
|
+
return TF_ERROR;
|
|
141
|
+
}
|
|
142
|
+
free(bin_col_name);
|
|
36
143
|
|
|
37
144
|
for (size_t r = 0; r < in->n_rows; r++) {
|
|
38
|
-
tf_batch_copy_row(ob, r, in, r)
|
|
145
|
+
if (tf_batch_copy_row(ob, r, in, r) != TF_OK) {
|
|
146
|
+
tf_batch_free(ob);
|
|
147
|
+
return TF_ERROR;
|
|
148
|
+
}
|
|
39
149
|
|
|
40
|
-
if (
|
|
41
|
-
tf_batch_set_null(ob, r, in->n_cols);
|
|
150
|
+
if (force_null || tf_batch_is_null(in, r, ci)) {
|
|
151
|
+
if (tf_batch_set_null(ob, r, in->n_cols) != TF_OK) { tf_batch_free(ob); return TF_ERROR; }
|
|
42
152
|
} else {
|
|
43
|
-
double val =
|
|
44
|
-
if (in->col_types[ci] == TF_TYPE_INT64) val = (double)tf_batch_get_int64(in, r, ci);
|
|
45
|
-
else if (in->col_types[ci] == TF_TYPE_FLOAT64) val = tf_batch_get_float64(in, r, ci);
|
|
153
|
+
double val = bin_get_numeric(in, r, ci);
|
|
46
154
|
|
|
47
155
|
char label[64];
|
|
48
156
|
if (st->n_boundaries == 0) {
|
|
49
|
-
snprintf(label, sizeof(label),
|
|
157
|
+
snprintf(label, sizeof(label), TF_FLOAT64_ROUNDTRIP_FORMAT, val);
|
|
50
158
|
} else if (val < st->boundaries[0]) {
|
|
51
|
-
snprintf(label, sizeof(label), "
|
|
159
|
+
snprintf(label, sizeof(label), "<" TF_FLOAT64_ROUNDTRIP_FORMAT, st->boundaries[0]);
|
|
52
160
|
} else {
|
|
53
161
|
size_t b;
|
|
54
162
|
for (b = 1; b < st->n_boundaries; b++) {
|
|
55
163
|
if (val < st->boundaries[b]) break;
|
|
56
164
|
}
|
|
57
165
|
if (b < st->n_boundaries) {
|
|
58
|
-
snprintf(label, sizeof(label), "
|
|
166
|
+
snprintf(label, sizeof(label), TF_FLOAT64_ROUNDTRIP_FORMAT "-" TF_FLOAT64_ROUNDTRIP_FORMAT, st->boundaries[b - 1], st->boundaries[b]);
|
|
59
167
|
} else {
|
|
60
|
-
snprintf(label, sizeof(label), "
|
|
168
|
+
snprintf(label, sizeof(label), TF_FLOAT64_ROUNDTRIP_FORMAT "+", st->boundaries[st->n_boundaries - 1]);
|
|
61
169
|
}
|
|
62
170
|
}
|
|
63
|
-
tf_batch_set_string(ob, r, in->n_cols, label)
|
|
171
|
+
if (tf_batch_set_string(ob, r, in->n_cols, label) != TF_OK) {
|
|
172
|
+
tf_batch_free(ob);
|
|
173
|
+
return TF_ERROR;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (tf_batch_expose_row(ob, r) != TF_OK) {
|
|
177
|
+
tf_batch_free(ob);
|
|
178
|
+
return TF_ERROR;
|
|
64
179
|
}
|
|
65
|
-
ob->n_rows = r + 1;
|
|
66
180
|
}
|
|
67
181
|
|
|
68
182
|
*out = ob;
|
|
@@ -82,24 +196,49 @@ static void bin_destroy(tf_step *self) {
|
|
|
82
196
|
tf_step *tf_bin_create(const cJSON *args) {
|
|
83
197
|
if (!args) return NULL;
|
|
84
198
|
cJSON *col_j = cJSON_GetObjectItemCaseSensitive(args, "column");
|
|
85
|
-
if (!cJSON_IsString(col_j))
|
|
199
|
+
if (!cJSON_IsString(col_j) || !col_j->valuestring[0]) {
|
|
200
|
+
tf_set_last_error("bin: column is required");
|
|
201
|
+
return NULL;
|
|
202
|
+
}
|
|
86
203
|
|
|
87
|
-
bin_state *st =
|
|
204
|
+
bin_state *st = tf_callocarray_checked(1, sizeof(bin_state));
|
|
88
205
|
if (!st) return NULL;
|
|
89
|
-
st->column =
|
|
206
|
+
st->column = tf_strdup_checked(col_j->valuestring);
|
|
207
|
+
if (!st->column) { free(st); return NULL; }
|
|
208
|
+
if (bin_parse_missing_policy(args, &st->missing) != TF_OK ||
|
|
209
|
+
bin_parse_type_policy(args, &st->on_type_error) != TF_OK) {
|
|
210
|
+
free(st->column);
|
|
211
|
+
free(st);
|
|
212
|
+
return NULL;
|
|
213
|
+
}
|
|
90
214
|
|
|
91
215
|
cJSON *bounds = cJSON_GetObjectItemCaseSensitive(args, "boundaries");
|
|
92
|
-
if (bounds
|
|
93
|
-
|
|
94
|
-
st->
|
|
95
|
-
st
|
|
216
|
+
if (!bounds || !cJSON_IsArray(bounds)) {
|
|
217
|
+
tf_set_last_error("bin: boundaries must be an array");
|
|
218
|
+
free(st->column);
|
|
219
|
+
free(st);
|
|
220
|
+
return NULL;
|
|
221
|
+
}
|
|
222
|
+
int n = cJSON_GetArraySize(bounds);
|
|
223
|
+
if (n > 0) {
|
|
224
|
+
st->boundaries = tf_mallocarray_checked((size_t)n, sizeof(double));
|
|
225
|
+
if (!st->boundaries) { free(st->column); free(st); return NULL; }
|
|
226
|
+
st->n_boundaries = (size_t)n;
|
|
96
227
|
for (int i = 0; i < n; i++) {
|
|
97
228
|
cJSON *item = cJSON_GetArrayItem(bounds, i);
|
|
98
|
-
|
|
229
|
+
if (!cJSON_IsNumber(item) || !isfinite(item->valuedouble)) {
|
|
230
|
+
tf_set_last_error("bin: boundaries must be finite, strictly increasing numbers");
|
|
231
|
+
free(st->column); free(st->boundaries); free(st); return NULL;
|
|
232
|
+
}
|
|
233
|
+
if (i > 0 && item->valuedouble <= st->boundaries[i - 1]) {
|
|
234
|
+
tf_set_last_error("bin: boundaries must be finite, strictly increasing numbers");
|
|
235
|
+
free(st->column); free(st->boundaries); free(st); return NULL;
|
|
236
|
+
}
|
|
237
|
+
st->boundaries[i] = item->valuedouble;
|
|
99
238
|
}
|
|
100
239
|
}
|
|
101
240
|
|
|
102
|
-
tf_step *step =
|
|
241
|
+
tf_step *step = tf_callocarray_checked(1, sizeof(tf_step));
|
|
103
242
|
if (!step) { free(st->column); free(st->boundaries); free(st); return NULL; }
|
|
104
243
|
step->process = bin_process;
|
|
105
244
|
step->flush = bin_flush;
|