Repository navigation
Expand file tree
/
Copy pathinsert_values_and_functions.ts
More file actions
103 lines (92 loc) · 3.19 KB
/
Copy pathinsert_values_and_functions.ts
File metadata and controls
103 lines (92 loc) · 3.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// An example how to send an INSERT INTO ... VALUES ... query that requires additional functions call.
// Inspired by https://github.com/ClickHouse/clickhouse-js/issues/239
import type { ClickHouseSettings } from "@clickhouse/client-web";
import { createClient } from "@clickhouse/client-web";
interface Data {
id: string;
timestamp: number;
email: string;
name: string | null;
}
const tableName = "insert_values_and_functions_web";
const client = createClient();
// Recommended for cluster usage to avoid situations where a query processing error occurred after the response code
// and HTTP headers were sent to the client, as it might happen before the changes were applied on the server.
// See https://clickhouse.com/docs/en/interfaces/http/#response-buffering
const commandSettings: ClickHouseSettings = {
wait_end_of_query: 1,
};
// Prepare an example table
await client.command({
query: `DROP TABLE IF EXISTS ${tableName}`,
clickhouse_settings: commandSettings,
});
await client.command({
query: `
CREATE TABLE ${tableName} (
id String,
timestamp DateTime64(3, 'UTC'),
email String,
name Nullable(String)
)
ENGINE MergeTree()
ORDER BY (id)
`,
clickhouse_settings: commandSettings,
});
// Here we are assuming that we are getting these rows from somewhere...
const rows = getRows(100);
// Generate the query and insert the values
const insertQuery = `
INSERT INTO ${tableName}
(id, timestamp, email, name)
VALUES
${rows.map((r) => toInsertValue(r)).join(",")}
`;
await client.command({
query: insertQuery,
clickhouse_settings: commandSettings,
});
// Get a few back and print those rows to check what was inserted
const sampleResultSet = await client.query({
query: `SELECT * FROM ${tableName} ORDER BY rand() LIMIT 3`,
format: "JSONEachRow",
});
console.info(`Sample inserted rows:`);
const sampleRows = await sampleResultSet.json<Data>();
sampleRows.forEach((row) => {
console.info(row);
});
// Close it during your application graceful shutdown
await client.close();
function getRows(n: number): Data[] {
const now = Date.now(); // UNIX timestamp in milliseconds
return [...new Array(n)].map((_, i) => ({
id: toHex(i.toString(10)),
timestamp: now - i * 1000, // subtract one second for each row
email: `email${i}@example.com`,
name: i % 2 === 0 ? `Name${i}` : null, // for every second row it is NULL
}));
}
// Convert an ASCII string to its hexadecimal representation using browser-friendly APIs.
// Equivalent to Buffer.from(value).toString('hex') in Node.js, but works in any JS runtime.
function toHex(str: string): string {
const bytes = new TextEncoder().encode(str);
let hex = "";
for (const b of bytes) {
hex += b.toString(16).padStart(2, "0");
}
return hex;
}
// Generates something like:
// (unhex('42'), '1623677409123', 'email42@example.com', 'Name')
// or
// (unhex('144'), '1623677409123', 'email144@example.com', NULL)
// if name is null.
function toInsertValue(row: Data): string {
const id = `unhex('${row.id}')`;
const timestamp = `'${row.timestamp}'`;
const email = `'${row.email}'`;
const name = row.name === null ? "NULL" : `'${row.name}'`;
return `(${id}, ${timestamp}, ${email}, ${name})`;
}