blazer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of blazer might be problematic. Click here for more details.

Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +144 -0
  6. data/Rakefile +2 -0
  7. data/app/assets/javascripts/blazer/ace/ace.js +11 -0
  8. data/app/assets/javascripts/blazer/ace/ext-language_tools.js +5 -0
  9. data/app/assets/javascripts/blazer/ace/mode-sql.js +1 -0
  10. data/app/assets/javascripts/blazer/ace/snippets/sql.js +1 -0
  11. data/app/assets/javascripts/blazer/ace/snippets/text.js +1 -0
  12. data/app/assets/javascripts/blazer/ace/theme-twilight.js +1 -0
  13. data/app/assets/javascripts/blazer/application.js +15 -0
  14. data/app/assets/javascripts/blazer/daterangepicker.js +1026 -0
  15. data/app/assets/javascripts/blazer/highlight.pack.js +1 -0
  16. data/app/assets/javascripts/blazer/jquery.js +10308 -0
  17. data/app/assets/javascripts/blazer/jquery.stickytableheaders.js +263 -0
  18. data/app/assets/javascripts/blazer/jquery_ujs.js +469 -0
  19. data/app/assets/javascripts/blazer/list.js +1474 -0
  20. data/app/assets/javascripts/blazer/moment.js +2400 -0
  21. data/app/assets/javascripts/blazer/selectize.js +3477 -0
  22. data/app/assets/javascripts/blazer/stupidtable.js +114 -0
  23. data/app/assets/stylesheets/blazer/application.css +66 -0
  24. data/app/assets/stylesheets/blazer/bootstrap.css +6203 -0
  25. data/app/assets/stylesheets/blazer/bootstrap.css.map +1 -0
  26. data/app/assets/stylesheets/blazer/daterangepicker-bs3.css +267 -0
  27. data/app/assets/stylesheets/blazer/github.css +126 -0
  28. data/app/assets/stylesheets/blazer/selectize.default.css +386 -0
  29. data/app/controllers/blazer/queries_controller.rb +216 -0
  30. data/app/helpers/blazer/queries_helper.rb +21 -0
  31. data/app/models/blazer/audit.rb +5 -0
  32. data/app/models/blazer/connection.rb +5 -0
  33. data/app/models/blazer/query.rb +13 -0
  34. data/app/views/blazer/queries/_form.html.erb +84 -0
  35. data/app/views/blazer/queries/edit.html.erb +1 -0
  36. data/app/views/blazer/queries/index.html.erb +47 -0
  37. data/app/views/blazer/queries/new.html.erb +1 -0
  38. data/app/views/blazer/queries/run.html.erb +50 -0
  39. data/app/views/blazer/queries/show.html.erb +138 -0
  40. data/app/views/layouts/blazer/application.html.erb +17 -0
  41. data/blazer.gemspec +25 -0
  42. data/config/routes.rb +6 -0
  43. data/lib/blazer/engine.rb +11 -0
  44. data/lib/blazer/version.rb +3 -0
  45. data/lib/blazer.rb +16 -0
  46. data/lib/generators/blazer/install_generator.rb +33 -0
  47. data/lib/generators/blazer/templates/config.yml +8 -0
  48. data/lib/generators/blazer/templates/install.rb +17 -0
  49. metadata +134 -0
