Skip to content

Commit 78816e6

Browse files
authored
Add minimal Variant/Dynamic/JSON examples and tests using JSONEachRow format (#305)
1 parent 9b5270b commit 78816e6

File tree

6 files changed

+146
-21
lines changed

6 files changed

+146
-21
lines changed

.docker/clickhouse/single_node_tls/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM clickhouse/clickhouse-server:24.3-alpine
1+
FROM clickhouse/clickhouse-server:24.8-alpine
22
COPY .docker/clickhouse/single_node_tls/certificates /etc/clickhouse-server/certs
33
RUN chown clickhouse:clickhouse -R /etc/clickhouse-server/certs \
44
&& chmod 600 /etc/clickhouse-server/certs/* \

docker-compose.cluster.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ version: '2.3'
22

33
services:
44
clickhouse1:
5-
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION-24.3-alpine}'
5+
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION-24.8-alpine}'
66
ulimits:
77
nofile:
88
soft: 262144
@@ -19,7 +19,7 @@ services:
1919
- './.docker/clickhouse/users.xml:/etc/clickhouse-server/users.xml'
2020

2121
clickhouse2:
22-
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION-24.3-alpine}'
22+
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION-24.8-alpine}'
2323
ulimits:
2424
nofile:
2525
soft: 262144

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
version: '3.8'
22
services:
33
clickhouse:
4-
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION-24.3-alpine}'
4+
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION-24.8-alpine}'
55
container_name: 'clickhouse-js-clickhouse-server'
66
ports:
77
- '8123:8123'

examples/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ If something is missing, or you found a mistake in one of these examples, please
5858
- [select_streaming_json_each_row_for_await.ts](node/select_streaming_json_each_row_for_await.ts) - (Node.js only) similar to [select_streaming_json_each_row.ts](node/select_streaming_json_each_row.ts), but using the `for await` loop syntax.
5959
- [select_streaming_text_line_by_line.ts](node/select_streaming_text_line_by_line.ts) - (Node.js only) streaming text formats from ClickHouse and processing it line by line. In this example, CSV format is used.
6060

61+
#### Data types
62+
63+
- [dynamic_variant_json.ts](./dynamic_variant_json.ts) - using experimental [Dynamic](https://clickhouse.com/docs/en/sql-reference/data-types/dynamic)/[Variant](https://clickhouse.com/docs/en/sql-reference/data-types/variant)/[JSON](https://clickhouse.com/docs/en/sql-reference/data-types/newjson) data types with [JSONEachRow](https://clickhouse.com/docs/en/interfaces/formats#jsoneachrow) format.
64+
6165
#### Special cases
6266

6367
- [default_format_setting.ts](default_format_setting.ts) - sending queries using `exec` method without a `FORMAT` clause; the default format will be set from the client settings.

examples/dynamic_variant_json.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { createClient } from '@clickhouse/client' // or '@clickhouse/client-web'
2+
3+
void (async () => {
4+
const tableName = `chjs_dynamic_variant_json`
5+
const client = createClient({
6+
clickhouse_settings: {
7+
// Since ClickHouse 24.1
8+
allow_experimental_variant_type: 1,
9+
// Since ClickHouse 24.5
10+
allow_experimental_dynamic_type: 1,
11+
// Since ClickHouse 24.8
12+
allow_experimental_json_type: 1,
13+
},
14+
})
15+
await client.command({
16+
query: `
17+
CREATE OR REPLACE TABLE ${tableName}
18+
(
19+
id UInt64,
20+
var Variant(Int64, String),
21+
dynamic Dynamic,
22+
json JSON
23+
)
24+
ENGINE MergeTree
25+
ORDER BY id
26+
`,
27+
})
28+
// Sample representation in JSONEachRow format
29+
const values = [
30+
{
31+
id: 1,
32+
var: 42,
33+
dynamic: 'foo',
34+
json: {
35+
foo: 'x',
36+
},
37+
},
38+
{
39+
id: 2,
40+
var: 'str',
41+
// defaults to Int64; will be represented as a string in JSON* family formats
42+
// this behavior can be changed with `output_format_json_quote_64bit_integers` setting (default is 1).
43+
// see https://clickhouse.com/docs/en/operations/settings/formats#output_format_json_quote_64bit_integers
44+
dynamic: 144,
45+
json: {
46+
bar: 10,
47+
},
48+
},
49+
]
50+
await client.insert({
51+
table: tableName,
52+
format: 'JSONEachRow',
53+
values,
54+
})
55+
const rs = await client.query({
56+
query: `
57+
SELECT *,
58+
variantType(var),
59+
dynamicType(dynamic),
60+
dynamicType(json.foo),
61+
dynamicType(json.bar)
62+
FROM ${tableName}
63+
`,
64+
format: 'JSONEachRow',
65+
})
66+
console.log(await rs.json())
67+
await client.close()
68+
})()

packages/client-common/__tests__/integration/data_types.test.ts

Lines changed: 70 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@ describe('data types', () => {
129129
})
130130
const result = await client
131131
.query({
132-
query: `SELECT * FROM ${table} ORDER BY id ASC`,
132+
query: `SELECT *
133+
FROM ${table}
134+
ORDER BY id ASC`,
133135
format: 'TabSeparated',
134136
})
135137
.then((r) => r.text())
@@ -238,7 +240,9 @@ describe('data types', () => {
238240
await insertData(table, values)
239241
const result = await client
240242
.query({
241-
query: `SELECT CAST(e1, 'Int8') AS e1, CAST(e2, 'Int8') AS e2 FROM ${table} ORDER BY id ASC`,
243+
query: `SELECT CAST(e1, 'Int8') AS e1, CAST(e2, 'Int8') AS e2
244+
FROM ${table}
245+
ORDER BY id ASC`,
242246
format: 'JSONEachRow',
243247
})
244248
.then((r) => r.json())
@@ -426,23 +430,26 @@ describe('data types', () => {
426430
expect(
427431
await client
428432
.query({
429-
query: `SELECT sum(distance) FROM ${table}`,
433+
query: `SELECT sum(distance)
434+
FROM ${table}`,
430435
format: 'TabSeparated',
431436
})
432437
.then((r) => r.text()),
433438
).toEqual('125.53\n')
434439
expect(
435440
await client
436441
.query({
437-
query: `SELECT max(distance) FROM ${table}`,
442+
query: `SELECT max(distance)
443+
FROM ${table}`,
438444
format: 'TabSeparated',
439445
})
440446
.then((r) => r.text()),
441447
).toEqual('100.52\n')
442448
expect(
443449
await client
444450
.query({
445-
query: `SELECT uniqExact(distance) FROM ${table}`,
451+
query: `SELECT uniqExact(distance)
452+
FROM ${table}`,
446453
format: 'TabSeparated',
447454
})
448455
.then((r) => r.text()),
@@ -504,9 +511,10 @@ describe('data types', () => {
504511
await insertAndAssert(table, values)
505512
})
506513

507-
// JSON cannot be used on a "modern" Cloud instance
508-
whenOnEnv(TestEnv.LocalSingleNode, TestEnv.LocalCluster, TestEnv.Cloud).it(
509-
'should work with JSON',
514+
// New experimental JSON type
515+
// https://clickhouse.com/docs/en/sql-reference/data-types/newjson
516+
whenOnEnv(TestEnv.LocalSingleNode, TestEnv.LocalCluster).it(
517+
'should work with (new) JSON',
510518
async () => {
511519
const values = [
512520
{
@@ -516,8 +524,40 @@ describe('data types', () => {
516524
o: { a: 2, b: { c: 3, d: [4, 5, 6] } },
517525
},
518526
]
519-
const table = await createTableWithFields(client, `o Object('json')`, {
520-
allow_experimental_object_type: 1,
527+
const table = await createTableWithFields(client, `o JSON`, {
528+
allow_experimental_json_type: 1,
529+
})
530+
await insertAndAssert(table, values, {
531+
output_format_json_quote_64bit_integers: 0,
532+
})
533+
},
534+
)
535+
536+
// New experimental Variant type
537+
// https://clickhouse.com/docs/en/sql-reference/data-types/variant
538+
whenOnEnv(TestEnv.LocalSingleNode, TestEnv.LocalCluster).it(
539+
'should work with Variant',
540+
async () => {
541+
const values = [{ var: 'foo' }, { var: 42 }]
542+
const table = await createTableWithFields(
543+
client,
544+
`var Variant(String, Int32)`,
545+
{
546+
allow_experimental_variant_type: 1,
547+
},
548+
)
549+
await insertAndAssert(table, values)
550+
},
551+
)
552+
553+
// New experimental Dynamic type
554+
// https://clickhouse.com/docs/en/sql-reference/data-types/dynamic
555+
whenOnEnv(TestEnv.LocalSingleNode, TestEnv.LocalCluster).it(
556+
'should work with Dynamic',
557+
async () => {
558+
const values = [{ dyn: 'foo' }, { dyn: { bar: 'qux' } }]
559+
const table = await createTableWithFields(client, `dyn Dynamic`, {
560+
allow_experimental_dynamic_type: 1,
521561
})
522562
await insertAndAssert(table, values)
523563
},
@@ -655,7 +695,9 @@ describe('data types', () => {
655695
})
656696
const result = await client
657697
.query({
658-
query: `SELECT n.id, n.name, n.createdAt, n.roles FROM ${table} ORDER BY id ASC`,
698+
query: `SELECT n.id, n.name, n.createdAt, n.roles
699+
FROM ${table}
700+
ORDER BY id ASC`,
659701
format: 'JSONEachRow',
660702
})
661703
.then((r) => r.json())
@@ -683,25 +725,36 @@ describe('data types', () => {
683725
) {
684726
const values = data.map((v, i) => ({ ...v, id: i + 1 }))
685727
await client.insert({
728+
format: 'JSONEachRow',
686729
table,
687730
values,
688-
format: 'JSONEachRow',
689731
clickhouse_settings,
690732
})
691733
}
692734

693-
async function assertData<T>(table: string, data: T[]) {
735+
async function assertData<T>(
736+
table: string,
737+
data: T[],
738+
clickhouse_settings: ClickHouseSettings = {},
739+
) {
694740
const result = await client
695741
.query({
696-
query: `SELECT * EXCEPT (id) FROM ${table} ORDER BY id ASC`,
742+
query: `SELECT * EXCEPT (id)
743+
FROM ${table}
744+
ORDER BY id ASC`,
697745
format: 'JSONEachRow',
746+
clickhouse_settings,
698747
})
699748
.then((r) => r.json())
700749
expect(result).toEqual(data)
701750
}
702751

703-
async function insertAndAssert<T>(table: string, data: T[]) {
704-
await insertData(table, data)
705-
await assertData(table, data)
752+
async function insertAndAssert<T>(
753+
table: string,
754+
data: T[],
755+
clickhouse_settings: ClickHouseSettings = {},
756+
) {
757+
await insertData(table, data, clickhouse_settings)
758+
await assertData(table, data, clickhouse_settings)
706759
}
707760
})

0 commit comments

Comments
 (0)