clickhouse-migrations 1.1.4 → 1.3.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 CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  # clickhouse-migrations
3
2
 
4
3
  > ClickHouse Migrations CLI
@@ -13,11 +12,11 @@ npm install clickhouse-migrations
13
12
 
14
13
  Create a directory, where migrations will be stored. It will be used as the value for the `--migrations-home` option (or for environment variable `CH_MIGRATIONS_HOME`).
15
14
 
16
- In the directory, create migration files, which should be named like this: `1_some_text.sql`, `2_other_text.sql`, `10_more_test.sql`. What's important here is that the migration version number should come first, followed by an underscore (`_`), and then any text can follow. The version number should increase for every next migration. Please note that once a migration file has been applied to the database, it cannot be modified or removed.
15
+ In the directory, create migration files, which should be named like this: `1_some_text.sql`, `2_other_text.sql`, `10_more_test.sql`. What's important here is that the migration version number should come first, followed by an underscore (`_`), and then any text can follow. The version number should increase for every next migration. Please note that once a migration file has been applied to the database, it cannot be modified or removed.
17
16
 
18
- For migrations' content should be used correct SQL ClickHouse queries. Multiple queries can be used in a single migration file, and each query should be terminated with a semicolon (;). The queries could be idempotent - for example: `CREATE TABLE IF NOT EXISTS table ...;` Clickhouse settings, that can be included at the query level, can be added like `SET allow_experimental_object_type = 1;`. For adding comments should be used `--`, `# `, `#!`.
17
+ For migrations' content should be used correct SQL ClickHouse queries. Multiple queries can be used in a single migration file, and each query should be terminated with a semicolon (;). The queries could be idempotent - for example: `CREATE TABLE IF NOT EXISTS table ...;` Clickhouse settings, that can be included at the query level, can be added like `SET allow_experimental_object_type = 1;`. For adding comments should be used `--`, `# `, `#!`.
19
18
 
20
- If the database provided in the `--db` option (or in `CH_MIGRATIONS_DB`) doesn't exist, it will be created automatically.
19
+ If the database provided in the `--db` option (or in `CH_MIGRATIONS_DB`) doesn't exist, it will be created automatically. To disable this behavior (for example, when the user has no privileges to create databases), use the `--skip-db-creation` option (or set `CH_MIGRATIONS_SKIP_DB_CREATION` to `'true'`); in that case the database must already exist.
21
20
 
22
21
  For TLS/HTTPS connections, you can provide a custom CA certificate and optional client certificate/key via the `--ca-cert`, `--cert`, and `--key` options (or the `CH_MIGRATIONS_CA_CERT`, `CH_MIGRATIONS_CERT`, and `CH_MIGRATIONS_KEY` environment variables).
23
22
 
@@ -26,7 +25,7 @@ For TLS/HTTPS connections, you can provide a custom CA certificate and optional
26
25
  $ clickhouse-migrations migrate <options>
27
26
 
28
27
  Required options
