blazer 3.0.3 → 3.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ecc87353b5a9b96402e82c59b497929b5544f320d6c9f82316b92d005c18f74d
4
- data.tar.gz: 19b1a0697e3901e25c8b77f2ce769d427849c97f8012240fdce26a74f069c03d
3
+ metadata.gz: 160f3a7275160ebbeb9446cfacbe2c24d7882820f3548e10239cfdf383b3af87
4
+ data.tar.gz: 809bb498a6c00217e10239f87352c3051b3bb95d956910aa8f39a610e6adf58d
5
5
  SHA512:
6
- metadata.gz: c090577a5e80ac9ae9a870e096d1317b78cd7815fb6f9e65a1e59bb41fb779d2cbac6f37ec3cb3854351069d57b52b5937fa7cb1e0a85d73919ee59229501d8a
7
- data.tar.gz: 1590b68605c634a98a3ee4794eae49c5b19b9d683ff453871117983684e70c3b0c3222298e63a312719b9a676aa3d364a56dcc1664c10c2146800736103e4638
6
+ metadata.gz: 81ad8488e41e590d3deba688200ec253f3d1f42c00794ce4c6819aa9c9e765d54b692f1172116a30d098877d80a2c07c38814adef07650ac6d56c1bd605d79cc
7
+ data.tar.gz: 88917858d1aea93202f411f5becd420e49d71b6619fd91cd5580760fbb0a5a8c9bdc8eb0fc604264effd9334ca78d9d111d3bd42067d1b7e1eb5bc8e35562e4e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 3.0.4 (2024-09-04)
2
+
3
+ - Improved CSP support
4
+ - Fixed error with Trilogy and Rails 7.2
5
+
1
6
  ## 3.0.3 (2024-01-10)
2
7
 
3
8
  - Fixed error with Trilogy, non-ASCII column names, and charts
data/README.md CHANGED
@@ -1026,51 +1026,6 @@ override_csp: true
1026
1026
 
1027
1027
  Maps now use Mapbox GL JS v1 instead of Mapbox.js, which affects Mapbox billing.
1028
1028
 
1029
- ### 2.6
1030
-
1031
- Custom adapters now need to specify how to quote variables in queries (there is no longer a default)
1032
-
1033
- ```ruby
1034
- class FooAdapter < Blazer::Adapters::BaseAdapter
1035
- def quoting
1036
- :backslash_escape # single quote strings and convert ' to \' and \ to \\
1037
- # or
1038
- :single_quote_escape # single quote strings and convert ' to ''
1039
- # or
1040
- ->(value) { ... } # custom method
1041
- end
1042
- end
1043
- ```
1044
-
1045
- ### 2.3
1046
-
1047
- To archive queries, create a migration
1048
-
1049
- ```sh
1050
- rails g migration add_status_to_blazer_queries
1051
- ```
1052
-
1053
- with:
1054
-
1055
- ```ruby
1056
- add_column :blazer_queries, :status, :string
1057
- Blazer::Query.update_all(status: "active")
1058
- ```
1059
-
1060
- ### 2.0
1061
-
1062
- To use Slack notifications, create a migration
1063
-
1064
- ```sh
1065
- rails g migration add_slack_channels_to_blazer_checks
1066
- ```
1067
-
1068
- with:
1069
-
1070
- ```ruby
1071
- add_column :blazer_checks, :slack_channels, :text
1072
- ```
1073
-
1074
1029
  ## History
1075
1030
 
