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.
- package/LICENSE +177 -0
- package/NOTICE +8 -0
- package/README.md +443 -51
- 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 +352 -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 +81 -41
- 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
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* op_quarantine.c -- Route matching rows to the errors side channel.
|
|
3
|
+
*
|
|
4
|
+
* Config: {"expr":"col('age') < 0", "name":"rule", "message":"bad row"}
|
|
5
|
+
* Keeps rows where expr is false. Rows where expr is true, or where the
|
|
6
|
+
* predicate cannot be evaluated, are dropped from main and emitted to errors.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "internal.h"
|
|
10
|
+
#include "cJSON.h"
|
|
11
|
+
#include <stdio.h>
|
|
12
|
+
#include <stdlib.h>
|
|
13
|
+
#include <string.h>
|
|
14
|
+
|
|
15
|
+
#ifndef HAVE_STRDUP
|
|
16
|
+
extern char *strdup(const char *);
|
|
17
|
+
#endif
|
|
18
|
+
|
|
19
|
+
typedef struct {
|
|
20
|
+
tf_expr *expr;
|
|
21
|
+
char *expr_text;
|
|
22
|
+
char *name;
|
|
23
|
+
char *message;
|
|
24
|
+
size_t row_index;
|
|
25
|
+
size_t checked_rows;
|
|
26
|
+
size_t kept_rows;
|
|
27
|
+
size_t quarantined_rows;
|
|
28
|
+
tf_audit_options audit_opts;
|
|
29
|
+
} quarantine_state;
|
|
30
|
+
|
|
31
|
+
static int emit_quarantine_record(quarantine_state *st, const tf_batch *b, size_t row,
|
|
32
|
+
tf_side_channels *side, const char *reason) {
|
|
33
|
+
if (!side || !side->errors) return TF_OK;
|
|
34
|
+
cJSON *obj = cJSON_CreateObject();
|
|
35
|
+
if (!obj) return TF_ERROR;
|
|
36
|
+
int rc = TF_ERROR;
|
|
37
|
+
if (tf_json_add_string(obj, "type", "quarantine") != TF_OK ||
|
|
38
|
+
tf_json_add_string(obj, "op", "quarantine") != TF_OK ||
|
|
39
|
+
tf_json_add_string(obj, "event", "row_quarantined") != TF_OK ||
|
|
40
|
+
tf_json_add_string(obj, "reason", reason ? reason : "predicate_true") != TF_OK ||
|
|
41
|
+
tf_json_add_string(obj, "severity", "error") != TF_OK ||
|
|
42
|
+
tf_json_add_string(obj, "name", st->name ? st->name : "quarantine") != TF_OK ||
|
|
43
|
+
tf_json_add_string(obj, "expr", st->expr_text ? st->expr_text : "") != TF_OK ||
|
|
44
|
+
tf_json_add_number(obj, "row", (double)st->row_index) != TF_OK) {
|
|
45
|
+
goto done;
|
|
46
|
+
}
|
|
47
|
+
if (st->message && st->message[0] &&
|
|
48
|
+
tf_json_add_string(obj, "message", st->message) != TF_OK) {
|
|
49
|
+
goto done;
|
|
50
|
+
}
|
|
51
|
+
cJSON *row_obj = tf_audit_row_to_json(b, row, &st->audit_opts);
|
|
52
|
+
if (row_obj) {
|
|
53
|
+
if (tf_json_add_item(obj, "data", row_obj) != TF_OK) goto done;
|
|
54
|
+
} else if (st->audit_opts.include_row) {
|
|
55
|
+
goto done;
|
|
56
|
+
}
|
|
57
|
+
rc = tf_buffer_write_json_line(side->errors, obj);
|
|
58
|
+
done:
|
|
59
|
+
cJSON_Delete(obj);
|
|
60
|
+
return rc;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static int quarantine_process(tf_step *self, tf_batch *in, tf_batch **out,
|
|
64
|
+
tf_side_channels *side) {
|
|
65
|
+
quarantine_state *st = self->state;
|
|
66
|
+
*out = NULL;
|
|
67
|
+
|
|
68
|
+
tf_batch *ob = tf_batch_create(in->n_cols, in->n_rows > 0 ? in->n_rows : 1);
|
|
69
|
+
if (!ob) return TF_ERROR;
|
|
70
|
+
if (tf_batch_clone_schema(ob, in) != TF_OK) { tf_batch_free(ob); return TF_ERROR; }
|
|
71
|
+
|
|
72
|
+
size_t out_row = 0;
|
|
73
|
+
for (size_t r = 0; r < in->n_rows; r++) {
|
|
74
|
+
st->row_index++;
|
|
75
|
+
st->checked_rows++;
|
|
76
|
+
bool should_quarantine = false;
|
|
77
|
+
int eval_ok = tf_expr_eval(st->expr, in, r, &should_quarantine) == TF_OK;
|
|
78
|
+
if (!eval_ok || should_quarantine) {
|
|
79
|
+
st->quarantined_rows++;
|
|
80
|
+
if (emit_quarantine_record(st, in, r, side, eval_ok ? "predicate_true" : "predicate_error") != TF_OK) {
|
|
81
|
+
tf_batch_free(ob);
|
|
82
|
+
return TF_ERROR;
|
|
83
|
+
}
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (tf_batch_copy_row(ob, out_row, in, r) != TF_OK) {
|
|
88
|
+
tf_batch_free(ob);
|
|
89
|
+
return TF_ERROR;
|
|
90
|
+
}
|
|
91
|
+
if (tf_batch_expose_row(ob, out_row) != TF_OK) {
|
|
92
|
+
tf_batch_free(ob);
|
|
93
|
+
return TF_ERROR;
|
|
94
|
+
}
|
|
95
|
+
out_row++;
|
|
96
|
+
st->kept_rows++;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (out_row > 0 || in->n_rows == 0) *out = ob;
|
|
100
|
+
else tf_batch_free(ob);
|
|
101
|
+
return TF_OK;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
static int quarantine_flush(tf_step *self, tf_batch **out, tf_side_channels *side) {
|
|
105
|
+
(void)self; (void)side;
|
|
106
|
+
*out = NULL;
|
|
107
|
+
return TF_OK;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static int quarantine_append_stats(tf_step *self, tf_buffer *out) {
|
|
111
|
+
if (!self || !self->state || !out) return TF_ERROR;
|
|
112
|
+
quarantine_state *st = self->state;
|
|
113
|
+
char buf[192];
|
|
114
|
+
snprintf(buf, sizeof(buf),
|
|
115
|
+
",\"checked_rows\":%zu,\"kept_rows\":%zu,\"quarantined_rows\":%zu",
|
|
116
|
+
st->checked_rows, st->kept_rows, st->quarantined_rows);
|
|
117
|
+
return tf_buffer_write_str(out, buf);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
static void quarantine_destroy(tf_step *self) {
|
|
121
|
+
if (!self) return;
|
|
122
|
+
quarantine_state *st = self->state;
|
|
123
|
+
if (st) {
|
|
124
|
+
tf_expr_free(st->expr);
|
|
125
|
+
free(st->expr_text);
|
|
126
|
+
free(st->name);
|
|
127
|
+
free(st->message);
|
|
128
|
+
tf_audit_options_free(&st->audit_opts);
|
|
129
|
+
free(st);
|
|
130
|
+
}
|
|
131
|
+
free(self);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
tf_step *tf_quarantine_create(const cJSON *args) {
|
|
135
|
+
if (!args) return NULL;
|
|
136
|
+
cJSON *expr_json = cJSON_GetObjectItemCaseSensitive(args, "expr");
|
|
137
|
+
if (!cJSON_IsString(expr_json) || !expr_json->valuestring[0]) {
|
|
138
|
+
tf_set_last_error("quarantine: expr is required");
|
|
139
|
+
return NULL;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
tf_expr *expr = tf_expr_parse(expr_json->valuestring);
|
|
143
|
+
if (!expr) return NULL;
|
|
144
|
+
|
|
145
|
+
quarantine_state *st = calloc(1, sizeof(quarantine_state));
|
|
146
|
+
if (!st) { tf_expr_free(expr); return NULL; }
|
|
147
|
+
tf_audit_options_init(&st->audit_opts, 1);
|
|
148
|
+
st->expr = expr;
|
|
149
|
+
st->expr_text = strdup(expr_json->valuestring);
|
|
150
|
+
cJSON *name_json = cJSON_GetObjectItemCaseSensitive(args, "name");
|
|
151
|
+
cJSON *message_json = cJSON_GetObjectItemCaseSensitive(args, "message");
|
|
152
|
+
st->name = strdup(cJSON_IsString(name_json) && name_json->valuestring[0] ? name_json->valuestring : "quarantine");
|
|
153
|
+
st->message = strdup(cJSON_IsString(message_json) ? message_json->valuestring : "");
|
|
154
|
+
if (!st->expr_text || !st->name || !st->message) {
|
|
155
|
+
tf_expr_free(expr);
|
|
156
|
+
free(st->expr_text);
|
|
157
|
+
free(st->name);
|
|
158
|
+
free(st->message);
|
|
159
|
+
tf_audit_options_free(&st->audit_opts);
|
|
160
|
+
free(st);
|
|
161
|
+
return NULL;
|
|
162
|
+
}
|
|
163
|
+
if (tf_audit_options_parse(&st->audit_opts, args, "quarantine") != TF_OK) {
|
|
164
|
+
tf_expr_free(expr);
|
|
165
|
+
free(st->expr_text);
|
|
166
|
+
free(st->name);
|
|
167
|
+
free(st->message);
|
|
168
|
+
tf_audit_options_free(&st->audit_opts);
|
|
169
|
+
free(st);
|
|
170
|
+
return NULL;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
tf_step *step = calloc(1, sizeof(tf_step));
|
|
174
|
+
if (!step) {
|
|
175
|
+
tf_expr_free(st->expr);
|
|
176
|
+
free(st->expr_text);
|
|
177
|
+
free(st->name);
|
|
178
|
+
free(st->message);
|
|
179
|
+
tf_audit_options_free(&st->audit_opts);
|
|
180
|
+
free(st);
|
|
181
|
+
return NULL;
|
|
182
|
+
}
|
|
183
|
+
step->process = quarantine_process;
|
|
184
|
+
step->flush = quarantine_flush;
|
|
185
|
+
step->append_stats = quarantine_append_stats;
|
|
186
|
+
step->destroy = quarantine_destroy;
|
|
187
|
+
step->state = st;
|
|
188
|
+
return step;
|
|
189
|
+
}
|