@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.
- package/README.md +69 -0
- package/dist/EonProvider.d.ts +51 -0
- package/dist/EonProvider.d.ts.map +1 -0
- package/dist/EonProvider.js +154 -0
- package/dist/EonProvider.js.map +1 -0
- package/dist/connection/EonConnection.d.ts +116 -0
- package/dist/connection/EonConnection.d.ts.map +1 -0
- package/dist/connection/EonConnection.js +15 -0
- package/dist/connection/EonConnection.js.map +1 -0
- package/dist/connection/config.d.ts +56 -0
- package/dist/connection/config.d.ts.map +1 -0
- package/dist/connection/config.js +14 -0
- package/dist/connection/config.js.map +1 -0
- package/dist/connection/websocket.d.ts +16 -0
- package/dist/connection/websocket.d.ts.map +1 -0
- package/dist/connection/websocket.js +383 -0
- package/dist/connection/websocket.js.map +1 -0
- package/dist/decorators/superTable.d.ts +73 -0
- package/dist/decorators/superTable.d.ts.map +1 -0
- package/dist/decorators/superTable.js +98 -0
- package/dist/decorators/superTable.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest/schemaless.d.ts +22 -0
- package/dist/ingest/schemaless.d.ts.map +1 -0
- package/dist/ingest/schemaless.js +161 -0
- package/dist/ingest/schemaless.js.map +1 -0
- package/dist/ingest/sql.d.ts +23 -0
- package/dist/ingest/sql.d.ts.map +1 -0
- package/dist/ingest/sql.js +59 -0
- package/dist/ingest/sql.js.map +1 -0
- package/dist/ingest/stmt.d.ts +82 -0
- package/dist/ingest/stmt.d.ts.map +1 -0
- package/dist/ingest/stmt.js +246 -0
- package/dist/ingest/stmt.js.map +1 -0
- package/dist/metadata-keys.d.ts +17 -0
- package/dist/metadata-keys.d.ts.map +1 -0
- package/dist/metadata-keys.js +17 -0
- package/dist/metadata-keys.js.map +1 -0
- package/dist/query/TimeSeriesQuery.d.ts +121 -0
- package/dist/query/TimeSeriesQuery.d.ts.map +1 -0
- package/dist/query/TimeSeriesQuery.js +291 -0
- package/dist/query/TimeSeriesQuery.js.map +1 -0
- package/dist/query/native.d.ts +22 -0
- package/dist/query/native.d.ts.map +1 -0
- package/dist/query/native.js +135 -0
- package/dist/query/native.js.map +1 -0
- package/dist/repository/SuperTableRepository.d.ts +80 -0
- package/dist/repository/SuperTableRepository.d.ts.map +1 -0
- package/dist/repository/SuperTableRepository.js +232 -0
- package/dist/repository/SuperTableRepository.js.map +1 -0
- package/dist/schema/CreateStableSpec.d.ts +140 -0
- package/dist/schema/CreateStableSpec.d.ts.map +1 -0
- package/dist/schema/CreateStableSpec.js +41 -0
- package/dist/schema/CreateStableSpec.js.map +1 -0
- package/dist/schema/EonMigrationRunner.d.ts +71 -0
- package/dist/schema/EonMigrationRunner.d.ts.map +1 -0
- package/dist/schema/EonMigrationRunner.js +295 -0
- package/dist/schema/EonMigrationRunner.js.map +1 -0
- package/dist/schema/EonSchema.d.ts +128 -0
- package/dist/schema/EonSchema.d.ts.map +1 -0
- package/dist/schema/EonSchema.js +309 -0
- package/dist/schema/EonSchema.js.map +1 -0
- package/dist/schema/Migration.d.ts +47 -0
- package/dist/schema/Migration.d.ts.map +1 -0
- package/dist/schema/Migration.js +55 -0
- package/dist/schema/Migration.js.map +1 -0
- package/dist/schema/compile.d.ts +33 -0
- package/dist/schema/compile.d.ts.map +1 -0
- package/dist/schema/compile.js +70 -0
- package/dist/schema/compile.js.map +1 -0
- package/dist/schema/sync.d.ts +45 -0
- package/dist/schema/sync.d.ts.map +1 -0
- package/dist/schema/sync.js +102 -0
- package/dist/schema/sync.js.map +1 -0
- package/dist/services/connection.d.ts +33 -0
- package/dist/services/connection.d.ts.map +1 -0
- package/dist/services/connection.js +71 -0
- package/dist/services/connection.js.map +1 -0
- package/dist/testing/Factory.d.ts +43 -0
- package/dist/testing/Factory.d.ts.map +1 -0
- package/dist/testing/Factory.js +134 -0
- package/dist/testing/Factory.js.map +1 -0
- package/dist/testing/FakeEonConnection.d.ts +43 -0
- package/dist/testing/FakeEonConnection.d.ts.map +1 -0
- package/dist/testing/FakeEonConnection.js +315 -0
- package/dist/testing/FakeEonConnection.js.map +1 -0
- package/dist/testing/index.d.ts +34 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +67 -0
- package/dist/testing/index.js.map +1 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +65 -0
- package/scripts/copy-napi.mjs +72 -0
- package/src/EonProvider.ts +222 -0
- package/src/connection/EonConnection.ts +146 -0
- package/src/connection/config.ts +60 -0
- package/src/connection/websocket.ts +436 -0
- package/src/decorators/superTable.ts +169 -0
- package/src/index.ts +118 -0
- package/src/ingest/schemaless.ts +211 -0
- package/src/ingest/sql.ts +73 -0
- package/src/ingest/stmt.ts +335 -0
- package/src/metadata-keys.ts +20 -0
- package/src/query/TimeSeriesQuery.ts +480 -0
- package/src/query/native.ts +180 -0
- package/src/repository/SuperTableRepository.ts +347 -0
- package/src/schema/CreateStableSpec.ts +184 -0
- package/src/schema/EonMigrationRunner.ts +378 -0
- package/src/schema/EonSchema.ts +396 -0
- package/src/schema/Migration.ts +66 -0
- package/src/schema/compile.ts +109 -0
- package/src/schema/sync.ts +142 -0
- package/src/services/connection.ts +89 -0
- package/src/testing/Factory.ts +186 -0
- package/src/testing/FakeEonConnection.ts +351 -0
- 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"}
|