1076
1031
  View the [changelog](https://github.com/ankane/blazer/blob/master/CHANGELOG.md)
@@ -71,9 +71,9 @@ module Blazer
71
71
  if smart_var_data_source
72
72
  query = smart_var_data_source.smart_variables[var]
73
73
 
74
- if query.is_a? Hash
75
- smart_var = query.map { |k,v| [v, k] }
76
- elsif query.is_a? Array
74
+ if query.is_a?(Hash)
75
+ smart_var = query.map { |k, v| [v, k] }
76
+ elsif query.is_a?(Array)
77
77
  smart_var = query.map { |v| [v, v] }
78
78
  elsif query
79
79
  result = smart_var_data_source.run_statement(query)
@@ -1,6 +1,6 @@
1
1
  <% if @bind_vars.any? %>
2
2
  <% var_params = request.query_parameters %>
3
- <script>
3
+ <%= javascript_tag nonce: true do %>
4
4
  <%= blazer_js_var "timeZone", Blazer.time_zone.tzinfo.name %>
5
5
  var now = moment.tz(timeZone)
6
6
  var format = "YYYY-MM-DD"
@@ -8,7 +8,7 @@
8
8
  function toDate(time) {
9
9
  return moment.tz(time.format(format), timeZone)
10
10
  }
11
- </script>
11
+ <% end %>
12
12
  <form id="bind" method="get" action="<%= action %>" class="form-inline" style="margin-bottom: 15px;">
13
13
  <% date_vars = ["start_time", "end_time"] %>
14
14
  <% if (date_vars - @bind_vars).empty? %>
@@ -21,11 +21,11 @@
21
21
  <%= label_tag var, var %>
22
22
  <% if (data = @smart_vars[var]) %>
23
23
  <%= select_tag var, options_for_select([[nil, nil]] + data, selected: var_params[var]), style: "margin-right: 20px; width: 200px; display: none;" %>
24
- <script>
24
+ <%= javascript_tag nonce: true do %>
25
25
  $("#<%= var %>").selectize({
26
26
  create: true
27
27
  });
28
- </script>
28
+ <% end %>
29
29
  <% elsif var.end_with?("_at") || var == "start_time" || var == "end_time" %>
30
30
  <%= hidden_field_tag var, var_params[var] %>
31
31
 
@@ -35,7 +35,7 @@
35
35
  </div>
36
36
  </div>
37
37
 
38
- <script>
38
+ <%= javascript_tag nonce: true do %>
39
39
  (function() {
40
40
  var input = $("#<%= var %>")
41
41
  var datePicker = $("#<%= var %>-select")
@@ -57,7 +57,7 @@
57
57
  datePicker.find("span").html(toDate(picker.startDate).format("MMMM D, YYYY"))
58
58
  }
59
59
  })()
60
- </script>
60
+ <% end %>
61
61
  <% else %>
62
62
  <%= text_field_tag var, var_params[var], style: "width: 120px; margin-right: 20px;", autofocus: i == 0 && !var.end_with?("_at") && !var_params[var], class: "form-control" %>
63
63
  <% end %>
@@ -75,7 +75,7 @@
75
75
  </div>
76
76
  </div>
77
77
 
78
- <script>
78
+ <%= javascript_tag nonce: true do %>
79
79
  function dateStr(daysAgo) {
80
80
  return now.clone().subtract(daysAgo || 0, "days").format(format)
81
81
  }
@@ -119,7 +119,7 @@
119
119
  $("#reportrange").trigger("apply.daterangepicker", picker)
120
120
  submitIfCompleted($("#start_time").closest("form"))
121
121
  }
122
- </script>
122
+ <% end %>
123
123
  <% end %>
124
124
 
125
125
  <input type="submit" class="btn btn-success" value="Run" style="vertical-align: top;" />
@@ -12,12 +12,12 @@
12
12
  <div class="hide">
13
13
  <%= f.select :query_id, [], {include_blank: true} %>
14
14
  </div>
15
- <script>
15
+ <%= javascript_tag nonce: true do %>
16
16
  <%= blazer_js_var "queries", Blazer::Query.active.named.order(:name).select("id, name").map { |q| {text: q.name, value: q.id} } %>
17
17
  <%= blazer_js_var "items", [@check.query_id].compact %>
18
18
 
19
19
  $("#check_query_id").selectize({options: queries, items: items, highlight: false, maxOptions: 100}).parents(".hide").removeClass("hide");
20
- </script>
20
+ <% end %>
21
21
  </div>
22
22
 
23
23
  <% if @check.respond_to?(:check_type) %>
@@ -28,9 +28,9 @@
28
28
  <% check_options << ["Anomaly (most recent data point)", "anomaly"] if Blazer.anomaly_checks %>
29
29
  <%= f.select :check_type, check_options %>
30
30
  </div>
31
- <script>
31
+ <%= javascript_tag nonce: true do %>
32
32
  $("#check_check_type").selectize({}).parent().removeClass("hide");
33
- </script>
33
+ <% end %>
34
34
  </div>
35
35
  <% elsif @check.respond_to?(:invert) %>
36
36
  <div class="form-group">
@@ -38,9 +38,9 @@
38
38
  <div class="hide">
39
39
  <%= f.select :invert, [["Any results (bad data)", false], ["No results (missing data)", true]] %>
40
40
  </div>
41
- <script>
41
+ <%= javascript_tag nonce: true do %>
42
42
  $("#check_invert").selectize({}).parent().removeClass("hide");
43
- </script>
43
+ <% end %>
44
44
  </div>
45
45
  <% end %>
46
46
 
@@ -50,9 +50,9 @@
50
50
  <div class="hide">
51
51
  <%= f.select :schedule, Blazer.check_schedules.map { |v| [v, v] } %>
52
52
  </div>
53
- <script>
53
+ <%= javascript_tag nonce: true do %>
54
54
  $("#check_schedule").selectize({}).parent().removeClass("hide");
55
- </script>
55
+ <% end %>
56
56
  </div>
57
57
  <% end %>
58
58
 
@@ -62,11 +62,11 @@
62
62
  </tbody>
63
63
  </table>
64
64
 
65
- <script>
65
+ <%= javascript_tag nonce: true do %>
66
66
  $("#search").on("keyup", function() {
67
67
  var value = $(this).val().toLowerCase()
68
68
  $("#checks tbody tr").filter( function() {
69
69
  $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
70
70
  })
71
71
  }).focus()
72
- </script>
72
+ <% end %>
@@ -30,7 +30,7 @@
30
30
  </p>
31
31
  <% end %>
32
32
 
33
- <script>
33
+ <%= javascript_tag nonce: true do %>
34
34
  <%= blazer_js_var "queries", Blazer::Query.active.named.order(:name).select("id, name").map { |q| {text: q.name, value: q.id} } %>
35
35
  <%= blazer_js_var "dashboardQueries", @queries || @dashboard.dashboard_queries.order(:position).map(&:query) %>
36
36
 
@@ -79,4 +79,4 @@
79
79
  app.queries.splice(e.newIndex, 0, app.queries.splice(e.oldIndex, 1)[0])
80
80
  }
81
81
  })
82
- </script>
82
+ <% end %>
@@ -38,7 +38,7 @@
38
38
  <p class="text-muted">Loading...</p>
39
39
  </div>
40
40
  </div>
41
- <script>
41
+ <%= javascript_tag nonce: true do %>
42
42
  <% data = {statement: query.statement, query_id: query.id, data_source: query.data_source, variables: variable_params(query), only_chart: true} %>
43
43
  <% data.merge!(cohort_period: params[:cohort_period]) if params[:cohort_period] %>
44
44
  <%= blazer_js_var "data", data %>
@@ -49,5 +49,5 @@
49
49
  }, function (message) {
50
50
  $("#chart-<%= i %>").addClass("query-error").html(message)
51
51
  });
52
- </script>
52
+ <% end %>
53
53
  <% end %>
@@ -68,7 +68,7 @@
68
68
  </div>
69
69
  </div>
70
70
 
71
- <script>
71
+ <%= javascript_tag nonce: true do %>
72
72
  <%= blazer_js_var "variableParams", @variable_params %>
73
73
  <%= blazer_js_var "previewStatement", Blazer.data_sources.to_h { |k, v| [k, (v.preview_statement rescue "")] } %>
74
74
 
@@ -252,4 +252,4 @@
252
252
  })
253
253
  app.config.compilerOptions.whitespace = "preserve"
254
254
  app.mount("#app")
255
- </script>
255
+ <% end %>
@@ -56,7 +56,7 @@
56
56
  <p v-if="more" class="text-muted">Loading...</p>
57
57
  </div>
58
58
 
59
- <script>
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
- </script>
169
+ <% 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
- <script>
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
- </script>
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
- <script>
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
- </script>
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 %>
@@ -28,7 +28,7 @@
28
28
  </table>
29
29
  <% end %>
30
30
 
31
- <script>
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
- </script>
55
+ <% end %>
@@ -46,7 +46,7 @@
46
46
  <p class="text-muted">Loading...</p>
47
47
  </div>
48
48
 
49
- <script>
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
- </script>
62
+ <% end %>
63
63
  <% end %>
64
64
 
65
- <script>
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
- </script>
72
+ <% end %>
@@ -45,11 +45,11 @@
45
45
  </tbody>
46
46
  </table>
47
47
 
48
- <script>
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
- </script>
55
+ <% end %>
@@ -7,14 +7,14 @@
7
7
  <%= favicon_link_tag "blazer/favicon.png" %>
