Setting the file. One moment.
Observability Example Test · Clickhouse Js Node Rowbinary · ClickHouse/agent-skills · Skills Docs
ContentsBack to the top of the page (opens in a new tab)
tests/ observability.example.test.ts
TypeScript · 84 lines · 4 KB
;
10
11 /**
12 * The gotcha-heavy example end to end: a single SELECT (no table needed) builds
13 * rows with `Variant`, `DateTime64(3)`, `Map(LowCardinality(String), String)`,
14 * `Array(Tuple(LowCardinality(String), Float64))`, `Array(Nullable(Int64))`,
15 * `Enum8`, and `UUID`, then both readers decode it. The experimental types need
16 * their `SETTINGS` flags on the query.
17 */
18 const SQL = ( n : number ) : string =>
19 `SELECT
20 toUInt64(number) AS id,
21 toDateTime64('2021-01-01 00:00:00', 3, 'UTC') + number AS ts,
22 CAST(number % 4 + 1 AS Enum8('debug'=1,'info'=2,'warn'=3,'error'=4)) AS level,
23 generateUUIDv4() AS trace_id,
24 multiIf(
25 number % 3 = 0, CAST(toInt64(number) AS Variant(String, Int64, Float64)),
26 number % 3 = 1, CAST(concat('s', toString(number)) AS Variant(String, Int64, Float64)),
27 CAST(toFloat64(number) / 2 AS Variant(String, Int64, Float64))
28 ) AS payload,
29 CAST(map('env','prod','az',toString(number % 3)) AS Map(LowCardinality(String), String)) AS tags,
30 arrayMap(x -> CAST(tuple(concat('m', toString(x)), toFloat64(x)/10) AS Tuple(name LowCardinality(String), value Float64)), range(number % 3)) AS metrics,
31 arrayMap(x -> CAST(if(x % 2 = 0, toInt64(x)*1000000000, NULL) AS Nullable(Int64)), range(number % 4)) AS attrs
32 FROM numbers(${ n })
33 SETTINGS allow_experimental_variant_type=1, allow_suspicious_variant_types=1, allow_suspicious_low_cardinality_types=1
34 FORMAT RowBinary` ;
35
36 describe ( "example: observability (Variant / DateTime64 / LowCardinality / nested)" , () => {
37 it ( "API and optimized readers agree, consume exactly, and decode the gotchas" , async () => {
38 const buf = await query ( SQL ( 64 ));
39
40 const a = new Cursor (buf);
41 const viaApi : ObsRow [] = readRows (readObsRow)(a);
42 expect (a.pos, "API reader consumes the whole buffer" ). toBe (a.buf. length );
43
44 const b = new Cursor (buf);
45 const viaFast : ObsRow [] = readRows (readObsRowFast)(b);
46 expect (b.pos, "fast reader consumes the whole buffer" ). toBe (b.buf. length );
47
48 // The optimized reader must produce byte-identical results to the API one.
49 expect (viaFast). toEqual (viaApi);
50 expect (viaApi). toHaveLength ( 64 );
51
52 // Spot-check the gotchas on the first rows.
53 expect (viaApi[ 0 ] ! .id). toBe ( 0 n ); // UInt64 -> bigint
54 expect (viaApi[ 0 ] ! .ts). toBe ( "2021-01-01T00:00:00.000Z" ); // DateTime64(3)
55 expect (viaApi[ 0 ] ! .level). toBe ( 1 ); // Enum8 underlying int ('debug')
56 expect (viaApi[ 0 ] ! .tags). toEqual (
57 new Map ([
58 [ "env" , "prod" ],
59 [ "az" , "0" ],
60 ]),
61 );
62 expect (viaApi[ 0 ] ! .metrics). toEqual ([]);
63 expect (viaApi[ 0 ] ! .attrs). toEqual ([]);
64
65 // Variant active type rotates by row — proves the sort-by-type-name
66 // discriminant mapping (0=Float64, 1=Int64, 2=String) is right.
67 expect (viaApi[ 0 ] ! .payload). toBe ( 0 n ); // number%3==0 -> Int64
68 expect (viaApi[ 1 ] ! .payload). toBe ( "s1" ); // number%3==1 -> String
69 expect (viaApi[ 2 ] ! .payload). toBe ( 1 ); // number==2 -> Float64 1.0
70
71 // Nested + Nullable + wide int.
72 expect (viaApi[ 2 ] ! .metrics). toEqual ([
73 { name: "m0" , value: 0 },
74 { name: "m1" , value: 0.1 },
75 ]);
76 expect (viaApi[ 1 ] ! .attrs). toEqual ([ 0 n ]);
77 expect (viaApi[ 2 ] ! .attrs). toEqual ([ 0 n , null ]);
78
79 // trace_id is a canonical UUID string.
80 expect (viaApi[ 0 ] ! .traceId). toMatch (
81 / ^ [0-9a-f] {8} - [0-9a-f] {4} - [0-9a-f] {4} - [0-9a-f] {4} - [0-9a-f] {12}$ / ,
82 );
83 });
84 });