29
- --host=<name> Clickhouse hostname
28
+ --host=<name> Clickhouse hostname
30
29
  (ex. https://clickhouse:8123)
31
30
  --user=<name> Username
32
31
  --password=<password> Password
@@ -36,11 +35,14 @@ For TLS/HTTPS connections, you can provide a custom CA certificate and optional
36
35
  Optional options
37
36
  --db-engine=<value> ON CLUSTER and/or ENGINE for DB
38
37
  (default: 'ENGINE=Atomic')
39
- --timeout=<value> Client request timeout
38
+ --table-engine=<value> Engine for the _migrations table
39
+ (default: 'MergeTree')
40
+ --timeout=<value> Client request timeout
40
41
  (milliseconds, default: 30000)
41
42
  --ca-cert=<path> CA certificate file path
42
43
  --cert=<path> Client certificate file path
43
- --key=<path> Client key file path
44
+ --key=<path> Client key file path
45
+ --skip-db-creation Skip database creation
44
46
 
45
47
  Environment variables
46
48
  Instead of options can be used environment variables.
@@ -51,24 +53,30 @@ For TLS/HTTPS connections, you can provide a custom CA certificate and optional
51
53
  CH_MIGRATIONS_HOME Migrations' directory (--migrations-home)
52
54
 
53
55
  CH_MIGRATIONS_DB_ENGINE (optional) DB engine (--db-engine)
54
- CH_MIGRATIONS_TIMEOUT (optional) Client request timeout
56
+ CH_MIGRATIONS_TABLE_ENGINE (optional) Migrations table engine (--table-engine)
57
+ CH_MIGRATIONS_TIMEOUT (optional) Client request timeout
55
58
  (--timeout)
56
59
  CH_MIGRATIONS_CA_CERT (optional) CA certificate file path
57
60
  CH_MIGRATIONS_CERT (optional) Client certificate file path
58
61
  CH_MIGRATIONS_KEY (optional) Client key file path
62
+ CH_MIGRATIONS_SKIP_DB_CREATION
63
+ (optional) Skip database creation,
64
+ set to 'true' to enable
65
+ (--skip-db-creation)
59
66
 
60
67
 
61
68
  CLI executions examples
62
69
  settings are passed as command-line options
63
70
  clickhouse-migrations migrate --host=http://localhost:8123
64
- --user=default --password='' --db=analytics
71
+ --user=default --password='' --db=analytics
65
72
  --migrations-home=/app/clickhouse/migrations
66
73
 
67
74
  settings provided as options, including timeout and db-engine
68
- clickhouse-migrations migrate --host=http://localhost:8123
69
- --user=default --password='' --db=analytics
70
- --migrations-home=/app/clickhouse/migrations --timeout=60000
71
- --db-engine="ON CLUSTER default ENGINE=Replicated('{replica}')"
75
+ clickhouse-migrations migrate --host=http://localhost:8123
76
+ --user=default --password='' --db=analytics
77
+ --migrations-home=/app/clickhouse/migrations --timeout=60000
78
+ --db-engine="ON CLUSTER default ENGINE=Replicated('{replica}')"
79
+ --table-engine="ReplicatedMergeTree('/clickhouse/tables/{database}/migrations', '{replica}')"
72
80
 
73
81
  settings provided as environment variables
74
82
  clickhouse-migrations migrate
@@ -81,10 +89,16 @@ For TLS/HTTPS connections, you can provide a custom CA certificate and optional
81
89
  --user=default --password='' --db=analytics
82
90
  --migrations-home=/app/clickhouse/migrations
83
91
  --ca-cert=/app/certs/ca.pem --cert=/app/certs/client.crt --key=/app/certs/client.key
92
+
93
+ skip database creation (assumes database already exists)
94
+ clickhouse-migrations migrate --host=http://localhost:8123
95
+ --user=default --password='' --db=analytics
96
+ --migrations-home=/app/clickhouse/migrations --skip-db-creation
84
97
  ```
85
98
 
86
99
  Migration file example:
87
100
  (e.g., located at /app/clickhouse/migrations/1_init.sql)
101
+
88
102
  ```
89
103
  -- an example of migration file 1_init.sql
90
104
 
@@ -96,8 +110,8 @@ CREATE TABLE IF NOT EXISTS events (
96
110
  event JSON
97
111
  )
98
112
  ENGINE=AggregatingMergeTree
99
- PARTITION BY toYYYYMM(timestamp)
100
- SAMPLE BY session_id
101
- ORDER BY (session_id)
113
+ PARTITION BY toYYYYMM(timestamp)
114
+ SAMPLE BY session_id
115
+ ORDER BY (session_id)
102
116
  SETTINGS index_granularity = 8192;
103
- ```
117
+ ```
package/lib/migrate.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- declare const migration: (migrations_home: string, host: string, username: string, password: string, db_name: string, db_engine?: string, timeout?: string, ca_cert?: string | undefined, cert?: string | undefined, key?: string | undefined) => Promise<void>;
1
+ declare const migration: (migrations_home: string, host: string, username: string, password: string, db_name: string, db_engine?: string, table_engine?: string, timeout?: string, ca_cert?: string | undefined, cert?: string | undefined, key?: string | undefined, skip_db_creation?: boolean) => Promise<void>;
2
2
  declare const migrate: () => void;
3
3
  export { migrate, migration };
package/lib/migrate.js CHANGED
@@ -35,6 +35,15 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
35
35
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
36
  }
37
37
  };
38
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
39
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
40
+ if (ar || !(i in from)) {
41
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
42
+ ar[i] = from[i];
43
+ }
44
+ }
45
+ return to.concat(ar || Array.prototype.slice.call(from));
46
+ };
38
47
  var __importDefault = (this && this.__importDefault) || function (mod) {
39
48
  return (mod && mod.__esModule) ? mod : { "default": mod };
40
49
  };
@@ -90,8 +99,8 @@ var connect = function (url, username, password, db_name, timeout, ca_cert, cert
90
99
  }
91
100
  return (0, client_1.createClient)(db_params);
92
101
  };
