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/ir.h CHANGED
@@ -8,6 +8,7 @@
8
8
  #ifndef TF_IR_H
9
9
  #define TF_IR_H
10
10
 
11
+ #include "config.h"
11
12
  #include <stddef.h>
12
13
  #include <stdint.h>
13
14
  #include <stdbool.h>
@@ -16,6 +17,7 @@
16
17
  typedef struct cJSON cJSON;
17
18
  typedef struct tf_ir_node tf_ir_node;
18
19
  typedef struct tf_schema tf_schema;
20
+ typedef struct tf_host_policy tf_host_policy;
19
21
 
20
22
  /* ---- Capability flags ---- */
21
23
 
@@ -41,6 +43,29 @@ typedef enum {
41
43
  TF_OP_TRANSFORM,
42
44
  } tf_op_kind;
43
45
 
46
+ /* ---- Streaming contract metadata ---- */
47
+
48
+ typedef enum {
49
+ TF_MEM_ROW_LOCAL, /* O(batch_rows * columns) */
50
+ TF_MEM_BOUNDED_STATE, /* O(parameter), e.g. window K or tail N */
51
+ TF_MEM_KEY_STATE, /* O(distinct keys/categories) */
52
+ TF_MEM_BLOCKING, /* needs full input in native mode */
53
+ TF_MEM_EXTERNAL, /* uses spill/SQL/external bounded storage */
54
+ } tf_memory_class;
55
+
56
+ typedef enum {
57
+ TF_EMIT_PER_BATCH, /* can emit during push() */
58
+ TF_EMIT_ON_FLUSH, /* emits only at finish(), e.g. tail/top/stats */
59
+ TF_EMIT_SIDE_ONLY, /* writes side channels, not main output */
60
+ TF_EMIT_MIXED, /* emits both during push() and flush/side output */
61
+ } tf_emit_class;
62
+
63
+ typedef enum {
64
+ TF_SCHEMA_STABLE, /* output columns known from input schema/args */
65
+ TF_SCHEMA_PARAMETRIC, /* output schema depends on explicit parameters */
66
+ TF_SCHEMA_DATA_DEPENDENT, /* output schema depends on observed data */
67
+ } tf_schema_class;
68
+
44
69
  /* ---- Argument descriptor ---- */
45
70
 
