blazer 2.2.0 → 2.2.5

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
  SHA256:
3
- metadata.gz: dac159313b83f05cfa2b39da88d889b08e0089a75047a6aff43c24d735b86eb2
4
- data.tar.gz: e1d3594c4e957f04ffa575ce1aac36abf29586c275a2c402c2da5b9401356c57
3
+ metadata.gz: 7bc246636d4907ea33d0194ed415aaa5669013ee3e71728ef024f89ac9860feb
4
+ data.tar.gz: 3c4d7cf6b528716d80578aea44ef733e8e30c040785d585b4abf183251b87e3e
5
5
  SHA512:
6
- metadata.gz: 05a6d614fd96a40526f0ef7bb34cf6207a48e7bcdb6495f7ea925bec919c116918ad721d388e856c388d6746033fd184eadf25ca93a4afb9c541a8ab8758f8e1
7
- data.tar.gz: 79e9087b9e4015cd866fe2b382f0bb015c104af05f9c8b1c209ce2aa06713a46436e2aa307a9901bf0d31fec861463f1224b0cc610d76e2dd5c9c12aa40a8807
6
+ metadata.gz: 66e86f97070e03626320557b119666898db9ffbf812edd6b4c502384d6ad1b1e4b428d9d832be83ba0eaa004188403db2f66cc7b6a76c70dd351c1861fd8d6b5
7
+ data.tar.gz: df1eeee72f609e1c4b5a19da492803bc86737ff26d3fce9ef86490cb54b3444baecd2ceaa4dc2fa5c1773d68462e28927142f67878ee6284de97a4cb7743cf63
@@ -1,21 +1,45 @@
1
- ## 2.2.0
1
+ ## 2.2.5 (2020-06-03)
2
+
3
+ - Updated maps to fix deprecation error
4
+
5
+ ## 2.2.4 (2020-05-30)
6
+
7
+ - Fixed error with new queries
8
+
9
+ ## 2.2.3 (2020-05-30)
10
+
11
+ - Improved query parameter handling
12
+
13
+ ## 2.2.2 (2020-04-13)
14
+
15
+ - Added experimental support for the Socrata Open Data API (SODA)
16
+ - Added experimental Prophet forecasting
17
+ - Fixed query search for non-ASCII characters
18
+
19
+ ## 2.2.1 (2019-10-08)
20
+
21
+ - Added support for Sprockets 4
22
+ - Improved Snowflake table preview
23
+ - Fixed bug with refresh link not showing
24
+
25
+ ## 2.2.0 (2019-07-12)
2
26
 
3
27
  - Added schema to table preview for Postgres and Redshift
4
28
  - Fixed bug with Slack notifications not sending
5
29
  - Dropped support for Rails 4.2
6
30
 
7
- ## 2.1.0
31
+ ## 2.1.0 (2019-06-04)
8
32
 
