@c9up/eon 0.1.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 (123) hide show
  1. package/README.md +69 -0
  2. package/dist/EonProvider.d.ts +51 -0
  3. package/dist/EonProvider.d.ts.map +1 -0
  4. package/dist/EonProvider.js +154 -0
  5. package/dist/EonProvider.js.map +1 -0
  6. package/dist/connection/EonConnection.d.ts +116 -0
  7. package/dist/connection/EonConnection.d.ts.map +1 -0
  8. package/dist/connection/EonConnection.js +15 -0
  9. package/dist/connection/EonConnection.js.map +1 -0
  10. package/dist/connection/config.d.ts +56 -0
  11. package/dist/connection/config.d.ts.map +1 -0
  12. package/dist/connection/config.js +14 -0
  13. package/dist/connection/config.js.map +1 -0
  14. package/dist/connection/websocket.d.ts +16 -0
  15. package/dist/connection/websocket.d.ts.map +1 -0
  16. package/dist/connection/websocket.js +383 -0
  17. package/dist/connection/websocket.js.map +1 -0
  18. package/dist/decorators/superTable.d.ts +73 -0
  19. package/dist/decorators/superTable.d.ts.map +1 -0
  20. package/dist/decorators/superTable.js +98 -0
  21. package/dist/decorators/superTable.js.map +1 -0
  22. package/dist/index.d.ts +20 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +19 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/ingest/schemaless.d.ts +22 -0
  27. package/dist/ingest/schemaless.d.ts.map +1 -0
  28. package/dist/ingest/schemaless.js +161 -0
  29. package/dist/ingest/schemaless.js.map +1 -0
  30. package/dist/ingest/sql.d.ts +23 -0
  31. package/dist/ingest/sql.d.ts.map +1 -0
  32. package/dist/ingest/sql.js +59 -0
  33. package/dist/ingest/sql.js.map +1 -0
  34. package/dist/ingest/stmt.d.ts +82 -0
  35. package/dist/ingest/stmt.d.ts.map +1 -0
  36. package/dist/ingest/stmt.js +246 -0
  37. package/dist/ingest/stmt.js.map +1 -0
  38. package/dist/metadata-keys.d.ts +17 -0
  39. package/dist/metadata-keys.d.ts.map +1 -0
  40. package/dist/metadata-keys.js +17 -0
  41. package/dist/metadata-keys.js.map +1 -0
  42. package/dist/query/TimeSeriesQuery.d.ts +121 -0
  43. package/dist/query/TimeSeriesQuery.d.ts.map +1 -0
  44. package/dist/query/TimeSeriesQuery.js +291 -0
  45. package/dist/query/TimeSeriesQuery.js.map +1 -0
  46. package/dist/query/native.d.ts +22 -0
  47. package/dist/query/native.d.ts.map +1 -0
  48. package/dist/query/native.js +135 -0
  49. package/dist/query/native.js.map +1 -0
  50. package/dist/repository/SuperTableRepository.d.ts +80 -0
  51. package/dist/repository/SuperTableRepository.d.ts.map +1 -0
  52. package/dist/repository/SuperTableRepository.js +232 -0
  53. package/dist/repository/SuperTableRepository.js.map +1 -0
  54. package/dist/schema/CreateStableSpec.d.ts +140 -0
  55. package/dist/schema/CreateStableSpec.d.ts.map +1 -0
  56. package/dist/schema/CreateStableSpec.js +41 -0
  57. package/dist/schema/CreateStableSpec.js.map +1 -0
  58. package/dist/schema/EonMigrationRunner.d.ts +71 -0
  59. package/dist/schema/EonMigrationRunner.d.ts.map +1 -0
  60. package/dist/schema/EonMigrationRunner.js +295 -0
  61. package/dist/schema/EonMigrationRunner.js.map +1 -0
  62. package/dist/schema/EonSchema.d.ts +128 -0
  63. package/dist/schema/EonSchema.d.ts.map +1 -0
  64. package/dist/schema/EonSchema.js +309 -0
  65. package/dist/schema/EonSchema.js.map +1 -0
  66. package/dist/schema/Migration.d.ts +47 -0
  67. package/dist/schema/Migration.d.ts.map +1 -0
  68. package/dist/schema/Migration.js +55 -0
  69. package/dist/schema/Migration.js.map +1 -0
  70. package/dist/schema/compile.d.ts +33 -0
  71. package/dist/schema/compile.d.ts.map +1 -0
  72. package/dist/schema/compile.js +70 -0
  73. package/dist/schema/compile.js.map +1 -0
  74. package/dist/schema/sync.d.ts +45 -0
  75. package/dist/schema/sync.d.ts.map +1 -0
  76. package/dist/schema/sync.js +102 -0
  77. package/dist/schema/sync.js.map +1 -0
  78. package/dist/services/connection.d.ts +33 -0
  79. package/dist/services/connection.d.ts.map +1 -0
  80. package/dist/services/connection.js +71 -0
  81. package/dist/services/connection.js.map +1 -0
  82. package/dist/testing/Factory.d.ts +43 -0
  83. package/dist/testing/Factory.d.ts.map +1 -0
  84. package/dist/testing/Factory.js +134 -0
  85. package/dist/testing/Factory.js.map +1 -0
  86. package/dist/testing/FakeEonConnection.d.ts +43 -0
  87. package/dist/testing/FakeEonConnection.d.ts.map +1 -0
  88. package/dist/testing/FakeEonConnection.js +315 -0
  89. package/dist/testing/FakeEonConnection.js.map +1 -0
  90. package/dist/testing/index.d.ts +34 -0
  91. package/dist/testing/index.d.ts.map +1 -0
  92. package/dist/testing/index.js +67 -0
  93. package/dist/testing/index.js.map +1 -0
  94. package/index.darwin-arm64.node +0 -0
  95. package/index.darwin-x64.node +0 -0
  96. package/index.linux-arm64-gnu.node +0 -0
  97. package/index.linux-x64-gnu.node +0 -0
  98. package/index.win32-x64-msvc.node +0 -0
  99. package/package.json +65 -0
  100. package/scripts/copy-napi.mjs +72 -0
  101. package/src/EonProvider.ts +222 -0
  102. package/src/connection/EonConnection.ts +146 -0
  103. package/src/connection/config.ts +60 -0
  104. package/src/connection/websocket.ts +436 -0
  105. package/src/decorators/superTable.ts +169 -0
  106. package/src/index.ts +118 -0
  107. package/src/ingest/schemaless.ts +211 -0
  108. package/src/ingest/sql.ts +73 -0
  109. package/src/ingest/stmt.ts +335 -0
  110. package/src/metadata-keys.ts +20 -0
  111. package/src/query/TimeSeriesQuery.ts +480 -0
  112. package/src/query/native.ts +180 -0
  113. package/src/repository/SuperTableRepository.ts +347 -0
  114. package/src/schema/CreateStableSpec.ts +184 -0
  115. package/src/schema/EonMigrationRunner.ts +378 -0
  116. package/src/schema/EonSchema.ts +396 -0
  117. package/src/schema/Migration.ts +66 -0
  118. package/src/schema/compile.ts +109 -0
  119. package/src/schema/sync.ts +142 -0
  120. package/src/services/connection.ts +89 -0
  121. package/src/testing/Factory.ts +186 -0
  122. package/src/testing/FakeEonConnection.ts +351 -0
  123. package/src/testing/index.ts +81 -0
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Schemaless line-protocol rendering (story 58.4, AC4).
3
+ *
4
+ * Renders points to InfluxDB line-protocol strings for
5
+ * `EonConnection.schemaless`. This is NOT SQL — it is InfluxDB's line format, so
6
+ * it is rendered in TS (no compiler seam), with the format's own escaping rules
7
+ * applied to the measurement, tag keys/values, and field keys, and string field
8
+ * values double-quoted (context7 `/taosdata/tdengine`, InfluxDB line protocol).
9
+ *
10
+ * Schemaless is a documented ~8–10× slower helper than the STMT path and must
11
+ * NOT be used as the default bulk path (AD5 / AC4).
12
+ */
13
+ import type { ColumnarPlan, IngestPoint } from "./stmt.js";
14
+ /**
15
+ * Render points to InfluxDB line-protocol lines. The measurement is the
16
+ * super-table name, tags come from the entity's `@Tag` columns, and every
17
+ * present metric column (excluding the timestamp) becomes a field. Points with
18
+ * no fields are skipped (line protocol requires ≥1 field) — reported by the
19
+ * caller, never silently emitted as an invalid line.
20
+ */
21
+ export declare function toLineProtocol(plan: ColumnarPlan, points: readonly IngestPoint[]): string[];
22
+ //# sourceMappingURL=schemaless.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemaless.d.ts","sourceRoot":"","sources":["../../src/ingest/schemaless.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAgI3D;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC7B,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,SAAS,WAAW,EAAE,GAC5B,MAAM,EAAE,CA0DV"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Schemaless line-protocol rendering (story 58.4, AC4).
3
+ *
4
+ * Renders points to InfluxDB line-protocol strings for
5
+ * `EonConnection.schemaless`. This is NOT SQL — it is InfluxDB's line format, so
6
+ * it is rendered in TS (no compiler seam), with the format's own escaping rules
7
+ * applied to the measurement, tag keys/values, and field keys, and string field
8
+ * values double-quoted (context7 `/taosdata/tdengine`, InfluxDB line protocol).
9
+ *
10
+ * Schemaless is a documented ~8–10× slower helper than the STMT path and must
11
+ * NOT be used as the default bulk path (AD5 / AC4).
12
+ */
13
+ import { coerceTimestamp, FLOAT32_MAX, INT_BOUNDS } from "./stmt.js";
14
+ /**
15
+ * Reject any control character (newline, CR, tab, NUL, …). Line protocol is
16
+ * newline-delimited and cannot encode a control byte in ANY position, so
17
+ * backslash-escaping does not neutralize it — a raw newline in a caller tag or
18
+ * field value would terminate the line and inject a forged point. These bytes
19
+ * must be refused, not escaped (memory `feedback_security_first`).
20
+ */
21
+ function assertNoControlChar(value, role) {
22
+ for (let i = 0; i < value.length; i++) {
23
+ const code = value.charCodeAt(i);
24
+ if (code <= 0x1f || code === 0x7f) {
25
+ throw new Error(`[E_EON_SCHEMALESS_CONTROL_CHAR] ${role} contains a control character (code ${code}); line protocol cannot encode it.`);
26
+ }
27
+ }
28
+ }
29
+ /**
30
+ * Escape a measurement name: comma, space, and backslash. Backslash is escaped
31
+ * too, else a trailing `\` would escape the following delimiter and desync the
32
+ * parser. Control chars are rejected upstream (so no `\s`).
33
+ */
34
+ function escapeMeasurement(value) {
35
+ assertNoControlChar(value, "measurement");
36
+ return value.replace(/[\\, ]/g, "\\$&");
37
+ }
38
+ /** Escape a tag key/value or field key: comma, equals, space, and backslash. */
39
+ function escapeKeyOrTag(value) {
40
+ assertNoControlChar(value, "tag/field key or value");
41
+ return value.replace(/[\\,= ]/g, "\\$&");
42
+ }
43
+ /** Escape a string field value: backslash and double-quote (then wrap in `"`). */
44
+ function quoteStringField(value) {
45
+ assertNoControlChar(value, "string field value");
46
+ return `"${value.replace(/["\\]/g, "\\$&")}"`;
47
+ }
48
+ /**
49
+ * Render one field value into its line-protocol form, typed by its bind kind.
50
+ * Numeric kinds are validated to the same precision/finiteness contract the STMT
51
+ * path enforces (`E_EON_PARAM_PRECISION`): an unsafe-integer `number`, a
52
+ * non-finite float, or a non-numeric value is rejected loud rather than emitted
53
+ * as a lossy/invalid token (e.g. `1e+21i`, `NaNi`) that silently corrupts data.
54
+ */
55
+ function renderFieldValue(kind, value, property) {
56
+ switch (kind) {
57
+ case "int":
58
+ case "bigInt":
59
+ case "smallInt":
60
+ case "tinyInt": {
61
+ // Integer field: the `i` suffix. bigint is exact; a `number` must be a
62
+ // safe integer or it has already lost precision. The value must also fit
63
+ // the column width — the SQL path's i64 guard (`stringifyPrecisionSafe`)
64
+ // never runs on the schemaless path, so bound it here or an out-of-range
65
+ // value renders as an invalid/overflowing token (`999...i`).
66
+ let asBig;
67
+ if (typeof value === "bigint") {
68
+ asBig = value;
69
+ }
70
+ else if (typeof value === "number" &&
71
+ Number.isInteger(value) &&
72
+ Number.isSafeInteger(value)) {
73
+ asBig = BigInt(value);
74
+ }
75
+ else {
76
+ throw new Error(`[E_EON_PARAM_PRECISION] integer field '${property}' value ${String(value)} is not a safe integer; pass i64 values as bigint.`);
77
+ }
78
+ const [min, max] = INT_BOUNDS[kind];
79
+ if (asBig < min || asBig > max) {
80
+ throw new Error(`[E_EON_SCHEMALESS_FIELD] ${kind} field '${property}' value ${String(value)} is outside the ${kind} range [${min}, ${max}].`);
81
+ }
82
+ return `${asBig}i`;
83
+ }
84
+ case "float":
85
+ case "double":
86
+ case "decimal": {
87
+ const asNum = typeof value === "bigint"
88
+ ? Number(value)
89
+ : typeof value === "number"
90
+ ? value
91
+ : undefined;
92
+ if (asNum === undefined || !Number.isFinite(asNum)) {
93
+ throw new Error(`[E_EON_SCHEMALESS_FIELD] numeric field '${property}' value ${String(value)} is not a finite number.`);
94
+ }
95
+ if (kind === "float" && Math.abs(asNum) > FLOAT32_MAX) {
96
+ throw new Error(`[E_EON_SCHEMALESS_FIELD] float (f32) field '${property}' value ${String(value)} exceeds the binary32 range and would render as Infinity.`);
97
+ }
98
+ return `${value}`;
99
+ }
100
+ case "bool":
101
+ if (typeof value !== "boolean") {
102
+ throw new Error(`[E_EON_SCHEMALESS_FIELD] bool field '${property}' requires a boolean (got ${typeof value}).`);
103
+ }
104
+ return value ? "true" : "false";
105
+ default:
106
+ // varchar / nchar / varbinary / json / timestamp → quoted string.
107
+ // A non-scalar (object/array) would stringify to "[object Object]" /
108
+ // "a,b" — silent corruption. Reject loud rather than emit garbage.
109
+ if (typeof value === "object") {
110
+ throw new Error(`[E_EON_SCHEMALESS_FIELD] string field '${property}' requires a scalar value, not an object/array.`);
111
+ }
112
+ return quoteStringField(String(value));
113
+ }
114
+ }
115
+ /**
116
+ * Render points to InfluxDB line-protocol lines. The measurement is the
117
+ * super-table name, tags come from the entity's `@Tag` columns, and every
118
+ * present metric column (excluding the timestamp) becomes a field. Points with
119
+ * no fields are skipped (line protocol requires ≥1 field) — reported by the
120
+ * caller, never silently emitted as an invalid line.
121
+ */
122
+ export function toLineProtocol(plan, points) {
123
+ if (plan.stable === "") {
124
+ throw new Error("[E_EON_SCHEMALESS_MEASUREMENT] super-table (measurement) name is empty; cannot render a line-protocol point.");
125
+ }
126
+ const measurement = escapeMeasurement(plan.stable);
127
+ const lines = [];
128
+ for (const point of points) {
129
+ const tagParts = plan.tags
130
+ .filter((tag) => point[tag.property] != null)
131
+ .map((tag) => {
132
+ const value = point[tag.property];
133
+ // Tags are not type-checked like fields; a non-scalar (object/array)
134
+ // would stringify to "[object Object]" / "a,b" — silent corruption.
135
+ if (typeof value === "object") {
136
+ throw new Error(`[E_EON_SCHEMALESS_TAG] tag '${tag.property}' requires a scalar value, not an object/array.`);
137
+ }
138
+ const raw = String(value);
139
+ // Line protocol forbids an empty tag value (`location=` is invalid and
140
+ // TDengine rejects the whole batch). Reject loud rather than emit a
141
+ // malformed token — a control char in `raw` is caught by escapeKeyOrTag.
142
+ if (raw === "") {
143
+ throw new Error(`[E_EON_SCHEMALESS_EMPTY_TAG] tag '${tag.property}' is an empty string; line protocol requires a non-empty tag value.`);
144
+ }
145
+ return `${escapeKeyOrTag(tag.property)}=${escapeKeyOrTag(raw)}`;
146
+ });
147
+ const fieldParts = plan.columns
148
+ .filter((col) => col.property !== plan.tsProperty && point[col.property] != null)
149
+ .map((col) => `${escapeKeyOrTag(col.property)}=${renderFieldValue(col.kind, point[col.property], col.property)}`);
150
+ if (fieldParts.length === 0) {
151
+ throw new Error(`[E_EON_SCHEMALESS_NO_FIELDS] point for '${plan.stable}' has no metric fields; line protocol requires at least one field.`);
152
+ }
153
+ const ts = coerceTimestamp(point[plan.tsProperty], plan.tsProperty);
154
+ const prefix = tagParts.length > 0
155
+ ? `${measurement},${tagParts.join(",")}`
156
+ : measurement;
157
+ lines.push(`${prefix} ${fieldParts.join(",")} ${ts}`);
158
+ }
159
+ return lines;
160
+ }
161
+ //# sourceMappingURL=schemaless.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemaless.js","sourceRoot":"","sources":["../../src/ingest/schemaless.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Literal SQL INSERT ingest planning (story 58.4, AC5) — the convenience /
3
+ * fallback path that runs through the literal-only `EonConnection.exec`.
4
+ *
5
+ * Because `exec` takes literal SQL (no bind params, 58.2 D3), the value literals
6
+ * are rendered by the **Rust compiler's `literal: true` INSERT mode** (D6, OQ1),
7
+ * reusing the single `render_literal` injection seam. This module NEVER
8
+ * string-builds SQL or interpolates a value — it assembles a JSON `InsertSpec`
9
+ * and hands it to `compileStatementNative`. It groups points by child table
10
+ * (the `USING … TAGS` auto-create form) exactly like the STMT path.
11
+ */
12
+ import type { ColumnarPlan, IngestPoint } from "./stmt.js";
13
+ /**
14
+ * Build one literal `INSERT … USING <stable> TAGS(...) VALUES(...)` statement per
15
+ * child table. Every value is validated against its declared bind kind up front —
16
+ * the timestamp through `coerceTimestamp` (rejecting fractional/string/unsafe
17
+ * inputs the compile boundary alone would pass, e.g. `1700000000000.5` or a date
18
+ * string), other columns through `assertColumnValue` — so the literal path is
19
+ * exactly as precision- and type-safe as the STMT path, and the Rust compiler
20
+ * renders only the vetted literals (never TS interpolation).
21
+ */
22
+ export declare function buildLiteralInserts(plan: ColumnarPlan, points: readonly IngestPoint[]): string[];
23
+ //# sourceMappingURL=sql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../src/ingest/sql.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAG3D;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAClC,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,SAAS,WAAW,EAAE,GAC5B,MAAM,EAAE,CA4CV"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Literal SQL INSERT ingest planning (story 58.4, AC5) — the convenience /
3
+ * fallback path that runs through the literal-only `EonConnection.exec`.
4
+ *
5
+ * Because `exec` takes literal SQL (no bind params, 58.2 D3), the value literals
6
+ * are rendered by the **Rust compiler's `literal: true` INSERT mode** (D6, OQ1),
7
+ * reusing the single `render_literal` injection seam. This module NEVER
8
+ * string-builds SQL or interpolates a value — it assembles a JSON `InsertSpec`
9
+ * and hands it to `compileStatementNative`. It groups points by child table
10
+ * (the `USING … TAGS` auto-create form) exactly like the STMT path.
11
+ */
12
+ import { compileStatementNative } from "../query/native.js";
13
+ import { assertColumnValue, coerceTimestamp, groupByChild } from "./stmt.js";
14
+ /**
15
+ * Build one literal `INSERT … USING <stable> TAGS(...) VALUES(...)` statement per
16
+ * child table. Every value is validated against its declared bind kind up front —
17
+ * the timestamp through `coerceTimestamp` (rejecting fractional/string/unsafe
18
+ * inputs the compile boundary alone would pass, e.g. `1700000000000.5` or a date
19
+ * string), other columns through `assertColumnValue` — so the literal path is
20
+ * exactly as precision- and type-safe as the STMT path, and the Rust compiler
21
+ * renders only the vetted literals (never TS interpolation).
22
+ */
23
+ export function buildLiteralInserts(plan, points) {
24
+ const columnNames = plan.columns.map((c) => c.property);
25
+ const tagProps = plan.tags.map((t) => t.property);
26
+ const statements = [];
27
+ for (const group of groupByChild(plan.stable, tagProps, points)) {
28
+ const rows = group.rows.map((point) => plan.columns.map((col) => {
29
+ if (col.property === plan.tsProperty) {
30
+ return coerceTimestamp(point[col.property], col.property);
31
+ }
32
+ const value = point[col.property] ?? null;
33
+ assertColumnValue(value, col.kind, col.property);
34
+ return value;
35
+ }));
36
+ const compiled = compileStatementNative({
37
+ kind: "insert",
38
+ table: group.table,
39
+ using: plan.stable,
40
+ tags: group.tagValues.map((v, i) => {
41
+ const value = v ?? null;
42
+ const tag = plan.tags[i];
43
+ if (tag !== undefined)
44
+ assertColumnValue(value, tag.kind, tag.property);
45
+ return value;
46
+ }),
47
+ columns: columnNames,
48
+ rows,
49
+ literal: true,
50
+ }, "tdengine");
51
+ const [sql, ...rest] = compiled.statements;
52
+ if (sql === undefined || rest.length > 0) {
53
+ throw new Error(`[E_EON_LITERAL_INSERT] expected exactly one statement for child '${group.table}', got ${compiled.statements.length}`);
54
+ }
55
+ statements.push(sql);
56
+ }
57
+ return statements;
58
+ }
59
+ //# sourceMappingURL=sql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.js","sourceRoot":"","sources":["../../src/ingest/sql.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE7E;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAClC,IAAkB,EAClB,MAA8B;IAE9B,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAClD,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACrC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACxB,IAAI,GAAG,CAAC,QAAQ,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;gBACtC,OAAO,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC3D,CAAC;YACD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC;YAC1C,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;YACjD,OAAO,KAAK,CAAC;QACd,CAAC,CAAC,CACF,CAAC;QACF,MAAM,QAAQ,GAAG,sBAAsB,CACtC;YACC,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,KAAK,EAAE,IAAI,CAAC,MAAM;YAClB,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;gBAClC,MAAM,KAAK,GAAG,CAAC,IAAI,IAAI,CAAC;gBACxB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACzB,IAAI,GAAG,KAAK,SAAS;oBACpB,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;gBAClD,OAAO,KAAK,CAAC;YACd,CAAC,CAAC;YACF,OAAO,EAAE,WAAW;YACpB,IAAI;YACJ,OAAO,EAAE,IAAI;SACb,EACD,UAAU,CACV,CAAC;QACF,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC;QAC3C,IAAI,GAAG,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CACd,oEAAoE,KAAK,CAAC,KAAK,UAAU,QAAQ,CAAC,UAAU,CAAC,MAAM,EAAE,CACrH,CAAC;QACH,CAAC;QACD,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,UAAU,CAAC;AACnB,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * STMT columnar bulk-ingest planning (story 58.4) — the default high-throughput
3
+ * write path.
4
+ *
5
+ * This module turns plain point objects into the transport-agnostic
6
+ * {@link EonColumnarIngest} request: it groups points by their (deterministic)
7
+ * child table, accumulates **struct-of-arrays columns** per child (one typed
8
+ * array per column, NOT an array of row objects — the locked 58.0 contract, kept
9
+ * even on the ws path), chunks each child at `batchSize`, and carries the
10
+ * compiler-produced STMT template. The actual `stmtInit`/`bind`/`exec` happens
11
+ * in the transport (`EonConnection.ingestColumnar`); this module never touches a
12
+ * ws-specific type. The SQL template is produced ONLY by the Rust compiler — the
13
+ * injection seam stays in Rust (memory `feedback_security_first`).
14
+ */
15
+ import type { EonBindKind, EonColumnarIngest } from "../connection/EonConnection.js";
16
+ /** The default STMT batch chunk (rows per child per bind). Overridable (OQ3). */
17
+ export declare const DEFAULT_BATCH_SIZE = 4096;
18
+ /** Resolve a logical column/tag type to its bind kind, or throw a typed error. */
19
+ export declare function toBindKind(logicalType: string | undefined, property: string): EonBindKind;
20
+ /** A column (or tag) in the ingest plan: its entity property + bind kind. */
21
+ export interface PlanColumn {
22
+ readonly property: string;
23
+ readonly kind: EonBindKind;
24
+ }
25
+ /** Resolved plan for one super-table's STMT ingest (built once per repository). */
26
+ export interface ColumnarPlan {
27
+ readonly stable: string;
28
+ readonly templateSql: string;
29
+ readonly tsProperty: string;
30
+ /** Value columns, timestamp first (prepared bind order). */
31
+ readonly columns: readonly PlanColumn[];
32
+ readonly tags: readonly PlanColumn[];
33
+ readonly batchSize: number;
34
+ }
35
+ /** A point: a plain object keyed by the entity's property names. */
36
+ export type IngestPoint = Record<string, unknown>;
37
+ /**
38
+ * Compile the STMT prepare template for a super-table via the Rust compiler
39
+ * (`INSERT INTO ? USING <stable> (<tagcols>) TAGS (?) VALUES (?)`). The single
40
+ * SQL authority stays in Rust — this never string-builds SQL.
41
+ */
42
+ export declare function compileStmtTemplate(stable: string, tagColumns: readonly string[], columns: readonly string[]): string;
43
+ /** A child table's grouped rows + the tag values that route to it. */
44
+ export interface ChildGroup {
45
+ readonly table: string;
46
+ readonly tagValues: unknown[];
47
+ readonly rows: IngestPoint[];
48
+ }
49
+ /**
50
+ * Group points by their deterministic child table (same tags → same child).
51
+ * Tag values are normalised (`undefined` → `null`) so routing is stable and a
52
+ * missing tag can never desync the FNV child name.
53
+ */
54
+ export declare function groupByChild(stable: string, tagProperties: readonly string[], points: readonly IngestPoint[]): ChildGroup[];
55
+ /**
56
+ * Coerce a timestamp value to `bigint`, honouring the 58.1
57
+ * `E_EON_PARAM_PRECISION` boundary: a `number` that is not a safe integer has
58
+ * already lost precision, so it is rejected loud rather than bound corrupted.
59
+ */
60
+ export declare function coerceTimestamp(value: unknown, property: string): bigint;
61
+ /** Inclusive [min, max] value bounds per signed-integer bind kind. */
62
+ export declare const INT_BOUNDS: Readonly<Record<"tinyInt" | "smallInt" | "int" | "bigInt", readonly [bigint, bigint]>>;
63
+ /** Largest finite magnitude representable in IEEE-754 binary32 (`FLOAT`). */
64
+ export declare const FLOAT32_MAX = 3.4028234663852886e+38;
65
+ /**
66
+ * Validate a non-timestamp value against its declared bind kind, rejecting the
67
+ * silent-corruption inputs the connector setters would otherwise truncate or
68
+ * coerce: a fractional/NaN/Infinity/string into an integer column, an integer
69
+ * OUTSIDE the column's width (i8/i16/i32/i64) that would wrap, a non-finite or
70
+ * f32-overflowing float, a non-boolean into a BOOL, or an object/array into a
71
+ * scalar string/binary column. `null`/`undefined` are allowed and bound as NULL;
72
+ * timestamps are validated separately by {@link coerceTimestamp}; JSON columns
73
+ * legitimately carry objects and are left to the connector setter.
74
+ */
75
+ export declare function assertColumnValue(value: unknown, kind: EonBindKind, property: string): void;
76
+ /**
77
+ * Build the columnar STMT ingest request from a plan + points: group by child,
78
+ * chunk at `batchSize`, and accumulate one SoA column per value column and one
79
+ * single-element column per tag. NO per-row object is produced.
80
+ */
81
+ export declare function buildColumnarIngest(plan: ColumnarPlan, points: readonly IngestPoint[]): EonColumnarIngest;
82
+ //# sourceMappingURL=stmt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stmt.d.ts","sourceRoot":"","sources":["../../src/ingest/stmt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACX,WAAW,EAGX,iBAAiB,EACjB,MAAM,gCAAgC,CAAC;AAIxC,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,OAAO,CAAC;AA6BvC,kFAAkF;AAClF,wBAAgB,UAAU,CACzB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,QAAQ,EAAE,MAAM,GACd,WAAW,CAQb;AAED,6EAA6E;AAC7E,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;CAC3B;AAED,mFAAmF;AACnF,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AAED,oEAAoE;AACpE,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAElD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAClC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,OAAO,EAAE,SAAS,MAAM,EAAE,GACxB,MAAM,CAiBR;AAED,sEAAsE;AACtE,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC3B,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,MAAM,EAAE,SAAS,WAAW,EAAE,GAC5B,UAAU,EAAE,CAqBd;AAkBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAaxE;AAED,sEAAsE;AACtE,eAAO,MAAM,UAAU,EAAE,QAAQ,CAChC,MAAM,CAAC,SAAS,GAAG,UAAU,GAAG,KAAK,GAAG,QAAQ,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAM5E,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,WAAW,yBAAwB,CAAC;AAEjD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,MAAM,GACd,IAAI,CA8EN;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAClC,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,SAAS,WAAW,EAAE,GAC5B,iBAAiB,CA4BnB"}
@@ -0,0 +1,246 @@
1
+ /**
2
+ * STMT columnar bulk-ingest planning (story 58.4) — the default high-throughput
3
+ * write path.
4
+ *
5
+ * This module turns plain point objects into the transport-agnostic
6
+ * {@link EonColumnarIngest} request: it groups points by their (deterministic)
7
+ * child table, accumulates **struct-of-arrays columns** per child (one typed
8
+ * array per column, NOT an array of row objects — the locked 58.0 contract, kept
9
+ * even on the ws path), chunks each child at `batchSize`, and carries the
10
+ * compiler-produced STMT template. The actual `stmtInit`/`bind`/`exec` happens
11
+ * in the transport (`EonConnection.ingestColumnar`); this module never touches a
12
+ * ws-specific type. The SQL template is produced ONLY by the Rust compiler — the
13
+ * injection seam stays in Rust (memory `feedback_security_first`).
14
+ */
15
+ import { compileStatementNative } from "../query/native.js";
16
+ import { childTableName, stringifyTagValue } from "../schema/sync.js";
17
+ /** The default STMT batch chunk (rows per child per bind). Overridable (OQ3). */
18
+ export const DEFAULT_BATCH_SIZE = 4096;
19
+ /**
20
+ * Logical column/tag type → the columnar bind kind that selects the transport
21
+ * setter. Typed precisely as `EonBindKind` (unlike the string-valued
22
+ * `TYPE_KIND_MAP`) so the plan carries a validated kind with no cast. Same
23
+ * logical alias set as the DDL type map.
24
+ */
25
+ const BIND_KIND_BY_LOGICAL = {
26
+ timestamp: "timestamp",
27
+ int: "int",
28
+ integer: "int",
29
+ bigint: "bigInt",
30
+ biginteger: "bigInt",
31
+ smallint: "smallInt",
32
+ tinyint: "tinyInt",
33
+ float: "float",
34
+ double: "double",
35
+ bool: "bool",
36
+ boolean: "bool",
37
+ string: "varchar",
38
+ varchar: "varchar",
39
+ nchar: "nchar",
40
+ binary: "varbinary",
41
+ varbinary: "varbinary",
42
+ json: "json",
43
+ decimal: "decimal",
44
+ };
45
+ /** Resolve a logical column/tag type to its bind kind, or throw a typed error. */
46
+ export function toBindKind(logicalType, property) {
47
+ const kind = BIND_KIND_BY_LOGICAL[(logicalType ?? "").toLowerCase()];
48
+ if (!kind) {
49
+ throw new Error(`[E_EON_TYPE] column/tag '${property}' has an unknown or missing type '${logicalType ?? ""}'`);
50
+ }
51
+ return kind;
52
+ }
53
+ /**
54
+ * Compile the STMT prepare template for a super-table via the Rust compiler
55
+ * (`INSERT INTO ? USING <stable> (<tagcols>) TAGS (?) VALUES (?)`). The single
56
+ * SQL authority stays in Rust — this never string-builds SQL.
57
+ */
58
+ export function compileStmtTemplate(stable, tagColumns, columns) {
59
+ const compiled = compileStatementNative({
60
+ kind: "stmtInsertTemplate",
61
+ using: stable,
62
+ tagColumns: [...tagColumns],
63
+ columns: [...columns],
64
+ }, "tdengine");
65
+ const sql = compiled.statements[0];
66
+ if (sql === undefined) {
67
+ throw new Error("[E_EON_TEMPLATE] the compiler returned no statement for the STMT insert template");
68
+ }
69
+ return sql;
70
+ }
71
+ /**
72
+ * Group points by their deterministic child table (same tags → same child).
73
+ * Tag values are normalised (`undefined` → `null`) so routing is stable and a
74
+ * missing tag can never desync the FNV child name.
75
+ */
76
+ export function groupByChild(stable, tagProperties, points) {
77
+ const groups = new Map();
78
+ for (const point of points) {
79
+ const tagValues = tagProperties.map((p) => point[p] ?? null);
80
+ const table = childTableName(stable, tagValues);
81
+ let group = groups.get(table);
82
+ if (!group) {
83
+ group = { table, tagValues, rows: [] };
84
+ groups.set(table, group);
85
+ }
86
+ else if (!sameTagValues(group.tagValues, tagValues)) {
87
+ // Defence-in-depth behind the 64-bit child name: if two DISTINCT
88
+ // tag-sets ever hashed to the same child, later points would bind under
89
+ // the first set's tags (silent cross-series corruption). Refuse loudly
90
+ // instead — astronomically unlikely at 64 bits, never silent.
91
+ throw new Error(`[E_EON_CHILD_COLLISION] two distinct tag-sets map to the same child table '${table}'; refusing to write mismatched rows under one tag-set.`);
92
+ }
93
+ group.rows.push(point);
94
+ }
95
+ return [...groups.values()];
96
+ }
97
+ /**
98
+ * Element-wise equality of two normalised tag-value tuples. Compares on the SAME
99
+ * canonical form {@link childTableName} hashes with ({@link stringifyTagValue}),
100
+ * not by reference — otherwise two structurally-equal but distinct object/JSON
101
+ * `@Tag` references (which hash to the same child) would read as unequal and
102
+ * trip a spurious `E_EON_CHILD_COLLISION`, blocking a legitimate batch. A TRUE
103
+ * hash collision of genuinely distinct tag-sets still differs here and is caught.
104
+ */
105
+ function sameTagValues(a, b) {
106
+ if (a.length !== b.length)
107
+ return false;
108
+ for (let i = 0; i < a.length; i++) {
109
+ if (stringifyTagValue(a[i]) !== stringifyTagValue(b[i]))
110
+ return false;
111
+ }
112
+ return true;
113
+ }
114
+ /**
115
+ * Coerce a timestamp value to `bigint`, honouring the 58.1
116
+ * `E_EON_PARAM_PRECISION` boundary: a `number` that is not a safe integer has
117
+ * already lost precision, so it is rejected loud rather than bound corrupted.
118
+ */
119
+ export function coerceTimestamp(value, property) {
120
+ if (typeof value === "bigint")
121
+ return value;
122
+ if (typeof value === "number") {
123
+ if (!Number.isInteger(value) || !Number.isSafeInteger(value)) {
124
+ throw new Error(`[E_EON_PARAM_PRECISION] timestamp '${property}' value ${value} is not a safe integer; pass nanosecond/BIGINT timestamps as bigint.`);
125
+ }
126
+ return BigInt(value);
127
+ }
128
+ throw new Error(`[E_EON_TS_TYPE] timestamp '${property}' must be a bigint or a safe-integer number (got ${typeof value}).`);
129
+ }
130
+ /** Inclusive [min, max] value bounds per signed-integer bind kind. */
131
+ export const INT_BOUNDS = {
132
+ tinyInt: [-128n, 127n],
133
+ smallInt: [-32768n, 32767n],
134
+ int: [-2147483648n, 2147483647n],
135
+ bigInt: [-9223372036854775808n, 9223372036854775807n],
136
+ };
137
+ /** Largest finite magnitude representable in IEEE-754 binary32 (`FLOAT`). */
138
+ export const FLOAT32_MAX = 3.4028234663852886e38;
139
+ /**
140
+ * Validate a non-timestamp value against its declared bind kind, rejecting the
141
+ * silent-corruption inputs the connector setters would otherwise truncate or
142
+ * coerce: a fractional/NaN/Infinity/string into an integer column, an integer
143
+ * OUTSIDE the column's width (i8/i16/i32/i64) that would wrap, a non-finite or
144
+ * f32-overflowing float, a non-boolean into a BOOL, or an object/array into a
145
+ * scalar string/binary column. `null`/`undefined` are allowed and bound as NULL;
146
+ * timestamps are validated separately by {@link coerceTimestamp}; JSON columns
147
+ * legitimately carry objects and are left to the connector setter.
148
+ */
149
+ export function assertColumnValue(value, kind, property) {
150
+ if (value === null || value === undefined)
151
+ return;
152
+ switch (kind) {
153
+ case "int":
154
+ case "smallInt":
155
+ case "tinyInt":
156
+ case "bigInt": {
157
+ let asBig;
158
+ if (typeof value === "bigint") {
159
+ asBig = value;
160
+ }
161
+ else if (typeof value === "number" &&
162
+ Number.isInteger(value) &&
163
+ Number.isSafeInteger(value)) {
164
+ asBig = BigInt(value);
165
+ }
166
+ else {
167
+ throw new Error(`[E_EON_VALUE_TYPE] integer column '${property}' requires a safe-integer number or bigint (got ${typeof value} ${String(value)}).`);
168
+ }
169
+ const [min, max] = INT_BOUNDS[kind];
170
+ if (asBig < min || asBig > max) {
171
+ throw new Error(`[E_EON_VALUE_RANGE] ${kind} column '${property}' value ${String(value)} is outside the ${kind} range [${min}, ${max}]; the connector setter would truncate it silently.`);
172
+ }
173
+ return;
174
+ }
175
+ case "float":
176
+ case "double": {
177
+ const asNum = typeof value === "bigint"
178
+ ? Number(value)
179
+ : typeof value === "number"
180
+ ? value
181
+ : undefined;
182
+ if (asNum === undefined || !Number.isFinite(asNum)) {
183
+ throw new Error(`[E_EON_VALUE_TYPE] float column '${property}' requires a finite number (got ${typeof value} ${String(value)}).`);
184
+ }
185
+ if (kind === "float" && Math.abs(asNum) > FLOAT32_MAX) {
186
+ throw new Error(`[E_EON_VALUE_RANGE] float (f32) column '${property}' value ${String(value)} exceeds the binary32 range and would be stored as Infinity; use a DOUBLE column.`);
187
+ }
188
+ return;
189
+ }
190
+ case "bool":
191
+ if (typeof value === "boolean")
192
+ return;
193
+ throw new Error(`[E_EON_VALUE_TYPE] bool column '${property}' requires a boolean (got ${typeof value} ${String(value)}).`);
194
+ case "varchar":
195
+ case "nchar":
196
+ case "varbinary":
197
+ // Mirror the schemaless path's object-reject: a non-scalar bound to a
198
+ // string/binary column stringifies to "[object Object]" — silent
199
+ // corruption. JSON columns (below, via default) legitimately take objects.
200
+ if (typeof value === "object") {
201
+ throw new Error(`[E_EON_VALUE_TYPE] string/binary column '${property}' requires a scalar value, not an object/array.`);
202
+ }
203
+ return;
204
+ case "decimal":
205
+ // DECIMAL binds as a string/number to preserve precision; only a
206
+ // non-finite number (NaN/Infinity) is unrenderable — reject it.
207
+ if (typeof value === "number" && !Number.isFinite(value)) {
208
+ throw new Error(`[E_EON_VALUE_TYPE] decimal column '${property}' requires a finite number or a string (got ${String(value)}).`);
209
+ }
210
+ return;
211
+ default:
212
+ return;
213
+ }
214
+ }
215
+ /**
216
+ * Build the columnar STMT ingest request from a plan + points: group by child,
217
+ * chunk at `batchSize`, and accumulate one SoA column per value column and one
218
+ * single-element column per tag. NO per-row object is produced.
219
+ */
220
+ export function buildColumnarIngest(plan, points) {
221
+ const children = [];
222
+ const tagProps = plan.tags.map((t) => t.property);
223
+ for (const group of groupByChild(plan.stable, tagProps, points)) {
224
+ for (let start = 0; start < group.rows.length; start += plan.batchSize) {
225
+ const slice = group.rows.slice(start, start + plan.batchSize);
226
+ const columns = plan.columns.map((col) => ({
227
+ kind: col.kind,
228
+ values: col.property === plan.tsProperty
229
+ ? slice.map((pt) => coerceTimestamp(pt[col.property], col.property))
230
+ : slice.map((pt) => {
231
+ const value = pt[col.property] ?? null;
232
+ assertColumnValue(value, col.kind, col.property);
233
+ return value;
234
+ }),
235
+ }));
236
+ const tags = plan.tags.map((tag, i) => {
237
+ const value = group.tagValues[i] ?? null;
238
+ assertColumnValue(value, tag.kind, tag.property);
239
+ return { kind: tag.kind, values: [value] };
240
+ });
241
+ children.push({ table: group.table, tags, columns });
242
+ }
243
+ }
244
+ return { sql: plan.templateSql, children };
245
+ }
246
+ //# sourceMappingURL=stmt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stmt.js","sourceRoot":"","sources":["../../src/ingest/stmt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtE,iFAAiF;AACjF,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEvC;;;;;GAKG;AACH,MAAM,oBAAoB,GAAgC;IACzD,SAAS,EAAE,WAAW;IACtB,GAAG,EAAE,KAAK;IACV,OAAO,EAAE,KAAK;IACd,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,QAAQ;IACpB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,QAAQ;IAChB,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,SAAS;IACjB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,WAAW;IACnB,SAAS,EAAE,WAAW;IACtB,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;CAClB,CAAC;AAEF,kFAAkF;AAClF,MAAM,UAAU,UAAU,CACzB,WAA+B,EAC/B,QAAgB;IAEhB,MAAM,IAAI,GAAG,oBAAoB,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACrE,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACd,4BAA4B,QAAQ,qCAAqC,WAAW,IAAI,EAAE,GAAG,CAC7F,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAsBD;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAClC,MAAc,EACd,UAA6B,EAC7B,OAA0B;IAE1B,MAAM,QAAQ,GAAG,sBAAsB,CACtC;QACC,IAAI,EAAE,oBAAoB;QAC1B,KAAK,EAAE,MAAM;QACb,UAAU,EAAE,CAAC,GAAG,UAAU,CAAC;QAC3B,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC;KACrB,EACD,UAAU,CACV,CAAC;IACF,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACd,kFAAkF,CAClF,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AASD;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC3B,MAAc,EACd,aAAgC,EAChC,MAA8B;IAE9B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC7C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;QAC7D,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAChD,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,KAAK,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;YACvC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC1B,CAAC;aAAM,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC;YACvD,iEAAiE;YACjE,wEAAwE;YACxE,uEAAuE;YACvE,8DAA8D;YAC9D,MAAM,IAAI,KAAK,CACd,8EAA8E,KAAK,yDAAyD,CAC5I,CAAC;QACH,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,aAAa,CAAC,CAAqB,EAAE,CAAqB;IAClE,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IACvE,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc,EAAE,QAAgB;IAC/D,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9D,MAAM,IAAI,KAAK,CACd,sCAAsC,QAAQ,WAAW,KAAK,sEAAsE,CACpI,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IACD,MAAM,IAAI,KAAK,CACd,8BAA8B,QAAQ,oDAAoD,OAAO,KAAK,IAAI,CAC1G,CAAC;AACH,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,MAAM,UAAU,GAEnB;IACH,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC;IACtB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC;IAC3B,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,WAAW,CAAC;IAChC,MAAM,EAAE,CAAC,CAAC,oBAAoB,EAAE,oBAAoB,CAAC;CACrD,CAAC;AAEF,6EAA6E;AAC7E,MAAM,CAAC,MAAM,WAAW,GAAG,qBAAqB,CAAC;AAEjD;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAChC,KAAc,EACd,IAAiB,EACjB,QAAgB;IAEhB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO;IAClD,QAAQ,IAAI,EAAE,CAAC;QACd,KAAK,KAAK,CAAC;QACX,KAAK,UAAU,CAAC;QAChB,KAAK,SAAS,CAAC;QACf,KAAK,QAAQ,CAAC,CAAC,CAAC;YACf,IAAI,KAAa,CAAC;YAClB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC/B,KAAK,GAAG,KAAK,CAAC;YACf,CAAC;iBAAM,IACN,OAAO,KAAK,KAAK,QAAQ;gBACzB,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC;gBACvB,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,EAC1B,CAAC;gBACF,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CACd,sCAAsC,QAAQ,mDAAmD,OAAO,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAClI,CAAC;YACH,CAAC;YACD,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,KAAK,GAAG,GAAG,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CACd,uBAAuB,IAAI,YAAY,QAAQ,WAAW,MAAM,CAAC,KAAK,CAAC,mBAAmB,IAAI,WAAW,GAAG,KAAK,GAAG,qDAAqD,CACzK,CAAC;YACH,CAAC;YACD,OAAO;QACR,CAAC;QACD,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ,CAAC,CAAC,CAAC;YACf,MAAM,KAAK,GACV,OAAO,KAAK,KAAK,QAAQ;gBACxB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;gBACf,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ;oBAC1B,CAAC,CAAC,KAAK;oBACP,CAAC,CAAC,SAAS,CAAC;YACf,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpD,MAAM,IAAI,KAAK,CACd,oCAAoC,QAAQ,mCAAmC,OAAO,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAChH,CAAC;YACH,CAAC;YACD,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,WAAW,EAAE,CAAC;gBACvD,MAAM,IAAI,KAAK,CACd,2CAA2C,QAAQ,WAAW,MAAM,CAAC,KAAK,CAAC,mFAAmF,CAC9J,CAAC;YACH,CAAC;YACD,OAAO;QACR,CAAC;QACD,KAAK,MAAM;YACV,IAAI,OAAO,KAAK,KAAK,SAAS;gBAAE,OAAO;YACvC,MAAM,IAAI,KAAK,CACd,mCAAmC,QAAQ,6BAA6B,OAAO,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CACzG,CAAC;QACH,KAAK,SAAS,CAAC;QACf,KAAK,OAAO,CAAC;QACb,KAAK,WAAW;YACf,sEAAsE;YACtE,iEAAiE;YACjE,2EAA2E;YAC3E,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CACd,4CAA4C,QAAQ,iDAAiD,CACrG,CAAC;YACH,CAAC;YACD,OAAO;QACR,KAAK,SAAS;YACb,iEAAiE;YACjE,gEAAgE;YAChE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1D,MAAM,IAAI,KAAK,CACd,sCAAsC,QAAQ,+CAA+C,MAAM,CAAC,KAAK,CAAC,IAAI,CAC9G,CAAC;YACH,CAAC;YACD,OAAO;QACR;YACC,OAAO;IACT,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAClC,IAAkB,EAClB,MAA8B;IAE9B,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAElD,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC;QACjE,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACxE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;YAC9D,MAAM,OAAO,GAAqB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAC5D,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EACL,GAAG,CAAC,QAAQ,KAAK,IAAI,CAAC,UAAU;oBAC/B,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;oBACpE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;wBACjB,MAAM,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC;wBACvC,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;wBACjD,OAAO,KAAK,CAAC;oBACd,CAAC,CAAC;aACL,CAAC,CAAC,CAAC;YACJ,MAAM,IAAI,GAAqB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;gBACvD,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;gBACzC,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACjD,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,CAAC,CAAC,CAAC;YACH,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACtD,CAAC;IACF,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,CAAC;AAC5C,CAAC"}