@@ -0,0 +1,386 @@
1
+ /**
2
+ * selectize.default.css (v0.10.1) - Default Theme
3
+ * Copyright (c) 2013 Brian Reavis & contributors
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
6
+ * file except in compliance with the License. You may obtain a copy of the License at:
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software distributed under
10
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ * ANY KIND, either express or implied. See the License for the specific language
12
+ * governing permissions and limitations under the License.
13
+ *
14
+ * @author Brian Reavis <brian@thirdroute.com>
15
+ */
16
+ .selectize-control.plugin-drag_drop.multi > .selectize-input > div.ui-sortable-placeholder {
17
+ visibility: visible !important;
18
+ background: #f2f2f2 !important;
19
+ background: rgba(0, 0, 0, 0.06) !important;
20
+ border: 0 none !important;
21
+ -webkit-box-shadow: inset 0 0 12px 4px #ffffff;
22
+ box-shadow: inset 0 0 12px 4px #ffffff;
23
+ }
24
+ .selectize-control.plugin-drag_drop .ui-sortable-placeholder::after {
25
+ content: '!';
26
+ visibility: hidden;
27
+ }
28
+ .selectize-control.plugin-drag_drop .ui-sortable-helper {
29
+ -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
30
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
31
+ }
32
+ .selectize-dropdown-header {
33
+ position: relative;
34
+ padding: 5px 8px;
35
+ border-bottom: 1px solid #d0d0d0;
36
+ background: #f8f8f8;
37
+ -webkit-border-radius: 3px 3px 0 0;
38
+ -moz-border-radius: 3px 3px 0 0;
39
+ border-radius: 3px 3px 0 0;
40
+ }
41
+ .selectize-dropdown-header-close {
42
+ position: absolute;
43
+ right: 8px;
44
+ top: 50%;
45
+ color: #303030;
46
+ opacity: 0.4;
47
+ margin-top: -12px;
48
+ line-height: 20px;
49
+ font-size: 20px !important;
50
+ }
51
+ .selectize-dropdown-header-close:hover {
52
+ color: #000000;
53
+ }
54
+ .selectize-dropdown.plugin-optgroup_columns .optgroup {
55
+ border-right: 1px solid #f2f2f2;
56
+ border-top: 0 none;
57
+ float: left;
58
+ -webkit-box-sizing: border-box;
59
+ -moz-box-sizing: border-box;
60
+ box-sizing: border-box;
61
+ }
62
+ .selectize-dropdown.plugin-optgroup_columns .optgroup:last-child {
63
+ border-right: 0 none;
64
+ }
65
+ .selectize-dropdown.plugin-optgroup_columns .optgroup:before {
66
+ display: none;
67
+ }
68
+ .selectize-dropdown.plugin-optgroup_columns .optgroup-header {
69
+ border-top: 0 none;
70
+ }
71
+ .selectize-control.plugin-remove_button [data-value] {
72
+ position: relative;
73
+ padding-right: 24px !important;
74
+ }
75
+ .selectize-control.plugin-remove_button [data-value] .remove {
76
+ z-index: 1;
77
+ /* fixes ie bug (see #392) */
78
+ position: absolute;
79
+ top: 0;
80
+ right: 0;
81
+ bottom: 0;
82
+ width: 17px;
83
+ text-align: center;
84
+ font-weight: bold;
85
+ font-size: 12px;
86
+ color: inherit;
87
+ text-decoration: none;
88
+ vertical-align: middle;
89
+ display: inline-block;
90
+ padding: 2px 0 0 0;
91
+ border-left: 1px solid #0073bb;
92
+ -webkit-border-radius: 0 2px 2px 0;
93
+ -moz-border-radius: 0 2px 2px 0;
94
+ border-radius: 0 2px 2px 0;
95
+ -webkit-box-sizing: border-box;
96
+ -moz-box-sizing: border-box;
97
+ box-sizing: border-box;
98
+ }
99
+ .selectize-control.plugin-remove_button [data-value] .remove:hover {
100
+ background: rgba(0, 0, 0, 0.05);
101
+ }
102
+ .selectize-control.plugin-remove_button [data-value].active .remove {
103
+ border-left-color: #00578d;
104
+ }
105
+ .selectize-control.plugin-remove_button .disabled [data-value] .remove:hover {
106
+ background: none;
107
+ }
108
+ .selectize-control.plugin-remove_button .disabled [data-value] .remove {
109
+ border-left-color: #aaaaaa;
110
+ }
111
+ .selectize-control {
112
+ position: relative;
113
+ }
114
+ .selectize-dropdown,
115
+ .selectize-input,
116
+ .selectize-input input {
117
+ color: #303030;
118
+ font-family: inherit;
119
+ font-size: 13px;
120
+ line-height: 18px;
121
+ -webkit-font-smoothing: inherit;
122
+ }
123
+ .selectize-input,
124
+ .selectize-control.single .selectize-input.input-active {
125
+ background: #ffffff;
126
+ cursor: text;
127
+ display: inline-block;
128
+ }
129
+ .selectize-input {
130
+ border: 1px solid #d0d0d0;
131
+ padding: 8px 8px;
132
+ display: inline-block;
133
+ width: 100%;
134
+ overflow: hidden;
135
+ position: relative;
136
+ z-index: 1;
137
+ -webkit-box-sizing: border-box;
138
+ -moz-box-sizing: border-box;
139
+ box-sizing: border-box;
140
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
141
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
142
+ -webkit-border-radius: 3px;
143
+ -moz-border-radius: 3px;
144
+ border-radius: 3px;
145
+ }
146
+ .selectize-control.multi .selectize-input.has-items {
147
+ padding: 5px 8px 2px;
148
+ }
149
+ .selectize-input.full {
150
+ background-color: #ffffff;
151
+ }
152
+ .selectize-input.disabled,
153
+ .selectize-input.disabled * {
154
+ cursor: default !important;
155
+ }
156
+ .selectize-input.focus {
157
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
158
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
159
+ }
160
+ .selectize-input.dropdown-active {
161
+ -webkit-border-radius: 3px 3px 0 0;
162
+ -moz-border-radius: 3px 3px 0 0;
163
+ border-radius: 3px 3px 0 0;
164
+ }
165
+ .selectize-input > * {
166
+ vertical-align: baseline;
167
+ display: -moz-inline-stack;
168
+ display: inline-block;
169
+ zoom: 1;
170
+ *display: inline;
171
+ }
172
+ .selectize-control.multi .selectize-input > div {
173
+ cursor: pointer;
174
+ margin: 0 3px 3px 0;
175
+ padding: 2px 6px;
176
+ background: #1da7ee;
177
+ color: #ffffff;
178
+ border: 1px solid #0073bb;
179
+ }
180
+ .selectize-control.multi .selectize-input > div.active {
181
+ background: #92c836;
182
+ color: #ffffff;
183
+ border: 1px solid #00578d;
184
+ }
185
+ .selectize-control.multi .selectize-input.disabled > div,
186
+ .selectize-control.multi .selectize-input.disabled > div.active {
187
+ color: #ffffff;
188
+ background: #d2d2d2;
189
+ border: 1px solid #aaaaaa;
190
+ }
191
+ .selectize-input > input {
192
+ padding: 0 !important;
193
+ min-height: 0 !important;
194
+ max-height: none !important;
195
+ max-width: 100% !important;
196
+ margin: 0 1px !important;
197
+ text-indent: 0 !important;
198
+ border: 0 none !important;
199
+ background: none !important;
200
+ line-height: inherit !important;
201
+ -webkit-user-select: auto !important;
202
+ -webkit-box-shadow: none !important;
203
+ box-shadow: none !important;
204
+ }
205
+ .selectize-input > input::-ms-clear {
206
+ display: none;
207
+ }
208
+ .selectize-input > input:focus {
209
+ outline: none !important;
210
+ }
211
+ .selectize-input::after {
212
+ content: ' ';
213
+ display: block;
214
+ clear: left;
215
+ }
216
+ .selectize-input.dropdown-active::before {
217
+ content: ' ';
218
+ display: block;
219
+ position: absolute;
220
+ background: #f0f0f0;
221
+ height: 1px;
222
+ bottom: 0;
223
+ left: 0;
224
+ right: 0;
225
+ }
226
+ .selectize-dropdown {
227
+ position: absolute;
228
+ z-index: 10;
229
+ border: 1px solid #d0d0d0;
230
+ background: #ffffff;
231
+ margin: -1px 0 0 0;
232
+ border-top: 0 none;
233
+ -webkit-box-sizing: border-box;
234
+ -moz-box-sizing: border-box;
235
+ box-sizing: border-box;
236
+ -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
237
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
238
+ -webkit-border-radius: 0 0 3px 3px;
239
+ -moz-border-radius: 0 0 3px 3px;
240
+ border-radius: 0 0 3px 3px;
241
+ }
242
+ .selectize-dropdown [data-selectable] {
243
+ cursor: pointer;
244
+ overflow: hidden;
245
+ }
246
+ .selectize-dropdown [data-selectable] .highlight {
247
+ background: rgba(125, 168, 208, 0.2);
248
+ -webkit-border-radius: 1px;
249
+ -moz-border-radius: 1px;
250
+ border-radius: 1px;
251
+ }
252
+ .selectize-dropdown [data-selectable],
253
+ .selectize-dropdown .optgroup-header {
254
+ padding: 5px 8px;
255
+ }
256
+ .selectize-dropdown .optgroup:first-child .optgroup-header {
257
+ border-top: 0 none;
258
+ }
259
+ .selectize-dropdown .optgroup-header {
260
+ color: #303030;
261
+ background: #ffffff;
262
+ cursor: default;
263
+ }
264
+ .selectize-dropdown .active {
265
+ background-color: #f5fafd;
266
+ color: #495c68;
267
+ }
268
+ .selectize-dropdown .active.create {
269
+ color: #495c68;
270
+ }
271
+ .selectize-dropdown .create {
272
+ color: rgba(48, 48, 48, 0.5);
273
+ }
274
+ .selectize-dropdown-content {
275
+ overflow-y: auto;
276
+ overflow-x: hidden;
277
+ max-height: 200px;
278
+ }
279
+ .selectize-control.single .selectize-input,
280
+ .selectize-control.single .selectize-input input {
281
+ cursor: pointer;
282
+ }
283
+ .selectize-control.single .selectize-input.input-active,
284
+ .selectize-control.single .selectize-input.input-active input {
285
+ cursor: text;
286
+ }
287
+ .selectize-control.single .selectize-input:after {
288
+ content: ' ';
289
+ display: block;
290
+ position: absolute;
291
+ top: 50%;
292
+ right: 15px;
293
+ margin-top: -3px;
294
+ width: 0;
295
+ height: 0;
296
+ border-style: solid;
297
+ border-width: 5px 5px 0 5px;
298
+ border-color: #808080 transparent transparent transparent;
299
+ }
300
+ .selectize-control.single .selectize-input.dropdown-active:after {
301
+ margin-top: -4px;
302
+ border-width: 0 5px 5px 5px;
303
+ border-color: transparent transparent #808080 transparent;
304
+ }
305
+ .selectize-control.rtl.single .selectize-input:after {
306
+ left: 15px;
307
+ right: auto;
308
+ }
309
+ .selectize-control.rtl .selectize-input > input {
310
+ margin: 0 4px 0 -2px !important;
311
+ }
312
+ .selectize-control .selectize-input.disabled {
313
+ opacity: 0.5;
314
+ background-color: #fafafa;
315
+ }
316
+ .selectize-control.multi .selectize-input.has-items {
317
+ padding-left: 5px;
318
+ padding-right: 5px;
319
+ }
320
+ .selectize-control.multi .selectize-input.disabled [data-value] {
321
+ color: #999;
322
+ text-shadow: none;
323
+ background: none;
324
+ -webkit-box-shadow: none;
325
+ box-shadow: none;
326
+ }
327
+ .selectize-control.multi .selectize-input.disabled [data-value],
328
+ .selectize-control.multi .selectize-input.disabled [data-value] .remove {
329
+ border-color: #e6e6e6;
330
+ }
331
+ .selectize-control.multi .selectize-input.disabled [data-value] .remove {
332
+ background: none;
333
+ }
334
+ .selectize-control.multi .selectize-input [data-value] {
335
+ text-shadow: 0 1px 0 rgba(0, 51, 83, 0.3);
336
+ -webkit-border-radius: 3px;
337
+ -moz-border-radius: 3px;
338
+ border-radius: 3px;
339
+ background-color: #1b9dec;
340
+ background-image: -moz-linear-gradient(top, #1da7ee, #178ee9);
341
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#1da7ee), to(#178ee9));
342
+ background-image: -webkit-linear-gradient(top, #1da7ee, #178ee9);
343
+ background-image: -o-linear-gradient(top, #1da7ee, #178ee9);
344
+ background-image: linear-gradient(to bottom, #1da7ee, #178ee9);
345
+ background-repeat: repeat-x;
346
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff1da7ee', endColorstr='#ff178ee9', GradientType=0);
347
+ -webkit-box-shadow: 0 1px 0 rgba(0,0,0,0.2),inset 0 1px rgba(255,255,255,0.03);
348
+ box-shadow: 0 1px 0 rgba(0,0,0,0.2),inset 0 1px rgba(255,255,255,0.03);
349
+ }
350
+ .selectize-control.multi .selectize-input [data-value].active {
351
+ background-color: #0085d4;
352
+ background-image: -moz-linear-gradient(top, #008fd8, #0075cf);
353
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#008fd8), to(#0075cf));
354
+ background-image: -webkit-linear-gradient(top, #008fd8, #0075cf);
355
+ background-image: -o-linear-gradient(top, #008fd8, #0075cf);
356
+ background-image: linear-gradient(to bottom, #008fd8, #0075cf);
357
+ background-repeat: repeat-x;
358
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff008fd8', endColorstr='#ff0075cf', GradientType=0);
359
+ }
360
+ .selectize-control.single .selectize-input {
361
+ -webkit-box-shadow: 0 1px 0 rgba(0,0,0,0.05), inset 0 1px 0 rgba(255,255,255,0.8);
362
+ box-shadow: 0 1px 0 rgba(0,0,0,0.05), inset 0 1px 0 rgba(255,255,255,0.8);
363
+ background-color: #f9f9f9;
364
+ background-image: -moz-linear-gradient(top, #fefefe, #f2f2f2);
365
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fefefe), to(#f2f2f2));
366
+ background-image: -webkit-linear-gradient(top, #fefefe, #f2f2f2);
367
+ background-image: -o-linear-gradient(top, #fefefe, #f2f2f2);
368
+ background-image: linear-gradient(to bottom, #fefefe, #f2f2f2);
369
+ background-repeat: repeat-x;
370
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffefefe', endColorstr='#fff2f2f2', GradientType=0);
371
+ }
372
+ .selectize-control.single .selectize-input,
373
+ .selectize-dropdown.single {
374
+ border-color: #b8b8b8;
375
+ }
376
+ .selectize-dropdown .optgroup-header {
377
+ padding-top: 7px;
378
+ font-weight: bold;
379
+ font-size: 0.85em;
380
+ }
381
+ .selectize-dropdown .optgroup {
382
+ border-top: 1px solid #f0f0f0;
383
+ }
384
+ .selectize-dropdown .optgroup:first-child {
385
+ border-top: 0 none;
386
+ }
@@ -0,0 +1,216 @@
1
+ module Blazer
2
+ class QueriesController < ApplicationController
3
+ # skip all filters
4
+ skip_filter *_process_action_callbacks.map(&:filter)
5
+
6
+ protect_from_forgery with: :exception
7
+
8
+ if ENV["BLAZER_PASSWORD"]
9
+ http_basic_authenticate_with name: ENV["BLAZER_USERNAME"], password: ENV["BLAZER_PASSWORD"]
10
+ end
11
+
12
+ layout "blazer/application"
13
+
14
+ before_action :ensure_database_url
15
+ before_action :set_query, only: [:show, :edit, :update, :destroy]
16
+
17
+ def index
18
+ @queries = Blazer::Query.order(:name)
19
+ end
20
+
21
+ def new
22
+ @query = Blazer::Query.new(statement: params[:statement])
23
+ end
24
+
25
+ def create
26
+ @query = Blazer::Query.new(query_params)
27
+ @query.creator = current_user if respond_to?(:current_user)
28
+
29
+ if @query.save
30
+ redirect_to @query
31
+ else
32
+ render :new
33
+ end
34
+ end
35
+
36
+ def show
37
+ @statement = @query.statement
38
+ process_vars(@statement)
39
+
40
+ @smart_vars = {}
41
+ @sql_errors = []
42
+ @bind_vars.each do |var|
43
+ query = smart_variables[var]
44
+ if query
45
+ rows, error = run_statement(query)
46
+ @smart_vars[var] = rows.map{|v| v.values.reverse }
47
+ @sql_errors << error if error
48
+ end
49
+ end
50
+ end
51
+
52
+ def edit
53
+ end
54
+
55
+ def run
56
+ @statement = params[:statement]
57
+ process_vars(@statement)
58
+
59
+ if @success
60
+ # audit
61
+ if Blazer.audit
62
+ audit = Blazer::Audit.new(statement: @statement)
63
+ audit.user = current_user if respond_to?(:current_user)
64
+ audit.save!
65
+ end
66
+
67
+ @rows, @error = run_statement(@statement)
68
+
69
+ @columns = {}
70
+ if @rows.any?
71
+ @rows.first.each do |key, value|
72
+ @columns[key] =
73
+ case value
74
+ when Integer
75
+ "int"
76
+ when Float
77
+ "float"
78
+ else
79
+ "string-ins"
80
+ end
81
+ end
82
+ end
83
+
84
+ @query = Query.find_by(id: params[:query_id]) if params[:query_id]
85
+ @filename = @query.name.parameterize if @query
86
+
87
+ @min_width_types = (@rows.first || {}).select{|k, v| v.is_a?(Time) or v.is_a?(String) or smart_columns[k] }.keys
88
+
89
+ @boom = {}
90
+ @columns.keys.each do |key|
91
+ query = smart_columns[key]
92
+ if query
93
+ values = @rows.map{|r| r[key] }.compact.uniq
94
+ rows, error = run_statement(ActiveRecord::Base.send(:sanitize_sql_array, [query.sub("{value}", "(?)"), values]))
95
+ @boom[key] = Hash[ rows.map(&:values) ]
96
+ end
97
+ end
98
+
99
+ @linked_columns = linked_columns
100
+ end
101
+
102
+ respond_to do |format|
103
+ format.html do
104
+ render layout: false
105
+ end
106
+ format.csv do
107
+ send_data csv_data(@rows), type: 'text/csv; charset=utf-8; header=present', disposition: "attachment; filename=\"#{@query ? @query.name.parameterize : "query"}.csv\""
108
+ end
109
+ end
110
+ end
111
+
112
+ def update
113
+ if @query.update(query_params)
114
+ redirect_to query_path(@query)
115
+ else
116
+ render :edit
117
+ end
118
+ end
119
+
120
+ def destroy
121
+ @query.destroy
122
+ redirect_to root_url
123
+ end
124
+
125
+ private
126
+
127
+ def ensure_database_url
128
+ render text: "BLAZER_DATABASE_URL required" if !ENV["BLAZER_DATABASE_URL"]
129
+ end
130
+
131
+ def set_query
132
+ @query = Blazer::Query.find(params[:id].to_s.split("-").first)
133
+ end
134
+
135
+ def query_params
136
+ params.require(:query).permit(:name, :description, :statement)
137
+ end
138
+
139
+ def csv_data(rows)
140
+ CSV.generate do |csv|
141
+ if rows.any?
142
+ csv << rows.first.keys
143
+ end
144
+ rows.each do |row|
145
+ csv << row.values
146
+ end
147
+ end
148
+ end
149
+
150
+ def run_statement(statement)
151
+ rows = []
152
+ error = nil
153
+ begin
154
+ Blazer::Connection.transaction do
155
+ result = Blazer::Connection.connection.select_all(statement)
156
+ result.each do |untyped_row|
157
+ row = {}
158
+ untyped_row.each do |k, v|
159
+ row[k] = result.column_types[k].type_cast(v)
160
+ end
161
+ rows << row
162
+ end
163
+ raise ActiveRecord::Rollback
164
+ end
165
+ rescue ActiveRecord::StatementInvalid => e
166
+ error = e.message.sub(/.+ERROR: /, "")
167
+ end
168
+ [rows, error]
169
+ end
170
+
171
+ def extract_vars(statement)
172
+ statement.scan(/\{.*?\}/).map{|v| v[1...-1] }.uniq
173
+ end
174
+
175
+ def process_vars(statement)
176
+ @bind_vars = extract_vars(statement)
177
+ @success = @bind_vars.all?{|v| params[v] }
178
+
179
+ if @success
180
+ @bind_vars.each do |var|
181
+ value = params[var].presence
182
+ value = value.to_i if value.to_i.to_s == value
183
+ if var.end_with?("_at")
184
+ value = Blazer.time_zone.parse(value) rescue nil
185
+ end
186
+ statement.gsub!("{#{var}}", ActiveRecord::Base.connection.quote(value))
187
+ end
188
+ end
189
+ end
190
+
191
+ def settings
192
+ YAML.load(File.read(Rails.root.join("config", "blazer.yml")))
193
+ end
194
+
195
+ def linked_columns
196
+ settings["linked_columns"] || {}
197
+ end
198
+
199
+ def smart_columns
200
+ settings["smart_columns"] || {}
201
+ end
202
+
203
+ def smart_variables
204
+ settings["smart_variables"] || {}
205
+ end
206
+
207
+ def tables
208
+ default_schema = Blazer::Connection.connection.adapter_name == "PostgreSQL" ? "public" : Blazer::Connection.connection_config[:database]
209
+ schema = Blazer::Connection.connection_config[:schema] || default_schema
210
+ rows, error = run_statement(Blazer::Connection.send(:sanitize_sql_array, ["SELECT table_name, column_name, ordinal_position, data_type FROM information_schema.columns WHERE table_schema = ?", schema]))
211
+ Hash[ rows.group_by{|r| r["table_name"] }.map{|t, f| [t, f.sort_by{|f| f["ordinal_position"] }.map{|f| f.slice("column_name", "data_type") }] }.sort_by{|t, f| t } ]
212
+ end
213
+ helper_method :tables
214
+
215
+ end
216
+ end
@@ -0,0 +1,21 @@
1
+ module Blazer
2
+ module QueriesHelper
3
+
4
+ def title(title = nil)
5
+ if title
6
+ content_for(:title) { title }
7
+ else
8
+ content_for?(:title) ? content_for(:title) : nil
9
+ end
10
+ end
11
+
12
+ def format_value(key, value)
13
+ if value.is_a?(Integer) and !key.to_s.end_with?("id")
14
+ number_with_delimiter(value)
15
+ else
16
+ value
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ module Blazer
2
+ class Audit < ActiveRecord::Base
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Blazer
2
+ class Connection < ActiveRecord::Base
3
+ establish_connection ENV["BLAZER_DATABASE_URL"] if ENV["BLAZER_DATABASE_URL"]
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ module Blazer
2
+ class Query < ActiveRecord::Base
3
+ belongs_to :creator, class_name: "User"
4
+
5
+ validates :name, presence: true
6
+ validates :statement, presence: true
7
+
8
+ def to_param
9
+ [id, name.remove("'").parameterize].join("-")
10
+ end
11
+
12
+ end
13
+ end