9
33
  - Require latest Chartkick to prevent possible XSS - see [#245](https://github.com/ankane/blazer/issues/245)
10
34
 
11
- ## 2.0.2
35
+ ## 2.0.2 (2019-05-26)
12
36
 
13
37
  - Added support for variable transformation for blind indexing
14
38
  - Added experimental support for Neo4j
15
39
  - Added experimental support for Salesforce
16
40
  - Fixed JavaScript sorting for numbers with commas
17
41
 
18
- ## 2.0.1
42
+ ## 2.0.1 (2019-01-07)
19
43
 
20
44
  - Added favicon
21
45
  - Added search for checks and schema
@@ -26,7 +50,7 @@
26
50
  - Improved docs for new installs
27
51
  - Fixed error with canceling queries
28
52
 
29
- ## 2.0.0
53
+ ## 2.0.0 (2019-01-03)
30
54
 
31
55
  - Added support for Slack
32
56
  - Added `async` option
@@ -39,68 +63,67 @@ Breaking changes
39
63
 
40
64
  - Dropped support for Rails < 4.2
41
65
 
42
- ## 1.9.0
66
+ ## 1.9.0 (2018-06-17)
43
67
 
44
68
  - Prompt developers to check custom `before_action`
45
69
  - Better ordering on home page
46
70
  - Added support for Snowflake
47
71
 
48
- ## 1.8.2
72
+ ## 1.8.2 (2018-02-22)
49
73
 
50
74
  - Added support for Cassandra
51
75
  - Fixes for Druid
52
-
53
- ## 1.8.1
54
-
55
76
  - Added support for Amazon Athena
56
77
  - Added support for Druid
57
78
  - Fixed query cancellation
58
79
 
59
- ## 1.8.0
80
+ There was no 1.8.1 release.
81
+
82
+ ## 1.8.0 (2017-05-01)
60
83
 
61
84
  - Added support for Rails 5.1
62
85
 
63
- ## 1.7.10
86
+ ## 1.7.10 (2017-04-03)
64
87
 
65
88
  - Added support for Google BigQuery
66
89
  - Require `drill-sergeant` gem for Apache Drill
67
90
  - Better handling of checks with variables
68
91
 
69
- ## 1.7.9
92
+ ## 1.7.9 (2017-03-20)
70
93
 
71
94
  - Added beta support for Apache Drill
72
95
  - Added email validation for checks
73
96
  - Updated Chart.js to 2.5.0
74
97
 
75
- ## 1.7.8
98
+ ## 1.7.8 (2017-02-06)
76
99
 
77
100
  - Added support for custom adapters
78
101
  - Fixed bug with scatter charts on dashboards
79
102
  - Fixed table preview for SQL Server
80
103
  - Fixed issue when `default_url_options` set
81
104
 
82
- ## 1.7.7
105
+ ## 1.7.7 (2016-12-17)
83
106
 
84
107
  - Fixed preview error for MySQL
85
108
  - Fixed error with timeouts for MySQL
86
109
 
87
- ## 1.7.6
110
+ ## 1.7.6 (2016-12-13)
88
111
 
89
112
  - Added scatter chart
90
113
  - Fixed issue with false values showing up blank
91
114
  - Fixed preview for table names with certain characters
92
115
 
93
- ## 1.7.5
116
+ ## 1.7.5 (2016-11-22)
94
117
 
95
118
  - Fixed issue with check emails sometimes failing for default Rails 5 ActiveJob adapter
96
119
  - Fixed sorting for new dashboards
97
120
 
98
- ## 1.7.4
121
+ ## 1.7.4 (2016-11-06)
99
122
 
100
123
  - Removed extra dependencies added in 1.7.1
101
124
  - Fixed `send_failing_checks` for default Rails 5 ActiveJob adapter
102
125
 
103
- ## 1.7.3
126
+ ## 1.7.3 (2016-11-01)
104
127
 
105
128
  - Fixed JavaScript errors
106
129
  - Fixed query cancel error
@@ -108,20 +131,20 @@ Breaking changes
108
131
  - Include sample data in email when bad data checks fail
109
132
  - Fixed deprecation warnings
110
133
 
111
- ## 1.7.2
134
+ ## 1.7.2 (2016-10-30)
112
135
 
113
136
  - Cancel all queries on page nav
114
137
  - Prevent Ace from taking over find command
115
138
  - Added ability to use hashes for smart columns
116
139
  - Added ability to inherit smart variables and columns from other data sources
117
140
 
118
- ## 1.7.1
141
+ ## 1.7.1 (2016-10-29)
119
142
 
120
143
  - Do not fork when enter key pressed
121
144
  - Use custom version of Chart.js to fix label overlap
122
145
  - Improved performance of home page
123
146
 
124
- ## 1.7.0
147
+ ## 1.7.0 (2016-09-07)
125
148
 
126
149
  - Added ability to cancel queries on backend for Postgres and Redshift
127
150
  - Only run 3 queries at a time on dashboards
@@ -129,65 +152,65 @@ Breaking changes
129
152
  - Attempt to reconnect when connection issues
130
153
  - Fixed issues with caching
131
154
 
132
- ## 1.6.2
155
+ ## 1.6.2 (2016-08-11)
133
156
 
134
157
  - Added basic query permissions
135
158
  - Added ability to use arrays and hashes for smart variables
136
159
  - Added cancel button for queries
137
160
  - Added `lat` and `lng` as map keys
138
161
 
139
- ## 1.6.1
162
+ ## 1.6.1 (2016-07-30)
140
163
 
141
164
  - Added support for Presto [beta]
142
165
  - Added support for Elasticsearch timeouts
143
166
  - Fixed error in Rails 5
144
167
 
145
- ## 1.6.0
168
+ ## 1.6.0 (2016-07-28)
146
169
 
147
170
  - Added support for MongoDB [beta]
148
171
  - Added support for Elasticsearch [beta]
149
172
  - Fixed deprecation warning in Rails 5
150
173
 
151
- ## 1.5.1
174
+ ## 1.5.1 (2016-07-24)
152
175
 
153
176
  - Added anomaly detection for data less than 2 weeks
154
177
  - Added autolinking urls
155
178
  - Added support for images
156
179
 
157
- ## 1.5.0
180
+ ## 1.5.0 (2016-06-29)
158
181
 
159
182
  - Added new bar chart format
160
183
  - Added anomaly detection checks
161
184
  - Added `async` option for polling
162
185
 
163
- ## 1.4.0
186
+ ## 1.4.0 (2016-06-09)
164
187
 
165
188
  - Added `slow` cache mode
166
189
  - Fixed `BLAZER_DATABASE_URL required` error
167
190
  - Fixed issue with duplicate column names
168
191
 
169
- ## 1.3.5
192
+ ## 1.3.5 (2016-05-11)
170
193
 
171
194
  - Fixed error with checks
172
195
 
173
- ## 1.3.4
196
+ ## 1.3.4 (2016-05-11)
174
197
 
175
198
  - Fixed issue with missing queries
176
199
 
177
- ## 1.3.3
200
+ ## 1.3.3 (2016-05-08)
178
201
 
179
202
  - Fixed error with Rails 4.1 and below
180
203
 
181
- ## 1.3.2
204
+ ## 1.3.2 (2016-05-07)
182
205
 
183
206
  - Added support for Rails 5
184
207
  - Attempt to reconnect for checks
185
208
 
186
- ## 1.3.1
209
+ ## 1.3.1 (2016-05-06)
187
210
 
188
211
  - Fixed migration error
189
212
 
190
- ## 1.3.0
213
+ ## 1.3.0 (2016-05-06)
191
214
 
192
215
  - Added schedule for checks
193
216
  - Switched to Chart.js for charts
@@ -196,11 +219,11 @@ Breaking changes
196
219
  - Raise error when timeout not supported
197
220
  - Added creator to dashboards and checks
198
221
 
199
- ## 1.2.1
222
+ ## 1.2.1 (2016-04-26)
200
223
 
201
224
  - Fixed checks
202
225
 
203
- ## 1.2.0
226
+ ## 1.2.0 (2016-03-22)
204
227
 
205
228
  - Added non-editable queries
206
229
  - Added variable defaults
@@ -209,7 +232,7 @@ Breaking changes
209
232
  - Hide variables from commented out lines
210
233
  - Fixed regex as variable names
211
234
 
212
- ## 1.1.1
235
+ ## 1.1.1 (2016-03-06)
213
236
 
214
237
  - Added `before_action` option
215
238
  - Added invert option for checks
@@ -218,7 +241,7 @@ Breaking changes
218
241
  - Fixed request URI too large
219
242
  - Prevent accidental backspace nav on query page
220
243
 
221
- ## 1.1.0
244
+ ## 1.1.0 (2015-12-27)
222
245
 
223
246
  - Replaced pie charts with column charts
224
247
  - Fixed error with datepicker
@@ -226,55 +249,55 @@ Breaking changes
226
249
  - Added a notice when editing a query that is part of a dashboard
227
250
  - Added refresh for dashboards
228
251
 
229
- ## 1.0.4
252
+ ## 1.0.4 (2015-11-04)
230
253
 
231
254
  - Added recently viewed queries and dashboards to home page
232
255
  - Fixed refresh when transform statement is used
233
256
  - Fixed error when no user model
234
257
 
235
- ## 1.0.3
258
+ ## 1.0.3 (2015-10-18)
236
259
 
237
260
  - Added maps
238
261
  - Added support for Rails 4.0
239
262
 
240
- ## 1.0.2
263
+ ## 1.0.2 (2015-10-11)
241
264
 
242
265
  - Fixed error when installing
243
266
  - Added `schemas` option
244
267
 
245
- ## 1.0.1
268
+ ## 1.0.1 (2015-10-08)
246
269
 
247
270
  - Added comments to queries
248
271
  - Added `cache` option
249
272
  - Added `user_method` option
250
273
  - Added `use_transaction` option
251
274
 
252
- ## 1.0.0
275
+ ## 1.0.0 (2015-10-04)
253
276
 
254
277
  - Added support for multiple data sources
255
278
  - Added dashboards
256
279
  - Added checks
257
280
  - Added support for Redshift
258
281
 
259
- ## 0.0.8
282
+ ## 0.0.8 (2015-09-05)
260
283
 
261
284
  - Easier to edit queries with variables
262
285
  - Dynamically expand editor height as needed
263
286
  - No need for spaces in search
264
287
 
265
- ## 0.0.7
288
+ ## 0.0.7 (2015-07-23)
266
289
 
267
290
  - Fixed error when no `User` class
268
291
  - Fixed forking a query with variables
269
292
  - Set time zone after Rails initializes
270
293
 
271
- ## 0.0.6
294
+ ## 0.0.6 (2015-06-18)
272
295
 
273
296
  - Added fork button
274
297
  - Fixed trending
275
298
  - Fixed time zones for date select
276
299
 
277
- ## 0.0.5
300
+ ## 0.0.5 (2015-01-31)
278
301
 
279
302
  - Added support for Rails 4.2
280
303
  - Fixed error with `mysql2` adapter
data/README.md CHANGED
@@ -4,9 +4,9 @@ Explore your data with SQL. Easily create charts and dashboards, and share them
4
4
 
5
5
  [Try it out](https://blazer.dokkuapp.com)
6
6
 
7
- [![Screenshot](https://blazer.dokkuapp.com/assets/screenshot-6ca3115a518b488026e48be83ba0d4c9.png)](https://blazer.dokkuapp.com)
7
+ [![Screenshot](https://blazer.dokkuapp.com/assets/blazer-90fb6ce8ad25614c6f9c3b4619cbfbd66fa3d6567dac34d83df540f6688665f1.png)](https://blazer.dokkuapp.com)
8
8
 
9
- Blazer 2.0 was recently released! See [instructions for upgrading](#20).
9
+ Blazer is also available as a [Docker image](https://github.com/ankane/blazer-docker).
10
10
 
11
11
  :tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
12
12
 
@@ -426,10 +426,32 @@ If you’re on Heroku, follow [these additional instructions](#anomaly-detection
426
426
 
427
427
  ## Forecasting
428
428
 
429
- Blazer has experimental support for forecasting through [Trend](https://trendapi.org/).
429
+ Blazer has experimental support for two different forecasting methods.
430
+
431
+ A forecast link will appear for queries that return 2 columns with types timestamp and numeric.
430
432
 
431
433
  [Example](https://blazer.dokkuapp.com/queries/18-forecast?forecast=t)
432
434
 
435
+ ### Prophet
436
+
437
+ **Note:** Prophet only supports daily forecasts right now.
438
+
439
+ Add [prophet](https://github.com/ankane/prophet) to your Gemfile:
440
+
441
+ ```ruby
442
+ gem 'prophet-rb'
443
+ ```
444
+
445
+ And add to `config/blazer.yml`:
446
+
447
+ ```yml
448
+ forecasting: prophet
449
+ ```
450
+
451
+ ### Trend
452
+
453
+ [Trend](https://trendapi.org/) uses an external service.
454
+
433
455
  Add [trend](https://github.com/ankane/trend) to your Gemfile:
434
456
 
435
457
  ```ruby
@@ -442,8 +464,6 @@ And add to `config/blazer.yml`:
442
464
  forecasting: trend
443
465
  ```
444
466
 
445
- A forecast link will appear for queries that return 2 columns with types timestamp and numeric.
446
-
447
467
  ## Data Sources
448
468
 
449
469
  Blazer supports multiple data sources :tada:
@@ -475,11 +495,12 @@ data_sources:
475
495
  - [IBM DB2 and Informix](#ibm-db2-and-informix)
476
496
  - [MongoDB](#mongodb-1)
477
497
  - [MySQL](#mysql-1)
478
- - [Neo4j](#neo4j-experimental)
498
+ - [Neo4j](#neo4j)
479
499
  - [Oracle](#oracle)
480
500
  - [PostgreSQL](#postgresql-1)
481
501
  - [Presto](#presto)
482
- - [Salesforce](#salesforce-experimental)
502
+ - [Salesforce](#salesforce)
503
+ - [Socrata Open Data API (SODA)](#socrata-open-data-api-soda)
483
504
  - [Snowflake](#snowflake)
484
505
  - [SQLite](#sqlite)
485
506
  - [SQL Server](#sql-server)
@@ -539,9 +560,7 @@ data_sources:
539
560
 
540
561
  ### Druid
541
562
 
542
- First, [enable SQL support](http://druid.io/docs/latest/querying/sql.html#configuration) on the broker.
543
-
544
- Set:
563
+ Enable [SQL support](http://druid.io/docs/latest/querying/sql.html#configuration) on the broker and set:
545
564
 
546
565
  ```yml
547
566
  data_sources:
@@ -597,7 +616,9 @@ data_sources:
597
616
  url: mysql2://user:password@hostname:3306/database
598
617
  ```
599
618
 
600
- ### Neo4j [experimental]
619
+ ### Neo4j
620
+
621
+ *Experimental*
601
622
 
602
623
  Add [neo4j-core](https://github.com/neo4jrb/neo4j-core) to your Gemfile and set:
603
624
 
@@ -632,7 +653,9 @@ data_sources:
632
653
  url: presto://user@hostname:8080/catalog
633
654
  ```
634
655
 
635
- ### Salesforce [experimental]
656
+ ### Salesforce
657
+
658
+ *Experimental*
636
659
 
637
660
  Add [restforce](https://github.com/restforce/restforce) to your Gemfile and set:
638
661
 
@@ -655,15 +678,52 @@ SALESFORCE_API_VERSION="41.0"
655
678
 
656
679
  Supports [SOQL](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql.htm)
657
680
 
681
+ ### Socrata Open Data API (SODA)
682
+
683
+ *Experimental*
684
+
685
+ Set:
686
+
687
+ ```yml
688
+ data_sources:
689
+ my_source:
690
+ adapter: soda
691
+ url: https://soda.demo.socrata.com/resource/4tka-6guv.json
692
+ app_token: ...
693
+ ```
694
+
695
+ Supports [SoQL](https://dev.socrata.com/docs/functions/)
696
+
658
697
  ### Snowflake
659
698
 
660
- First, install the [ODBC driver](https://docs.snowflake.net/manuals/user-guide/odbc.html). Add [odbc_adapter](https://github.com/localytics/odbc_adapter) to your Gemfile and set:
699
+ First, install ODBC. For Homebrew, use:
700
+
701
+ ```sh
702
+ brew install unixodbc
703
+ ```
704
+
705
+ For Ubuntu, use:
706
+
707
+ ```sh
708
+ sudo apt-get install unixodbc-dev
709
+ ```
710
+
711
+ For Heroku, use the [Apt buildpack](https://github.com/heroku/heroku-buildpack-apt) and create an `Aptfile` with:
712
+
713
+ ```text
714
+ unixodbc-dev
715
+ https://sfc-repo.snowflakecomputing.com/odbc/linux/2.19.16/snowflake-odbc-2.19.16.x86_64.deb
716
+ ```
717
+
718
+ > This installs the driver at `/app/.apt/usr/lib/snowflake/odbc/lib/libSnowflake.so`
719
+
720
+ Then, download the [Snowflake ODBC driver](https://docs.snowflake.net/manuals/user-guide/odbc-download.html). Add [odbc_adapter](https://github.com/localytics/odbc_adapter) to your Gemfile and set:
661
721
 
662
722
  ```yml
663
723
  data_sources:
664
724
  my_source:
665
725
  adapter: snowflake
666
- dsn: ProductionSnowflake
726
+ conn_str: Driver=/path/to/libSnowflake.so;uid=user;pwd=password;server=host.snowflakecomputing.com
667
727
  ```
668
728
 
669
729
  ### SQLite
@@ -719,8 +779,8 @@ Blazer supports a basic permissions model.
719
779
 
720
780
  Have team members who want to learn SQL? Here are a few great, free resources.
721
781
 
722
- - [Khan Academy](https://www.khanacademy.org/computing/computer-programming/sql)
723
- - [Codecademy](https://www.codecademy.com/learn/learn-sql)
782
+ - [The Data School](https://dataschool.com/learn-sql/)
783
+ - [SQLBolt](https://sqlbolt.com/)
724
784
 
725
785
  ## Useful Tools
726
786
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  *= require ./bootstrap
3
- *= require ./selectize.default
3
+ *= require ./selectize
4
4
  *= require ./github
5
5
  *= require ./daterangepicker
6
6
  *= require_self
@@ -86,8 +86,22 @@ module Blazer
86
86
  [smart_var, error]
87
87
  end
88
88
 
89
- def variable_params
90
- params.except(:controller, :action, :id, :host, :query, :dashboard, :query_id, :query_ids, :table_names, :authenticity_token, :utf8, :_method, :commit, :statement, :data_source, :name, :fork_query_id, :blazer, :run_id).permit!
89
+ # don't pass to url helpers
90
+ #
91
+ # some are dangerous when passed as symbols
92
+ # root_url({host: "evilsite.com"})
93
+ #
94
+ # certain ones (like host) only affect *_url and not *_path
95
+ #
96
+ # when permitted parameters are passed in Rails 6,
97
+ # they appear to be added as GET parameters
98
+ # root_url(params.permit(:host))
99
+ BLACKLISTED_KEYS = [:controller, :action, :id, :host, :query, :dashboard, :query_id, :query_ids, :table_names, :authenticity_token, :utf8, :_method, :commit, :statement, :data_source, :name, :fork_query_id, :blazer, :run_id, :script_name, :original_script_name]
100
+
101
+ # remove blacklisted keys from both params and permitted keys for better sleep
102
+ def variable_params(resource)
103
+ permitted_keys = resource.variables - BLACKLISTED_KEYS.map(&:to_s)
104
+ params.except(*BLACKLISTED_KEYS).permit(*permitted_keys)
91
105
  end
92
106
  helper_method :variable_params
93
107
 
@@ -43,7 +43,7 @@ module Blazer
43
43
 
44
44
  def update
45
45
  if update_dashboard(@dashboard)
46
- redirect_to dashboard_path(@dashboard, variable_params)
46
+ redirect_to dashboard_path(@dashboard, variable_params(@dashboard))
47
47
  else
48
48
  render_errors @dashboard
49
49
  end
@@ -62,7 +62,7 @@ module Blazer
62
62
  Blazer.transform_statement.call(data_source, statement) if Blazer.transform_statement
63
63
  data_source.clear_cache(statement)
64
64
  end
65
- redirect_to dashboard_path(@dashboard, variable_params)
65
+ redirect_to dashboard_path(@dashboard, variable_params(@dashboard))
66
66
  end
67
67
 
68
68
  private
@@ -45,7 +45,7 @@ module Blazer
45
45
  @query.creator = blazer_user if @query.respond_to?(:creator)
46
46
 
47
47
  if @query.save
48
- redirect_to query_path(@query, variable_params)
48
+ redirect_to query_path(@query, variable_params(@query))
49
49
  else
50
50
  render_errors @query
51
51
  end
@@ -156,7 +156,7 @@ module Blazer
156
156
  process_vars(@statement, @query.data_source)
157
157
  Blazer.transform_statement.call(data_source, @statement) if Blazer.transform_statement
158
158
  data_source.clear_cache(@statement)
159
- redirect_to query_path(@query, variable_params)
159
+ redirect_to query_path(@query, variable_params(@query))
160
160
  end
161
161
 
162
162
  def update
@@ -168,7 +168,7 @@ module Blazer
168
168
  @query.errors.add(:base, "Sorry, permission denied")
169
169
  end
170
170
  if @query.errors.empty? && @query.update(query_params)
171
- redirect_to query_path(@query, variable_params)
171
+ redirect_to query_path(@query, variable_params(@query))
172
172
  else
173
173
  render_errors @query
174
174
  end
@@ -176,7 +176,7 @@ module Blazer
176
176
 
177
177
  def destroy
178
178
  @query.destroy if @query.editable?(blazer_user)
179
- redirect_to root_url
179
+ redirect_to root_path
180
180
  end
181
181
 
182
182
  def tables
@@ -249,7 +249,9 @@ module Blazer
249
249
  r[lat_index] && r[lon_index]
250
250
  end.map do |r|
251
251
  {
252
- title: r.each_with_index.map{ |v, i| i == lat_index || i == lon_index ? nil : "<strong>#{@columns[i]}:</strong> #{v}" }.compact.join("<br />").truncate(140),
252
+ # Mapbox.js does sanitization with https://github.com/mapbox/sanitize-caja
253
+ # but we should do it here as well
254
+ title: r.each_with_index.map { |v, i| i == lat_index || i == lon_index ? nil : "<strong>#{ERB::Util.html_escape(@columns[i])}:</strong> #{ERB::Util.html_escape(v)}" }.compact.join("<br />").truncate(140),
253
255
  latitude: r[lat_index],
254
256
  longitude: r[lon_index]
255
257
  }
@@ -14,7 +14,7 @@ module Blazer
14
14
  def blazer_format_value(key, value)
15
15
  if value.is_a?(Numeric) && !key.to_s.end_with?("id") && !key.to_s.start_with?("id")
16
16
  number_with_delimiter(value)
17
- elsif value =~ BLAZER_URL_REGEX
17
+ elsif value.is_a?(String) && value =~ BLAZER_URL_REGEX
18
18
  # see if image or link
19
19
  if Blazer.images && (key.include?("image") || BLAZER_IMAGE_EXT.include?(value.split(".").last.split("?").first.try(:downcase)))
20
20
  link_to value, target: "_blank" do
@@ -60,6 +60,9 @@ module Blazer
60
60
  ActionController::Base.helpers.pluralize(*args)
61
61
  end
62
62
 
63
+ # checks shouldn't have variables, but in any case,
64
+ # avoid passing variable params to url helpers
65
+ # (known unsafe parameters are removed, but blacklist isn't ideal)
63
66
  def self.query_url(id)
64
67
  Blazer::Engine.routes.url_helpers.query_url(id, ActionMailer::Base.default_url_options)
65
68
  end
@@ -6,6 +6,10 @@ module Blazer
6
6
 
7
7
  validates :name, presence: true
8
8
 
9
+ def variables
10
+ queries.flat_map { |q| q.variables }.uniq
11
+ end
12
+
9
13
  def to_param
10
14
  [id, name.gsub("'", "").parameterize].join("-")
11
15
  end
@@ -1,5 +1,6 @@
1
1
  <ul>
2
2
  <% @checks.each do |check| %>
3
+ <%# check queries shouldn't have variables, but in any case, don't pass them to url helpers %>
3
4
  <li><%= link_to check.query.name, query_url(check.query_id) %> <%= check.state %></li>
4
5
  <% end %>
5
6
  </ul>
@@ -2,6 +2,7 @@
2
2
  <head>
3
3
  </head>
4
4
  <body style="font-family: 'Helvetica Neue', Arial, Helvetica; font-size: 14px; color: #333;">
5
+ <%# check queries shouldn't have variables, but in any case, don't pass them to url helpers %>
5
6
  <p><%= link_to "View", query_url(@check.query_id) %></p>
6
7
  <% if @error %>
7
8
  <p><%= @error %></p>
@@ -1,4 +1,4 @@
1
- <%= form_for @dashboard, url: (@dashboard.persisted? ? dashboard_path(@dashboard, variable_params) : dashboards_path(variable_params)), html: {id: "app", class: "small-form"} do |f| %>
1
+ <%= form_for @dashboard, url: (@dashboard.persisted? ? dashboard_path(@dashboard, variable_params(@dashboard)) : dashboards_path(variable_params(@dashboard))), html: {id: "app", class: "small-form"} do |f| %>
2
2
  <% if @dashboard.errors.any? %>
3
3
  <div class="alert alert-danger"><%= @dashboard.errors.full_messages.first %></div>
4
4
  <% end %>
@@ -10,7 +10,7 @@
10
10
  </h3>
11
11
  </div>
12
12
  <div class="col-sm-3 text-right">
13
- <%= link_to "Edit", edit_dashboard_path(@dashboard, variable_params), class: "btn btn-info" %>
13
+ <%= link_to "Edit", edit_dashboard_path(@dashboard, variable_params(@dashboard)), class: "btn btn-info" %>
14
14
  </div>
15
15
  </div>
16
16
  </div>
@@ -21,7 +21,7 @@
21
21
  <% if @data_sources.any? { |ds| ds.cache_mode != "off" } %>
22
22
  <p class="text-muted" style="float: right;">
23
23
  Some queries may be cached
24
- <%= link_to "Refresh", refresh_dashboard_path(@dashboard, variable_params), method: :post %>
24
+ <%= link_to "Refresh", refresh_dashboard_path(@dashboard, variable_params(@dashboard)), method: :post %>
25
25
  </p>
26
26
  <% end %>
27
27
 
@@ -33,7 +33,7 @@
33
33
 
34
34
  <% @queries.each_with_index do |query, i| %>
35
35
  <div class="chart-container">
36
- <h4><%= link_to query.friendly_name, query_path(query, variable_params), target: "_blank" %></h4>
36
+ <h4><%= link_to query.friendly_name, query_path(query, variable_params(query)), target: "_blank" %></h4>
37
37
  <div id="chart-<%= i %>" class="chart">
38
38
  <p class="text-muted">Loading...</p>
39
39
  </div>
@@ -3,7 +3,7 @@
3
3
  <% end %>
4
4
 
5
5
  <div id="app" v-cloak>
6
- <%= form_for @query, url: (@query.persisted? ? query_path(@query, variable_params) : queries_path(variable_params)), html: {autocomplete: "off"} do |f| %>
6
+ <%= form_for @query, url: (@query.persisted? ? query_path(@query, variable_params(@query)) : queries_path(variable_params(@query))), html: {autocomplete: "off"} do |f| %>
7
7
  <div class="row">
8
8
  <div id="statement-box" class="col-xs-8">
9
9
  <div class= "form-group">
@@ -51,7 +51,7 @@
51
51
  <% words << pluralize(dashboards_count, "dashboard") if dashboards_count > 0 %>
52
52
  <% words << pluralize(checks_count, "check") if checks_count > 0 %>
53
53
  <% if words.any? %>
54
- <div class="alert alert-info" style="margin-bottom: 0;">
54
+ <div class="alert alert-info">
55
55
  Part of <%= words.to_sentence %>. Be careful when editing.
56
56
  </div>
57
57
  <% end %>
@@ -67,7 +67,7 @@
67
67
  </div>
68
68
 
69
69
  <script>
70
- <%= blazer_js_var "params", variable_params %>
70
+ <%= blazer_js_var "params", variable_params(@query) %>
71
71
  <%= blazer_js_var "previewStatement", Hash[Blazer.data_sources.map { |k, v| [k, (v.preview_statement rescue "")] }] %>
72
72
 
73
73
  var app = new Vue({
@@ -71,7 +71,7 @@
71
71
  }
72
72
 
73
73
  var prepareQuery = function (str) {
74
- return str.toLowerCase().replace(/\W+/g, "")
74
+ return str.toLowerCase()
75
75
  }
76
76
 
77
77
  var app = new Vue({
@@ -12,15 +12,15 @@
12
12
  <p class="text-muted" style="float: right;">
13
13
  <% if @cached_at %>
14
14
  Cached <%= time_ago_in_words(@cached_at, include_seconds: true) %> ago
15
- <% elsif !params[:data_source] %>
15
+ <% elsif params[:query_id] %>
16
16
  Cached just now
17
17
  <% if @data_source.cache_mode == "slow" %>
18
18
  (over <%= "%g" % @data_source.cache_slow_threshold %>s)
19
19
  <% end %>
20
20
  <% end %>
21
21
 
22
- <% if @query && !params[:data_source] %>
23
- <%= link_to "Refresh", refresh_query_path(@query, variable_params), method: :post %>
22
+ <% if @query && params[:query_id] %>
23
+ <%= link_to "Refresh", refresh_query_path(@query, variable_params(@query)), method: :post %>
24
24
  <% end %>
25
25
  </p>
26
26
  <% end %>
@@ -36,7 +36,7 @@
36
36
 
37
37
  <% if @query && @result.forecastable? && !params[:forecast] %>
38
38
  &middot;
39
- <%= link_to "Forecast", query_path(@query, {forecast: "t"}.merge(variable_params)) %>
39
+ <%= link_to "Forecast", query_path(@query, {forecast: "t"}.merge(variable_params(@query))) %>
40
40
  <% end %>
41
41
  </p>
42
42
  <% end %>
@@ -67,7 +67,8 @@
67
67
  <% series_library = {} %>
68
68
  <% target_index = @columns.index { |k| k.downcase == "target" } %>
69
69
  <% if target_index %>
70
- <% series_library[target_index - 1] = {pointStyle: "line", hitRadius: 5, borderColor: "#109618", pointBackgroundColor: "#109618", backgroundColor: "#109618"} %>
70
+ <% color = "#109618" %>
71
+ <% series_library[target_index - 1] = {pointStyle: "line", hitRadius: 5, borderColor: color, pointBackgroundColor: color, backgroundColor: color, pointHoverBackgroundColor: color} %>
71
72
  <% end %>
72
73
  <% if @forecast %>
73
74
  <% color = "#54a3ee" %>
@@ -79,7 +80,8 @@
79
80
  <%= blazer_js_var "mapboxAccessToken", Blazer.mapbox_access_token %>
80
81
  <%= blazer_js_var "markers", @markers %>
81
82
  L.mapbox.accessToken = mapboxAccessToken;
82
- var map = L.mapbox.map('map', 'ankane.ioo8nki0');
83
+ var map = L.mapbox.map('map')
84
+ .addLayer(L.mapbox.styleLayer('mapbox://styles/mapbox/streets-v11'));
83
85
  var featureLayer = L.mapbox.featureLayer().addTo(map);
84
86
  var geojson = [];
85
87
  for (var i = 0; i < markers.length; i++) {
@@ -10,8 +10,8 @@
10
10
  </h3>
11
11
  </div>
12
12
  <div class="col-sm-3 text-right">
13
- <%= link_to "Edit", edit_query_path(@query, variable_params), class: "btn btn-default", disabled: !@query.editable?(blazer_user) %>
14
- <%= link_to "Fork", new_query_path(variable_params.merge(fork_query_id: @query.id, data_source: @query.data_source, name: @query.name)), class: "btn btn-info" %>
13
+ <%= link_to "Edit", edit_query_path(@query, variable_params(@query)), class: "btn btn-default", disabled: !@query.editable?(blazer_user) %>
14
+ <%= link_to "Fork", new_query_path(variable_params(@query).merge(fork_query_id: @query.id, data_source: @query.data_source, name: @query.name)), class: "btn btn-info" %>
15
15
 
16
16
  <% if !@error && @success %>
17
17
  <%= button_to "Download", run_queries_path(query_id: @query.id, format: "csv", forecast: params[:forecast]), params: {statement: @statement}, class: "btn btn-primary" %>
@@ -56,7 +56,7 @@
56
56
  $("#results").addClass("query-error").html(message)
57
57
  }
58
58
 
59
- <%= blazer_js_var "data", variable_params.merge(statement: @statement, query_id: @query.id, data_source: @query.data_source) %>
59
+ <%= blazer_js_var "data", variable_params(@query).merge(statement: @statement, query_id: @query.id, data_source: @query.data_source) %>
60
60
 
61
61
  runQuery(data, showRun, showError)
62
62
  </script>
@@ -11,8 +11,8 @@
11
11
  <%= blazer_js_var "rootPath", root_path %>
12
12
  </script>
13
13
  <% if blazer_maps? %>
14
- <%= stylesheet_link_tag "https://api.mapbox.com/mapbox.js/v3.1.1/mapbox.css", integrity: "sha384-o8tecBIfqi9yU5yYK2Ne/9A9hlOGFV9MBvCpmemvJH1XxqOe6h8Bl4mLxMi6PgjG", crossorigin: "anonymous" %>
15
- <%= javascript_include_tag "https://api.mapbox.com/mapbox.js/v3.1.1/mapbox.js", integrity: "sha384-j81LqvtvYigFzGSUgAoFijpvoq4yGoCJSOXI9DFaUEpenR029MBE3E/X5Gr+WdO0", crossorigin: "anonymous" %>
14
+ <%= stylesheet_link_tag "https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.css", integrity: "sha384-vxzdEt+wZRPNQbhChjmiaFMLWg86IGuq1NGDehJHsD2mphYkxXll/eSs16WWi6Dq", crossorigin: "anonymous" %>
15
+ <%= javascript_include_tag "https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.js", integrity: "sha384-CTBEiDLiZJ8gkAQ3fYGoeiRp81/ecNiBkGz11jXFALOZ6++rbnqmdo6OImkmr1MO", crossorigin: "anonymous" %>
16
16
  <% end %>
17
17
  <%= csrf_meta_tags %>
18
18
  </head>
@@ -22,6 +22,7 @@ require "blazer/adapters/mongodb_adapter"
22
22
  require "blazer/adapters/neo4j_adapter"
23
23
  require "blazer/adapters/presto_adapter"
24
24
  require "blazer/adapters/salesforce_adapter"
25
+ require "blazer/adapters/soda_adapter"
25
26
  require "blazer/adapters/sql_adapter"
26
27
  require "blazer/adapters/snowflake_adapter"
27
28
 
@@ -118,7 +119,7 @@ module Blazer
118
119
  def self.extract_vars(statement)
119
120
  # strip commented out lines
120
121
  # and regex {1} or {1,2}
121
- statement.gsub(/\-\-.+/, "").gsub(/\/\*.+\*\//m, "").scan(/\{\w*?\}/i).map { |v| v[1...-1] }.reject { |v| /\A\d+(\,\d+)?\z/.match(v) || v.empty? }.uniq
122
+ statement.to_s.gsub(/\-\-.+/, "").gsub(/\/\*.+\*\//m, "").scan(/\{\w*?\}/i).map { |v| v[1...-1] }.reject { |v| /\A\d+(\,\d+)?\z/.match(v) || v.empty? }.uniq
122
123
  end
123
124
 
124
125
  def self.run_checks(schedule: nil)
@@ -223,5 +224,6 @@ Blazer.register_adapter "neo4j", Blazer::Adapters::Neo4jAdapter
223
224
  Blazer.register_adapter "presto", Blazer::Adapters::PrestoAdapter
224
225
  Blazer.register_adapter "mongodb", Blazer::Adapters::MongodbAdapter
225
226
  Blazer.register_adapter "salesforce", Blazer::Adapters::SalesforceAdapter
227
+ Blazer.register_adapter "soda", Blazer::Adapters::SodaAdapter
226
228
  Blazer.register_adapter "sql", Blazer::Adapters::SqlAdapter
227
229
  Blazer.register_adapter "snowflake", Blazer::Adapters::SnowflakeAdapter
@@ -32,7 +32,7 @@ module Blazer
32
32
  query_execution_id: query_execution_id
33
33
  )
34
34
  rescue Aws::Athena::Errors::InvalidRequestException => e
35
- if e.message != "Query has not yet finished. Current state: RUNNING"
35
+ unless e.message.start_with?("Query has not yet finished.")
36
36
  raise e
37
37
  end
38
38
  if Time.now < stop_at
@@ -56,6 +56,7 @@ module Blazer
56
56
  utc = ActiveSupport::TimeZone['Etc/UTC']
57
57
 
58
58
  rows = untyped_rows[1..-1] || []
59
+ rows = untyped_rows[0..-1] unless column_info.present?
59
60
  column_types.each_with_index do |ct, i|
60
61
  # TODO more column_types
61
62
  case ct
@@ -0,0 +1,96 @@
1
+ module Blazer
2
+ module Adapters
3
+ class SodaAdapter < BaseAdapter
4
+ def run_statement(statement, comment)
5
+ columns = []
6
+ rows = []
7
+ error = nil
8
+
9
+ # remove comments manually
10
+ statement = statement.gsub(/--.+/, "")
11
+ # only supports single line /* */ comments
12
+ # regex not perfect, but should be good enough
13
+ statement = statement.gsub(/\/\*.+\*\//, "")
14
+
15
+ # remove trailing semicolon
16
+ statement = statement.sub(/;\s*\z/, "")
17
+
18
+ # remove whitespace
19
+ statement = statement.squish
20
+
21
+ uri = URI(settings["url"])
22
+ uri.query = URI.encode_www_form("$query" => statement)
23
+
24
+ req = Net::HTTP::Get.new(uri)
25
+ req["X-App-Token"] = settings["app_token"] if settings["app_token"]
26
+
27
+ options = {
28
+ use_ssl: uri.scheme == "https",
29
+ open_timeout: 3,
30
+ read_timeout: 30
31
+ }
32
+
33
+ begin
34
+ # use Net::HTTP instead of soda-ruby for types and better error messages
35
+ res = Net::HTTP.start(uri.hostname, uri.port, options) do |http|
36
+ http.request(req)
37
+ end
38
+
39
+ if res.is_a?(Net::HTTPSuccess)
40
+ body = JSON.parse(res.body)
41
+
42
+ columns = JSON.parse(res["x-soda2-fields"])
43
+ column_types = columns.zip(JSON.parse(res["x-soda2-types"])).to_h
44
+
45
+ columns.reject! { |f| f.start_with?(":@") }
46
+ # rows can be missing some keys in JSON, so need to map by column
47
+ rows = body.map { |r| columns.map { |c| r[c] } }
48
+
49
+ columns.each_with_index do |column, i|
50
+ # nothing to do for boolean
51
+ case column_types[column]
52
+ when "number"
53
+ # check if likely an integer column
54
+ if rows.all? { |r| r[i].to_i == r[i].to_f }
55
+ rows.each do |row|
56
+ row[i] = row[i].to_i
57
+ end
58
+ else
59
+ rows.each do |row|
60
+ row[i] = row[i].to_f
61
+ end
62
+ end
63
+ when "floating_timestamp"
64
+ # check if likely a date column
65
+ if rows.all? { |r| r[i].end_with?("T00:00:00.000") }
66
+ rows.each do |row|
67
+ row[i] = Date.parse(row[i])
68
+ end
69
+ else
70
+ utc = ActiveSupport::TimeZone["Etc/UTC"]
71
+ rows.each do |row|
72
+ row[i] = utc.parse(row[i])
73
+ end
74
+ end
75
+ end
76
+ end
77
+ else
78
+ error = JSON.parse(res.body)["message"] rescue "Bad response: #{res.code}"
79
+ end
80
+ rescue => e
81
+ error = e.message
82
+ end
83
+
84
+ [columns, rows, error]
85
+ end
86
+
87
+ def preview_statement
88
+ "SELECT * LIMIT 10"
89
+ end
90
+
91
+ def tables
92
+ ["all"]
93
+ end
94
+ end
95
+ end
96
+ end
@@ -42,7 +42,7 @@ module Blazer
42
42
  def tables
43
43
  sql = add_schemas("SELECT table_schema, table_name FROM information_schema.tables")
44
44
  result = data_source.run_statement(sql, refresh_cache: true)
45
- if postgresql? || redshift?
45
+ if postgresql? || redshift? || snowflake?
46
46
  result.rows.sort_by { |r| [r[0] == default_schema ? "" : r[0], r[1]] }.map do |row|
47
47
  table =
48
48
  if row[0] == default_schema
@@ -51,6 +51,8 @@ module Blazer
51
51
  "#{row[0]}.#{row[1]}"
52
52
  end
53
53
 
54
+ table = table.downcase if snowflake?
55
+
54
56
  {
55
57
  table: table,
56
58
  value: connection_model.connection.quote_table_name(table)
@@ -148,6 +150,10 @@ module Blazer
148
150
  ["SQLServer", "tinytds", "mssql"].include?(adapter_name)
149
151
  end
150
152
 
153
+ def snowflake?
154
+ data_source.adapter == "snowflake"
155
+ end
156
+
151
157
  def adapter_name
152
158
  # prevent bad data source from taking down queries/new
153
159
  connection_model.connection.adapter_name rescue nil
@@ -172,6 +178,7 @@ module Blazer
172
178
  else
173
179
  where = "table_schema NOT IN (?)"
174
180
  schemas = ["information_schema"]
181
+ schemas.map!(&:upcase) if snowflake?
175
182
  schemas << "pg_catalog" if postgresql? || redshift?
176
183
  end
177
184
  connection_model.send(:sanitize_sql_array, ["#{query} WHERE #{where}", schemas])
@@ -3,10 +3,21 @@ module Blazer
3
3
  isolate_namespace Blazer
4
4
 
5
5
  initializer "blazer" do |app|
6
- # use a proc instead of a string
7
- app.config.assets.precompile << proc { |path| path =~ /\Ablazer\/application\.(js|css)\z/ }
8
- app.config.assets.precompile << proc { |path| path =~ /\Ablazer\/.+\.(eot|svg|ttf|woff)\z/ }
9
- app.config.assets.precompile << proc { |path| path == "blazer/favicon.png" }
6
+ if defined?(Sprockets) && Sprockets::VERSION >= "4"
7
+ app.config.assets.precompile << "blazer/application.js"
8
+ app.config.assets.precompile << "blazer/application.css"
9
+ app.config.assets.precompile << "blazer/glyphicons-halflings-regular.eot"
10
+ app.config.assets.precompile << "blazer/glyphicons-halflings-regular.svg"
11
+ app.config.assets.precompile << "blazer/glyphicons-halflings-regular.ttf"
12
+ app.config.assets.precompile << "blazer/glyphicons-halflings-regular.woff"
13
+ app.config.assets.precompile << "blazer/glyphicons-halflings-regular.woff2"
14
+ app.config.assets.precompile << "blazer/favicon.png"
15
+ else
16
+ # use a proc instead of a string
17
+ app.config.assets.precompile << proc { |path| path =~ /\Ablazer\/application\.(js|css)\z/ }
18
+ app.config.assets.precompile << proc { |path| path =~ /\Ablazer\/.+\.(eot|svg|ttf|woff|woff2)\z/ }
19
+ app.config.assets.precompile << proc { |path| path == "blazer/favicon.png" }
20
+ end
10
21
 
11
22
  Blazer.time_zone ||= Blazer.settings["time_zone"] || Time.zone
12
23
  Blazer.audit = Blazer.settings.key?("audit") ? Blazer.settings["audit"] : true
@@ -85,11 +85,45 @@ module Blazer
85
85
  @forecastable ||= Blazer.forecasting && column_types == ["time", "numeric"] && @rows.size >= 10
86
86
  end
87
87
 
88
+ # TODO cache it?
89
+ # don't want to put result data (even hashed version)
90
+ # into cache without developer opt-in
88
91
  def forecast
89
- # TODO cache it?
90
- # don't want to put result data (even hashed version)
91
- # into cache without developer opt-in
92
- forecast = Trend.forecast(Hash[@rows], count: 30)
92
+ count = (@rows.size * 0.25).round.clamp(30, 365)
93
+
94
+ case Blazer.forecasting
95
+ when "prophet"
96
+ require "prophet"
97
+
98
+ df =
99
+ Daru::DataFrame.new(
100
+ "ds" => @rows.map { |r| r[0] },
101
+ "y" => @rows.map { |r| r[1] }
102
+ )
103
+
104
+ # TODO determine frequency
105
+ freq = "D"
106
+
107
+ m = Prophet.new
108
+ m.fit(df)
109
+ future = m.make_future_dataframe(periods: count, freq: freq, include_history: false)
110
+ fcst = m.predict(future)
111
+ ds = fcst["ds"]
112
+ if @rows[0][0].is_a?(Date)
113
+ ds = ds.map { |v| v.to_date }
114
+ end
115
+ forecast = ds.zip(fcst["yhat"]).to_h
116
+ else
117
+ require "trend"
118
+
119
+ forecast = Trend.forecast(Hash[@rows], count: count)
120
+ end
121
+
122
+ # round integers
123
+ if @rows[0][1].is_a?(Integer)
124
+ forecast = forecast.map { |k, v| [k, v.round] }.to_h
125
+ end
126
+
93
127
  @rows.each do |row|
94
128
  row[2] = nil
95
129
  end
@@ -1,3 +1,3 @@
1
1
  module Blazer
2
- VERSION = "2.2.0"
2
+ VERSION = "2.2.5"
3
3
  end
@@ -67,7 +67,7 @@ check_schedules:
67
67
 
68
68
  # enable forecasting
69
69
  # note: with trend, time series are sent to https://trendapi.org
70
- # forecasting: trend
70
+ # forecasting: trend / prophet
71
71
 
72
72
  # enable map
73
73
  # mapbox_access_token: <%%= ENV["MAPBOX_ACCESS_TOKEN"] %>
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.2.0
4
+ version: 2.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-12 00:00:00.000000000 Z
11
+ date: 2020-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -140,7 +140,7 @@ files:
140
140
  - app/assets/stylesheets/blazer/bootstrap.css.erb
141
141
  - app/assets/stylesheets/blazer/daterangepicker.css
142
142
  - app/assets/stylesheets/blazer/github.css
143
- - app/assets/stylesheets/blazer/selectize.default.css
143
+ - app/assets/stylesheets/blazer/selectize.css
144
144
  - app/controllers/blazer/base_controller.rb
145
145
  - app/controllers/blazer/checks_controller.rb
146
146
  - app/controllers/blazer/dashboards_controller.rb
@@ -190,6 +190,7 @@ files:
190
190
  - lib/blazer/adapters/presto_adapter.rb
191
191
  - lib/blazer/adapters/salesforce_adapter.rb
192
192
  - lib/blazer/adapters/snowflake_adapter.rb
193
+ - lib/blazer/adapters/soda_adapter.rb
193
194
  - lib/blazer/adapters/sql_adapter.rb
194
195
  - lib/blazer/data_source.rb
195
196
  - lib/blazer/detect_anomalies.R
@@ -221,7 +222,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
221
222
  - !ruby/object:Gem::Version
222
223
  version: '0'
223
224
  requirements: []
224
- rubygems_version: 3.0.4
225
+ rubygems_version: 3.1.2
225
226
  signing_key:
226
227
  specification_version: 4
227
228
  summary: Explore your data with SQL. Easily create charts and dashboards, and share