ch-client 0.0.1

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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +22 -0
  3. data/.gitignore +9 -0
  4. data/.travis.yml +3 -0
  5. data/CHANGELOG.md +58 -0
  6. data/Gemfile +3 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +262 -0
  9. data/Rakefile +15 -0
  10. data/VERSION +1 -0
  11. data/bin/clickhouse +9 -0
  12. data/clickhouse.gemspec +36 -0
  13. data/lib/clickhouse.rb +60 -0
  14. data/lib/clickhouse/cli.rb +46 -0
  15. data/lib/clickhouse/cli/client.rb +149 -0
  16. data/lib/clickhouse/cli/console.rb +73 -0
  17. data/lib/clickhouse/cli/server.rb +37 -0
  18. data/lib/clickhouse/cli/server/assets/css/clickhouse.css +177 -0
  19. data/lib/clickhouse/cli/server/assets/css/codemirror.css +341 -0
  20. data/lib/clickhouse/cli/server/assets/css/datatables.css +1 -0
  21. data/lib/clickhouse/cli/server/assets/css/normalize.css +427 -0
  22. data/lib/clickhouse/cli/server/assets/css/skeleton.css +418 -0
  23. data/lib/clickhouse/cli/server/assets/js/clickhouse.js +188 -0
  24. data/lib/clickhouse/cli/server/assets/js/codemirror.js +9096 -0
  25. data/lib/clickhouse/cli/server/assets/js/datatables.js +166 -0
  26. data/lib/clickhouse/cli/server/assets/js/disableswipeback.js +97 -0
  27. data/lib/clickhouse/cli/server/assets/js/jquery.js +11015 -0
  28. data/lib/clickhouse/cli/server/assets/js/sql.js +232 -0
  29. data/lib/clickhouse/cli/server/views/index.erb +46 -0
  30. data/lib/clickhouse/cluster.rb +43 -0
  31. data/lib/clickhouse/connection.rb +42 -0
  32. data/lib/clickhouse/connection/client.rb +135 -0
  33. data/lib/clickhouse/connection/logger.rb +12 -0
  34. data/lib/clickhouse/connection/query.rb +160 -0
  35. data/lib/clickhouse/connection/query/result_row.rb +36 -0
  36. data/lib/clickhouse/connection/query/result_set.rb +103 -0
  37. data/lib/clickhouse/connection/query/table.rb +50 -0
  38. data/lib/clickhouse/error.rb +18 -0
  39. data/lib/clickhouse/utils.rb +23 -0
  40. data/lib/clickhouse/version.rb +7 -0
  41. data/script/console +58 -0
  42. data/test/test_helper.rb +15 -0
  43. data/test/test_helper/coverage.rb +16 -0
  44. data/test/test_helper/minitest.rb +13 -0
  45. data/test/test_helper/simple_connection.rb +12 -0
  46. data/test/unit/connection/query/test_result_row.rb +36 -0
  47. data/test/unit/connection/query/test_result_set.rb +196 -0
  48. data/test/unit/connection/query/test_table.rb +39 -0
  49. data/test/unit/connection/test_client.rb +206 -0
  50. data/test/unit/connection/test_cluster.rb +81 -0
  51. data/test/unit/connection/test_logger.rb +35 -0
  52. data/test/unit/connection/test_query.rb +410 -0
  53. data/test/unit/test_clickhouse.rb +99 -0
  54. data/test/unit/test_connection.rb +55 -0
  55. data/test/unit/test_utils.rb +39 -0
  56. metadata +326 -0
