blazer 2.5.0 → 2.6.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +55 -9
- data/app/assets/stylesheets/blazer/application.css +1 -0
- data/app/assets/stylesheets/blazer/bootstrap-propshaft.css +10 -0
- data/app/assets/stylesheets/blazer/bootstrap-sprockets.css.erb +10 -0
- data/app/assets/stylesheets/blazer/{bootstrap.css.erb → bootstrap.css} +0 -6
- data/app/controllers/blazer/base_controller.rb +45 -45
- data/app/controllers/blazer/dashboards_controller.rb +4 -11
- data/app/controllers/blazer/queries_controller.rb +28 -48
- data/app/models/blazer/query.rb +8 -2
- data/app/views/blazer/_variables.html.erb +5 -4
- data/app/views/blazer/dashboards/_form.html.erb +1 -1
- data/app/views/blazer/dashboards/show.html.erb +4 -4
- data/app/views/blazer/queries/_caching.html.erb +1 -1
- data/app/views/blazer/queries/_form.html.erb +3 -3
- data/app/views/blazer/queries/run.html.erb +1 -1
- data/app/views/blazer/queries/show.html.erb +12 -7
- data/app/views/layouts/blazer/application.html.erb +7 -2
- data/lib/blazer/adapters/athena_adapter.rb +51 -15
- data/lib/blazer/adapters/base_adapter.rb +16 -1
- data/lib/blazer/adapters/bigquery_adapter.rb +13 -2
- data/lib/blazer/adapters/cassandra_adapter.rb +15 -4
- data/lib/blazer/adapters/drill_adapter.rb +10 -0
- data/lib/blazer/adapters/druid_adapter.rb +36 -1
- data/lib/blazer/adapters/elasticsearch_adapter.rb +13 -2
- data/lib/blazer/adapters/hive_adapter.rb +10 -0
- data/lib/blazer/adapters/ignite_adapter.rb +12 -2
- data/lib/blazer/adapters/influxdb_adapter.rb +22 -10
- data/lib/blazer/adapters/mongodb_adapter.rb +4 -0
- data/lib/blazer/adapters/neo4j_adapter.rb +17 -2
- data/lib/blazer/adapters/opensearch_adapter.rb +4 -0
- data/lib/blazer/adapters/presto_adapter.rb +9 -0
- data/lib/blazer/adapters/salesforce_adapter.rb +5 -0
- data/lib/blazer/adapters/snowflake_adapter.rb +9 -0
- data/lib/blazer/adapters/soda_adapter.rb +9 -0
- data/lib/blazer/adapters/spark_adapter.rb +5 -0
- data/lib/blazer/adapters/sql_adapter.rb +30 -3
- data/lib/blazer/data_source.rb +85 -5
- data/lib/blazer/engine.rb +0 -4
- data/lib/blazer/run_statement.rb +7 -3
- data/lib/blazer/run_statement_job.rb +4 -2
- data/lib/blazer/slack_notifier.rb +5 -2
- data/lib/blazer/statement.rb +75 -0
- data/lib/blazer/version.rb +1 -1
- data/lib/blazer.rb +14 -6
- metadata +7 -4
@@ -35,6 +35,11 @@ module Blazer
|
|
35
35
|
"SELECT Id FROM {table} LIMIT 10"
|
36
36
|
end
|
37
37
|
|
38
|
+
# https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_quotedstringescapes.htm
|
39
|
+
def quoting
|
40
|
+
:backslash_escape
|
41
|
+
end
|
42
|
+
|
38
43
|
protected
|
39
44
|
|
40
45
|
def client
|
@@ -68,6 +68,15 @@ module Blazer
|
|
68
68
|
def cancel(run_id)
|
69
69
|
# todo
|
70
70
|
end
|
71
|
+
|
72
|
+
# https://docs.snowflake.com/en/sql-reference/data-types-text.html#escape-sequences
|
73
|
+
def quoting
|
74
|
+
:backslash_escape
|
75
|
+
end
|
76
|
+
|
77
|
+
def parameter_binding
|
78
|
+
# TODO
|
79
|
+
end
|
71
80
|
end
|
72
81
|
end
|
73
82
|
end
|
@@ -2,6 +2,10 @@ module Blazer
|
|
2
2
|
module Adapters
|
3
3
|
class SodaAdapter < BaseAdapter
|
4
4
|
def run_statement(statement, comment)
|
5
|
+
require "json"
|
6
|
+
require "net/http"
|
7
|
+
require "uri"
|
8
|
+
|
5
9
|
columns = []
|
6
10
|
rows = []
|
7
11
|
error = nil
|
@@ -91,6 +95,11 @@ module Blazer
|
|
91
95
|
def tables
|
92
96
|
["all"]
|
93
97
|
end
|
98
|
+
|
99
|
+
# https://dev.socrata.com/docs/datatypes/text.html
|
100
|
+
def quoting
|
101
|
+
:single_quote_escape
|
102
|
+
end
|
94
103
|
end
|
95
104
|
end
|
96
105
|
end
|
@@ -15,7 +15,7 @@ module Blazer
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def run_statement(statement, comment)
|
18
|
+
def run_statement(statement, comment, bind_params = [])
|
19
19
|
columns = []
|
20
20
|
rows = []
|
21
21
|
error = nil
|
@@ -24,7 +24,8 @@ module Blazer
|
|
24
24
|
in_transaction do
|
25
25
|
set_timeout(data_source.timeout) if data_source.timeout
|
26
26
|
|
27
|
-
|
27
|
+
binds = bind_params.map { |v| ActiveRecord::Relation::QueryAttribute.new(nil, v, ActiveRecord::Type::Value.new) }
|
28
|
+
result = connection_model.connection.select_all("#{statement} /*#{comment}*/", nil, binds)
|
28
29
|
columns = result.columns
|
29
30
|
result.rows.each do |untyped_row|
|
30
31
|
rows << (result.column_types.empty? ? untyped_row : columns.each_with_index.map { |c, i| untyped_row[i] && result.column_types[c] ? result.column_types[c].send(:cast_value, untyped_row[i]) : untyped_row[i] })
|
@@ -33,6 +34,7 @@ module Blazer
|
|
33
34
|
rescue => e
|
34
35
|
error = e.message.sub(/.+ERROR: /, "")
|
35
36
|
error = Blazer::TIMEOUT_MESSAGE if Blazer::TIMEOUT_ERRORS.any? { |e| error.include?(e) }
|
37
|
+
error = Blazer::VARIABLE_MESSAGE if error.include?("syntax error at or near \"$") || error.include?("Incorrect syntax near '@") || error.include?("your MySQL server version for the right syntax to use near '?")
|
36
38
|
reconnect if error.include?("PG::ConnectionBad")
|
37
39
|
end
|
38
40
|
|
@@ -156,7 +158,7 @@ module Blazer
|
|
156
158
|
# WITH not an optimization fence in Postgres 12+
|
157
159
|
statement = <<~SQL
|
158
160
|
WITH query AS (
|
159
|
-
|
161
|
+
{placeholder}
|
160
162
|
),
|
161
163
|
cohorts AS (
|
162
164
|
SELECT user_id, MIN(#{cohort_column}) AS cohort_time FROM query
|
@@ -183,6 +185,27 @@ module Blazer
|
|
183
185
|
connection_model.send(:sanitize_sql_array, params)
|
184
186
|
end
|
185
187
|
|
188
|
+
def quoting
|
189
|
+
->(value) { connection_model.connection.quote(value) }
|
190
|
+
end
|
191
|
+
|
192
|
+
# Redshift adapter silently ignores binds
|
193
|
+
def parameter_binding
|
194
|
+
if postgresql? || sqlite?
|
195
|
+
:numeric
|
196
|
+
elsif mysql? && connection_model.connection.prepared_statements?
|
197
|
+
# Active Record silently ignores binds with MySQL when prepared statements are disabled
|
198
|
+
:positional
|
199
|
+
elsif sqlserver?
|
200
|
+
proc do |statement, variables|
|
201
|
+
variables.each_with_index do |(k, _), i|
|
202
|
+
statement = statement.gsub("{#{k}}", "@#{i} ")
|
203
|
+
end
|
204
|
+
[statement, variables.values]
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
186
209
|
protected
|
187
210
|
|
188
211
|
def select_all(statement, params = [])
|
@@ -207,6 +230,10 @@ module Blazer
|
|
207
230
|
["MySQL", "Mysql2", "Mysql2Spatial"].include?(adapter_name)
|
208
231
|
end
|
209
232
|
|
233
|
+
def sqlite?
|
234
|
+
["SQLite"].include?(adapter_name)
|
235
|
+
end
|
236
|
+
|
210
237
|
def sqlserver?
|
211
238
|
["SQLServer", "tinytds", "mssql"].include?(adapter_name)
|
212
239
|
end
|
data/lib/blazer/data_source.rb
CHANGED
@@ -89,7 +89,19 @@ module Blazer
|
|
89
89
|
Blazer.cache.delete(run_cache_key(run_id))
|
90
90
|
end
|
91
91
|
|
92
|
+
def sub_variables(statement, vars)
|
93
|
+
statement = statement.dup
|
94
|
+
vars.each do |var, value|
|
95
|
+
# use block form to disable back-references
|
96
|
+
statement.gsub!("{#{var}}") { quote(value) }
|
97
|
+
end
|
98
|
+
statement
|
99
|
+
end
|
100
|
+
|
92
101
|
def run_statement(statement, options = {})
|
102
|
+
statement = Statement.new(statement, self) if statement.is_a?(String)
|
103
|
+
statement.bind unless statement.bind_statement
|
104
|
+
|
93
105
|
async = options[:async]
|
94
106
|
result = nil
|
95
107
|
if cache_mode != "off"
|
@@ -118,7 +130,7 @@ module Blazer
|
|
118
130
|
if options[:run_id]
|
119
131
|
comment << ",run_id:#{options[:run_id]}"
|
120
132
|
end
|
121
|
-
result = run_statement_helper(statement, comment, async ? options[:run_id] : nil)
|
133
|
+
result = run_statement_helper(statement, comment, async ? options[:run_id] : nil, options)
|
122
134
|
end
|
123
135
|
|
124
136
|
result
|
@@ -133,13 +145,68 @@ module Blazer
|
|
133
145
|
end
|
134
146
|
|
135
147
|
def statement_cache_key(statement)
|
136
|
-
cache_key(["statement", id, Digest::MD5.hexdigest(statement.to_s.gsub("\r\n", "\n"))])
|
148
|
+
cache_key(["statement", id, Digest::MD5.hexdigest(statement.bind_statement.to_s.gsub("\r\n", "\n") + statement.bind_values.sort_by { |k, _| k }.to_json)])
|
137
149
|
end
|
138
150
|
|
139
151
|
def run_cache_key(run_id)
|
140
152
|
cache_key(["run", run_id])
|
141
153
|
end
|
142
154
|
|
155
|
+
def quote(value)
|
156
|
+
if quoting == :backslash_escape || quoting == :single_quote_escape
|
157
|
+
# only need to support types generated by process_vars
|
158
|
+
if value.is_a?(Integer) || value.is_a?(Float)
|
159
|
+
value.to_s
|
160
|
+
elsif value.nil?
|
161
|
+
"NULL"
|
162
|
+
else
|
163
|
+
value = value.to_formatted_s(:db) if value.is_a?(ActiveSupport::TimeWithZone)
|
164
|
+
|
165
|
+
if quoting == :backslash_escape
|
166
|
+
"'#{value.gsub("\\") { "\\\\" }.gsub("'") { "\\'" }}'"
|
167
|
+
else
|
168
|
+
"'#{value.gsub("'", "''")}'"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
elsif quoting.respond_to?(:call)
|
172
|
+
quoting.call(value)
|
173
|
+
elsif quoting.nil?
|
174
|
+
raise Blazer::Error, "Quoting not specified"
|
175
|
+
else
|
176
|
+
raise Blazer::Error, "Unknown quoting"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def bind_params(statement, variables)
|
181
|
+
if parameter_binding == :positional
|
182
|
+
locations = []
|
183
|
+
variables.each do |k, v|
|
184
|
+
i = 0
|
185
|
+
while (idx = statement.index("{#{k}}", i))
|
186
|
+
locations << [v, idx]
|
187
|
+
i = idx + 1
|
188
|
+
end
|
189
|
+
end
|
190
|
+
variables.each do |k, v|
|
191
|
+
statement = statement.gsub("{#{k}}", "?")
|
192
|
+
end
|
193
|
+
[statement, locations.sort_by(&:last).map(&:first)]
|
194
|
+
elsif parameter_binding == :numeric
|
195
|
+
variables.each_with_index do |(k, v), i|
|
196
|
+
# add trailing space if followed by digit
|
197
|
+
# try to keep minimal to avoid fixing invalid queries like SELECT{var}
|
198
|
+
statement = statement.gsub(/#{Regexp.escape("{#{k}}")}(\d)/, "$#{i + 1} \\1").gsub("{#{k}}", "$#{i + 1}")
|
199
|
+
end
|
200
|
+
[statement, variables.values]
|
201
|
+
elsif parameter_binding.respond_to?(:call)
|
202
|
+
parameter_binding.call(statement, variables)
|
203
|
+
elsif parameter_binding.nil?
|
204
|
+
[sub_variables(statement, variables), []]
|
205
|
+
else
|
206
|
+
raise Blazer::Error, "Unknown bind parameters"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
143
210
|
protected
|
144
211
|
|
145
212
|
def adapter_instance
|
@@ -157,9 +224,22 @@ module Blazer
|
|
157
224
|
end
|
158
225
|
end
|
159
226
|
|
160
|
-
def
|
227
|
+
def quoting
|
228
|
+
@quoting ||= adapter_instance.quoting
|
229
|
+
end
|
230
|
+
|
231
|
+
def parameter_binding
|
232
|
+
@parameter_binding ||= adapter_instance.parameter_binding
|
233
|
+
end
|
234
|
+
|
235
|
+
def run_statement_helper(statement, comment, run_id, options)
|
161
236
|
start_time = Time.now
|
162
|
-
columns, rows, error =
|
237
|
+
columns, rows, error =
|
238
|
+
if adapter_instance.parameter_binding
|
239
|
+
adapter_instance.run_statement(statement.bind_statement, comment, statement.bind_values)
|
240
|
+
else
|
241
|
+
adapter_instance.run_statement(statement.bind_statement, comment)
|
242
|
+
end
|
163
243
|
duration = Time.now - start_time
|
164
244
|
|
165
245
|
cache_data = nil
|
@@ -168,7 +248,7 @@ module Blazer
|
|
168
248
|
cache_data = Marshal.dump([columns, rows, error, cache ? Time.now : nil]) rescue nil
|
169
249
|
end
|
170
250
|
|
171
|
-
if cache && cache_data && adapter_instance.cachable?(statement)
|
251
|
+
if cache && cache_data && adapter_instance.cachable?(statement.bind_statement)
|
172
252
|
Blazer.cache.write(statement_cache_key(statement), cache_data, expires_in: cache_expires_in.to_f * 60)
|
173
253
|
end
|
174
254
|
|
data/lib/blazer/engine.rb
CHANGED
@@ -30,10 +30,6 @@ module Blazer
|
|
30
30
|
Blazer.anomaly_checks = Blazer.settings["anomaly_checks"] || false
|
31
31
|
Blazer.forecasting = Blazer.settings["forecasting"] || false
|
32
32
|
Blazer.async = Blazer.settings["async"] || false
|
33
|
-
if Blazer.async
|
34
|
-
require "blazer/run_statement_job"
|
35
|
-
end
|
36
|
-
|
37
33
|
Blazer.images = Blazer.settings["images"] || false
|
38
34
|
Blazer.override_csp = Blazer.settings["override_csp"] || false
|
39
35
|
Blazer.slack_oauth_token = Blazer.settings["slack_oauth_token"] || ENV["BLAZER_SLACK_OAUTH_TOKEN"]
|
data/lib/blazer/run_statement.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
module Blazer
|
2
2
|
class RunStatement
|
3
|
-
def perform(
|
3
|
+
def perform(statement, options = {})
|
4
4
|
query = options[:query]
|
5
|
-
|
5
|
+
|
6
|
+
data_source = statement.data_source
|
7
|
+
statement.bind
|
6
8
|
|
7
9
|
# audit
|
8
10
|
if Blazer.audit
|
9
|
-
|
11
|
+
audit_statement = statement.bind_statement
|
12
|
+
audit_statement += "\n\n#{statement.bind_values.to_json}" if statement.bind_values.any?
|
13
|
+
audit = Blazer::Audit.new(statement: audit_statement)
|
10
14
|
audit.query = query
|
11
15
|
audit.data_source = data_source.id
|
12
16
|
audit.user = options[:user]
|
@@ -3,10 +3,12 @@ module Blazer
|
|
3
3
|
self.queue_adapter = :async
|
4
4
|
|
5
5
|
def perform(data_source_id, statement, options)
|
6
|
-
|
6
|
+
statement = Blazer::Statement.new(statement, data_source_id)
|
7
|
+
statement.values = options.delete(:values)
|
8
|
+
data_source = statement.data_source
|
7
9
|
begin
|
8
10
|
ActiveRecord::Base.connection_pool.with_connection do
|
9
|
-
Blazer::RunStatement.new.perform(
|
11
|
+
Blazer::RunStatement.new.perform(statement, options)
|
10
12
|
end
|
11
13
|
rescue Exception => e
|
12
14
|
Blazer::Result.new(data_source, [], [], "Unknown error", nil, false)
|
@@ -67,15 +67,18 @@ module Blazer
|
|
67
67
|
Blazer::Engine.routes.url_helpers.query_url(id, ActionMailer::Base.default_url_options)
|
68
68
|
end
|
69
69
|
|
70
|
+
# TODO use return value
|
70
71
|
def self.post(payload)
|
71
72
|
if Blazer.slack_webhook_url.present?
|
72
|
-
post_api(Blazer.slack_webhook_url, payload, {})
|
73
|
+
response = post_api(Blazer.slack_webhook_url, payload, {})
|
74
|
+
response.is_a?(Net::HTTPSuccess) && response.body == "ok"
|
73
75
|
else
|
74
76
|
headers = {
|
75
77
|
"Authorization" => "Bearer #{Blazer.slack_oauth_token}",
|
76
78
|
"Content-type" => "application/json"
|
77
79
|
}
|
78
|
-
post_api("https://slack.com/api/chat.postMessage", payload, headers)
|
80
|
+
response = post_api("https://slack.com/api/chat.postMessage", payload, headers)
|
81
|
+
response.is_a?(Net::HTTPSuccess) && (JSON.parse(response.body)["ok"] rescue false)
|
79
82
|
end
|
80
83
|
end
|
81
84
|
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Blazer
|
2
|
+
class Statement
|
3
|
+
attr_reader :statement, :data_source, :bind_statement, :bind_values
|
4
|
+
attr_accessor :values
|
5
|
+
|
6
|
+
def initialize(statement, data_source = nil)
|
7
|
+
@statement = statement
|
8
|
+
@data_source = data_source.is_a?(String) ? Blazer.data_sources[data_source] : data_source
|
9
|
+
@values = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def variables
|
13
|
+
@variables ||= Blazer.extract_vars(statement)
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_values(var_params)
|
17
|
+
variables.each do |var|
|
18
|
+
value = var_params[var].presence
|
19
|
+
value = nil unless value.is_a?(String) # ignore arrays and hashes
|
20
|
+
if value
|
21
|
+
if ["start_time", "end_time"].include?(var)
|
22
|
+
value = value.to_s.gsub(" ", "+") # fix for Quip bug
|
23
|
+
end
|
24
|
+
|
25
|
+
if var.end_with?("_at")
|
26
|
+
begin
|
27
|
+
value = Blazer.time_zone.parse(value)
|
28
|
+
rescue
|
29
|
+
# do nothing
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
unless value.is_a?(ActiveSupport::TimeWithZone)
|
34
|
+
if value =~ /\A\d+\z/
|
35
|
+
value = value.to_i
|
36
|
+
elsif value =~ /\A\d+\.\d+\z/
|
37
|
+
value = value.to_f
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
value = Blazer.transform_variable.call(var, value) if Blazer.transform_variable
|
42
|
+
@values[var] = value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def cohort_analysis?
|
47
|
+
/\/\*\s*cohort analysis\s*\*\//i.match?(statement)
|
48
|
+
end
|
49
|
+
|
50
|
+
def apply_cohort_analysis(period:, days:)
|
51
|
+
@statement = data_source.cohort_analysis_statement(statement, period: period, days: days).sub("{placeholder}") { statement }
|
52
|
+
end
|
53
|
+
|
54
|
+
# should probably transform before cohort analysis
|
55
|
+
# but keep previous order for now
|
56
|
+
def transformed_statement
|
57
|
+
statement = self.statement.dup
|
58
|
+
Blazer.transform_statement.call(data_source, statement) if Blazer.transform_statement
|
59
|
+
statement
|
60
|
+
end
|
61
|
+
|
62
|
+
def bind
|
63
|
+
@bind_statement, @bind_values = data_source.bind_params(transformed_statement, values)
|
64
|
+
end
|
65
|
+
|
66
|
+
def display_statement
|
67
|
+
data_source.sub_variables(transformed_statement, values)
|
68
|
+
end
|
69
|
+
|
70
|
+
def clear_cache
|
71
|
+
bind if bind_statement.nil?
|
72
|
+
data_source.clear_cache(self)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/blazer/version.rb
CHANGED
data/lib/blazer.rb
CHANGED
@@ -1,14 +1,18 @@
|
|
1
1
|
# dependencies
|
2
|
-
require "csv"
|
3
|
-
require "yaml"
|
4
2
|
require "chartkick"
|
5
3
|
require "safely/core"
|
6
4
|
|
5
|
+
# stdlib
|
6
|
+
require "csv"
|
7
|
+
require "json"
|
8
|
+
require "yaml"
|
9
|
+
|
7
10
|
# modules
|
8
11
|
require "blazer/version"
|
9
12
|
require "blazer/data_source"
|
10
13
|
require "blazer/result"
|
11
14
|
require "blazer/run_statement"
|
15
|
+
require "blazer/statement"
|
12
16
|
|
13
17
|
# adapters
|
14
18
|
require "blazer/adapters/base_adapter"
|
@@ -43,6 +47,8 @@ module Blazer
|
|
43
47
|
autoload :CheckMailer, "blazer/check_mailer"
|
44
48
|
# net/http optional
|
45
49
|
autoload :SlackNotifier, "blazer/slack_notifier"
|
50
|
+
# activejob optional
|
51
|
+
autoload :RunStatementJob, "blazer/run_statement_job"
|
46
52
|
|
47
53
|
class << self
|
48
54
|
attr_accessor :audit
|
@@ -76,6 +82,7 @@ module Blazer
|
|
76
82
|
self.images = false
|
77
83
|
self.override_csp = false
|
78
84
|
|
85
|
+
VARIABLE_MESSAGE = "Variable cannot be used in this position"
|
79
86
|
TIMEOUT_MESSAGE = "Query timed out :("
|
80
87
|
TIMEOUT_ERRORS = [
|
81
88
|
"canceling statement due to statement timeout", # postgres
|
@@ -128,6 +135,7 @@ module Blazer
|
|
128
135
|
end
|
129
136
|
end
|
130
137
|
|
138
|
+
# TODO move to Statement and remove in 3.0.0
|
131
139
|
def self.extract_vars(statement)
|
132
140
|
# strip commented out lines
|
133
141
|
# and regex {1} or {1,2}
|
@@ -148,9 +156,8 @@ module Blazer
|
|
148
156
|
|
149
157
|
ActiveSupport::Notifications.instrument("run_check.blazer", check_id: check.id, query_id: check.query.id, state_was: check.state) do |instrument|
|
150
158
|
# try 3 times on timeout errors
|
151
|
-
|
152
|
-
|
153
|
-
Blazer.transform_statement.call(data_source, statement) if Blazer.transform_statement
|
159
|
+
statement = check.query.statement_object
|
160
|
+
data_source = statement.data_source
|
154
161
|
|
155
162
|
while tries <= 3
|
156
163
|
result = data_source.run_statement(statement, refresh_cache: true, check: check, query: check.query)
|
@@ -178,7 +185,8 @@ module Blazer
|
|
178
185
|
# TODO use proper logfmt
|
179
186
|
Rails.logger.info "[blazer check] query=#{check.query.name} state=#{check.state} rows=#{result.rows.try(:size)} error=#{result.error}"
|
180
187
|
|
181
|
-
|
188
|
+
# should be no variables
|
189
|
+
instrument[:statement] = statement.bind_statement
|
182
190
|
instrument[:data_source] = data_source
|
183
191
|
instrument[:state] = check.state
|
184
192
|
instrument[:rows] = result.rows.try(:size)
|
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: 2.
|
4
|
+
version: 2.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: 2022-
|
11
|
+
date: 2022-04-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -109,7 +109,9 @@ files:
|
|
109
109
|
- app/assets/javascripts/blazer/stupidtable.js
|
110
110
|
- app/assets/javascripts/blazer/vue.js
|
111
111
|
- app/assets/stylesheets/blazer/application.css
|
112
|
-
- app/assets/stylesheets/blazer/bootstrap.css
|
112
|
+
- app/assets/stylesheets/blazer/bootstrap-propshaft.css
|
113
|
+
- app/assets/stylesheets/blazer/bootstrap-sprockets.css.erb
|
114
|
+
- app/assets/stylesheets/blazer/bootstrap.css
|
113
115
|
- app/assets/stylesheets/blazer/daterangepicker.css
|
114
116
|
- app/assets/stylesheets/blazer/github.css
|
115
117
|
- app/assets/stylesheets/blazer/selectize.css
|
@@ -184,6 +186,7 @@ files:
|
|
184
186
|
- lib/blazer/run_statement.rb
|
185
187
|
- lib/blazer/run_statement_job.rb
|
186
188
|
- lib/blazer/slack_notifier.rb
|
189
|
+
- lib/blazer/statement.rb
|
187
190
|
- lib/blazer/version.rb
|
188
191
|
- lib/generators/blazer/install_generator.rb
|
189
192
|
- lib/generators/blazer/templates/config.yml.tt
|
@@ -226,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
226
229
|
- !ruby/object:Gem::Version
|
227
230
|
version: '0'
|
228
231
|
requirements: []
|
229
|
-
rubygems_version: 3.
|
232
|
+
rubygems_version: 3.3.7
|
230
233
|
signing_key:
|
231
234
|
specification_version: 4
|
232
235
|
summary: Explore your data with SQL. Easily create charts and dashboards, and share
|