blazer 1.6.2 → 1.7.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: 72563e8886e9e04823f21ad5e7ca11f5cc112b81
4
- data.tar.gz: 51c6ed0f30b9eafc05a77aa3dff44ae44f2092e9
3
+ metadata.gz: 51a0d5ecca671fbd2647ea5fcfac3235da673fb1
4
+ data.tar.gz: 5b502ae948a5e7ecc1c28f7c847f9937274922a4
5
5
  SHA512:
6
- metadata.gz: 50a816c915b87433037a0eff3e7477708a6c99e8197638a1a5f1a04865d59a70ce45feab5dfdefe864012e15835d556145fe0ae05ce3f4c903c23b068aafb04b
7
- data.tar.gz: 0fc76958a41ebd094be658cd429ecb2c3984e67d152c067540fb921c3b93e6790c3c56b8e7eda1d2753c18a05d9b37658383ab9b2daa6c3cc81597125b79e16a
6
+ metadata.gz: 678d3473e2aa19a0e2ae5078f54a0d82661e69d60b4dc8f8b0ca4753d5fe7c36404aac1a1241a6bea12ff823464d918843a7e443884ef6e78ec43020f6c03490
7
+ data.tar.gz: 16d6ad910db22bd09ff36cfb6f70d158c8b267bd4f306bf42a6bb23e9233f99d323779b4d9b5556ad8bdbcd7adead7cd4f745d9e88d2908e742d5973031d480a
@@ -1,3 +1,11 @@
1
+ ## 1.7.0
2
+
3
+ - Added ability to cancel queries on backend for Postgres and Redshift
4
+ - Only run 3 queries at a time on dashboards
5
+ - Better anomaly detection
6
+ - Attempt to reconnect when connection issues
7
+ - Fixed issues with caching
8
+
1
9
  ## 1.6.2
2
10
 
3
11
  - Added basic query permissions
data/README.md CHANGED
@@ -4,11 +4,11 @@ Explore your data with SQL. Easily create charts and dashboards, and share them
4
4
 