@@ -0,0 +1,418 @@
1
+ /*
2
+ * Skeleton V2.0.4
3
+ * Copyright 2014, Dave Gamache
4
+ * www.getskeleton.com
5
+ * Free to use under the MIT license.
6
+ * http://www.opensource.org/licenses/mit-license.php
7
+ * 12/29/2014
8
+ */
9
+
10
+
11
+ /* Table of contents
12
+ ––––––––––––––––––––––––––––––––––––––––––––––––––
13
+ - Grid
14
+ - Base Styles
15
+ - Typography
16
+ - Links
17
+ - Buttons
18
+ - Forms
19
+ - Lists
20
+ - Code
21
+ - Tables
22
+ - Spacing
23
+ - Utilities
24
+ - Clearing
25
+ - Media Queries
26
+ */
27
+
28
+
29
+ /* Grid
30
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
31
+ .container {
32
+ position: relative;
33
+ width: 100%;
34
+ max-width: 960px;
35
+ margin: 0 auto;
36
+ padding: 0 20px;
37
+ box-sizing: border-box; }
38
+ .column,
39
+ .columns {
40
+ width: 100%;
41
+ float: left;
42
+ box-sizing: border-box; }
43
+
44
+ /* For devices larger than 400px */
45
+ @media (min-width: 400px) {
46
+ .container {
47
+ width: 85%;
48
+ padding: 0; }
49
+ }
50
+
51
+ /* For devices larger than 550px */
52
+ @media (min-width: 550px) {
53
+ .container {
54
+ width: 80%; }
55
+ .column,
56
+ .columns {
57
+ margin-left: 4%; }
58
+ .column:first-child,
59
+ .columns:first-child {
60
+ margin-left: 0; }
61
+
62
+ .one.column,
63
+ .one.columns { width: 4.66666666667%; }
64
+ .two.columns { width: 13.3333333333%; }
65
+ .three.columns { width: 22%; }
66
+ .four.columns { width: 30.6666666667%; }
67
+ .five.columns { width: 39.3333333333%; }
68
+ .six.columns { width: 48%; }
69
+ .seven.columns { width: 56.6666666667%; }
70
+ .eight.columns { width: 65.3333333333%; }
71
+ .nine.columns { width: 74.0%; }
72
+ .ten.columns { width: 82.6666666667%; }
73
+ .eleven.columns { width: 91.3333333333%; }
74
+ .twelve.columns { width: 100%; margin-left: 0; }
75
+
76
+ .one-third.column { width: 30.6666666667%; }
77
+ .two-thirds.column { width: 65.3333333333%; }
78
+
79
+ .one-half.column { width: 48%; }
80
+
81
+ /* Offsets */
82
+ .offset-by-one.column,
83
+ .offset-by-one.columns { margin-left: 8.66666666667%; }
84
+ .offset-by-two.column,
85
+ .offset-by-two.columns { margin-left: 17.3333333333%; }
86
+ .offset-by-three.column,
87
+ .offset-by-three.columns { margin-left: 26%; }
88
+ .offset-by-four.column,
89
+ .offset-by-four.columns { margin-left: 34.6666666667%; }
90
+ .offset-by-five.column,
91
+ .offset-by-five.columns { margin-left: 43.3333333333%; }
92
+ .offset-by-six.column,
93
+ .offset-by-six.columns { margin-left: 52%; }
94
+ .offset-by-seven.column,
95
+ .offset-by-seven.columns { margin-left: 60.6666666667%; }
96
+ .offset-by-eight.column,
97
+ .offset-by-eight.columns { margin-left: 69.3333333333%; }
98
+ .offset-by-nine.column,
99
+ .offset-by-nine.columns { margin-left: 78.0%; }
100
+ .offset-by-ten.column,
101
+ .offset-by-ten.columns { margin-left: 86.6666666667%; }
102
+ .offset-by-eleven.column,
103
+ .offset-by-eleven.columns { margin-left: 95.3333333333%; }
104
+
105
+ .offset-by-one-third.column,
106
+ .offset-by-one-third.columns { margin-left: 34.6666666667%; }
107
+ .offset-by-two-thirds.column,
108
+ .offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
109
+
110
+ .offset-by-one-half.column,
111
+ .offset-by-one-half.columns { margin-left: 52%; }
112
+
113
+ }
114
+
115
+
116
+ /* Base Styles
117
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
118
+ /* NOTE
119
+ html is set to 62.5% so that all the REM measurements throughout Skeleton
120
+ are based on 10px sizing. So basically 1.5rem = 15px :) */
121
+ html {
122
+ font-size: 62.5%; }
123
+ body {
124
+ font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
125
+ line-height: 1.6;
126
+ font-weight: 400;
127
+ font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
128
+ color: #222; }
129
+
130
+
131
+ /* Typography
132
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
133
+ h1, h2, h3, h4, h5, h6 {
134
+ margin-top: 0;
135
+ margin-bottom: 2rem;
136
+ font-weight: 300; }
137
+ h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
138
+ h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
139
+ h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
140
+ h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
141
+ h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
142
+ h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
143
+
144
+ /* Larger than phablet */
145
+ @media (min-width: 550px) {
146
+ h1 { font-size: 5.0rem; }
147
+ h2 { font-size: 4.2rem; }
148
+ h3 { font-size: 3.6rem; }
149
+ h4 { font-size: 3.0rem; }
150
+ h5 { font-size: 2.4rem; }
151
+ h6 { font-size: 1.5rem; }
152
+ }
153
+
154
+ p {
155
+ margin-top: 0; }
156
+
157
+
158
+ /* Links
159
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
160
+ a {
161
+ color: #1EAEDB; }
162
+ a:hover {
163
+ color: #0FA0CE; }
164
+
165
+
166
+ /* Buttons
167
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
168
+ .button,
169
+ button,
170
+ input[type="submit"],
171
+ input[type="reset"],
172
+ input[type="button"] {
173
+ display: inline-block;
174
+ height: 38px;
175
+ padding: 0 30px;
176
+ color: #555;
177
+ text-align: center;
178
+ font-size: 11px;
179
+ font-weight: 600;
180
+ line-height: 38px;
181
+ letter-spacing: .1rem;
182
+ text-transform: uppercase;
183
+ text-decoration: none;
184
+ white-space: nowrap;
185
+ background-color: transparent;
186
+ border-radius: 4px;
187
+ border: 1px solid #bbb;
188
+ cursor: pointer;
189
+ box-sizing: border-box; }
190
+ .button:hover,
191
+ button:hover,
192
+ input[type="submit"]:hover,
193
+ input[type="reset"]:hover,
194
+ input[type="button"]:hover,
195
+ .button:focus,
196
+ button:focus,
197
+ input[type="submit"]:focus,
198
+ input[type="reset"]:focus,
199
+ input[type="button"]:focus {
200
+ color: #333;
201
+ border-color: #888;
202
+ outline: 0; }
203
+ .button.button-primary,
204
+ button.button-primary,
205
+ input[type="submit"].button-primary,
206
+ input[type="reset"].button-primary,
207
+ input[type="button"].button-primary {
208
+ color: #FFF;
209
+ background-color: #33C3F0;
210
+ border-color: #33C3F0; }
211
+ .button.button-primary:hover,
212
+ button.button-primary:hover,
213
+ input[type="submit"].button-primary:hover,
214
+ input[type="reset"].button-primary:hover,
215
+ input[type="button"].button-primary:hover,
216
+ .button.button-primary:focus,
217
+ button.button-primary:focus,
218
+ input[type="submit"].button-primary:focus,
219
+ input[type="reset"].button-primary:focus,
220
+ input[type="button"].button-primary:focus {
221
+ color: #FFF;
222
+ background-color: #1EAEDB;
223
+ border-color: #1EAEDB; }
224
+
225
+
226
+ /* Forms
227
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
228
+ input[type="email"],
229
+ input[type="number"],
230
+ input[type="search"],
231
+ input[type="text"],
232
+ input[type="tel"],
233
+ input[type="url"],
234
+ input[type="password"],
235
+ textarea,
236
+ select {
237
+ height: 38px;
238
+ padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
239
+ background-color: #fff;
240
+ border: 1px solid #D1D1D1;
241
+ border-radius: 4px;
242
+ box-shadow: none;
243
+ box-sizing: border-box; }
244
+ /* Removes awkward default styles on some inputs for iOS */
245
+ input[type="email"],
246
+ input[type="number"],
247
+ input[type="search"],
248
+ input[type="text"],
249
+ input[type="tel"],
250
+ input[type="url"],
251
+ input[type="password"],
252
+ textarea {
253
+ -webkit-appearance: none;
254
+ -moz-appearance: none;
255
+ appearance: none; }
256
+ textarea {
257
+ min-height: 65px;
258
+ padding-top: 6px;
259
+ padding-bottom: 6px; }
260
+ input[type="email"]:focus,
261
+ input[type="number"]:focus,
262
+ input[type="search"]:focus,
263
+ input[type="text"]:focus,
264
+ input[type="tel"]:focus,
265
+ input[type="url"]:focus,
266
+ input[type="password"]:focus,
267
+ textarea:focus,
268
+ select:focus {
269
+ border: 1px solid #33C3F0;
270
+ outline: 0; }
271
+ label,
272
+ legend {
273
+ display: block;
274
+ margin-bottom: .5rem;
275
+ font-weight: 600; }
276
+ fieldset {
277
+ padding: 0;
278
+ border-width: 0; }
279
+ input[type="checkbox"],
280
+ input[type="radio"] {
281
+ display: inline; }
282
+ label > .label-body {
283
+ display: inline-block;
284
+ margin-left: .5rem;
285
+ font-weight: normal; }
286
+
287
+
288
+ /* Lists
289
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
290
+ ul {
291
+ list-style: circle inside; }
292
+ ol {
293
+ list-style: decimal inside; }
294
+ ol, ul {
295
+ padding-left: 0;
296
+ margin-top: 0; }
297
+ ul ul,
298
+ ul ol,
299
+ ol ol,
300
+ ol ul {
301
+ margin: 1.5rem 0 1.5rem 3rem;
302
+ font-size: 90%; }
303
+ li {
304
+ margin-bottom: 1rem; }
305
+
306
+
307
+ /* Code
308
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
309
+ code {
310
+ padding: .2rem .5rem;
311
+ margin: 0 .2rem;
312
+ font-size: 90%;
313
+ white-space: nowrap;
314
+ background: #F1F1F1;
315
+ border: 1px solid #E1E1E1;
316
+ border-radius: 4px; }
317
+ pre > code {
318
+ display: block;
319
+ padding: 1rem 1.5rem;
320
+ white-space: pre; }
321
+
322
+
323
+ /* Tables
324
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
325
+ th,
326
+ td {
327
+ padding: 12px 15px;
328
+ text-align: left;
329
+ border-bottom: 1px solid #E1E1E1; }
330
+ th:first-child,
331
+ td:first-child {
332
+ padding-left: 0; }
333
+ th:last-child,
334
+ td:last-child {
335
+ padding-right: 0; }
336
+
337
+
338
+ /* Spacing
339
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
340
+ button,
341
+ .button {
342
+ margin-bottom: 1rem; }
343
+ input,
344
+ textarea,
345
+ select,
346
+ fieldset {
347
+ margin-bottom: 1.5rem; }
348
+ pre,
349
+ blockquote,
350
+ dl,
351
+ figure,
352
+ table,
353
+ p,
354
+ ul,
355
+ ol,
356
+ form {
357
+ margin-bottom: 2.5rem; }
358
+
359
+
360
+ /* Utilities
361
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
362
+ .u-full-width {
363
+ width: 100%;
364
+ box-sizing: border-box; }
365
+ .u-max-full-width {
366
+ max-width: 100%;
367
+ box-sizing: border-box; }
368
+ .u-pull-right {
369
+ float: right; }
370
+ .u-pull-left {
371
+ float: left; }
372
+
373
+
374
+ /* Misc
375
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
376
+ hr {
377
+ margin-top: 3rem;
378
+ margin-bottom: 3.5rem;
379
+ border-width: 0;
380
+ border-top: 1px solid #E1E1E1; }
381
+
382
+
383
+ /* Clearing
384
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
385
+
386
+ /* Self Clearing Goodness */
387
+ .container:after,
388
+ .row:after,
389
+ .u-cf {
390
+ content: "";
391
+ display: table;
392
+ clear: both; }
393
+
394
+
395
+ /* Media Queries
396
+ –––––––––––––––––––––––––––––––––––––––––––––––––– */
397
+ /*
398
+ Note: The best way to structure the use of media queries is to create the queries
399
+ near the relevant code. For example, if you wanted to change the styles for buttons
400
+ on small devices, paste the mobile query code up in the buttons section and style it
401
+ there.
402
+ */
403
+
404
+
405
+ /* Larger than mobile */
406
+ @media (min-width: 400px) {}
407
+
408
+ /* Larger than phablet (also point when grid becomes active) */
409
+ @media (min-width: 550px) {}
410
+
411
+ /* Larger than tablet */
412
+ @media (min-width: 750px) {}
413
+
414
+ /* Larger than desktop */
415
+ @media (min-width: 1000px) {}
416
+
417
+ /* Larger than Desktop HD */
418
+ @media (min-width: 1200px) {}
@@ -0,0 +1,188 @@
1
+ Clickhouse = (function() {
2
+ var
3
+ connections = [],
4
+ historyArray = [],
5
+ historyIndex = -1,
6
+ editor,
7
+
8
+ init = function(herstory, conns) {
9
+ editor = CodeMirror.fromTextArea($('#sql').get(0), {
10
+ mode: 'text/x-mariadb',
11
+ indentWithTabs: true,
12
+ smartIndent: true,
13
+ lineNumbers: true,
14
+ matchBrackets : true,
15
+ autofocus: true
16
+ });
17
+
18
+ editor.addKeyMap({
19
+ 'Alt-Up': prev,
20
+ 'Alt-Down': next,
21
+ 'Cmd-Enter': submit,
22
+ 'Cmd-R': submit
23
+ });
24
+
25
+ history(herstory);
26
+ urls(conns);
27
+
28
+ $(document).on('submit', 'form', query);
29
+ $(document).on('click', 'a.download', downloadAsTSV);
30
+ $(document).on('mousewheel', '#result_wrapper', disableSwipeBack);
31
+ },
32
+
33
+ urls = function(conns) {
34
+ if (conns !== undefined) {
35
+ connections = conns;
36
+
37
+ var
38
+ urls = $('#urls').empty(),
39
+ sql = historyArray.slice(historyIndex)[0] || '',
40
+ querystring = '';
41
+
42
+ if (sql.match(/^(SELECT|SHOW|DESCRIBE)/)) {
43
+ querystring = '/?query=' + encodeURIComponent(sql.replace(';', ' FORMAT JSONCompact;'));
44
+ }
45
+
46
+ $(connections.sort()).each(function(index, connection) {
47
+ if (index > 0) {
48
+ urls.append(' - ');
49
+ }
50
+ urls.append('<a href="' + connection + querystring + '">' + connection + '</a>');
51
+ });
52
+
53
+ if (connections.length) {
54
+ $('input,.download').removeAttr('disabled');
55
+ } else {
56
+ $('input,.download').attr('disabled', 'disabled');
57
+ urls.append('<strong class="not_connected">Not connected</span>');
58
+ }
59
+ }
60
+
61
+ return connections;
62
+ },
63
+
64
+ history = function(herstory) {
65
+ if (herstory !== undefined) {
66
+ historyArray = herstory;
67
+ historyIndex = -1;
68
+ load();
69
+ }
70
+ return historyArray;
71
+ },
72
+
73
+ load = function(delta) {
74
+ var
75
+ index = historyIndex + (delta || 0),
76
+ sql = historyArray.slice(index)[0];
77
+
78
+ if (index >= -historyArray.length && index < 0 && sql !== undefined) {
79
+ historyIndex = index;
80
+ editor.getDoc().setValue(sql);
81
+ }
82
+ },
83
+
84
+ prev = function() {
85
+ load(-1);
86
+ },
87
+
88
+ next = function() {
89
+ load(1);
90
+ },
91
+
92
+ submit = function() {
93
+ editor.save();
94
+ if (connections.length && $('[name="sql"]').val().match(';')) {
95
+ $('form').submit();
96
+ }
97
+ },
98
+
99
+ runTimer = function() {
100
+ var
101
+ start = new Date().getTime(),
102
+ stats = $('#stats').html('Running: <span>0.00</span>s'),
103
+ timer = stats.find('span');
104
+
105
+ return setInterval(function() {
106
+ now = new Date().getTime();
107
+ timer.html((now - start) / 1000);
108
+ }, 60);
109
+ },
110
+
111
+ clearResult = function() {
112
+ if ($('table#result').length) {
113
+ $('#result').DataTable().destroy();
114
+ }
115
+ $('#result').remove();
116
+ },
117
+
118
+ query = function(event) {
119
+ event.preventDefault();
120
+ var timer = runTimer(), start = new Date().getTime();
121
+
122
+ $.ajax({
123
+ url: '/',
124
+ method: 'POST',
125
+ data: $(event.target).serialize(),
126
+ success: function(json, status) {
127
+ var time = (new Date().getTime() - start) / 1000;
128
+ clearResult();
129
+
130
+ if (json.data) {
131
+ urls(json.urls);
132
+ history(json.history);
133
+
134
+ $('#stats').html(json.stats.replace('. Processed', '. Request time: ' + time + 's. Processed'));
135
+ $('form').after('<table id="result" class="stripe"></table>');
136
+ $('#result').DataTable({
137
+ paging: false,
138
+ ordering: false,
139
+ columns: $.map(json.names, function(title) {
140
+ return {title: title};
141
+ }),
142
+ data: json.data
143
+ });
144
+ } else {
145
+ $('#stats').empty();
146
+ }
147
+ },
148
+ error: function(response) {
149
+ clearResult();
150
+ $('#stats').empty();
151
+ var error = response.responseText.replace('Got status 500 (expected 200): ', '');
152
+ $('form').after('<span id="result">' + error + '</span>');
153
+ },
154
+ complete: function() {
155
+ clearInterval(timer);
156
+ }
157
+ });
158
+ },
159
+
160
+ downloadAsTSV = function(event) {
161
+ event.preventDefault();
162
+
163
+ editor.save();
164
+ var sql = $('[name="sql"]').val();
165
+
166
+ if (connections.length && sql.match(';')) {
167
+ sql = encodeURIComponent(sql.replace(';', ' FORMAT TabSeparatedWithNames;'));
168
+ var url = $('#urls a:first').attr('href').replace(/query=.*/, 'query=' + sql);
169
+ window.open(url);
170
+ }
171
+ },
172
+
173
+ disableSwipeBack = function(event) {
174
+ var wrapper = $('#result_wrapper');
175
+ if (wrapper.scrollLeft() + event.originalEvent.deltaX < 0) {
176
+ event.preventDefault();
177
+ wrapper.scrollLeft(0);
178
+ wrapper.scrollTop(wrapper.scrollTop() + (event.originalEvent.deltaY || 0));
179
+ }
180
+ };
181
+
182
+ return {
183
+ init: init,
184
+ urls: urls,
185
+ history: history,
186
+ version: '0.1.5'
187
+ };
188
+ })();