blazer 1.5.1 → 1.6.0

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: af24e4d2d3a7574a1b6e03186ea77d54dcb4f4b5
4
- data.tar.gz: 3d9b34fd4cb0c26cb7516d75cfe2eab85a2d3b8f
3
+ metadata.gz: 04d14bae947237ea5450d0c8104572d41030e2ba
4
+ data.tar.gz: 1cf2e2ecad47ab458a653382728911dfaa82b1d9
5
5
  SHA512:
6
- metadata.gz: 5c9590d8f9798d5cef1ca335ba38f990ae51d021d2a04d4fa01929b43a032a823988ddc39b697e36888d62a84fe663d9a974fdbd9c6339fa00d50b15688aa899
7
- data.tar.gz: 55fe87e6539b8f9b776c68bb18dd9b20564151f3b5dbb47ad3a0380e811914f4c4b5e6f8202dd891406e6c790c4f17ddfc21abd1f97ff05b65fd160950231cef
6
+ metadata.gz: 6331237e96ba16d02561cfeb1f2de6e95abdbc2b6f2069cdfa2a72309e92720137ae899498b4ac177abc9b3fb663293950006ff84e186560101b0786c9a6c75a
7
+ data.tar.gz: b71679dded9d87c6637c082da7a41bda1ff448122fbfd3de62b1a8d8b5604b14196a26a96d8b2a14b0db38e65b77a8f2e0299761b3c25f411955541ce276e865
@@ -1,3 +1,9 @@
1
+ ## 1.6.0
2
+
3
+ - Added support for MongoDB [beta]
4
+ - Added support for Elasticsearch [beta]
5
+ - Fixed deprecation warning in Rails 5
6
+
1
7
  ## 1.5.1
2
8
 
3
9
  - Added anomaly detection for data less than 2 weeks
data/README.md CHANGED
@@ -12,7 +12,7 @@ Explore your data with SQL. Easily create charts and dashboards, and share them
12
12
 
13
13
  ## Features
14
14
 