5
5
  [Try it out](https://blazerme.herokuapp.com)
6
6
 
7
- [![Screenshot](https://blazerme.herokuapp.com/assets/screenshot-18d79092e635b4b220f57ff7a1ecea41.png)](https://blazerme.herokuapp.com)
7
+ [![Screenshot](https://blazerme.herokuapp.com/assets/screenshot-6ca3115a518b488026e48be83ba0d4c9.png)](https://blazerme.herokuapp.com)
8
8
 
9
- :tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
9
+ :envelope: [Get notified of updates](http://eepurl.com/cbUwsD)
10
10
 
11
- :envelope: [Subscribe to releases](https://libraries.io/rubygems/blazer)
11
+ :tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
12
12
 
13
13
  ## Features
14
14
 
@@ -373,9 +373,9 @@ data_sources:
373
373
  - IBM DB2 and Informix
374
374
  - SQLite
375
375
  - [Redshift](#redshift)
376
+ - [Presto](#presto)
376
377
  - [MongoDB](#mongodb) [beta]
377
378
  - [Elasticsearch](#elasticsearch) [beta]
378
- - [Presto](#presto) [beta]
379
379
 
380
380
  You can also create an adapter for any other data store.
381
381
 
@@ -397,40 +397,40 @@ data_sources:
397
397
  url: redshift://user:password@hostname:5439/database
398
398
  ```
399
399
 
400
- ### MongoDB
400
+ ### Presto
401
401
 
402
- Add [mongo](https://github.com/mongodb/mongo-ruby-driver) to your Gemfile and set:
402
+ Add [presto-client](https://github.com/treasure-data/presto-client-ruby) to your Gemfile and set:
403
403
 
404
404
  ```yml
405
405
  data_sources:
406
406
  my_source:
407
- url: mongodb://user:password@hostname:27017/database
407
+ url: presto://user@hostname:8080/catalog
408
408
  ```
409
409
 
410
- ### Elasticsearch
410
+ ### MongoDB
411
411
 
412
- Add [elasticsearch](https://github.com/elastic/elasticsearch-ruby) to your Gemfile and set:
412
+ Add [mongo](https://github.com/mongodb/mongo-ruby-driver) to your Gemfile and set:
413
413
 
414
414
  ```yml
415
415
  data_sources:
416
416
  my_source:
417
- adapter: elasticsearch
418
- url: http://user:password@hostname:9200/
417
+ url: mongodb://user:password@hostname:27017/database
419
418
  ```
420
419
 
421
- ### Presto
420
+ ### Elasticsearch
422
421
 
423
- Add [presto-client](https://github.com/treasure-data/presto-client-ruby) to your Gemfile and set:
422
+ Add [elasticsearch](https://github.com/elastic/elasticsearch-ruby) to your Gemfile and set:
424
423
 
425
424
  ```yml
426
425
  data_sources:
427
426
  my_source:
428
- url: presto://user@hostname:8080/catalog
427
+ adapter: elasticsearch
428
+ url: http://user:password@hostname:9200/
429
429
  ```
430
430
 
431
- ## Permissions [master]
431
+ ## Query Permissions
432
432
 
433
- Blazer supports a simple permissions model.
433
+ Blazer supports a basic permissions model.
434
434
 
435
435
  1. Queries without a name are unlisted
436
436
  2. Queries whose name starts with `#` are only listed to the creator
@@ -25,15 +25,76 @@ $( function () {
25
25
  });
26
26
  });
27
27
 
28
+ function uuid() {
29
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
30
+ var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
31
+ return v.toString(16);
32
+ });
33
+ }
34
+
28
35
  function cancelQuery(runningQuery) {
29
36
  runningQuery.canceled = true;
30
37
  var xhr = runningQuery.xhr;
31
38
  if (xhr) {
32
39
  xhr.abort();
33
40
  }
41
+ remoteCancelQuery(runningQuery);
42
+ queryComplete();
43
+ }
44
+
45
+ function csrfProtect(payload) {
46
+ var param = $("meta[name=csrf-param]").attr("content");
47
+ var token = $("meta[name=csrf-token]").attr("content");
48
+ if (param && token) payload[param] = token;
49
+ return new Blob([JSON.stringify(payload)], {type : "application/json; charset=utf-8"});
50
+ }
51
+
52
+ function remoteCancelQuery(runningQuery) {
53
+ var path = window.cancelQueriesPath;
54
+ var data = {run_id: runningQuery.run_id, data_source: runningQuery.data_source};
55
+ if (navigator.sendBeacon) {
56
+ navigator.sendBeacon(path, csrfProtect(data));
57
+ } else {
58
+ // TODO make sync
59
+ $.post(path, data);
60
+ }
61
+ }
62
+
63
+ var queriesQueue = [];
64
+ var runningQueries = 0;
65
+ var maxQueries = 3;
66
+
67
+ function queueQuery(callback) {
68
+ queriesQueue.push(callback);
69
+ runNext();
70
+ }
71
+
72
+ function runNext() {
73
+ if (runningQueries < maxQueries) {
74
+ var callback = queriesQueue.shift();
75
+ if (callback) {
76
+ runningQueries++;
77
+ callback();
78
+ runNext();
79
+ }
80
+ }
81
+ }
82
+
83
+ function queryComplete() {
84
+ runningQueries--;
85
+ runNext();
34
86
  }
35
87
 
36
88
  function runQuery(data, success, error, runningQuery) {
89
+ queueQuery( function () {
90
+ runningQuery = runningQuery || {};
91
+ runningQuery.run_id = data.run_id = uuid();
92
+ runningQuery.data_source = data.data_source;
93
+ return runQueryHelper(data, success, error, runningQuery);
94
+ });
95
+ }
96
+
97
+ function runQueryHelper(data, success, error, runningQuery) {
37
98
  var xhr = $.ajax({
38
99
  url: window.runQueriesPath,
39
100
  method: "POST",
@@ -45,15 +106,17 @@ function runQuery(data, success, error, runningQuery) {
45
106
  data.blazer = response;
46
107
  setTimeout( function () {
47
108
  if (!(runningQuery && runningQuery.canceled)) {
48
- runQuery(data, success, error, runningQuery);
109
+ runQueryHelper(data, success, error, runningQuery);
49
110
  }
50
111
  }, 1000);
51
112
  } else {
52
113
  success(d);
114
+ queryComplete();
53
115
  }
54
116
  }).fail( function(jqXHR, textStatus, errorThrown) {
55
117
  var message = (typeof errorThrown === "string") ? errorThrown : errorThrown.message;
56
118
  error(message);
119
+ queryComplete();
57
120
  });
58
121
  if (runningQuery) {
59
122
  runningQuery.xhr = xhr;
@@ -5,11 +5,13 @@ module Blazer
5
5
  def home
6
6
  set_queries(1000)
7
7
 
8
- @dashboards = Blazer::Dashboard.order(:name)
9
- @dashboards = @dashboards.includes(:creator) if Blazer.user_class
10
- if params[:filter] == "mine"
8
+ if params[:filter]
11
9
  @dashboards = [] # TODO show my dashboards
10
+ else
11
+ @dashboards = Blazer::Dashboard.order(:name)
12
+ @dashboards = @dashboards.includes(:creator) if Blazer.user_class
12
13
  end
14
+
13
15
  @dashboards =
14
16
  @dashboards.map do |d|
15
17
  {
@@ -91,9 +93,9 @@ module Blazer
91
93
  @cached_at = nil
92
94
  params[:data_source] = nil
93
95
  render_run
94
- elsif Time.now > Time.at(@timestamp + (@data_source.timeout || 120).to_i)
95
- # timed out
96
- @error = Blazer::TIMEOUT_MESSAGE
96
+ elsif Time.now > Time.at(@timestamp + (@data_source.timeout || 600).to_i + 5)
97
+ # query lost
98
+ @error = "We lost your query :("
97
99
  @rows = []
98
100
  @columns = []
99
101
  render_run
@@ -101,9 +103,9 @@ module Blazer
101
103
  continue_run
102
104
  end
103
105
  elsif @success
104
- @run_id = Blazer.async ? SecureRandom.uuid : nil
106
+ @run_id = blazer_run_id
105
107
 
106
- options = {user: blazer_user, query: @query, refresh_cache: params[:check], run_id: @run_id}
108
+ options = {user: blazer_user, query: @query, refresh_cache: params[:check], run_id: @run_id, async: Blazer.async}
107
109
  if Blazer.async && request.format.symbol != :csv
108
110
  result = []
109
111
  Blazer::RunStatementJob.perform_async(result, @data_source, @statement, options)
@@ -114,7 +116,7 @@ module Blazer
114
116
  end
115
117
  @result = result.first
116
118
  else
117
- @result = RunStatement.new.perform(@data_source, @statement, options)
119
+ @result = Blazer::RunStatement.new.perform(@data_source, @statement, options)
118
120
  end
119
121
 
120
122
  if @result
@@ -174,6 +176,11 @@ module Blazer
174
176
  @schema = Blazer.data_sources[params[:data_source]].schema
175
177
  end
176
178
 
179
+ def cancel
180
+ Blazer.data_sources[params[:data_source]].cancel(blazer_run_id)
181
+ render json: {}
182
+ end
183
+
177
184
  private
178
185
 
179
186
  def continue_run
@@ -191,7 +198,7 @@ module Blazer
191
198
  case @first_row[i]
192
199
  when Integer
193
200
  "int"
194
- when Float
201
+ when Float, BigDecimal
195
202
  "float"
196
203
  else
197
204
  "string-ins"
@@ -237,24 +244,24 @@ module Blazer
237
244
 
238
245
  def set_queries(limit = nil)
239
246
  @my_queries =
240
- if limit && blazer_user && !params[:filter]
241
- favorite_query_ids = Blazer::Audit.where(user_id: blazer_user.id).where("created_at > ?", 30.days.ago).where("query_id IS NOT NULL").group(:query_id).order("count_all desc").count.keys
242
- queries = Blazer::Query.named.where(id: favorite_query_ids)
243
- queries = queries.includes(:creator) if Blazer.user_class
244
- queries = queries.index_by(&:id)
245
- favorite_query_ids.map { |query_id| queries[query_id] }.compact
247
+ if limit && blazer_user && !params[:filter] && Blazer.audit
248
+ queries_by_ids(Blazer::Audit.where(user_id: blazer_user.id).where("created_at > ?", 30.days.ago).where("query_id IS NOT NULL").group(:query_id).order("count_all desc").count.keys)
246
249
  else
247
250
  []
248
251
  end
249
252
 
250
- @queries = Blazer::Query.named.order(:name)
251
- if params[:filter] == "mine"
252
- @queries = @queries.where(creator_id: blazer_user.try(:id)).reorder(updated_at: :desc)
253
- limit = nil
254
- end
255
- @queries = @queries.where("id NOT IN (?)", @my_queries.map(&:id)) if @my_queries.any?
253
+ @queries = Blazer::Query.named
256
254
  @queries = @queries.includes(:creator) if Blazer.user_class
257
- @queries = @queries.limit(limit) if limit
255
+
256
+ if blazer_user && params[:filter] == "mine"
257
+ @queries = @queries.where(creator_id: blazer_user.id).reorder(updated_at: :desc)
258
+ elsif blazer_user && params[:filter] == "viewed" && Blazer.audit
259
+ @queries = queries_by_ids(Blazer::Audit.where(user_id: blazer_user.id).order(created_at: :desc).limit(500).pluck(:query_id).uniq)
260
+ else
261
+ @queries = @queries.where("id NOT IN (?)", @my_queries.map(&:id)) if @my_queries.any?
262
+ @queries = @queries.limit(limit) if limit
263
+ @queries = @queries.order(:name)
264
+ end
258
265
  @queries = @queries.to_a
259
266
 
260
267
  @more = limit && @queries.size >= limit
@@ -273,6 +280,13 @@ module Blazer
273
280
  end
274
281
  end
275
282
 
283
+ def queries_by_ids(favorite_query_ids)
284
+ queries = Blazer::Query.named.where(id: favorite_query_ids)
285
+ queries = queries.includes(:creator) if Blazer.user_class
286
+ queries = queries.index_by(&:id)
287
+ favorite_query_ids.map { |query_id| queries[query_id] }.compact
288
+ end
289
+
276
290
  def set_query
277
291
  @query = Blazer::Query.find(params[:id].to_s.split("-").first)
278
292
  end
@@ -298,5 +312,9 @@ module Blazer
298
312
  data_source.local_time_suffix.any? { |s| k.ends_with?(s) } ? v.to_s.sub(" UTC", "") : v.in_time_zone(Blazer.time_zone)
299
313
  end
300
314
  helper_method :blazer_time_value
315
+
316
+ def blazer_run_id
317
+ params[:run_id].to_s.gsub(/[^a-z0-9\-]/i, "")
318
+ end
301
319
  end
302
320
  end
@@ -15,7 +15,8 @@ module Blazer
15
15
 
16
16
  def failing_checks(email, checks)
17
17
  @checks = checks
18
- mail to: email, subject: "#{pluralize(checks.size, "Check")} Failing"
18
+ # add reply_to for mailing lists
19
+ mail to: email, reply_to: email, subject: "#{pluralize(checks.size, "Check")} Failing"
19
20
  end
20
21
  end
21
22
  end
@@ -8,14 +8,14 @@ module Blazer
8
8
 
9
9
  validates :statement, presence: true
10
10
 
11
- scope :named, -> { where("name <> ''") }
11
+ scope :named, -> { where("blazer_queries.name <> ''") }
12
12
 
13
13
  def to_param
14
14
  [id, name].compact.join("-").gsub("'", "").parameterize
15
15
  end
16
16
 
17
17
  def friendly_name
18
- name.to_s.gsub(/\[.+\]/, "").strip
18
+ name.to_s.sub(/\A[#\*]/, "").gsub(/\[.+\]/, "").strip
19
19
  end
20
20
 
21
21
  def editable?(user)
@@ -88,6 +88,8 @@
88
88
  },
89
89
  readOnly: false // false if this command should not apply in readOnly mode
90
90
  });
91
+ // fix command+L
92
+ editor.commands.removeCommands(["gotoline"]);
91
93
 
92
94
  // http://stackoverflow.com/questions/11584061/
93
95
  function adjustHeight() {
@@ -131,6 +133,7 @@
131
133
 
132
134
 
133
135
  function queryDone() {
136
+ runningQuery = null
134
137
  $("#run").removeClass("hide")
135
138
  $("#cancel").addClass("hide")
136
139
  }
@@ -144,6 +147,12 @@
144
147
  $("#results").html("")
145
148
  })
146
149
 
150
+ $(window).unload(function() {
151
+ if (runningQuery) {
152
+ remoteCancelQuery(runningQuery)
153
+ }
154
+ })
155
+
147
156
  $("#run").click( function (e) {
148
157
  e.preventDefault();
149
158
 
@@ -1,8 +1,15 @@
1
1
  <div id="queries">
2
2
  <div id="header" style="margin-bottom: 20px;">
3
3
  <div class="pull-right">
4
- <%= link_to "All", root_path, class: params[:filter] != "mine" ? "active" : nil, style: "margin-right: 40px;" %>
5
- <%= link_to "Mine", root_path(filter: "mine"), class: params[:filter] == "mine" ? "active" : nil, style: "margin-right: 40px;" %>
4
+ <% if blazer_user %>
5
+ <%= link_to "All", root_path, class: !params[:filter] ? "active" : nil, style: "margin-right: 40px;" %>
6
+
7
+ <% if Blazer.audit %>
8
+ <%= link_to "Viewed", root_path(filter: "viewed"), class: params[:filter] == "viewed" ? "active" : nil, style: "margin-right: 40px;" %>
9
+ <% end %>
10
+
11
+ <%= link_to "Mine", root_path(filter: "mine"), class: params[:filter] == "mine" ? "active" : nil, style: "margin-right: 40px;" %>
12
+ <% end %>
6
13
  <div class="btn-group">
7
14
  <%= link_to "New Query", new_query_path, class: "btn btn-info" %>
8
15
  <button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@@ -9,6 +9,7 @@
9
9
  <%= javascript_include_tag "blazer/application" %>
10
10
  <script>
11
11
  var runQueriesPath = <%= run_queries_path.to_json.html_safe %>;
12
+ var cancelQueriesPath = <%= cancel_queries_path.to_json.html_safe %>;
12
13
  </script>
13
14
  <% if blazer_maps? %>
14
15
  <%= stylesheet_link_tag "https://api.mapbox.com/mapbox.js/v2.4.0/mapbox.css" %>
@@ -1,6 +1,7 @@
1
1
  Blazer::Engine.routes.draw do
2
2
  resources :queries do
3
3
  post :run, on: :collection # err on the side of caution
4
+ post :cancel, on: :collection
4
5
  post :refresh, on: :member
5
6
  get :tables, on: :collection
6
7
  get :schema, on: :collection
@@ -35,6 +35,10 @@ module Blazer
35
35
  # optional
36
36
  end
37
37
 
38
+ def cancel(run_id)
39
+ # optional
40
+ end
41
+
38
42
  protected
39
43
 
40
44
  def settings
@@ -9,7 +9,7 @@ module Blazer
9
9
  @connection_model =
10
10
  Class.new(Blazer::Connection) do
11
11
  def self.name
12
- "Blazer::Connection::#{object_id}"
12
+ "Blazer::Connection::Adapter#{object_id}"
13
13
  end
14
14
  establish_connection(data_source.settings["url"]) if data_source.settings["url"]
15
15
  end
@@ -24,16 +24,17 @@ module Blazer
24
24
  in_transaction do
25
25
  set_timeout(data_source.timeout) if data_source.timeout
26
26
 
27
- result = connection_model.connection.select_all("#{statement} /*#{comment}*/")
27
+ result = select_all("#{statement} /*#{comment}*/")
28
28
  columns = result.columns
29
29
  cast_method = Rails::VERSION::MAJOR < 5 ? :type_cast : :cast_value
30
30
  result.rows.each do |untyped_row|
31
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
32
  end
33
33
  end
34
- rescue ActiveRecord::StatementInvalid => e
34
+ rescue => e
35
35
  error = e.message.sub(/.+ERROR: /, "")
36
36
  error = Blazer::TIMEOUT_MESSAGE if Blazer::TIMEOUT_ERRORS.any? { |e| error.include?(e) }
37
+ reconnect if error.include?("can't get socket descriptor")
37
38
  end
38
39
 
39
40
  [columns, rows, error]
@@ -65,14 +66,29 @@ module Blazer
65
66
 
66
67
  def explain(statement)
67
68
  if postgresql? || redshift?
68
- connection_model.connection.select_all("EXPLAIN #{statement}").rows.first.first
69
+ select_all("EXPLAIN #{statement}").rows.first.first
69
70
  end
70
71
  rescue
71
72
  nil
72
73
  end
73
74
 
75
+ def cancel(run_id)
76
+ if postgresql?
77
+ select_all("SELECT pg_cancel_backend(pid) FROM pg_stat_activity WHERE pid <> pg_backend_pid() AND query LIKE '%,run_id:#{run_id}%'")
78
+ elsif redshift?
79
+ first_row = select_all("SELECT pid FROM stv_recents WHERE status = 'Running' AND query LIKE '%,run_id:#{run_id}%'").first
80
+ if first_row
81
+ select_all("CANCEL #{first_row["pid"].to_i}")
82
+ end
83
+ end
84
+ end
85
+
74
86
  protected
75
87
 
88
+ def select_all(statement)
89
+ connection_model.connection.select_all(statement)
90
+ end
91
+
76
92
  def postgresql?
77
93
  ["PostgreSQL", "PostGIS"].include?(adapter_name)
78
94
  end
@@ -96,9 +112,9 @@ module Blazer
96
112
 
97
113
  def set_timeout(timeout)
98
114
  if postgresql? || redshift?
99
- connection_model.connection.execute("SET statement_timeout = #{timeout.to_i * 1000}")
115
+ select_all("SET statement_timeout = #{timeout.to_i * 1000}")
100
116
  elsif mysql?
101
- connection_model.connection.execute("SET max_execution_time = #{timeout.to_i * 1000}")
117
+ select_all("SET max_execution_time = #{timeout.to_i * 1000}")
102
118
  else
103
119
  raise Blazer::TimeoutNotSupported, "Timeout not supported for #{adapter_name} adapter"
104
120
  end
@@ -6,7 +6,7 @@ module Blazer
6
6
 
7
7
  attr_reader :id, :settings, :adapter, :adapter_instance
8
8
 
9
- def_delegators :adapter_instance, :schema, :tables, :preview_statement, :reconnect, :cost, :explain
9
+ def_delegators :adapter_instance, :schema, :tables, :preview_statement, :reconnect, :cost, :explain, :cancel
10
10
 
11
11
  def initialize(id, settings)
12
12
  @id = id
@@ -109,9 +109,14 @@ module Blazer
109
109
 
110
110
  def run_statement(statement, options = {})
111
111
  run_id = options[:run_id]
112
+ async = options[:async]
112
113
  result = nil
113
- if cache_mode != "off" && !options[:refresh_cache]
114
- result = read_cache(statement_cache_key(statement))
114
+ if cache_mode != "off"
115
+ if options[:refresh_cache]
116
+ clear_cache(statement) # for checks
117
+ else
118
+ result = read_cache(statement_cache_key(statement))
119
+ end
115
120
  end
116
121
 
117
122
  unless result
@@ -129,7 +134,10 @@ module Blazer
129
134
  if options[:check]
130
135
  comment << ",check_id:#{options[:check].id},check_emails:#{options[:check].emails}"
131
136
  end
132
- result = run_statement_helper(statement, comment, options[:run_id])
137
+ if options[:run_id]
138
+ comment << ",run_id:#{options[:run_id]}"
139
+ end
140
+ result = run_statement_helper(statement, comment, async ? options[:run_id] : nil)
133
141
  end
134
142
 
135
143
  result
@@ -144,7 +152,7 @@ module Blazer
144
152
  end
145
153
 
146
154
  def statement_cache_key(statement)
147
- cache_key(["statement", id, Digest::MD5.hexdigest(statement)])
155
+ cache_key(["statement", id, Digest::MD5.hexdigest(statement.to_s.gsub("\r\n", "\n"))])
148
156
  end
149
157
 
150
158
  def run_cache_key(run_id)
@@ -8,9 +8,9 @@ tryCatch({
8
8
  data$timestamp <- as.POSIXct(data$timestamp)
9
9
 
10
10
  if (identical(args[1], "ts")) {
11
- res = AnomalyDetectionTs(data, direction = "both", alpha = 0.05)
11
+ res <- AnomalyDetectionTs(data, direction = "both", alpha = 0.05, max_anoms = 0.2)
12
12
  } else {
13
- res = AnomalyDetectionVec(data$count, direction = "both", alpha = 0.05, period = length(data$count) / 2 - 1)
13
+ res <- AnomalyDetectionVec(data$count, direction = "both", alpha = 0.05, max_anoms = 0.2, period = length(data$count) / 2 - 1)
14
14
  }
15
15
 
16
16
  write.csv(res$anoms)
@@ -1,38 +1,40 @@
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
1
+ module Blazer
2
+ class RunStatement
3
+ def perform(data_source, statement, options = {})
4
+ query = options[:query]
5
+ Blazer.transform_statement.call(data_source, statement) if Blazer.transform_statement
5
6
 
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
7
+ # audit
8
+ if Blazer.audit
9
+ audit = Blazer::Audit.new(statement: statement)
10
+ audit.query = query
11
+ audit.data_source = data_source.id
12
+ audit.user = options[:user]
13
+ audit.save!
14
+ end
14
15
 
15
- start_time = Time.now
16
- result = data_source.run_statement(statement, options)
17
- duration = Time.now - start_time
16
+ start_time = Time.now
17
+ result = data_source.run_statement(statement, options)
18
+ duration = Time.now - start_time
18
19
 
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=)
20
+ if Blazer.audit
21
+ audit.duration = duration if audit.respond_to?(:duration=)
22
+ audit.error = result.error if audit.respond_to?(:error=)
23
+ audit.timed_out = result.timed_out? if audit.respond_to?(:timed_out=)
24
+ audit.cached = result.cached? if audit.respond_to?(:cached=)
25
+ if !result.cached? && duration >= 10
26
+ audit.cost = data_source.cost(statement) if audit.respond_to?(:cost=)
27
+ end
28
+ audit.save! if audit.changed?
26
29
  end
27
- audit.save! if audit.changed?
28
- end
29
30
 
30
- if query && !result.timed_out?
31
- query.checks.each do |check|
32
- check.update_state(result)
31
+ if query && !result.timed_out?
32
+ query.checks.each do |check|
33
+ check.update_state(result)
34
+ end
33
35
  end
34
- end
35
36
 
36
- result
37
+ result
38
+ end
37
39
  end
38
40
  end
@@ -8,7 +8,7 @@ module Blazer
8
8
  def perform(result, data_source, statement, options)
9
9
  begin
10
10
  ActiveRecord::Base.connection_pool.with_connection do
11
- result << RunStatement.new.perform(data_source, statement, options)
11
+ result << Blazer::RunStatement.new.perform(data_source, statement, options)
12
12
  end
13
13
  rescue Exception => e
14
14
  result.clear
@@ -1,3 +1,3 @@
1
1
  module Blazer
2
- VERSION = "1.6.2"
2
+ VERSION = "1.7.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.6.2
4
+ version: 1.7.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-08-11 00:00:00.000000000 Z
11
+ date: 2016-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -196,9 +196,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
196
196
  version: '0'
197
197
  requirements: []
198
198
  rubyforge_project:
199
- rubygems_version: 2.6.1
199
+ rubygems_version: 2.5.1
200
200
  signing_key:
201
201
  specification_version: 4
202
202
  summary: Share data effortlessly with your team
203
203
  test_files: []
204
- has_rdoc: