blazer 3.0.0 → 3.3.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 +57 -0
- data/LICENSE.txt +1 -1
- data/README.md +69 -102
- data/app/controllers/blazer/base_controller.rb +5 -3
- data/app/controllers/blazer/queries_controller.rb +12 -2
- data/app/views/blazer/_variables.html.erb +8 -8
- data/app/views/blazer/checks/_form.html.erb +8 -8
- data/app/views/blazer/checks/index.html.erb +2 -2
- data/app/views/blazer/dashboards/_form.html.erb +2 -2
- data/app/views/blazer/dashboards/show.html.erb +2 -2
- data/app/views/blazer/queries/_form.html.erb +2 -2
- data/app/views/blazer/queries/home.html.erb +2 -2
- data/app/views/blazer/queries/run.html.erb +7 -7
- data/app/views/blazer/queries/schema.html.erb +3 -3
- data/app/views/blazer/queries/show.html.erb +4 -4
- data/app/views/blazer/uploads/index.html.erb +2 -2
- data/app/views/layouts/blazer/application.html.erb +5 -5
- data/lib/blazer/adapters/athena_adapter.rb +1 -1
- data/lib/blazer/adapters/hive_adapter.rb +1 -1
- data/lib/blazer/adapters/neo4j_adapter.rb +41 -13
- data/lib/blazer/adapters/presto_adapter.rb +4 -3
- data/lib/blazer/adapters/sql_adapter.rb +54 -17
- data/lib/blazer/adapters.rb +1 -0
- data/lib/blazer/data_source.rb +2 -2
- data/lib/blazer/engine.rb +18 -16
- data/lib/blazer/result.rb +2 -2
- data/lib/blazer/run_statement.rb +2 -1
- data/lib/blazer/statement.rb +6 -3
- data/lib/blazer/version.rb +1 -1
- metadata +22 -12
@@ -56,7 +56,7 @@
|
|
56
56
|
<p v-if="more" class="text-muted">Loading...</p>
|
57
57
|
</div>
|
58
58
|
|
59
|
-
|
59
|
+
<%= javascript_tag nonce: true do %>
|
60
60
|
<%= blazer_js_var "dashboards", @dashboards %>
|
61
61
|
<%= blazer_js_var "queries", @queries %>
|
62
62
|
<%= blazer_js_var "more", @more %>
|
@@ -166,4 +166,4 @@
|
|
166
166
|
})
|
167
167
|
app.config.compilerOptions.whitespace = "preserve"
|
168
168
|
app.mount("#queries")
|
169
|
-
|
169
|
+
<% end %>
|
@@ -4,7 +4,7 @@
|
|
4
4
|
<% if @only_chart %>
|
5
5
|
<p class="text-muted">Select variables</p>
|
6
6
|
<% else %>
|
7
|
-
<div class="alert alert-info">Can’t preview queries with variables
|
7
|
+
<div class="alert alert-info">Can’t preview queries with variables</div>
|
8
8
|
<% end %>
|
9
9
|
<% elsif @cohort_analysis %>
|
10
10
|
<% if @cohort_error %>
|
@@ -46,7 +46,7 @@
|
|
46
46
|
<% chart_id = SecureRandom.hex %>
|
47
47
|
<% column_types = @result.column_types %>
|
48
48
|
<% chart_type = @result.chart_type %>
|
49
|
-
<% chart_options = {id: chart_id} %>
|
49
|
+
<% chart_options = {id: chart_id, thousands: t("number.format.delimiter"), decimal: t("number.format.separator")} %>
|
50
50
|
<% if ["line", "line2"].include?(chart_type) %>
|
51
51
|
<% chart_options.merge!(min: nil) %>
|
52
52
|
<% end %>
|
@@ -75,21 +75,21 @@
|
|
75
75
|
<% if @markers.any? %>
|
76
76
|
<% map_id = SecureRandom.hex %>
|
77
77
|
<%= content_tag :div, nil, id: map_id, style: "height: #{@only_chart ? 300 : 500}px;" %>
|
78
|
-
|
78
|
+
<%= javascript_tag nonce: true do %>
|
79
79
|
<%= blazer_js_var "mapboxAccessToken", Blazer.mapbox_access_token %>
|
80
80
|
<%= blazer_js_var "markers", @markers %>
|
81
81
|
<%= blazer_js_var "mapId", map_id %>
|
82
82
|
new Mapkick.Map(mapId, markers, {accessToken: mapboxAccessToken, tooltips: {hover: false, html: true}});
|
83
|
-
|
83
|
+
<% end %>
|
84
84
|
<% elsif @geojson.any? %>
|
85
85
|
<% map_id = SecureRandom.hex %>
|
86
86
|
<%= content_tag :div, nil, id: map_id, style: "height: #{@only_chart ? 300 : 500}px;" %>
|
87
|
-
|
87
|
+
<%= javascript_tag nonce: true do %>
|
88
88
|
<%= blazer_js_var "mapboxAccessToken", Blazer.mapbox_access_token %>
|
89
89
|
<%= blazer_js_var "geojson", @geojson %>
|
90
90
|
<%= blazer_js_var "mapId", map_id %>
|
91
91
|
new Mapkick.AreaMap(mapId, geojson, {accessToken: mapboxAccessToken, tooltips: {hover: false, html: true}});
|
92
|
-
|
92
|
+
<% end %>
|
93
93
|
<% elsif chart_type == "line" %>
|
94
94
|
<% chart_data = @columns[1..-1].each_with_index.map{ |k, i| {name: blazer_series_name(k), data: @rows.map{ |r| [r[0], r[i + 1]] }, library: series_library[i]} } %>
|
95
95
|
<%= line_chart chart_data, **chart_options %>
|
@@ -165,7 +165,7 @@
|
|
165
165
|
<% end %>
|
166
166
|
<% end %>
|
167
167
|
|
168
|
-
<% if v2 =
|
168
|
+
<% if (v2 = @smart_values.dig(k, v&.to_s)) %>
|
169
169
|
<div class="text-muted"><%= v2 %></div>
|
170
170
|
<% end %>
|
171
171
|
</td>
|
@@ -13,7 +13,7 @@
|
|
13
13
|
<thead>
|
14
14
|
<tr>
|
15
15
|
<th colspan="2">
|
16
|
-
<% if table[:schema] != "public" %><%= table[:schema] %>.<% end %><%= table[:table] %>
|
16
|
+
<% if table[:schema] && table[:schema] != "public" %><%= table[:schema] %>.<% end %><%= table[:table] %>
|
17
17
|
</th>
|
18
18
|
</tr>
|
19
19
|
</thead>
|
@@ -28,7 +28,7 @@
|
|
28
28
|
</table>
|
29
29
|
<% end %>
|
30
30
|
|
31
|
-
|
31
|
+
<%= javascript_tag nonce: true do %>
|
32
32
|
$("#search").on("keyup", function() {
|
33
33
|
var value = $(this).val().toLowerCase()
|
34
34
|
$(".schema-table").filter(function() {
|
@@ -52,4 +52,4 @@
|
|
52
52
|
$(this).toggle(found)
|
53
53
|
})
|
54
54
|
}).focus()
|
55
|
-
|
55
|
+
<% end %>
|
@@ -46,7 +46,7 @@
|
|
46
46
|
<p class="text-muted">Loading...</p>
|
47
47
|
</div>
|
48
48
|
|
49
|
-
|
49
|
+
<%= javascript_tag nonce: true do %>
|
50
50
|
function showRun(data) {
|
51
51
|
$("#results").html(data)
|
52
52
|
$("#results table").stupidtable(stupidtableCustomSettings).stickyTableHeaders({fixedOffset: 60})
|
@@ -59,14 +59,14 @@
|
|
59
59
|
<%= blazer_js_var "data", @run_data %>
|
60
60
|
|
61
61
|
runQuery(data, showRun, showError)
|
62
|
-
|
62
|
+
<% end %>
|
63
63
|
<% end %>
|
64
64
|
|
65
|
-
|
65
|
+
<%= javascript_tag nonce: true do %>
|
66
66
|
// do not highlight really long queries
|
67
67
|
// this can lead to performance issues
|
68
68
|
var code = $("#code code")
|
69
69
|
if (code.text().length < 10000) {
|
70
70
|
hljs.highlightElement(code.get(0))
|
71
71
|
}
|
72
|
-
|
72
|
+
<% end %>
|
@@ -45,11 +45,11 @@
|
|
45
45
|
</tbody>
|
46
46
|
</table>
|
47
47
|
|
48
|
-
|
48
|
+
<%= javascript_tag nonce: true do %>
|
49
49
|
$("#search").on("keyup", function() {
|
50
50
|
var value = $(this).val().toLowerCase()
|
51
51
|
$("#uploads tbody tr").filter( function() {
|
52
52
|
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
|
53
53
|
})
|
54
54
|
}).focus()
|
55
|
-
|
55
|
+
<% end %>
|
@@ -5,16 +5,16 @@
|
|
5
5
|
|
6
6
|
<meta charset="utf-8" />
|
7
7
|
<%= favicon_link_tag "blazer/favicon.png" %>
|
8
|
-
<% if defined?(Propshaft::Railtie) %>
|
8
|
+
<% if defined?(Propshaft::Railtie) && Rails.application.assets.is_a?(Propshaft::Assembly) %>
|
9
9
|
<%= stylesheet_link_tag "blazer/bootstrap-propshaft", "blazer/bootstrap", "blazer/selectize", "blazer/github", "blazer/daterangepicker", "blazer/application" %>
|
10
|
-
<%= javascript_include_tag "blazer/jquery", "blazer/rails-ujs", "blazer/stupidtable", "blazer/stupidtable-custom-settings", "blazer/jquery.stickytableheaders", "blazer/selectize", "blazer/highlight.min", "blazer/moment", "blazer/moment-timezone-with-data", "blazer/daterangepicker", "blazer/chart.umd", "blazer/chartjs-adapter-date-fns.bundle", "blazer/chartkick", "blazer/mapkick.bundle", "blazer/ace/ace", "blazer/ace/ext-language_tools", "blazer/ace/theme-twilight", "blazer/ace/mode-sql", "blazer/ace/snippets/text", "blazer/ace/snippets/sql", "blazer/Sortable", "blazer/bootstrap", "blazer/vue.global.prod", "blazer/routes", "blazer/queries", "blazer/fuzzysearch", "blazer/application" %>
|
10
|
+
<%= javascript_include_tag "blazer/jquery", "blazer/rails-ujs", "blazer/stupidtable", "blazer/stupidtable-custom-settings", "blazer/jquery.stickytableheaders", "blazer/selectize", "blazer/highlight.min", "blazer/moment", "blazer/moment-timezone-with-data", "blazer/daterangepicker", "blazer/chart.umd", "blazer/chartjs-adapter-date-fns.bundle", "blazer/chartkick", "blazer/mapkick.bundle", "blazer/ace/ace", "blazer/ace/ext-language_tools", "blazer/ace/theme-twilight", "blazer/ace/mode-sql", "blazer/ace/snippets/text", "blazer/ace/snippets/sql", "blazer/Sortable", "blazer/bootstrap", "blazer/vue.global.prod", "blazer/routes", "blazer/queries", "blazer/fuzzysearch", "blazer/application", nonce: true %>
|
11
11
|
<% else %>
|
12
12
|
<%= stylesheet_link_tag "blazer/application" %>
|
13
|
-
<%= javascript_include_tag "blazer/application" %>
|
13
|
+
<%= javascript_include_tag "blazer/application", nonce: true %>
|
14
14
|
<% end %>
|
15
|
-
|
15
|
+
<%= javascript_tag nonce: true do %>
|
16
16
|
<%= blazer_js_var "rootPath", root_path %>
|
17
|
-
|
17
|
+
<% end %>
|
18
18
|
<%= csrf_meta_tags %>
|
19
19
|
</head>
|
20
20
|
<body>
|
@@ -7,14 +7,20 @@ module Blazer
|
|
7
7
|
error = nil
|
8
8
|
|
9
9
|
begin
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
if bolt?
|
11
|
+
result = session.run("#{statement} /*#{comment}*/", bind_params).to_a
|
12
|
+
columns = result.any? ? result.first.keys.map(&:to_s) : []
|
13
|
+
rows = result.map(&:values)
|
14
|
+
else
|
15
|
+
result = session.query("#{statement} /*#{comment}*/", bind_params)
|
16
|
+
columns = result.columns.map(&:to_s)
|
17
|
+
rows = []
|
18
|
+
result.each do |row|
|
19
|
+
rows << columns.map do |c|
|
20
|
+
v = row.send(c)
|
21
|
+
v = v.properties if v.respond_to?(:properties)
|
22
|
+
v
|
23
|
+
end
|
18
24
|
end
|
19
25
|
end
|
20
26
|
rescue => e
|
@@ -26,8 +32,13 @@ module Blazer
|
|
26
32
|
end
|
27
33
|
|
28
34
|
def tables
|
29
|
-
|
30
|
-
|
35
|
+
if bolt?
|
36
|
+
result = session.run("CALL db.labels()").to_a
|
37
|
+
result.map { |r| r.values.first }
|
38
|
+
else
|
39
|
+
result = session.query("CALL db.labels()")
|
40
|
+
result.rows.map(&:first)
|
41
|
+
end
|
31
42
|
end
|
32
43
|
|
33
44
|
def preview_statement
|
@@ -52,10 +63,27 @@ module Blazer
|
|
52
63
|
|
53
64
|
def session
|
54
65
|
@session ||= begin
|
55
|
-
|
56
|
-
|
57
|
-
|
66
|
+
if bolt?
|
67
|
+
uri = URI.parse(settings["url"])
|
68
|
+
auth = Neo4j::Driver::AuthTokens.basic(uri.user, uri.password)
|
69
|
+
database = uri.path.delete_prefix("/")
|
70
|
+
uri.user = nil
|
71
|
+
uri.password = nil
|
72
|
+
uri.path = ""
|
73
|
+
Neo4j::Driver::GraphDatabase.driver(uri, auth).session(database: database)
|
74
|
+
else
|
75
|
+
require "neo4j/core/cypher_session/adaptors/http"
|
76
|
+
http_adaptor = Neo4j::Core::CypherSession::Adaptors::HTTP.new(settings["url"])
|
77
|
+
Neo4j::Core::CypherSession.new(http_adaptor)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def bolt?
|
83
|
+
if !defined?(@bolt)
|
84
|
+
@bolt = settings["url"].start_with?("bolt")
|
58
85
|
end
|
86
|
+
@bolt
|
59
87
|
end
|
60
88
|
end
|
61
89
|
end
|
@@ -39,10 +39,11 @@ module Blazer
|
|
39
39
|
def client
|
40
40
|
@client ||= begin
|
41
41
|
uri = URI.parse(settings["url"])
|
42
|
-
query = uri.query ? CGI
|
43
|
-
Presto::Client
|
42
|
+
query = uri.query ? CGI.parse(uri.query) : {}
|
43
|
+
cls = uri.scheme == "trino" ? Trino::Client : Presto::Client
|
44
|
+
cls.new(
|
44
45
|
server: "#{uri.host}:#{uri.port}",
|
45
|
-
catalog: uri.path.to_s.
|
46
|
+
catalog: uri.path.to_s.delete_prefix("/"),
|
46
47
|
schema: query["schema"] || "public",
|
47
48
|
user: uri.user,
|
48
49
|
http_debug: false
|
@@ -21,16 +21,42 @@ module Blazer
|
|
21
21
|
error = nil
|
22
22
|
|
23
23
|
begin
|
24
|
-
|
24
|
+
types = []
|
25
|
+
in_transaction do |connection|
|
25
26
|
set_timeout(data_source.timeout) if data_source.timeout
|
26
|
-
|
27
27
|
binds = bind_params.map { |v| ActiveRecord::Relation::QueryAttribute.new(nil, v, ActiveRecord::Type::Value.new) }
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
if sqlite?
|
29
|
+
type_map = connection.send(:type_map)
|
30
|
+
connection.raw_connection.prepare("#{statement} /*#{comment}*/") do |stmt|
|
31
|
+
stmt.bind_params(connection.send(:type_casted_binds, binds))
|
32
|
+
columns = stmt.columns
|
33
|
+
rows = stmt.to_a
|
34
|
+
types = stmt.types.map { |t| type_map.lookup(t) }
|
35
|
+
end
|
36
|
+
else
|
37
|
+
result = connection.select_all("#{statement} /*#{comment}*/", nil, binds)
|
38
|
+
columns = result.columns
|
39
|
+
rows = result.rows
|
40
|
+
if result.column_types.any?
|
41
|
+
types = columns.size.times.map { |i| result.column_types[i] }
|
42
|
+
end
|
32
43
|
end
|
33
44
|
end
|
45
|
+
|
46
|
+
# cast values
|
47
|
+
if types.any?
|
48
|
+
rows =
|
49
|
+
rows.map do |row|
|
50
|
+
row.map.with_index do |v, i|
|
51
|
+
v && (t = types[i]) ? t.send(:cast_value, v) : v
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# fix for non-ASCII column names and charts
|
57
|
+
if adapter_name == "Trilogy"
|
58
|
+
columns = columns.map { |k| k.dup.force_encoding(Encoding::UTF_8) }
|
59
|
+
end
|
34
60
|
rescue => e
|
35
61
|
error = e.message.sub(/.+ERROR: /, "")
|
36
62
|
error = Blazer::TIMEOUT_MESSAGE if Blazer::TIMEOUT_ERRORS.any? { |e| error.include?(e) }
|
@@ -45,7 +71,12 @@ module Blazer
|
|
45
71
|
end
|
46
72
|
|
47
73
|
def tables
|
48
|
-
sql =
|
74
|
+
sql =
|
75
|
+
if sqlite?
|
76
|
+
"SELECT NULL, name FROM sqlite_master WHERE type IN ('table', 'view') ORDER BY name"
|
77
|
+
else
|
78
|
+
add_schemas("SELECT table_schema, table_name FROM information_schema.tables")
|
79
|
+
end
|
49
80
|
result = data_source.run_statement(sql, refresh_cache: true)
|
50
81
|
if postgresql? || redshift? || snowflake?
|
51
82
|
result.rows.sort_by { |r| [r[0] == default_schema ? "" : r[0], r[1]] }.map do |row|
|
@@ -69,7 +100,12 @@ module Blazer
|
|
69
100
|
end
|
70
101
|
|
71
102
|
def schema
|
72
|
-
sql =
|
103
|
+
sql =
|
104
|
+
if sqlite?
|
105
|
+
"SELECT NULL, t.name, c.name, c.type, c.cid FROM sqlite_master t INNER JOIN pragma_table_info(t.name) c WHERE t.type IN ('table', 'view')"
|
106
|
+
else
|
107
|
+
add_schemas("SELECT table_schema, table_name, column_name, data_type, ordinal_position FROM information_schema.columns")
|
108
|
+
end
|
73
109
|
result = data_source.run_statement(sql)
|
74
110
|
result.rows.group_by { |r| [r[0], r[1]] }.map { |k, vs| {schema: k[0], table: k[1], columns: vs.sort_by { |v| v[2] }.map { |v| {name: v[2], data_type: v[3]} }} }.sort_by { |t| [t[:schema] == default_schema ? "" : t[:schema], t[:table]] }
|
75
111
|
end
|
@@ -135,7 +171,7 @@ module Blazer
|
|
135
171
|
def cohort_analysis_statement(statement, period:, days:)
|
136
172
|
raise "Cohort analysis not supported" unless supports_cohort_analysis?
|
137
173
|
|
138
|
-
cohort_column = statement
|
174
|
+
cohort_column = statement.match?(/\bcohort_time\b/) ? "cohort_time" : "conversion_time"
|
139
175
|
tzname = Blazer.time_zone.tzinfo.name
|
140
176
|
|
141
177
|
if mysql?
|
@@ -194,10 +230,10 @@ module Blazer
|
|
194
230
|
|
195
231
|
# Redshift adapter silently ignores binds
|
196
232
|
def parameter_binding
|
197
|
-
if postgresql?
|
198
|
-
# Active Record < 6.1 silently ignores binds with Postgres when prepared statements are disabled
|
233
|
+
if postgresql?
|
199
234
|
:numeric
|
200
|
-
elsif sqlite?
|
235
|
+
elsif sqlite? && prepared_statements?
|
236
|
+
# Active Record silently ignores binds with SQLite when prepared statements are disabled
|
201
237
|
:numeric
|
202
238
|
elsif mysql? && prepared_statements?
|
203
239
|
# Active Record silently ignores binds with MySQL when prepared statements are disabled
|
@@ -259,6 +295,8 @@ module Blazer
|
|
259
295
|
"public"
|
260
296
|
elsif sqlserver?
|
261
297
|
"dbo"
|
298
|
+
elsif sqlite?
|
299
|
+
nil
|
262
300
|
elsif connection_model.respond_to?(:connection_db_config)
|
263
301
|
connection_model.connection_db_config.database
|
264
302
|
else
|
@@ -287,8 +325,7 @@ module Blazer
|
|
287
325
|
if postgresql? || redshift?
|
288
326
|
execute("SET #{use_transaction? ? "LOCAL " : ""}statement_timeout = #{timeout.to_i * 1000}")
|
289
327
|
elsif mysql?
|
290
|
-
|
291
|
-
mariadb = connection_model.connection.send(:mariadb?) rescue false
|
328
|
+
mariadb = connection_model.connection.mariadb? rescue false
|
292
329
|
if mariadb
|
293
330
|
execute("SET max_statement_time = #{timeout.to_i * 1000}")
|
294
331
|
else
|
@@ -304,14 +341,14 @@ module Blazer
|
|
304
341
|
end
|
305
342
|
|
306
343
|
def in_transaction
|
307
|
-
connection_model.connection_pool.with_connection do
|
344
|
+
connection_model.connection_pool.with_connection do |connection|
|
308
345
|
if use_transaction?
|
309
346
|
connection_model.transaction do
|
310
|
-
yield
|
347
|
+
yield connection
|
311
348
|
raise ActiveRecord::Rollback
|
312
349
|
end
|
313
350
|
else
|
314
|
-
yield
|
351
|
+
yield connection
|
315
352
|
end
|
316
353
|
end
|
317
354
|
end
|
data/lib/blazer/adapters.rb
CHANGED
@@ -15,3 +15,4 @@ Blazer.register_adapter "soda", Blazer::Adapters::SodaAdapter
|
|
15
15
|
Blazer.register_adapter "spark", Blazer::Adapters::SparkAdapter
|
16
16
|
Blazer.register_adapter "sql", Blazer::Adapters::SqlAdapter
|
17
17
|
Blazer.register_adapter "snowflake", Blazer::Adapters::SnowflakeAdapter
|
18
|
+
Blazer.register_adapter "trino", Blazer::Adapters::PrestoAdapter
|
data/lib/blazer/data_source.rb
CHANGED
@@ -107,7 +107,7 @@ module Blazer
|
|
107
107
|
end
|
108
108
|
|
109
109
|
unless result
|
110
|
-
comment = "blazer"
|
110
|
+
comment = "blazer".dup
|
111
111
|
if options[:user].respond_to?(:id)
|
112
112
|
comment << ",user_id:#{options[:user].id}"
|
113
113
|
end
|
@@ -256,7 +256,7 @@ module Blazer
|
|
256
256
|
def detect_adapter
|
257
257
|
scheme = settings["url"].to_s.split("://").first
|
258
258
|
case scheme
|
259
|
-
when "presto", "cassandra", "ignite"
|
259
|
+
when "presto", "trino", "cassandra", "ignite"
|
260
260
|
scheme
|
261
261
|
else
|
262
262
|
"sql"
|
data/lib/blazer/engine.rb
CHANGED
@@ -3,22 +3,24 @@ module Blazer
|
|
3
3
|
isolate_namespace Blazer
|
4
4
|
|
5
5
|
initializer "blazer" do |app|
|
6
|
-
if
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
6
|
+
if app.config.respond_to?(:assets) && defined?(Sprockets)
|
7
|
+
if Sprockets::VERSION.to_i >= 4
|
8
|
+
app.config.assets.precompile += [
|
9
|
+
"blazer/application.js",
|
10
|
+
"blazer/application.css",
|
11
|
+
"blazer/glyphicons-halflings-regular.eot",
|
12
|
+
"blazer/glyphicons-halflings-regular.svg",
|
13
|
+
"blazer/glyphicons-halflings-regular.ttf",
|
14
|
+
"blazer/glyphicons-halflings-regular.woff",
|
15
|
+
"blazer/glyphicons-halflings-regular.woff2",
|
16
|
+
"blazer/favicon.png"
|
17
|
+
]
|
18
|
+
else
|
19
|
+
# use a proc instead of a string
|
20
|
+
app.config.assets.precompile << proc { |path| path =~ /\Ablazer\/application\.(js|css)\z/ }
|
21
|
+
app.config.assets.precompile << proc { |path| path =~ /\Ablazer\/.+\.(eot|svg|ttf|woff|woff2)\z/ }
|
22
|
+
app.config.assets.precompile << proc { |path| path == "blazer/favicon.png" }
|
23
|
+
end
|
22
24
|
end
|
23
25
|
|
24
26
|
Blazer.time_zone ||= Blazer.settings["time_zone"] || Time.zone
|
data/lib/blazer/result.rb
CHANGED
@@ -5,7 +5,7 @@ module Blazer
|
|
5
5
|
|
6
6
|
def initialize(data_source, columns, rows, error, cached_at, just_cached)
|
7
7
|
@data_source = data_source
|
8
|
-
@columns = columns
|
8
|
+
@columns = columns.dup
|
9
9
|
@rows = rows
|
10
10
|
@error = error
|
11
11
|
@cached_at = cached_at
|
@@ -131,7 +131,7 @@ module Blazer
|
|
131
131
|
|
132
132
|
if chart_type == "line"
|
133
133
|
columns[1..-1].each_with_index.each do |k, i|
|
134
|
-
series << {name: k, data: rows.map{ |r| [r[0], r[i + 1]] }}
|
134
|
+
series << {name: k, data: rows.map { |r| [r[0], r[i + 1]] }}
|
135
135
|
end
|
136
136
|
else
|
137
137
|
rows.group_by { |r| v = r[1]; (smart_values[columns[1]] || {})[v.to_s] || v }.each_with_index.map do |(name, v), i|
|
data/lib/blazer/run_statement.rb
CHANGED
@@ -13,7 +13,8 @@ module Blazer
|
|
13
13
|
audit = Blazer::Audit.new(statement: audit_statement)
|
14
14
|
audit.query = query
|
15
15
|
audit.data_source = data_source.id
|
16
|
-
|
16
|
+
# only set user if present to avoid error with Rails 7.1 when no user model
|
17
|
+
audit.user = options[:user] unless options[:user].nil?
|
17
18
|
audit.save!
|
18
19
|
end
|
19
20
|
|
data/lib/blazer/statement.rb
CHANGED
@@ -33,9 +33,12 @@ module Blazer
|
|
33
33
|
end
|
34
34
|
|
35
35
|
unless value.is_a?(ActiveSupport::TimeWithZone)
|
36
|
-
if value
|
37
|
-
|
38
|
-
|
36
|
+
if value.match?(/\A\d+\z/)
|
37
|
+
# check no leading zeros (when not zero)
|
38
|
+
if value == value.to_i.to_s
|
39
|
+
value = value.to_i
|
40
|
+
end
|
41
|
+
elsif value.match?(/\A\d+\.\d+\z/)
|
39
42
|
value = value.to_f
|
40
43
|
end
|
41
44
|
end
|
data/lib/blazer/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blazer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-04-13 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: railties
|
@@ -16,28 +15,28 @@ dependencies:
|
|
16
15
|
requirements:
|
17
16
|
- - ">="
|
18
17
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
18
|
+
version: '7.1'
|
20
19
|
type: :runtime
|
21
20
|
prerelease: false
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
23
22
|
requirements:
|
24
23
|
- - ">="
|
25
24
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
25
|
+
version: '7.1'
|
27
26
|
- !ruby/object:Gem::Dependency
|
28
27
|
name: activerecord
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
30
29
|
requirements:
|
31
30
|
- - ">="
|
32
31
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
32
|
+
version: '7.1'
|
34
33
|
type: :runtime
|
35
34
|
prerelease: false
|
36
35
|
version_requirements: !ruby/object:Gem::Requirement
|
37
36
|
requirements:
|
38
37
|
- - ">="
|
39
38
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
39
|
+
version: '7.1'
|
41
40
|
- !ruby/object:Gem::Dependency
|
42
41
|
name: chartkick
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,7 +65,20 @@ dependencies:
|
|
66
65
|
- - ">="
|
67
66
|
- !ruby/object:Gem::Version
|
68
67
|
version: '0.4'
|
69
|
-
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: csv
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
type: :runtime
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
70
82
|
email: andrew@ankane.org
|
71
83
|
executables: []
|
72
84
|
extensions: []
|
@@ -222,7 +234,6 @@ homepage: https://github.com/ankane/blazer
|
|
222
234
|
licenses:
|
223
235
|
- MIT
|
224
236
|
metadata: {}
|
225
|
-
post_install_message:
|
226
237
|
rdoc_options: []
|
227
238
|
require_paths:
|
228
239
|
- lib
|
@@ -230,15 +241,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
230
241
|
requirements:
|
231
242
|
- - ">="
|
232
243
|
- !ruby/object:Gem::Version
|
233
|
-
version: '3'
|
244
|
+
version: '3.2'
|
234
245
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
235
246
|
requirements:
|
236
247
|
- - ">="
|
237
248
|
- !ruby/object:Gem::Version
|
238
249
|
version: '0'
|
239
250
|
requirements: []
|
240
|
-
rubygems_version: 3.
|
241
|
-
signing_key:
|
251
|
+
rubygems_version: 3.6.2
|
242
252
|
specification_version: 4
|
243
253
|
summary: Explore your data with SQL. Easily create charts and dashboards, and share
|
244
254
|
them with your team.
|