8
8
  <% if defined?(Propshaft::Railtie) %>
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
- <script>
15
+ <%= javascript_tag nonce: true do %>
16
16
  <%= blazer_js_var "rootPath", root_path %>
17
- </script>
17
+ <% end %>
18
18
  <%= csrf_meta_tags %>
19
19
  </head>
20
20
  <body>
@@ -33,7 +33,7 @@ module Blazer
33
33
  # use token so we fetch cached results after query is run
34
34
  client_request_token: request_token,
35
35
  query_execution_context: {
36
- database: database,
36
+ database: database
37
37
  }
38
38
  }
39
39
 
@@ -45,7 +45,7 @@ module Blazer
45
45
  port: uri.port,
46
46
  username: uri.user,
47
47
  password: uri.password,
48
- database: uri.path.sub(/\A\//, ""),
48
+ database: uri.path.delete_prefix("/"),
49
49
  mode: uri.scheme.to_sym
50
50
  )
51
51
  end
@@ -39,10 +39,10 @@ module Blazer
39
39
  def client
40
40
  @client ||= begin
41
41
  uri = URI.parse(settings["url"])
42
- query = uri.query ? CGI::parse(uri.query) : {}
42
+ query = uri.query ? CGI.parse(uri.query) : {}
43
43
  Presto::Client.new(
44
44
  server: "#{uri.host}:#{uri.port}",
45
- catalog: uri.path.to_s.sub(/\A\//, ""),
45
+ catalog: uri.path.to_s.delete_prefix("/"),
46
46
  schema: query["schema"] || "public",
47
47
  user: uri.user,
48
48
  http_debug: false
@@ -29,13 +29,22 @@ module Blazer
29
29
  end
30
30
 
31
31
  columns = result.columns
32
- result.rows.each do |untyped_row|
33
- 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] })
32
+ rows = result.rows
33
+
34
+ # cast values
35
+ if result.column_types.any?
36
+ types = columns.map { |c| result.column_types[c] }
37
+ rows =
38
+ rows.map do |row|
39
+ row.map.with_index do |v, i|
40
+ v && (t = types[i]) ? t.send(:cast_value, v) : v
41
+ end
42
+ end
34
43
  end
35
44
 
36
45
  # fix for non-ASCII column names and charts
37
46
  if adapter_name == "Trilogy"
38
- columns.map! { |k| k.dup.force_encoding(Encoding::UTF_8) }
47
+ columns = columns.map { |k| k.dup.force_encoding(Encoding::UTF_8) }
39
48
  end
40
49
  rescue => e
41
50
  error = e.message.sub(/.+ERROR: /, "")
@@ -141,7 +150,7 @@ module Blazer
141
150
  def cohort_analysis_statement(statement, period:, days:)
142
151
  raise "Cohort analysis not supported" unless supports_cohort_analysis?
143
152
 
144
- cohort_column = statement =~ /\bcohort_time\b/ ? "cohort_time" : "conversion_time"
153
+ cohort_column = statement.match?(/\bcohort_time\b/) ? "cohort_time" : "conversion_time"
145
154
  tzname = Blazer.time_zone.tzinfo.name
146
155
 
147
156
  if mysql?
@@ -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
data/lib/blazer/result.rb CHANGED
@@ -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|
@@ -33,9 +33,9 @@ module Blazer
33
33
  end
34
34
 
35
35
  unless value.is_a?(ActiveSupport::TimeWithZone)
36
- if value =~ /\A\d+\z/
36
+ if value.match?(/\A\d+\z/)
37
37
  value = value.to_i
38
- elsif value =~ /\A\d+\.\d+\z/
38
+ elsif value.match?(/\A\d+\.\d+\z/)
39
39
  value = value.to_f
40
40
  end
41
41
  end
@@ -1,3 +1,3 @@
1
1
  module Blazer
2
- VERSION = "3.0.3"
2
+ VERSION = "3.0.4"
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: 3.0.3
4
+ version: 3.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-10 00:00:00.000000000 Z
11
+ date: 2024-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -251,7 +251,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
251
251
  - !ruby/object:Gem::Version
252
252
  version: '0'
253
253
  requirements: []
254
- rubygems_version: 3.5.3
254
+ rubygems_version: 3.5.11
255
255
  signing_key:
256
256
  specification_version: 4
257
257
  summary: Explore your data with SQL. Easily create charts and dashboards, and share