@transitive-sdk/clickhouse 0.3.2 → 0.3.4
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/index.js +37 -26
- package/package.json +3 -2
- package/test/clickhouse.test.js +1 -1
package/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
|
+
const waitPort = require('wait-port');
|
|
2
3
|
const { createClient } = require('@clickhouse/client');
|
|
4
|
+
|
|
3
5
|
const { topicToPath, topicMatch } = require('@transitive-sdk/datacache');
|
|
4
6
|
|
|
5
7
|
// Default TTL in days for mqtt_history table
|
|
@@ -43,11 +45,21 @@ class ClickHouse {
|
|
|
43
45
|
topics = {}; // list of topics registered for storage, as object for de-duplication
|
|
44
46
|
|
|
45
47
|
/** Create the client, connecting to Clickhouse */
|
|
46
|
-
init({ url, dbName, user, password } = {}) {
|
|
48
|
+
async init({ url, dbName, user, password } = {}) {
|
|
49
|
+
|
|
47
50
|
const _url = url || process.env.CLICKHOUSE_URL || 'http://clickhouse:8123';
|
|
48
51
|
const _dbName = dbName || process.env.CLICKHOUSE_DB || 'default';
|
|
49
52
|
const _user = user || process.env.CLICKHOUSE_USER || 'default';
|
|
50
53
|
|
|
54
|
+
const {hostname, port} = URL.parse(_url);
|
|
55
|
+
const interval = 200;
|
|
56
|
+
await waitPort({
|
|
57
|
+
host: hostname,
|
|
58
|
+
port: port || 80,
|
|
59
|
+
interval
|
|
60
|
+
}, 10000);
|
|
61
|
+
await new Promise(done => setTimeout(done, 200));
|
|
62
|
+
|
|
51
63
|
// console.debug(`Creating ClickHouse client for URL: ${_url}, DB: ${_dbName}, User: ${_user}`);
|
|
52
64
|
|
|
53
65
|
this._client = createClient({
|
|
@@ -72,6 +84,8 @@ class ClickHouse {
|
|
|
72
84
|
// asterisk_include_materialized_columns: 1
|
|
73
85
|
},
|
|
74
86
|
});
|
|
87
|
+
|
|
88
|
+
await this._client.query({ query: 'SELECT 1' });
|
|
75
89
|
}
|
|
76
90
|
|
|
77
91
|
/** Get the Clickhouse client (from @clickhouse/client) */
|
|
@@ -83,6 +97,15 @@ class ClickHouse {
|
|
|
83
97
|
return this._client;
|
|
84
98
|
}
|
|
85
99
|
|
|
100
|
+
/* sets up default row level security policies in ClickHouse */
|
|
101
|
+
async ensureDefaultPermissions() {
|
|
102
|
+
const cmd = 'CREATE ROW POLICY IF NOT EXISTS';
|
|
103
|
+
for (let query of [
|
|
104
|
+
`${cmd} default_users ON default.* USING OrgId = splitByString('_', currentUser())[2] TO ALL`,
|
|
105
|
+
`${cmd} default_admin ON default.* USING 1 TO ${process.env.CLICKHOUSE_USER || 'default'}`
|
|
106
|
+
]) await this.client.command({ query });
|
|
107
|
+
}
|
|
108
|
+
|
|
86
109
|
/** Create a table if it does not already exist adding OrgId and DeviceId
|
|
87
110
|
* columns to the schema for multi-tenancy support.
|
|
88
111
|
* @param {string} tableName - name of the table to create
|
|
@@ -260,35 +283,26 @@ class ClickHouse {
|
|
|
260
283
|
* @param {string} topic - MQTT topic to register
|
|
261
284
|
*/
|
|
262
285
|
async registerMqttTopicForStorage(selector, ttlDays = DEFAULT_TTL_DAYS) {
|
|
263
|
-
this.topics[selector] = true;
|
|
264
|
-
|
|
265
|
-
// ---------------------------------------------------------------
|
|
266
|
-
// Set/update TTL for this capability and sub-topic
|
|
267
286
|
|
|
268
287
|
const path = topicToPath(selector);
|
|
269
288
|
|
|
270
289
|
if (path.length < 4) {
|
|
271
290
|
// underspecified, don't set TTL
|
|
291
|
+
console.warn('Not registering topic as it is too short', selector);
|
|
272
292
|
return;
|
|
273
293
|
}
|
|
274
294
|
|
|
275
|
-
|
|
276
|
-
// const topicPartSelectors = [
|
|
277
|
-
// [2, path[2]],
|
|
278
|
-
// [3, path[3]]
|
|
279
|
-
// ];
|
|
295
|
+
this.topics[selector] = true;
|
|
280
296
|
|
|
281
|
-
//
|
|
297
|
+
// ---------------------------------------------------------------
|
|
298
|
+
// Set/update TTL for this capability and sub-topic
|
|
282
299
|
|
|
283
|
-
//
|
|
284
|
-
// // filter out wildcards
|
|
285
|
-
// .filter(([i, value]) => !['+','#'].includes(value[0]))
|
|
286
|
-
// // map to WHERE conditions
|
|
287
|
-
// .map(([i, value]) => `((TopicParts[${i + 1}]) = '${value}')`);
|
|
300
|
+
// Derive WHERE conditions for TTL expression from non-wildcards
|
|
288
301
|
const where = path2where(path);
|
|
289
302
|
|
|
290
303
|
if (where.length == 0) {
|
|
291
304
|
// underspecified, don't set TTL
|
|
305
|
+
console.warn('Not setting TTL as topic is under specified', selector);
|
|
292
306
|
return;
|
|
293
307
|
}
|
|
294
308
|
|
|
@@ -307,17 +321,14 @@ class ClickHouse {
|
|
|
307
321
|
const newTTLStatement =
|
|
308
322
|
`toDateTime(Timestamp) + toIntervalDay(${ttlDays}) ${whereStatement}`;
|
|
309
323
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
ttls.forEach((ttl, i) => {
|
|
313
|
-
if (ttl.replace(/[()]/g, '').endsWith(whereStatement)) {
|
|
314
|
-
// condition already present, just replace it to update time
|
|
315
|
-
ttls[i] = newTTLStatement;
|
|
316
|
-
present = true;
|
|
317
|
-
}
|
|
318
|
-
});
|
|
324
|
+
const currentIndex =
|
|
325
|
+
ttls.findIndex(ttl => ttl.replace(/[()]/g, '').endsWith(whereStatement));
|
|
319
326
|
|
|
320
|
-
if (
|
|
327
|
+
if (currentIndex >= 0) {
|
|
328
|
+
// replace existing
|
|
329
|
+
ttls[currentIndex] = newTTLStatement;
|
|
330
|
+
} else {
|
|
331
|
+
// add new
|
|
321
332
|
ttls.push(newTTLStatement);
|
|
322
333
|
}
|
|
323
334
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transitive-sdk/clickhouse",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "A tiny ClickHouse utility class for use in the Transitive framework.",
|
|
5
5
|
"homepage": "https://transitiverobotics.com",
|
|
6
6
|
"repository": {
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@clickhouse/client": "^1.12.1",
|
|
28
|
-
"@transitive-sdk/datacache": "^0.14.1"
|
|
28
|
+
"@transitive-sdk/datacache": "^0.14.1",
|
|
29
|
+
"wait-port": "^1.1.0"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"dotenv": "^17.2.3"
|
package/test/clickhouse.test.js
CHANGED
|
@@ -47,7 +47,7 @@ describe('ClickHouse', function() {
|
|
|
47
47
|
const dataCache = new DataCache({});
|
|
48
48
|
|
|
49
49
|
before(async () => {
|
|
50
|
-
clickhouse.init({ url: CLICKHOUSE_URL });
|
|
50
|
+
await clickhouse.init({ url: CLICKHOUSE_URL });
|
|
51
51
|
/* Register for `insert` events on ClickHouse client */
|
|
52
52
|
emitter = interceptInserts();
|
|
53
53
|
|