15
- - **Multiple data sources** - works with PostgreSQL, MySQL, and Redshift
15
+ - **Multiple data sources** - PostgreSQL, MySQL, Redshift, and [many more](#full-list)
16
16
  - **Variables** - run the same queries with different values
17
17
  - **Checks & alerts** - get emailed when bad data appears
18
18
  - **Audits** - all queries are tracked
@@ -346,12 +346,57 @@ data_sources:
346
346
  # ...
347
347
  ```
348
348
 
349
+ ### Full List
350
+
351
+ - PostgreSQL
352
+ - MySQL
353
+ - SQL Server
354
+ - Oracle
355
+ - IBM DB2 and Informix
356
+ - SQLite
357
+ - [Redshift](#redshift)
358
+ - [MongoDB](#mongodb) [beta]
359
+ - [Elasticsearch](#elasticsearch) [beta]
360
+
361
+ You can also create an adapter for any other data store.
362
+
363
+ **Note:** In the examples below, we recommend using environment variables for urls.
364
+
365
+ ```yml
366
+ data_sources:
367
+ my_source:
368
+ url: <%= ENV["BLAZER_MY_SOURCE_URL"] %>
369
+ ```
370
+
349
371
  ### Redshift
350
372
 
351
373
  Add [activerecord4-redshift-adapter](https://github.com/aamine/activerecord4-redshift-adapter) to your Gemfile and set:
352
374
 
353
- ```ruby
354
- ENV["BLAZER_DATABASE_URL"] = "redshift://user:password@hostname:5439/database"
375
+ ```yml
376
+ data_sources:
377
+ my_source:
378
+ url: redshift://user:password@hostname:5439/database
379
+ ```
380
+
381
+ ### MongoDB
382
+
383
+ Add [mongo](https://github.com/mongodb/mongo-ruby-driver) to your Gemfile and set:
384
+
385
+ ```yml
386
+ data_sources:
387
+ my_source:
388
+ url: mongodb://user:password@hostname:27017/database
389
+ ```
390
+
391
+ ### Elasticsearch
392
+
393
+ Add [elasticsearch](https://github.com/elastic/elasticsearch-ruby) to your Gemfile and set:
394
+
395
+ ```yml
396
+ data_sources:
397
+ my_source:
398
+ adapter: elasticsearch
399
+ url: http://user:password@hostname:9200/
355
400
  ```
356
401
 
357
402
  ## Learn SQL
@@ -1,7 +1,15 @@
1
1
  module Blazer
2
2
  class BaseController < ApplicationController
3
3
  # skip all filters
4
- skip_filter *_process_action_callbacks.map(&:filter)
4
+ filters = _process_action_callbacks.map(&:filter)
5
+ if Rails::VERSION::MAJOR >= 5
6
+ skip_before_action(*filters, raise: false)
7
+ skip_after_action(*filters, raise: false)
8
+ skip_around_action(*filters, raise: false)
9
+ before_action :verify_request_size
10
+ else
11
+ skip_action_callback *filters
12
+ end
5
13
 
6
14
  protect_from_forgery with: :exception
7
15
 
@@ -46,7 +54,7 @@ module Blazer
46
54
  def extract_vars(statement)
47
55
  # strip commented out lines
48
56
  # and regex {1} or {1,2}
49
- statement.gsub(/\-\-.+/, "").gsub(/\/\*.+\*\//m, "").scan(/\{.*?\}/).map { |v| v[1...-1] }.reject { |v| /\A\d+(\,\d+)?\z/.match(v) }.uniq
57
+ statement.gsub(/\-\-.+/, "").gsub(/\/\*.+\*\//m, "").scan(/\{\w*?\}/i).map { |v| v[1...-1] }.reject { |v| /\A\d+(\,\d+)?\z/.match(v) || v.empty? }.uniq
50
58
  end
51
59
  helper_method :extract_vars
52
60
 
@@ -114,7 +114,7 @@ module Blazer
114
114
  end
115
115
  @result = result.first
116
116
  else
117
- @result = @data_source.run_main_statement(@statement, options)
117
+ @result = RunStatement.new.perform(@data_source, @statement, options)
118
118
  end
119
119
 
120
120
  if @result
@@ -1,6 +1,6 @@
1
1
  <ul>
2
2
  <% @checks.each do |check| %>
3
- <li><%= link_to check.query.name, query_url(check.query_id) %></li>
3
+ <li><%= link_to check.query.name, query_url(check.query_id) %> <%= check.state %></li>
4
4
  <% end %>
5
5
  </ul>
6
6
  <p><%= link_to "Manage checks", checks_url %></p>
@@ -126,6 +126,7 @@
126
126
  var error_line = null;
127
127
  var xhr;
128
128
  var params = <%= raw blazer_json_escape(variable_params.to_json) %>;
129
+ var previewStatement = <%= raw blazer_json_escape(Hash[Blazer.data_sources.map { |k, v| [k, v.preview_statement] }].to_json) %>;
129
130
 
130
131
  $("#run").click(function (e) {
131
132
  e.preventDefault();
@@ -162,7 +163,8 @@
162
163
  $(document).on("change", "#table_names", function () {
163
164
  var val = $(this).val();
164
165
  if (val.length > 0) {
165
- editor.setValue("SELECT * FROM " + val + " LIMIT 10");
166
+ var dataSource = $("#query_data_source").val();
167
+ editor.setValue(previewStatement[dataSource].replace("{table}", val));
166
168
  $("#run").click();
167
169
  }
168
170
  });
@@ -172,13 +172,17 @@
172
172
  </script>
173
173
  <% end %>
174
174
 
175
- <script>
176
- // do not highlight really long queries
177
- // this can lead to performance issues
178
- if ($("code").text().length < 10000) {
179
- hljs.initHighlightingOnLoad();
180
- }
175
+ <% if Blazer.data_sources[@query.data_source].adapter == "activerecord" %>
176
+ <script>
177
+ // do not highlight really long queries
178
+ // this can lead to performance issues
179
+ if ($("code").text().length < 10000) {
180
+ hljs.initHighlightingOnLoad();
181
+ }
182
+ </script>
183
+ <% end %>
181
184
 
185
+ <script>
182
186
  $(".form-inline input, .form-inline select").change( function () {
183
187
  submitIfCompleted($(this).closest("form"));
184
188
  });
@@ -5,6 +5,11 @@ require "safely/core"
5
5
  require "blazer/version"
6
6
  require "blazer/data_source"
7
7
  require "blazer/result"
8
+ require "blazer/run_statement"
9
+ require "blazer/adapters/base_adapter"
10
+ require "blazer/adapters/elasticsearch_adapter"
11
+ require "blazer/adapters/mongodb_adapter"
12
+ require "blazer/adapters/sql_adapter"
8
13
  require "blazer/engine"
9
14
 
10
15
  module Blazer
@@ -0,0 +1,41 @@
1
+ module Blazer
2
+ module Adapters
3
+ class BaseAdapter
4
+ attr_reader :data_source
5
+
6
+ def initialize(data_source)
7
+ @data_source = data_source
8
+ end
9
+
10
+ def run_statement(statement, comment)
11
+ # the one required method
12
+ end
13
+
14
+ def tables
15
+ [] # optional, but nice to have
16
+ end
17
+
18
+ def preview_statement
19
+ "" # also optional, but nice to have
20
+ end
21
+
22
+ def reconnect
23
+ # optional
24
+ end
25
+
26
+ def cost(statement)
27
+ # optional
28
+ end
29
+
30
+ def explain(statement)
31
+ # optional
32
+ end
33
+
34
+ protected
35
+
36
+ def settings
37
+ @data_source.settings
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,43 @@
1
+ module Blazer
2
+ module Adapters
3
+ class ElasticsearchAdapter < BaseAdapter
4
+ def run_statement(statement, comment)
5
+ columns = []
6
+ rows = []
7
+ error = nil
8
+
9
+ begin
10
+ header, body = statement.gsub(/\/\/.+/, "").strip.split("\n", 2)
11
+ response = client.msearch(body: [JSON.parse(header), JSON.parse(body)])["responses"].first
12
+ hits = response["hits"]["hits"]
13
+ source_keys = hits.flat_map { |r| r["_source"].keys }.uniq
14
+ hit_keys = (hits.first.try(:keys) || []) - ["_source"]
15
+ columns = source_keys + hit_keys
16
+ rows =
17
+ hits.map do |r|
18
+ source = r["_source"]
19
+ source_keys.map { |k| source[k] } + hit_keys.map { |k| r[k] }
20
+ end
21
+ rescue => e
22
+ error = e.message
23
+ end
24
+
25
+ [columns, rows, error]
26
+ end
27
+
28
+ def tables
29
+ client.indices.get_aliases.map { |k, v| [k, v["aliases"].keys] }.flatten.uniq.sort
30
+ end
31
+
32
+ def preview_statement
33
+ %!// header\n{"index": "{table}"}\n\n// body\n{"query": {"match_all": {}}, "size": 10}!
34
+ end
35
+
36
+ protected
37
+
38
+ def client
39
+ @client ||= Elasticsearch::Client.new(url: settings["url"])
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,39 @@
1
+ module Blazer
2
+ module Adapters
3
+ class MongodbAdapter < BaseAdapter
4
+ def run_statement(statement, comment)
5
+ columns = []
6
+ rows = []
7
+ error = nil
8
+
9
+ begin
10
+ documents = db.command({:$eval => "#{statement.strip}.toArray()"}).documents.first["retval"]
11
+ columns = documents.flat_map { |r| r.keys }.uniq
12
+ rows = documents.map { |r| columns.map { |c| r[c] } }
13
+ rescue => e
14
+ error = e.message
15
+ end
16
+
17
+ [columns, rows, error]
18
+ end
19
+
20
+ def tables
21
+ db.collection_names
22
+ end
23
+
24
+ def preview_statement
25
+ "db.{table}.find().limit(10)"
26
+ end
27
+
28
+ protected
29
+
30
+ def client
31
+ @client ||= Mongo::Client.new(settings["url"])
32
+ end
33
+
34
+ def db
35
+ @db ||= client.database
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,120 @@
1
+ module Blazer
2
+ module Adapters
3
+ class SqlAdapter < BaseAdapter
4
+ attr_reader :connection_model
5
+
6
+ def initialize(data_source)
7
+ super
8
+
9
+ @connection_model =
10
+ Class.new(Blazer::Connection) do
11
+ def self.name
12
+ "Blazer::Connection::#{object_id}"
13
+ end
14
+ establish_connection(data_source.settings["url"]) if data_source.settings["url"]
15
+ end
16
+ end
17
+
18
+ def run_statement(statement, comment)
19
+ columns = []
20
+ rows = []
21
+ error = nil
22
+
23
+ begin
24
+ in_transaction do
25
+ set_timeout(data_source.timeout) if data_source.timeout
26
+
27
+ result = connection_model.connection.select_all("#{statement} /*#{comment}*/")
28
+ columns = result.columns
29
+ cast_method = Rails::VERSION::MAJOR < 5 ? :type_cast : :cast_value
30
+ result.rows.each do |untyped_row|
31
+ rows << (result.column_types.empty? ? untyped_row : columns.each_with_index.map { |c, i| untyped_row[i] ? result.column_types[c].send(cast_method, untyped_row[i]) : nil })
32
+ end
33
+ end
34
+ rescue ActiveRecord::StatementInvalid => e
35
+ error = e.message.sub(/.+ERROR: /, "")
36
+ error = Blazer::TIMEOUT_MESSAGE if Blazer::TIMEOUT_ERRORS.any? { |e| error.include?(e) }
37
+ end
38
+
39
+ [columns, rows, error]
40
+ end
41
+
42
+ def tables
43
+ result = data_source.run_statement(connection_model.send(:sanitize_sql_array, ["SELECT table_name FROM information_schema.tables WHERE table_schema IN (?) ORDER BY table_name", schemas]))
44
+ result.rows.map(&:first)
45
+ end
46
+
47
+ def preview_statement
48
+ "SELECT * FROM {table} LIMIT 10"
49
+ end
50
+
51
+ def reconnect
52
+ connection_model.establish_connection(settings["url"])
53
+ end
54
+
55
+ def cost(statement)
56
+ result = explain(statement)
57
+ match = /cost=\d+\.\d+..(\d+\.\d+) /.match(result)
58
+ match[1] if match
59
+ end
60
+
61
+ def explain(statement)
62
+ if postgresql? || redshift?
63
+ connection_model.connection.select_all("EXPLAIN #{statement}").rows.first.first
64
+ end
65
+ rescue
66
+ nil
67
+ end
68
+
69
+ protected
70
+
71
+ def postgresql?
72
+ ["PostgreSQL", "PostGIS"].include?(adapter_name)
73
+ end
74
+
75
+ def redshift?
76
+ ["Redshift"].include?(adapter_name)
77
+ end
78
+
79
+ def mysql?
80
+ ["MySQL", "Mysql2", "Mysql2Spatial"].include?(adapter_name)
81
+ end
82
+
83
+ def adapter_name
84
+ connection_model.connection.adapter_name
85
+ end
86
+
87
+ def schemas
88
+ default_schema = (postgresql? || redshift?) ? "public" : connection_model.connection_config[:database]
89
+ settings["schemas"] || [connection_model.connection_config[:schema] || default_schema]
90
+ end
91
+
92
+ def set_timeout(timeout)
93
+ if postgresql? || redshift?
94
+ connection_model.connection.execute("SET statement_timeout = #{timeout.to_i * 1000}")
95
+ elsif mysql?
96
+ connection_model.connection.execute("SET max_execution_time = #{timeout.to_i * 1000}")
97
+ else
98
+ raise Blazer::TimeoutNotSupported, "Timeout not supported for #{adapter_name} adapter"
99
+ end
100
+ end
101
+
102
+ def use_transaction?
103
+ settings.key?("use_transaction") ? settings["use_transaction"] : true
104
+ end
105
+
106
+ def in_transaction
107
+ connection_model.connection_pool.with_connection do
108
+ if use_transaction?
109
+ connection_model.transaction do
110
+ yield
111
+ raise ActiveRecord::Rollback
112
+ end
113
+ else
114
+ yield
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -2,7 +2,11 @@ require "digest/md5"
2
2
 
3
3
  module Blazer
4
4
  class DataSource
5
- attr_reader :id, :settings, :connection_model
5
+ extend Forwardable
6
+
7
+ attr_reader :id, :settings, :adapter, :adapter_instance
8
+
9
+ def_delegators :adapter_instance, :schema, :tables, :preview_statement, :reconnect, :cost, :explain
6
10
 
7
11
  def initialize(id, settings)
8
12
  @id = id
@@ -12,15 +16,23 @@ module Blazer
12
16
  raise Blazer::Error, "Empty url"
13
17
  end
14
18
 
15
- @connection_model =
16
- Class.new(Blazer::Connection) do
17
- def self.name
18
- "Blazer::Connection::#{object_id}"
19
- end
20
- establish_connection(settings["url"]) if settings["url"]
19
+ @adapter_instance =
20
+ case adapter
21
+ when "sql"
22
+ Blazer::Adapters::SqlAdapter.new(self)
23
+ when "elasticsearch"
24
+ Blazer::Adapters::ElasticsearchAdapter.new(self)
25
+ when "mongodb"
26
+ Blazer::Adapters::MongodbAdapter.new(self)
27
+ else
28
+ raise Blazer::Error, "Unknown adapter"
21
29
  end
22
30
  end
23
31
 
32
+ def adapter
33
+ settings["adapter"] || detect_adapter
34
+ end
35
+
24
36
  def name
25
37
  settings["name"] || @id
26
38
  end
@@ -78,61 +90,6 @@ module Blazer
78
90
  @local_time_suffix ||= Array(settings["local_time_suffix"])
79
91
  end
80
92
 
81
- def use_transaction?
82
- settings.key?("use_transaction") ? settings["use_transaction"] : true
83
- end
84
-
85
- def cost(statement)
86
- result = explain(statement)
87
- match = /cost=\d+\.\d+..(\d+\.\d+) /.match(result)
88
- match[1] if match
89
- end
90
-
91
- def explain(statement)
92
- if postgresql? || redshift?
93
- connection_model.connection.select_all("EXPLAIN #{statement}").rows.first.first
94
- end
95
- rescue
96
- nil
97
- end
98
-
99
- def run_main_statement(statement, options = {})
100
- query = options[:query]
101
- Blazer.transform_statement.call(self, statement) if Blazer.transform_statement
102
-
103
- # audit
104
- if Blazer.audit
105
- audit = Blazer::Audit.new(statement: statement)
106
- audit.query = query
107
- audit.data_source = id
108
- audit.user = options[:user]
109
- audit.save!
110
- end
111
-
112
- start_time = Time.now
113
- result = run_statement(statement, options)
114
- duration = Time.now - start_time
115
-
116
- if Blazer.audit
117
- audit.duration = duration if audit.respond_to?(:duration=)
118
- audit.error = result.error if audit.respond_to?(:error=)
119
- audit.timed_out = result.timed_out? if audit.respond_to?(:timed_out=)
120
- audit.cached = result.cached? if audit.respond_to?(:cached=)
121
- if !result.cached? && duration >= 10
122
- audit.cost = cost(statement) if audit.respond_to?(:cost=)
123
- end
124
- audit.save! if audit.changed?
125
- end
126
-
127
- if query && !result.timed_out?
128
- query.checks.each do |check|
129
- check.update_state(result)
130
- end
131
- end
132
-
133
- result
134
- end
135
-
136
93
  def read_cache(cache_key)
137
94
  value = Blazer.cache.read(cache_key)
138
95
  if value
@@ -192,70 +149,13 @@ module Blazer
192
149
  cache_key(["run", run_id])
193
150
  end
194
151
 
195
- def schemas
196
- default_schema = (postgresql? || redshift?) ? "public" : connection_model.connection_config[:database]
197
- settings["schemas"] || [connection_model.connection_config[:schema] || default_schema]
198
- end
199
-
200
- def tables
201
- result = run_statement(connection_model.send(:sanitize_sql_array, ["SELECT table_name FROM information_schema.tables WHERE table_schema IN (?) ORDER BY table_name", schemas]))
202
- result.rows.map(&:first)
203
- end
204
-
205
- def postgresql?
206
- ["PostgreSQL", "PostGIS"].include?(adapter_name)
207
- end
208
-
209
- def redshift?
210
- ["Redshift"].include?(adapter_name)
211
- end
212
-
213
- def mysql?
214
- ["MySQL", "Mysql2", "Mysql2Spatial"].include?(adapter_name)
215
- end
216
-
217
- def reconnect
218
- connection_model.establish_connection(settings["url"])
219
- end
220
-
221
152
  protected
222
153
 
223
154
  def run_statement_helper(statement, comment, run_id)
224
- columns = []
225
- rows = []
226
- error = nil
227
155
  start_time = Time.now
228
- result = nil
229
-
230
- begin
231
- in_transaction do
232
- if timeout
233
- if postgresql? || redshift?
234
- connection_model.connection.execute("SET statement_timeout = #{timeout.to_i * 1000}")
235
- elsif mysql?
236
- connection_model.connection.execute("SET max_execution_time = #{timeout.to_i * 1000}")
237
- else
238
- raise Blazer::TimeoutNotSupported, "Timeout not supported for #{adapter_name} adapter"
239
- end
240
- end
241
-
242
- result = connection_model.connection.select_all("#{statement} /*#{comment}*/")
243
- end
244
- rescue ActiveRecord::StatementInvalid => e
245
- error = e.message.sub(/.+ERROR: /, "")
246
- error = Blazer::TIMEOUT_MESSAGE if Blazer::TIMEOUT_ERRORS.any? { |e| error.include?(e) }
247
- end
248
-
156
+ columns, rows, error = @adapter_instance.run_statement(statement, comment)
249
157
  duration = Time.now - start_time
250
158
 
251
- if result
252
- columns = result.columns
253
- cast_method = Rails::VERSION::MAJOR < 5 ? :type_cast : :cast_value
254
- result.rows.each do |untyped_row|
255
- rows << (result.column_types.empty? ? untyped_row : columns.each_with_index.map { |c, i| untyped_row[i] ? result.column_types[c].send(cast_method, untyped_row[i]) : nil })
256
- end
257
- end
258
-
259
159
  cache_data = nil
260
160
  cache = !error && (cache_mode == "all" || (cache_mode == "slow" && duration >= cache_slow_threshold))
261
161
  if cache || run_id
@@ -277,18 +177,11 @@ module Blazer
277
177
  Blazer::Result.new(self, columns, rows, error, nil, cache && !cache_data.nil?)
278
178
  end
279
179
 
280
- def adapter_name
281
- connection_model.connection.adapter_name
282
- end
283
-
284
- def in_transaction
285
- if use_transaction?
286
- connection_model.transaction do
287
- yield
288
- raise ActiveRecord::Rollback
289
- end
180
+ def detect_adapter
181
+ if settings["url"].to_s.start_with?("mongodb://")
182
+ "mongodb"
290
183
  else
291
- yield
184
+ "sql"
292
185
  end
293
186
  end
294
187
  end
@@ -0,0 +1,38 @@
1
+ class RunStatement
2
+ def perform(data_source, statement, options = {})
3
+ query = options[:query]
4
+ Blazer.transform_statement.call(data_source, statement) if Blazer.transform_statement
5
+
6
+ # audit
7
+ if Blazer.audit
8
+ audit = Blazer::Audit.new(statement: statement)
9
+ audit.query = query
10
+ audit.data_source = data_source.id
11
+ audit.user = options[:user]
12
+ audit.save!
13
+ end
14
+
15
+ start_time = Time.now
16
+ result = data_source.run_statement(statement, options)
17
+ duration = Time.now - start_time
18
+
19
+ if Blazer.audit
20
+ audit.duration = duration if audit.respond_to?(:duration=)
21
+ audit.error = result.error if audit.respond_to?(:error=)
22
+ audit.timed_out = result.timed_out? if audit.respond_to?(:timed_out=)
23
+ audit.cached = result.cached? if audit.respond_to?(:cached=)
24
+ if !result.cached? && duration >= 10
25
+ audit.cost = data_source.cost(statement) if audit.respond_to?(:cost=)
26
+ end
27
+ audit.save! if audit.changed?
28
+ end
29
+
30
+ if query && !result.timed_out?
31
+ query.checks.each do |check|
32
+ check.update_state(result)
33
+ end
34
+ end
35
+
36
+ result
37
+ end
38
+ end
@@ -6,10 +6,15 @@ module Blazer
6
6
  workers 4
7
7
 
8
8
  def perform(result, data_source, statement, options)
9
- ActiveRecord::Base.connection_pool.with_connection do
10
- data_source.connection_model.connection_pool.with_connection do
11
- result << data_source.run_main_statement(statement, options)
9
+ begin
10
+ ActiveRecord::Base.connection_pool.with_connection do
11
+ result << RunStatement.new.perform(data_source, statement, options)
12
12
  end
13
+ rescue Exception => e
14
+ result.clear
15
+ result << Blazer::Result.new(data_source, [], [], "Unknown error", nil, false)
16
+ Blazer.cache.write(data_source.run_cache_key(options[:run_id]), Marshal.dump([[], [], "Unknown error", nil]), expires_in: 30.seconds)
17
+ raise e
13
18
  end
14
19
  end
15
20
  end
@@ -1,3 +1,3 @@
1
1
  module Blazer
2
- VERSION = "1.5.1"
2
+ VERSION = "1.6.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blazer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-25 00:00:00.000000000 Z
11
+ date: 2016-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -159,10 +159,15 @@ files:
159
159
  - blazer.gemspec
160
160
  - config/routes.rb
161
161
  - lib/blazer.rb
162
+ - lib/blazer/adapters/base_adapter.rb
163
+ - lib/blazer/adapters/elasticsearch_adapter.rb
164
+ - lib/blazer/adapters/mongodb_adapter.rb
165
+ - lib/blazer/adapters/sql_adapter.rb
162
166
  - lib/blazer/data_source.rb
163
167
  - lib/blazer/detect_anomalies.R
164
168
  - lib/blazer/engine.rb
165
169
  - lib/blazer/result.rb
170
+ - lib/blazer/run_statement.rb
166
171
  - lib/blazer/run_statement_job.rb
167
172
  - lib/blazer/version.rb
168
173
  - lib/generators/blazer/install_generator.rb