93
- var create_db = function (host, username, password, db_name, db_engine, timeout, ca_cert, cert, key) { return __awaiter(void 0, void 0, void 0, function () {
94
- var client, e_1, q, e_2;
102
+ var create_db = function (host, username, password, db_name, db_engine, timeout, ca_cert, cert, key, skip_db_creation) { return __awaiter(void 0, void 0, void 0, function () {
103
+ var client, e_1, exists, resultSet, rows, e_2, q, e_3;
95
104
  return __generator(this, function (_a) {
96
105
  switch (_a.label) {
97
106
  case 0:
@@ -109,60 +118,105 @@ var create_db = function (host, username, password, db_name, db_engine, timeout,
109
118
  process.exit(1);
110
119
  return [3 /*break*/, 4];
111
120
  case 4:
112
- q = db_engine
113
- ? "CREATE DATABASE IF NOT EXISTS \"".concat(db_name, "\" ").concat(db_engine)
114
- : "CREATE DATABASE IF NOT EXISTS \"".concat(db_name, "\"");
121
+ if (!skip_db_creation) return [3 /*break*/, 14];
122
+ exists = false;
115
123
  _a.label = 5;
116
124
  case 5:
117
- _a.trys.push([5, 7, , 8]);
118
- return [4 /*yield*/, client.command({
119
- query: q,
120
- clickhouse_settings: {
121
- wait_end_of_query: 1,
122
- },
125
+ _a.trys.push([5, 8, , 10]);
126
+ return [4 /*yield*/, client.query({
127
+ query: "SELECT 1 AS ok FROM system.databases WHERE name = {db_name:String}",
128
+ query_params: { db_name: db_name },
129
+ format: 'JSONEachRow',
123
130
  })];
124
131
  case 6:
125
- _a.sent();
126
- return [3 /*break*/, 8];
132
+ resultSet = _a.sent();
133
+ return [4 /*yield*/, resultSet.json()];
127
134
  case 7:
135
+ rows = (_a.sent());
136
+ exists = rows.length > 0;
137
+ return [3 /*break*/, 10];
138
+ case 8:
128
139
  e_2 = _a.sent();
129
- log('error', "can't create the database ".concat(db_name, "."), e_2.message);
130
- process.exit(1);
131
- return [3 /*break*/, 8];
132
- case 8: return [4 /*yield*/, client.close()];
140
+ log('error', "can't verify that the database ".concat(db_name, " exists."), e_2.message);
141
+ return [4 /*yield*/, client.close()];
133
142
  case 9:
143
+ _a.sent();
144
+ process.exit(1);
145
+ return [3 /*break*/, 10];
146
+ case 10:
147
+ if (!!exists) return [3 /*break*/, 12];
148
+ log('error', "the database ".concat(db_name, " doesn't exist and --skip-db-creation is set. Please create the database manually or remove --skip-db-creation."));
149
+ return [4 /*yield*/, client.close()];
150
+ case 11:
151
+ _a.sent();
152
+ process.exit(1);
153
+ _a.label = 12;
154
+ case 12: return [4 /*yield*/, client.close()];
155
+ case 13:
134
156
  _a.sent();
135
157
  return [2 /*return*/];
136
- }
137
- });
138
- }); };
139
- var init_migration_table = function (client) { return __awaiter(void 0, void 0, void 0, function () {
140
- var q, e_3;
141
- return __generator(this, function (_a) {
142
- switch (_a.label) {
143
- case 0:
144
- q = "CREATE TABLE IF NOT EXISTS _migrations (\n uid UUID DEFAULT generateUUIDv4(),\n version UInt32,\n checksum String,\n migration_name String,\n applied_at DateTime DEFAULT now()\n )\n ENGINE = MergeTree\n ORDER BY tuple(applied_at)";
145
- _a.label = 1;
146
- case 1:
147
- _a.trys.push([1, 3, , 4]);
158
+ case 14:
159
+ q = db_engine
160
+ ? "CREATE DATABASE IF NOT EXISTS \"".concat(db_name, "\" ").concat(db_engine)
161
+ : "CREATE DATABASE IF NOT EXISTS \"".concat(db_name, "\"");
162
+ _a.label = 15;
163
+ case 15:
164
+ _a.trys.push([15, 17, , 18]);
148
165
  return [4 /*yield*/, client.command({
149
166
  query: q,
150
167
  clickhouse_settings: {
151
168
  wait_end_of_query: 1,
152
169
  },
153
170
  })];
154
- case 2:
171
+ case 16:
155
172
  _a.sent();
156
- return [3 /*break*/, 4];
157
- case 3:
173
+ return [3 /*break*/, 18];
174
+ case 17:
158
175
  e_3 = _a.sent();
159
- log('error', "can't create the _migrations table.", e_3.message);
176
+ log('error', "can't create the database ".concat(db_name, "."), e_3.message);
160
177
  process.exit(1);
161
- return [3 /*break*/, 4];
162
- case 4: return [2 /*return*/];
178
+ return [3 /*break*/, 18];
179
+ case 18: return [4 /*yield*/, client.close()];
180
+ case 19:
181
+ _a.sent();
182
+ return [2 /*return*/];
163
183
  }
164
184
  });
165
185
  }); };
186
+ var init_migration_table = function (client_2) {
187
+ var args_1 = [];
188
+ for (var _i = 1; _i < arguments.length; _i++) {
189
+ args_1[_i - 1] = arguments[_i];
190
+ }
191
+ return __awaiter(void 0, __spreadArray([client_2], args_1, true), void 0, function (client, table_engine) {
192
+ var q, e_4;
193
+ if (table_engine === void 0) { table_engine = 'MergeTree'; }
194
+ return __generator(this, function (_a) {
195
+ switch (_a.label) {
196
+ case 0:
197
+ q = "CREATE TABLE IF NOT EXISTS _migrations (\n uid UUID DEFAULT generateUUIDv4(),\n version UInt32,\n checksum String,\n migration_name String,\n applied_at DateTime DEFAULT now()\n )\n ENGINE = ".concat(table_engine, "\n ORDER BY tuple(applied_at)");
198
+ _a.label = 1;
199
+ case 1:
200
+ _a.trys.push([1, 3, , 4]);
201
+ return [4 /*yield*/, client.command({
202
+ query: q,
203
+ clickhouse_settings: {
204
+ wait_end_of_query: 1,
205
+ },
206
+ })];
207
+ case 2:
208
+ _a.sent();
209
+ return [3 /*break*/, 4];
210
+ case 3:
211
+ e_4 = _a.sent();
212
+ log('error', "can't create the _migrations table.", e_4.message);
213
+ process.exit(1);
214
+ return [3 /*break*/, 4];
215
+ case 4: return [2 /*return*/];
216
+ }
217
+ });
218
+ });
219
+ };
166
220
  var get_migrations = function (migrations_home) {
167
221
  var files;
168
222
  try {
@@ -196,7 +250,7 @@ var get_migrations = function (migrations_home) {
196
250
  return migrations;
197
251
  };
198
252
  var apply_migrations = function (client, migrations, migrations_home) { return __awaiter(void 0, void 0, void 0, function () {
199
- var migration_query_result, resultSet, e_4, migrations_applied, applied_migrations, _i, migrations_1, migration_1, content, checksum, queries, sets, _a, queries_1, query, e_5, e_6;
253
+ var migration_query_result, resultSet, e_5, migrations_applied, applied_migrations, _i, migrations_1, migration_1, content, checksum, queries, sets, _a, queries_1, query, e_6, e_7;
200
254
  return __generator(this, function (_b) {
201
255
  switch (_b.label) {
202
256
  case 0:
@@ -215,8 +269,8 @@ var apply_migrations = function (client, migrations, migrations_home) { return _
215
269
  migration_query_result = _b.sent();
216
270
  return [3 /*break*/, 5];
217
271
  case 4:
218
- e_4 = _b.sent();
219
- log('error', "can't select data from the _migrations table.", e_4.message);
272
+ e_5 = _b.sent();
273
+ log('error', "can't select data from the _migrations table.", e_5.message);
220
274
  process.exit(1);
221
275
  return [3 /*break*/, 5];
222
276
  case 5:
@@ -272,11 +326,11 @@ var apply_migrations = function (client, migrations, migrations_home) { return _
272
326
  _b.sent();
273
327
  return [3 /*break*/, 11];
274
328
  case 10:
275
- e_5 = _b.sent();
329
+ e_6 = _b.sent();
276
330
  if (applied_migrations) {
277
331
  log('info', "The migration(s) ".concat(applied_migrations, " was successfully applied!"));
278
332
  }
279
- log('error', "the migrations ".concat(migration_1.file, " has an error. Please, fix it (be sure that already executed parts of the migration would not be run second time) and re-run migration script."), e_5.message);
333
+ log('error', "the migrations ".concat(migration_1.file, " has an error. Please, fix it (be sure that already executed parts of the migration would not be run second time) and re-run migration script."), e_6.message);
280
334
  process.exit(1);
281
335
  return [3 /*break*/, 11];
282
336
  case 11:
@@ -293,8 +347,8 @@ var apply_migrations = function (client, migrations, migrations_home) { return _
293
347
  _b.sent();
294
348
  return [3 /*break*/, 15];
295
349
  case 14:
296
- e_6 = _b.sent();
297
- log('error', "can't insert a data into the table _migrations.", e_6.message);
350
+ e_7 = _b.sent();
351
+ log('error', "can't insert a data into the table _migrations.", e_7.message);
298
352
  process.exit(1);
299
353
  return [3 /*break*/, 15];
300
354
  case 15:
@@ -314,17 +368,17 @@ var apply_migrations = function (client, migrations, migrations_home) { return _
314
368
  }
315
369
  });
316
370
  }); };
317
- var migration = function (migrations_home, host, username, password, db_name, db_engine, timeout, ca_cert, cert, key) { return __awaiter(void 0, void 0, void 0, function () {
371
+ var migration = function (migrations_home, host, username, password, db_name, db_engine, table_engine, timeout, ca_cert, cert, key, skip_db_creation) { return __awaiter(void 0, void 0, void 0, function () {
318
372
  var migrations, client;
319
373
  return __generator(this, function (_a) {
320
374
  switch (_a.label) {
321
375
  case 0:
322
376
  migrations = get_migrations(migrations_home);
323
- return [4 /*yield*/, create_db(host, username, password, db_name, db_engine, timeout, ca_cert, cert, key)];
377
+ return [4 /*yield*/, create_db(host, username, password, db_name, db_engine, timeout, ca_cert, cert, key, skip_db_creation)];
324
378
  case 1:
325
379
  _a.sent();
326
380
  client = connect(host, username, password, db_name, timeout, ca_cert, cert, key);
327
- return [4 /*yield*/, init_migration_table(client)];
381
+ return [4 /*yield*/, init_migration_table(client, table_engine)];
328
382
  case 2:
329
383
  _a.sent();
330
384
  return [4 /*yield*/, apply_migrations(client, migrations, migrations_home)];
@@ -350,14 +404,16 @@ var migrate = function () {
350
404
  .requiredOption('--db <name>', 'Database name', process.env.CH_MIGRATIONS_DB)
351
405
  .requiredOption('--migrations-home <dir>', "Migrations' directory", process.env.CH_MIGRATIONS_HOME)
352
406
  .option('--db-engine <value>', 'ON CLUSTER and/or ENGINE clauses for database (default: "ENGINE=Atomic")', process.env.CH_MIGRATIONS_DB_ENGINE)
407
+ .option('--table-engine <value>', 'Engine for the _migrations table (default: "MergeTree")', process.env.CH_MIGRATIONS_TABLE_ENGINE)
353
408
  .option('--timeout <value>', 'Client request timeout (milliseconds, default value 30000)', process.env.CH_MIGRATIONS_TIMEOUT)
354
409
  .option('--ca-cert <path>', 'CA certificate file path', process.env.CH_MIGRATIONS_CA_CERT)
355
410
  .option('--cert <path>', 'Client certificate file path', process.env.CH_MIGRATIONS_CERT)
356
411
  .option('--key <path>', 'Client key file path', process.env.CH_MIGRATIONS_KEY)
412
+ .option('--skip-db-creation', 'Skip database creation', process.env.CH_MIGRATIONS_SKIP_DB_CREATION === 'true')
357
413
  .action(function (options) { return __awaiter(void 0, void 0, void 0, function () {
358
414
  return __generator(this, function (_a) {
359
415
  switch (_a.label) {
360
- case 0: return [4 /*yield*/, migration(options.migrationsHome, options.host, options.user, options.password, options.db, options.dbEngine, options.timeout, options.caCert, options.cert, options.key)];
416
+ case 0: return [4 /*yield*/, migration(options.migrationsHome, options.host, options.user, options.password, options.db, options.dbEngine, options.tableEngine, options.timeout, options.caCert, options.cert, options.key, options.skipDbCreation)];
361
417
  case 1:
362
418
  _a.sent();
363
419
  return [2 /*return*/];
package/lib/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "1.1.4";
1
+ export declare const VERSION = "1.3.0";
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
- exports.VERSION = '1.1.4'; // x-release-please-version
4
+ exports.VERSION = '1.3.0'; // x-release-please-version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clickhouse-migrations",
3
- "version": "1.1.4",
3
+ "version": "1.3.0",
4
4
  "description": "ClickHouse Migrations",
5
5
  "bin": {
6
6
  "clickhouse-migrations": "lib/cli.js"