46
71
  typedef struct {
@@ -52,6 +77,8 @@ typedef struct {
52
77
 
53
78
  /* ---- Value types (shared with batch system) ---- */
54
79
 
80
+ #ifndef TF_TYPE_DEFINED
81
+ #define TF_TYPE_DEFINED
55
82
  typedef enum tf_type {
56
83
  TF_TYPE_NULL = 0,
57
84
  TF_TYPE_BOOL,
@@ -61,6 +88,7 @@ typedef enum tf_type {
61
88
  TF_TYPE_DATE, /* int32_t: days since 1970-01-01 */
62
89
  TF_TYPE_TIMESTAMP, /* int64_t: microseconds since 1970-01-01T00:00:00Z */
63
90
  } tf_type;
91
+ #endif
64
92
 
65
93
  /* ---- Schema ---- */
66
94
 
@@ -73,6 +101,7 @@ struct tf_schema {
73
101
 
74
102
  void tf_schema_free(tf_schema *s);
75
103
  void tf_schema_copy(tf_schema *dst, const tf_schema *src);
104
+ int tf_schema_copy_checked(tf_schema *dst, const tf_schema *src);
76
105
 
77
106
  /* ---- Op registry entry ---- */
78
107
 
@@ -81,6 +110,10 @@ typedef struct {
81
110
  tf_op_kind kind;
82
111
  tf_op_tier tier;
83
112
  uint32_t caps; /* TF_CAP_* bitfield */
113
+ tf_memory_class memory_class;
114
+ tf_emit_class emit_class;
115
+ tf_schema_class schema_class;
116
+ const char *state_estimate; /* Big-O state retained by the op */
84
117
  tf_arg_desc *args;
85
118
  size_t n_args;
86
119
  /* Schema transform: given input schema, compute output schema.
@@ -97,6 +130,9 @@ typedef struct {
97
130
  const tf_op_entry *tf_op_registry_find(const char *name);
98
131
  size_t tf_op_registry_count(void);
99
132
  const tf_op_entry *tf_op_registry_get(size_t index);
133
+ const char *tf_memory_class_name(tf_memory_class cls);
134
+ const char *tf_emit_class_name(tf_emit_class cls);
135
+ const char *tf_schema_class_name(tf_schema_class cls);
100
136
 
101
137
  /* ---- IR node ---- */
102
138
 
@@ -106,6 +142,10 @@ struct tf_ir_node {
106
142
  tf_schema input_schema;
107
143
  tf_schema output_schema;
108
144
  uint32_t caps; /* resolved capability flags from registry */
145
+ tf_memory_class memory_class;
146
+ tf_emit_class emit_class;
147
+ tf_schema_class schema_class;
148
+ const char *state_estimate; /* Big-O state estimate, static string */
109
149
  size_t index; /* position in plan */
110
150
  };
111
151
 
@@ -138,6 +178,7 @@ char *tf_ir_to_sql(const tf_ir_plan *plan, char **error);
138
178
  /* ---- IR passes ---- */
139
179
 
140
180
  int tf_ir_validate(tf_ir_plan *plan);
181
+ int tf_ir_validate_with_host_policy(tf_ir_plan *plan, const tf_host_policy *policy);
141
182
  int tf_ir_infer_schema(tf_ir_plan *plan);
142
183
 
143
184
  /* ---- Expression eval result ---- */
package/csrc/ir_schema.c CHANGED
@@ -25,16 +25,27 @@ int tf_ir_infer_schema(tf_ir_plan *plan) {
25
25
 
26
26
  /* Copy current schema as this node's input */
27
27
  tf_schema_free(&node->input_schema);
28
- tf_schema_copy(&node->input_schema, &current);
28
+ if (tf_schema_copy_checked(&node->input_schema, &current) != TF_OK) {
29
+ tf_schema_free(&current);
30
+ plan->schema_inferred = false;
31
+ return TF_ERROR;
32
+ }
29
33
 
30
34
  if (entry && entry->infer_schema) {
31
35
  /* Clear old output schema */
32
36
  tf_schema_free(&node->output_schema);
33
- entry->infer_schema(node, &current, &node->output_schema);
37
+ if (entry->infer_schema(node, &current, &node->output_schema) != TF_OK) {
38
+ tf_schema_free(&current);
39
+ plan->schema_inferred = false;
40
+ return TF_ERROR;
41
+ }
34
42
 
35
43
  /* Advance current to this node's output */
36
44
  tf_schema_free(&current);
37
- tf_schema_copy(&current, &node->output_schema);
45
+ if (tf_schema_copy_checked(&current, &node->output_schema) != TF_OK) {
46
+ plan->schema_inferred = false;
47
+ return TF_ERROR;
48
+ }
38
49
  } else {
39
50
  /* No schema inference available — propagate unknown */
40
51
  tf_schema_free(&node->output_schema);
@@ -48,8 +59,12 @@ int tf_ir_infer_schema(tf_ir_plan *plan) {
48
59
  tf_schema_free(&plan->final_schema);
49
60
  if (plan->n_nodes >= 2) {
50
61
  /* The schema before the encoder is the second-to-last node's output */
51
- tf_schema_copy(&plan->final_schema,
52
- &plan->nodes[plan->n_nodes - 2].output_schema);
62
+ if (tf_schema_copy_checked(&plan->final_schema,
63
+ &plan->nodes[plan->n_nodes - 2].output_schema) != TF_OK) {
64
+ tf_schema_free(&current);
65
+ plan->schema_inferred = false;
66
+ return TF_ERROR;
67
+ }
53
68
  } else {
54
69
  plan->final_schema.known = false;
55
70
  }
@@ -11,7 +11,7 @@
11
11
  * }
12
12
  */
13
13
 
14
- #include "ir.h"
14
+ #include "internal.h"
15
15
  #include "cJSON.h"
16
16
  #include <stdlib.h>
17
17
  #include <string.h>
@@ -84,18 +84,80 @@ tf_ir_plan *tf_ir_from_json(const char *json, size_t len, char **error) {
84
84
 
85
85
  char *tf_ir_to_json(const tf_ir_plan *plan) {
86
86
  cJSON *root = cJSON_CreateObject();
87
- cJSON *steps = cJSON_AddArrayToObject(root, "steps");
87
+ if (!root) return NULL;
88
+ cJSON *steps = cJSON_CreateArray();
89
+ if (!steps || tf_json_add_item(root, "steps", steps) != TF_OK) {
90
+ cJSON_Delete(root);
91
+ return NULL;
92
+ }
88
93
 
89
94
  for (size_t i = 0; i < plan->n_nodes; i++) {
90
95
  const tf_ir_node *node = &plan->nodes[i];
91
96
  cJSON *step = cJSON_CreateObject();
92
- cJSON_AddStringToObject(step, "op", node->op);
97
+ if (!step) {
98
+ cJSON_Delete(root);
99
+ return NULL;
100
+ }
101
+ if (tf_json_add_string(step, "op", node->op) != TF_OK) {
102
+ cJSON_Delete(step);
103
+ cJSON_Delete(root);
104
+ return NULL;
105
+ }
93
106
  if (node->args) {
94
- cJSON_AddItemToObject(step, "args", cJSON_Duplicate(node->args, 1));
107
+ cJSON *args = cJSON_Duplicate(node->args, 1);
108
+ if (args) {
109
+ cJSON_DeleteItemFromObjectCaseSensitive(args, TF_POLICY_VALIDATED_FILE_PATH_ARG);
110
+ cJSON_DeleteItemFromObjectCaseSensitive(args, TF_POLICY_VALIDATED_RULES_FILE_PATH_ARG);
111
+ }
112
+ if (!args || tf_json_add_item(step, "args", args) != TF_OK) {
113
+ cJSON_Delete(step);
114
+ cJSON_Delete(root);
115
+ return NULL;
116
+ }
95
117
  } else {
96
- cJSON_AddItemToObject(step, "args", cJSON_CreateObject());
118
+ cJSON *args = cJSON_CreateObject();
119
+ if (!args || tf_json_add_item(step, "args", args) != TF_OK) {
120
+ cJSON_Delete(step);
121
+ cJSON_Delete(root);
122
+ return NULL;
123
+ }
124
+ }
125
+ if (tf_json_add_string(step, "memory_class", tf_memory_class_name(node->memory_class)) != TF_OK ||
126
+ tf_json_add_string(step, "emit_class", tf_emit_class_name(node->emit_class)) != TF_OK ||
127
+ tf_json_add_string(step, "schema_class", tf_schema_class_name(node->schema_class)) != TF_OK ||
128
+ tf_json_add_string(step, "state_estimate",
129
+ node->state_estimate ? node->state_estimate : "unknown") != TF_OK) {
130
+ cJSON_Delete(step);
131
+ cJSON_Delete(root);
132
+ return NULL;
133
+ }
134
+ size_t state_bytes = 0;
135
+ char state_reason[192] = {0};
136
+ if (tf_estimate_step_state_bytes(node, &state_bytes, state_reason, sizeof(state_reason))) {
137
+ if (tf_json_add_number(step, "state_bytes_estimate", (double)state_bytes) != TF_OK) {
138
+ cJSON_Delete(step);
139
+ cJSON_Delete(root);
140
+ return NULL;
141
+ }
142
+ } else {
143
+ if (tf_json_add_null(step, "state_bytes_estimate") != TF_OK) {
144
+ cJSON_Delete(step);
145
+ cJSON_Delete(root);
146
+ return NULL;
147
+ }
148
+ if (node->memory_class == TF_MEM_KEY_STATE || node->memory_class == TF_MEM_BLOCKING) {
149
+ if (tf_json_add_string(step, "state_bytes_reason",
150
+ state_reason[0] ? state_reason : "no native byte estimator") != TF_OK) {
151
+ cJSON_Delete(step);
152
+ cJSON_Delete(root);
153
+ return NULL;
154
+ }
155
+ }
156
+ }
157
+ if (tf_json_add_array_item(steps, step) != TF_OK) {
158
+ cJSON_Delete(root);
159
+ return NULL;
97
160
  }
98
- cJSON_AddItemToArray(steps, step);
99
161
  }
100
162
 
101
163
  char *out = cJSON_PrintUnformatted(root);