ch-client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ })();