blazer_xlsx 3.0.5
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 +7 -0
- data/CHANGELOG.md +442 -0
- data/CONTRIBUTING.md +42 -0
- data/LICENSE.txt +22 -0
- data/README.md +1093 -0
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.eot +0 -0
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.svg +288 -0
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.ttf +0 -0
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.woff +0 -0
- data/app/assets/fonts/blazer/glyphicons-halflings-regular.woff2 +0 -0
- data/app/assets/images/blazer/favicon.png +0 -0
- data/app/assets/javascripts/blazer/Sortable.js +3709 -0
- data/app/assets/javascripts/blazer/ace/ace.js +19630 -0
- data/app/assets/javascripts/blazer/ace/ext-language_tools.js +1981 -0
- data/app/assets/javascripts/blazer/ace/mode-sql.js +215 -0
- data/app/assets/javascripts/blazer/ace/snippets/sql.js +16 -0
- data/app/assets/javascripts/blazer/ace/snippets/text.js +9 -0
- data/app/assets/javascripts/blazer/ace/theme-twilight.js +18 -0
- data/app/assets/javascripts/blazer/ace.js +6 -0
- data/app/assets/javascripts/blazer/application.js +84 -0
- data/app/assets/javascripts/blazer/bootstrap.js +2580 -0
- data/app/assets/javascripts/blazer/chart.umd.js +13 -0
- data/app/assets/javascripts/blazer/chartjs-adapter-date-fns.bundle.js +6322 -0
- data/app/assets/javascripts/blazer/chartkick.js +2570 -0
- data/app/assets/javascripts/blazer/daterangepicker.js +1578 -0
- data/app/assets/javascripts/blazer/fuzzysearch.js +24 -0
- data/app/assets/javascripts/blazer/highlight.min.js +466 -0
- data/app/assets/javascripts/blazer/jquery.js +10872 -0
- data/app/assets/javascripts/blazer/jquery.stickytableheaders.js +325 -0
- data/app/assets/javascripts/blazer/mapkick.bundle.js +1029 -0
- data/app/assets/javascripts/blazer/moment-timezone-with-data.js +1548 -0
- data/app/assets/javascripts/blazer/moment.js +5685 -0
- data/app/assets/javascripts/blazer/queries.js +130 -0
- data/app/assets/javascripts/blazer/rails-ujs.js +746 -0
- data/app/assets/javascripts/blazer/routes.js +26 -0
- data/app/assets/javascripts/blazer/selectize.js +3891 -0
- data/app/assets/javascripts/blazer/stupidtable-custom-settings.js +13 -0
- data/app/assets/javascripts/blazer/stupidtable.js +281 -0
- data/app/assets/javascripts/blazer/vue.global.prod.js +1 -0
- data/app/assets/stylesheets/blazer/application.css +243 -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 +6828 -0
- data/app/assets/stylesheets/blazer/daterangepicker.css +410 -0
- data/app/assets/stylesheets/blazer/github.css +125 -0
- data/app/assets/stylesheets/blazer/selectize.css +403 -0
- data/app/controllers/blazer/base_controller.rb +135 -0
- data/app/controllers/blazer/checks_controller.rb +56 -0
- data/app/controllers/blazer/dashboards_controller.rb +99 -0
- data/app/controllers/blazer/queries_controller.rb +472 -0
- data/app/controllers/blazer/uploads_controller.rb +147 -0
- data/app/helpers/blazer/base_helper.rb +39 -0
- data/app/models/blazer/audit.rb +6 -0
- data/app/models/blazer/check.rb +104 -0
- data/app/models/blazer/connection.rb +5 -0
- data/app/models/blazer/dashboard.rb +17 -0
- data/app/models/blazer/dashboard_query.rb +9 -0
- data/app/models/blazer/query.rb +42 -0
- data/app/models/blazer/record.rb +5 -0
- data/app/models/blazer/upload.rb +11 -0
- data/app/models/blazer/uploads_connection.rb +7 -0
- data/app/views/blazer/_nav.html.erb +18 -0
- data/app/views/blazer/_variables.html.erb +127 -0
- data/app/views/blazer/check_mailer/failing_checks.html.erb +7 -0
- data/app/views/blazer/check_mailer/state_change.html.erb +48 -0
- data/app/views/blazer/checks/_form.html.erb +79 -0
- data/app/views/blazer/checks/edit.html.erb +3 -0
- data/app/views/blazer/checks/index.html.erb +72 -0
- data/app/views/blazer/checks/new.html.erb +3 -0
- data/app/views/blazer/dashboards/_form.html.erb +82 -0
- data/app/views/blazer/dashboards/edit.html.erb +3 -0
- data/app/views/blazer/dashboards/new.html.erb +3 -0
- data/app/views/blazer/dashboards/show.html.erb +53 -0
- data/app/views/blazer/queries/_caching.html.erb +16 -0
- data/app/views/blazer/queries/_cohorts.html.erb +48 -0
- data/app/views/blazer/queries/_form.html.erb +255 -0
- data/app/views/blazer/queries/docs.html.erb +147 -0
- data/app/views/blazer/queries/edit.html.erb +2 -0
- data/app/views/blazer/queries/home.html.erb +169 -0
- data/app/views/blazer/queries/new.html.erb +2 -0
- data/app/views/blazer/queries/run.html.erb +183 -0
- data/app/views/blazer/queries/schema.html.erb +55 -0
- data/app/views/blazer/queries/show.html.erb +72 -0
- data/app/views/blazer/uploads/_form.html.erb +27 -0
- data/app/views/blazer/uploads/edit.html.erb +3 -0
- data/app/views/blazer/uploads/index.html.erb +55 -0
- data/app/views/blazer/uploads/new.html.erb +3 -0
- data/app/views/layouts/blazer/application.html.erb +25 -0
- data/config/routes.rb +25 -0
- data/lib/blazer/adapters/athena_adapter.rb +182 -0
- data/lib/blazer/adapters/base_adapter.rb +76 -0
- data/lib/blazer/adapters/bigquery_adapter.rb +79 -0
- data/lib/blazer/adapters/cassandra_adapter.rb +70 -0
- data/lib/blazer/adapters/drill_adapter.rb +38 -0
- data/lib/blazer/adapters/druid_adapter.rb +102 -0
- data/lib/blazer/adapters/elasticsearch_adapter.rb +61 -0
- data/lib/blazer/adapters/hive_adapter.rb +55 -0
- data/lib/blazer/adapters/ignite_adapter.rb +64 -0
- data/lib/blazer/adapters/influxdb_adapter.rb +57 -0
- data/lib/blazer/adapters/neo4j_adapter.rb +62 -0
- data/lib/blazer/adapters/opensearch_adapter.rb +52 -0
- data/lib/blazer/adapters/presto_adapter.rb +54 -0
- data/lib/blazer/adapters/salesforce_adapter.rb +50 -0
- data/lib/blazer/adapters/snowflake_adapter.rb +82 -0
- data/lib/blazer/adapters/soda_adapter.rb +105 -0
- data/lib/blazer/adapters/spark_adapter.rb +14 -0
- data/lib/blazer/adapters/sql_adapter.rb +353 -0
- data/lib/blazer/adapters.rb +17 -0
- data/lib/blazer/anomaly_detectors.rb +22 -0
- data/lib/blazer/check_mailer.rb +27 -0
- data/lib/blazer/data_source.rb +266 -0
- data/lib/blazer/engine.rb +42 -0
- data/lib/blazer/forecasters.rb +7 -0
- data/lib/blazer/result.rb +178 -0
- data/lib/blazer/result_cache.rb +71 -0
- data/lib/blazer/run_statement.rb +45 -0
- data/lib/blazer/run_statement_job.rb +20 -0
- data/lib/blazer/slack_notifier.rb +94 -0
- data/lib/blazer/statement.rb +77 -0
- data/lib/blazer/version.rb +3 -0
- data/lib/blazer.rb +282 -0
- data/lib/generators/blazer/install_generator.rb +22 -0
- data/lib/generators/blazer/templates/config.yml.tt +79 -0
- data/lib/generators/blazer/templates/install.rb.tt +47 -0
- data/lib/generators/blazer/templates/uploads.rb.tt +10 -0
- data/lib/generators/blazer/uploads_generator.rb +18 -0
- data/lib/tasks/blazer.rake +20 -0
- data/licenses/LICENSE-ace.txt +24 -0
- data/licenses/LICENSE-bootstrap.txt +21 -0
- data/licenses/LICENSE-chart.js.txt +9 -0
- data/licenses/LICENSE-chartjs-adapter-date-fns.txt +9 -0
- data/licenses/LICENSE-chartkick.js.txt +22 -0
- data/licenses/LICENSE-date-fns.txt +21 -0
- data/licenses/LICENSE-daterangepicker.txt +21 -0
- data/licenses/LICENSE-fuzzysearch.txt +20 -0
- data/licenses/LICENSE-highlight.js.txt +29 -0
- data/licenses/LICENSE-jquery.txt +20 -0
- data/licenses/LICENSE-kurkle-color.txt +9 -0
- data/licenses/LICENSE-mapkick-bundle.txt +1029 -0
- data/licenses/LICENSE-moment-timezone.txt +20 -0
- data/licenses/LICENSE-moment.txt +22 -0
- data/licenses/LICENSE-rails-ujs.txt +20 -0
- data/licenses/LICENSE-selectize.txt +202 -0
- data/licenses/LICENSE-sortable.txt +21 -0
- data/licenses/LICENSE-stickytableheaders.txt +20 -0
- data/licenses/LICENSE-stupidtable.txt +19 -0
- data/licenses/LICENSE-vue.txt +21 -0
- metadata +271 -0
data/README.md
ADDED
|
@@ -0,0 +1,1093 @@
|
|
|
1
|
+
# Blazer
|
|
2
|
+
|
|
3
|
+
Explore your data with SQL. Easily create charts and dashboards, and share them with your team.
|
|
4
|
+
|
|
5
|
+
[Try it out](https://blazer.dokkuapp.com)
|
|
6
|
+
|
|
7
|
+
[](https://blazer.dokkuapp.com)
|
|
8
|
+
|
|
9
|
+
Blazer is also available as a [Docker image](https://github.com/ankane/blazer-docker).
|
|
10
|
+
|
|
11
|
+
:tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
|
|
12
|
+
|
|
13
|
+
[](https://github.com/ankane/blazer/actions)
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- **Multiple data sources** - PostgreSQL, MySQL, Redshift, and [many more](#full-list)
|
|
18
|
+
- **Variables** - run the same queries with different values
|
|
19
|
+
- **Checks & alerts** - get emailed when bad data appears
|
|
20
|
+
- **Audits** - all queries are tracked
|
|
21
|
+
- **Security** - works with your authentication system
|
|
22
|
+
|
|
23
|
+
## Docs
|
|
24
|
+
|
|
25
|
+
- [Installation](#installation)
|
|
26
|
+
- [Queries](#queries)
|
|
27
|
+
- [Charts](#charts)
|
|
28
|
+
- [Dashboards](#dashboards)
|
|
29
|
+
- [Checks](#checks)
|
|
30
|
+
- [Cohorts](#cohorts)
|
|
31
|
+
- [Anomaly Detection](#anomaly-detection)
|
|
32
|
+
- [Forecasting](#forecasting)
|
|
33
|
+
- [Uploads](#uploads)
|
|
34
|
+
- [Data Sources](#data-sources)
|
|
35
|
+
- [Query Permissions](#query-permissions)
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
Add this line to your application’s Gemfile:
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
gem "blazer"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Run:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
rails generate blazer:install
|
|
49
|
+
rails db:migrate
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
And mount the dashboard in your `config/routes.rb`:
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
mount Blazer::Engine, at: "blazer"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For production, specify your database:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
ENV["BLAZER_DATABASE_URL"] = "postgres://user:password@hostname:5432/database"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
When possible, Blazer tries to protect against queries which modify data by running each query in a transaction and rolling it back, but a safer approach is to use a read-only user. [See how to create one](#permissions).
|
|
65
|
+
|
|
66
|
+
#### Checks (optional)
|
|
67
|
+
|
|
68
|
+
Be sure to set a host in `config/environments/production.rb` for emails to work.
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
config.action_mailer.default_url_options = {host: "blazer.dokkuapp.com"}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Schedule checks to run (with cron, [Heroku Scheduler](https://elements.heroku.com/addons/scheduler), etc). The default options are every 5 minutes, 1 hour, or 1 day, which you can customize. For each of these options, set up a task to run.
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
rake blazer:run_checks SCHEDULE="5 minutes"
|
|
78
|
+
rake blazer:run_checks SCHEDULE="1 hour"
|
|
79
|
+
rake blazer:run_checks SCHEDULE="1 day"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
You can also set up failing checks to be sent once a day (or whatever you prefer).
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
rake blazer:send_failing_checks
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Here’s what it looks like with cron.
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
*/5 * * * * rake blazer:run_checks SCHEDULE="5 minutes"
|
|
92
|
+
0 * * * * rake blazer:run_checks SCHEDULE="1 hour"
|
|
93
|
+
30 7 * * * rake blazer:run_checks SCHEDULE="1 day"
|
|
94
|
+
0 8 * * * rake blazer:send_failing_checks
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
For Slack notifications, create an [incoming webhook](https://slack.com/apps/A0F7XDUAZ-incoming-webhooks) and set:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
BLAZER_SLACK_WEBHOOK_URL=https://hooks.slack.com/...
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Name the webhook “Blazer” and add a cool icon.
|
|
104
|
+
|
|
105
|
+
## Authentication
|
|
106
|
+
|
|
107
|
+
Don’t forget to protect the dashboard in production.
|
|
108
|
+
|
|
109
|
+
### Basic Authentication
|
|
110
|
+
|
|
111
|
+
Set the following variables in your environment or an initializer.
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
ENV["BLAZER_USERNAME"] = "andrew"
|
|
115
|
+
ENV["BLAZER_PASSWORD"] = "secret"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Devise
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
authenticate :user, ->(user) { user.admin? } do
|
|
122
|
+
mount Blazer::Engine, at: "blazer"
|
|
123
|
+
end
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Other
|
|
127
|
+
|
|
128
|
+
Specify a `before_action` method to run in `blazer.yml`.
|
|
129
|
+
|
|
130
|
+
```yml
|
|
131
|
+
before_action_method: require_admin
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
You can define this method in your `ApplicationController`.
|
|
135
|
+
|
|
136
|
+
```ruby
|
|
137
|
+
def require_admin
|
|
138
|
+
# depending on your auth, something like...
|
|
139
|
+
redirect_to root_path unless current_user && current_user.admin?
|
|
140
|
+
end
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Be sure to render or redirect for unauthorized users.
|
|
144
|
+
|
|
145
|
+
## Permissions
|
|
146
|
+
|
|
147
|
+
### PostgreSQL
|
|
148
|
+
|
|
149
|
+
Create a user with read-only permissions:
|
|
150
|
+
|
|
151
|
+
```sql
|
|
152
|
+
BEGIN;
|
|
153
|
+
CREATE ROLE blazer LOGIN PASSWORD 'secret';
|
|
154
|
+
GRANT CONNECT ON DATABASE dbname TO blazer;
|
|
155
|
+
GRANT USAGE ON SCHEMA public TO blazer;
|
|
156
|
+
GRANT SELECT ON ALL TABLES IN SCHEMA public TO blazer;
|
|
157
|
+
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO blazer;
|
|
158
|
+
COMMIT;
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### MySQL
|
|
162
|
+
|
|
163
|
+
Create a user with read-only permissions:
|
|
164
|
+
|
|
165
|
+
```sql
|
|
166
|
+
CREATE USER 'blazer'@'127.0.0.1' IDENTIFIED BY 'secret';
|
|
167
|
+
GRANT SELECT, SHOW VIEW ON dbname.* TO 'blazer'@'127.0.0.1';
|
|
168
|
+
FLUSH PRIVILEGES;
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Sensitive Data
|
|
172
|
+
|
|
173
|
+
If your database contains sensitive or personal data, check out [Hypershield](https://github.com/ankane/hypershield) to shield it.
|
|
174
|
+
|
|
175
|
+
## Encrypted Data
|
|
176
|
+
|
|
177
|
+
If you need to search encrypted data, use [blind indexing](https://github.com/ankane/blind_index).
|
|
178
|
+
|
|
179
|
+
You can have Blazer transform specific variables with:
|
|
180
|
+
|
|
181
|
+
```ruby
|
|
182
|
+
Blazer.transform_variable = lambda do |name, value|
|
|
183
|
+
value = User.generate_email_bidx(value) if name == "email_bidx"
|
|
184
|
+
value
|
|
185
|
+
end
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Queries
|
|
189
|
+
|
|
190
|
+
### Variables
|
|
191
|
+
|
|
192
|
+
Create queries with variables.
|
|
193
|
+
|
|
194
|
+
```sql
|
|
195
|
+
SELECT * FROM users WHERE gender = {gender}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Use `{start_time}` and `{end_time}` for time ranges. [Example](https://blazer.dokkuapp.com/queries/9-time-range-selector?start_time=1997-10-03T05%3A00%3A00%2B00%3A00&end_time=1997-10-04T04%3A59%3A59%2B00%3A00)
|
|
199
|
+
|
|
200
|
+
```sql
|
|
201
|
+
SELECT * FROM ratings WHERE rated_at >= {start_time} AND rated_at <= {end_time}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Smart Variables
|
|
205
|
+
|
|
206
|
+
[Example](https://blazer.dokkuapp.com/queries/1-smart-variable)
|
|
207
|
+
|
|
208
|
+
Suppose you have the query:
|
|
209
|
+
|
|
210
|
+
```sql
|
|
211
|
+
SELECT * FROM users WHERE occupation_id = {occupation_id}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Instead of remembering each occupation’s id, users can select occupations by name.
|
|
215
|
+
|
|
216
|
+
Add a smart variable with:
|
|
217
|
+
|
|
218
|
+
```yml
|
|
219
|
+
smart_variables:
|
|
220
|
+
occupation_id: "SELECT id, name FROM occupations ORDER BY name ASC"
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
The first column is the value of the variable, and the second column is the label.
|
|
224
|
+
|
|
225
|
+
You can also use an array or hash for static data and enums.
|
|
226
|
+
|
|
227
|
+
```yml
|
|
228
|
+
smart_variables:
|
|
229
|
+
period: ["day", "week", "month"]
|
|
230
|
+
status: {0: "Active", 1: "Archived"}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Linked Columns
|
|
234
|
+
|
|
235
|
+
[Example](https://blazer.dokkuapp.com/queries/3-linked-column) - title column
|
|
236
|
+
|
|
237
|
+
Link results to other pages in your apps or around the web. Specify a column name and where it should link to. You can use the value of the result with `{value}`.
|
|
238
|
+
|
|
239
|
+
```yml
|
|
240
|
+
linked_columns:
|
|
241
|
+
user_id: "/admin/users/{value}"
|
|
242
|
+
ip_address: "https://www.infosniper.net/index.php?ip_address={value}"
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Smart Columns
|
|
246
|
+
|
|
247
|
+
[Example](https://blazer.dokkuapp.com/queries/2-smart-column) - occupation_id column
|
|
248
|
+
|
|
249
|
+
Suppose you have the query:
|
|
250
|
+
|
|
251
|
+
```sql
|
|
252
|
+
SELECT name, city_id FROM users
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
See which city the user belongs to without a join.
|
|
256
|
+
|
|
257
|
+
```yml
|
|
258
|
+
smart_columns:
|
|
259
|
+
city_id: "SELECT id, name FROM cities WHERE id IN {value}"
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
You can also use a hash for static data and enums.
|
|
263
|
+
|
|
264
|
+
```yml
|
|
265
|
+
smart_columns:
|
|
266
|
+
status: {0: "Active", 1: "Archived"}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Caching
|
|
270
|
+
|
|
271
|
+
Blazer can automatically cache results to improve speed. It can cache slow queries:
|
|
272
|
+
|
|
273
|
+
```yml
|
|
274
|
+
cache:
|
|
275
|
+
mode: slow
|
|
276
|
+
expires_in: 60 # min
|
|
277
|
+
slow_threshold: 15 # sec
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Or it can cache all queries:
|
|
281
|
+
|
|
282
|
+
```yml
|
|
283
|
+
cache:
|
|
284
|
+
mode: all
|
|
285
|
+
expires_in: 60 # min
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Of course, you can force a refresh at any time.
|
|
289
|
+
|
|
290
|
+
## Charts
|
|
291
|
+
|
|
292
|
+
Blazer will automatically generate charts based on the types of the columns returned in your query.
|
|
293
|
+
|
|
294
|
+
**Note:** The order of columns matters.
|
|
295
|
+
|
|
296
|
+
### Line Chart
|
|
297
|
+
|
|
298
|
+
There are two ways to generate line charts.
|
|
299
|
+
|
|
300
|
+
2+ columns - timestamp, numeric(s) - [Example](https://blazer.dokkuapp.com/queries/4-line-chart-format-1)
|
|
301
|
+
|
|
302
|
+
```sql
|
|
303
|
+
SELECT date_trunc('week', created_at), COUNT(*) FROM users GROUP BY 1
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
3 columns - timestamp, string, numeric - [Example](https://blazer.dokkuapp.com/queries/5-line-chart-format-2)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
```sql
|
|
310
|
+
SELECT date_trunc('week', created_at), gender, COUNT(*) FROM users GROUP BY 1, 2
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Column Chart
|
|
314
|
+
|
|
315
|
+
There are also two ways to generate column charts.
|
|
316
|
+
|
|
317
|
+
2+ columns - string, numeric(s) - [Example](https://blazer.dokkuapp.com/queries/6-column-chart-format-1)
|
|
318
|
+
|
|
319
|
+
```sql
|
|
320
|
+
SELECT gender, COUNT(*) FROM users GROUP BY 1
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
3 columns - string, string, numeric - [Example](https://blazer.dokkuapp.com/queries/7-column-chart-format-2)
|
|
324
|
+
|
|
325
|
+
```sql
|
|
326
|
+
SELECT gender, zip_code, COUNT(*) FROM users GROUP BY 1, 2
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Scatter Chart
|
|
330
|
+
|
|
331
|
+
2 columns - both numeric - [Example](https://blazer.dokkuapp.com/queries/16-scatter-chart)
|
|
332
|
+
|
|
333
|
+
```sql
|
|
334
|
+
SELECT x, y FROM table
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Pie Chart
|
|
338
|
+
|
|
339
|
+
2 columns - string, numeric - and last column named `pie` - [Example](https://blazer.dokkuapp.com/queries/17-pie-chart)
|
|
340
|
+
|
|
341
|
+
```sql
|
|
342
|
+
SELECT gender, COUNT(*) AS pie FROM users GROUP BY 1
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Maps
|
|
346
|
+
|
|
347
|
+
Columns named `latitude` and `longitude` or `lat` and `lon` or `lat` and `lng` - [Example](https://blazer.dokkuapp.com/queries/15-map)
|
|
348
|
+
|
|
349
|
+
```sql
|
|
350
|
+
SELECT name, latitude, longitude FROM cities
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
or a column named `geojson`
|
|
354
|
+
|
|
355
|
+
```sql
|
|
356
|
+
SELECT name, geojson FROM counties
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
To enable, get an access token from [Mapbox](https://www.mapbox.com/) and set `ENV["MAPBOX_ACCESS_TOKEN"]`.
|
|
360
|
+
|
|
361
|
+
### Targets
|
|
362
|
+
|
|
363
|
+
Use the column name `target` to draw a line for goals. [Example](https://blazer.dokkuapp.com/queries/8-target-line)
|
|
364
|
+
|
|
365
|
+
```sql
|
|
366
|
+
SELECT date_trunc('week', created_at), COUNT(*) AS new_users, 100000 AS target FROM users GROUP BY 1
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## Dashboards
|
|
370
|
+
|
|
371
|
+
Create a dashboard with multiple queries. [Example](https://blazer.dokkuapp.com/dashboards/1-dashboard-demo)
|
|
372
|
+
|
|
373
|
+
If the query has a chart, the chart is shown. Otherwise, you’ll see a table.
|
|
374
|
+
|
|
375
|
+
If any queries have variables, they will show up on the dashboard.
|
|
376
|
+
|
|
377
|
+
## Checks
|
|
378
|
+
|
|
379
|
+
Checks give you a centralized place to see the health of your data. [Example](https://blazer.dokkuapp.com/checks)
|
|
380
|
+
|
|
381
|
+
Create a query to identify bad rows.
|
|
382
|
+
|
|
383
|
+
```sql
|
|
384
|
+
SELECT * FROM ratings WHERE user_id IS NULL /* all ratings should have a user */
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Then create check with optional emails if you want to be notified. Emails are sent when a check starts failing, and when it starts passing again.
|
|
388
|
+
|
|
389
|
+
## Cohorts
|
|
390
|
+
|
|
391
|
+
Create a cohort analysis from a simple SQL query. [Example](https://blazer.dokkuapp.com/queries/19-cohort-analysis-from-first-order)
|
|
392
|
+
|
|
393
|
+
Create a query with the comment `/* cohort analysis */`. The result should have columns named `user_id` and `conversion_time` and optionally `cohort_time`.
|
|
394
|
+
|
|
395
|
+
You can generate cohorts from the first conversion time:
|
|
396
|
+
|
|
397
|
+
```sql
|
|
398
|
+
/* cohort analysis */
|
|
399
|
+
SELECT user_id, created_at AS conversion_time FROM orders
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
(the first conversion isn’t counted in the first time period with this format)
|
|
403
|
+
|
|
404
|
+
Or from another time, like sign up:
|
|
405
|
+
|
|
406
|
+
```sql
|
|
407
|
+
/* cohort analysis */
|
|
408
|
+
SELECT users.id AS user_id, orders.created_at AS conversion_time, users.created_at AS cohort_time
|
|
409
|
+
FROM users LEFT JOIN orders ON orders.user_id = users.id
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
This feature requires PostgreSQL or MySQL 8.
|
|
413
|
+
|
|
414
|
+
## Anomaly Detection
|
|
415
|
+
|
|
416
|
+
Blazer supports three different approaches to anomaly detection.
|
|
417
|
+
|
|
418
|
+
### Prophet
|
|
419
|
+
|
|
420
|
+
Add [prophet-rb](https://github.com/ankane/prophet) to your Gemfile:
|
|
421
|
+
|
|
422
|
+
```ruby
|
|
423
|
+
gem "prophet-rb"
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
And add to `config/blazer.yml`:
|
|
427
|
+
|
|
428
|
+
```yml
|
|
429
|
+
anomaly_checks: prophet
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Trend
|
|
433
|
+
|
|
434
|
+
[Trend](https://trendapi.org/) uses an external service by default, but you can run it on your own infrastructure as well.
|
|
435
|
+
|
|
436
|
+
Add [trend](https://github.com/ankane/trend) to your Gemfile:
|
|
437
|
+
|
|
438
|
+
```ruby
|
|
439
|
+
gem "trend"
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
And add to `config/blazer.yml`:
|
|
443
|
+
|
|
444
|
+
```yml
|
|
445
|
+
anomaly_checks: trend
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
For the [self-hosted API](https://github.com/ankane/trend-api), create an initializer with:
|
|
449
|
+
|
|
450
|
+
```ruby
|
|
451
|
+
Trend.url = "http://localhost:8000"
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### AnomalyDetection.rb
|
|
455
|
+
|
|
456
|
+
Add [anomaly_detection](https://github.com/ankane/AnomalyDetection.rb) to your Gemfile:
|
|
457
|
+
|
|
458
|
+
```ruby
|
|
459
|
+
gem "anomaly_detection"
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
And add to `config/blazer.yml`:
|
|
463
|
+
|
|
464
|
+
```yml
|
|
465
|
+
anomaly_checks: anomaly_detection
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
## Forecasting
|
|
469
|
+
|
|
470
|
+
Blazer supports for two different forecasting methods. [Example](https://blazer.dokkuapp.com/queries/18-forecast?forecast=t)
|
|
471
|
+
|
|
472
|
+
A forecast link will appear for queries that return 2 columns with types timestamp and numeric.
|
|
473
|
+
|
|
474
|
+
### Prophet
|
|
475
|
+
|
|
476
|
+
Add [prophet-rb](https://github.com/ankane/prophet) to your Gemfile:
|
|
477
|
+
|
|
478
|
+
```ruby
|
|
479
|
+
gem "prophet-rb", ">= 0.2.1"
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
And add to `config/blazer.yml`:
|
|
483
|
+
|
|
484
|
+
```yml
|
|
485
|
+
forecasting: prophet
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### Trend
|
|
489
|
+
|
|
490
|
+
[Trend](https://trendapi.org/) uses an external service by default, but you can run it on your own infrastructure as well.
|
|
491
|
+
|
|
492
|
+
Add [trend](https://github.com/ankane/trend) to your Gemfile:
|
|
493
|
+
|
|
494
|
+
```ruby
|
|
495
|
+
gem "trend"
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
And add to `config/blazer.yml`:
|
|
499
|
+
|
|
500
|
+
```yml
|
|
501
|
+
forecasting: trend
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
For the [self-hosted API](https://github.com/ankane/trend-api), create an initializer with:
|
|
505
|
+
|
|
506
|
+
```ruby
|
|
507
|
+
Trend.url = "http://localhost:8000"
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
## Uploads
|
|
511
|
+
|
|
512
|
+
Create database tables from CSV files. [Example](https://blazer.dokkuapp.com/uploads)
|
|
513
|
+
|
|
514
|
+
Run:
|
|
515
|
+
|
|
516
|
+
```sh
|
|
517
|
+
rails generate blazer:uploads
|
|
518
|
+
rails db:migrate
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
And add to `config/blazer.yml`:
|
|
522
|
+
|
|
523
|
+
```yml
|
|
524
|
+
uploads:
|
|
525
|
+
url: postgres://...
|
|
526
|
+
schema: uploads
|
|
527
|
+
data_source: main
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
This feature requires PostgreSQL. Create a new schema just for uploads.
|
|
531
|
+
|
|
532
|
+
```sql
|
|
533
|
+
CREATE SCHEMA uploads;
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
## Data Sources
|
|
537
|
+
|
|
538
|
+
Blazer supports multiple data sources :tada:
|
|
539
|
+
|
|
540
|
+
Add additional data sources in `config/blazer.yml`:
|
|
541
|
+
|
|
542
|
+
```yml
|
|
543
|
+
data_sources:
|
|
544
|
+
main:
|
|
545
|
+
url: <%= ENV["BLAZER_DATABASE_URL"] %>
|
|
546
|
+
# timeout, smart_variables, linked_columns, smart_columns
|
|
547
|
+
catalog:
|
|
548
|
+
url: <%= ENV["CATALOG_DATABASE_URL"] %>
|
|
549
|
+
# ...
|
|
550
|
+
redshift:
|
|
551
|
+
url: <%= ENV["REDSHIFT_DATABASE_URL"] %>
|
|
552
|
+
# ...
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### Full List
|
|
556
|
+
|
|
557
|
+
- [Amazon Athena](#amazon-athena)
|
|
558
|
+
- [Amazon Redshift](#amazon-redshift)
|
|
559
|
+
- [Apache Drill](#apache-drill)
|
|
560
|
+
- [Apache Hive](#apache-hive)
|
|
561
|
+
- [Apache Ignite](#apache-ignite)
|
|
562
|
+
- [Apache Spark](#apache-spark)
|
|
563
|
+
- [Cassandra](#cassandra)
|
|
564
|
+
- [Druid](#druid)
|
|
565
|
+
- [Elasticsearch](#elasticsearch)
|
|
566
|
+
- [Google BigQuery](#google-bigquery)
|
|
567
|
+
- [IBM DB2 and Informix](#ibm-db2-and-informix)
|
|
568
|
+
- [InfluxDB](#influxdb)
|
|
569
|
+
- [MySQL](#mysql-1)
|
|
570
|
+
- [Neo4j](#neo4j)
|
|
571
|
+
- [OpenSearch](#opensearch)
|
|
572
|
+
- [Oracle](#oracle)
|
|
573
|
+
- [PostgreSQL](#postgresql-1)
|
|
574
|
+
- [Presto](#presto)
|
|
575
|
+
- [Salesforce](#salesforce)
|
|
576
|
+
- [Socrata Open Data API (SODA)](#socrata-open-data-api-soda)
|
|
577
|
+
- [Snowflake](#snowflake)
|
|
578
|
+
- [SQLite](#sqlite)
|
|
579
|
+
- [SQL Server](#sql-server)
|
|
580
|
+
|
|
581
|
+
You can also [create an adapter](#creating-an-adapter) for any other data store.
|
|
582
|
+
|
|
583
|
+
**Note:** In the examples below, we recommend using environment variables for urls.
|
|
584
|
+
|
|
585
|
+
```yml
|
|
586
|
+
data_sources:
|
|
587
|
+
my_source:
|
|
588
|
+
url: <%= ENV["BLAZER_MY_SOURCE_URL"] %>
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
### Amazon Athena
|
|
592
|
+
|
|
593
|
+
Add [aws-sdk-athena](https://github.com/aws/aws-sdk-ruby) and [aws-sdk-glue](https://github.com/aws/aws-sdk-ruby) to your Gemfile and set:
|
|
594
|
+
|
|
595
|
+
```yml
|
|
596
|
+
data_sources:
|
|
597
|
+
my_source:
|
|
598
|
+
adapter: athena
|
|
599
|
+
database: database
|
|
600
|
+
|
|
601
|
+
# optional settings
|
|
602
|
+
output_location: s3://some-bucket/
|
|
603
|
+
workgroup: primary
|
|
604
|
+
access_key_id: ...
|
|
605
|
+
secret_access_key: ...
|
|
606
|
+
region: ...
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
Here’s an example IAM policy:
|
|
610
|
+
|
|
611
|
+
```json
|
|
612
|
+
{
|
|
613
|
+
"Version": "2012-10-17",
|
|
614
|
+
"Statement": [
|
|
615
|
+
{
|
|
616
|
+
"Effect": "Allow",
|
|
617
|
+
"Action": [
|
|
618
|
+
"athena:GetQueryExecution",
|
|
619
|
+
"athena:GetQueryResults",
|
|
620
|
+
"athena:StartQueryExecution"
|
|
621
|
+
],
|
|
622
|
+
"Resource": [
|
|
623
|
+
"arn:aws:athena:region:account-id:workgroup/primary"
|
|
624
|
+
]
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
"Effect": "Allow",
|
|
628
|
+
"Action": [
|
|
629
|
+
"glue:GetTable",
|
|
630
|
+
"glue:GetTables"
|
|
631
|
+
],
|
|
632
|
+
"Resource": [
|
|
633
|
+
"arn:aws:glue:region:account-id:catalog",
|
|
634
|
+
"arn:aws:glue:region:account-id:database/default",
|
|
635
|
+
"arn:aws:glue:region:account-id:table/default/*"
|
|
636
|
+
]
|
|
637
|
+
}
|
|
638
|
+
]
|
|
639
|
+
}
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
You also need to configure [S3 permissions](https://aws.amazon.com/premiumsupport/knowledge-center/access-denied-athena/).
|
|
643
|
+
|
|
644
|
+
### Amazon Redshift
|
|
645
|
+
|
|
646
|
+
Add [activerecord6-redshift-adapter](https://github.com/kwent/activerecord6-redshift-adapter) or [activerecord5-redshift-adapter](https://github.com/ConsultingMD/activerecord5-redshift-adapter) to your Gemfile and set:
|
|
647
|
+
|
|
648
|
+
```yml
|
|
649
|
+
data_sources:
|
|
650
|
+
my_source:
|
|
651
|
+
url: redshift://user:password@hostname:5439/database
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
Use a [read-only user](https://docs.aws.amazon.com/redshift/latest/dg/r_GRANT.html).
|
|
655
|
+
|
|
656
|
+
### Apache Drill
|
|
657
|
+
|
|
658
|
+
Add [drill-sergeant](https://github.com/ankane/drill-sergeant) to your Gemfile and set:
|
|
659
|
+
|
|
660
|
+
```yml
|
|
661
|
+
data_sources:
|
|
662
|
+
my_source:
|
|
663
|
+
adapter: drill
|
|
664
|
+
url: http://hostname:8047
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
Use a [read-only user](https://drill.apache.org/docs/roles-and-privileges/).
|
|
668
|
+
|
|
669
|
+
### Apache Hive
|
|
670
|
+
|
|
671
|
+
Add [hexspace](https://github.com/ankane/hexspace) to your Gemfile and set:
|
|
672
|
+
|
|
673
|
+
```yml
|
|
674
|
+
data_sources:
|
|
675
|
+
my_source:
|
|
676
|
+
adapter: hive
|
|
677
|
+
url: sasl://user:password@hostname:10000/database
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
Use a [read-only user](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Authorization). Requires [HiveServer2](https://cwiki.apache.org/confluence/display/Hive/Setting+Up+HiveServer2).
|
|
681
|
+
|
|
682
|
+
### Apache Ignite
|
|
683
|
+
|
|
684
|
+
Add [ignite-client](https://github.com/ankane/ignite-ruby) to your Gemfile and set:
|
|
685
|
+
|
|
686
|
+
```yml
|
|
687
|
+
data_sources:
|
|
688
|
+
my_source:
|
|
689
|
+
url: ignite://user:password@hostname:10800
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
Use a [read-only user](https://www.gridgain.com/docs/latest/administrators-guide/security/authorization-permissions) (requires a third-party plugin).
|
|
693
|
+
|
|
694
|
+
### Apache Spark
|
|
695
|
+
|
|
696
|
+
Add [hexspace](https://github.com/ankane/hexspace) to your Gemfile and set:
|
|
697
|
+
|
|
698
|
+
```yml
|
|
699
|
+
data_sources:
|
|
700
|
+
my_source:
|
|
701
|
+
adapter: spark
|
|
702
|
+
url: sasl://user:password@hostname:10000/database
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
Use a read-only user. Requires the [Thrift server](https://spark.apache.org/docs/latest/sql-distributed-sql-engine.html).
|
|
706
|
+
|
|
707
|
+
### Cassandra
|
|
708
|
+
|
|
709
|
+
Add [cassandra-driver](https://github.com/datastax/ruby-driver) (and [sorted_set](https://github.com/knu/sorted_set) for Ruby 3+) to your Gemfile and set:
|
|
710
|
+
|
|
711
|
+
```yml
|
|
712
|
+
data_sources:
|
|
713
|
+
my_source:
|
|
714
|
+
url: cassandra://user:password@hostname:9042/keyspace
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
Use a [read-only role](https://docs.datastax.com/en/cql-oss/3.3/cql/cql_using/useSecurePermission.html).
|
|
718
|
+
|
|
719
|
+
### Druid
|
|
720
|
+
|
|
721
|
+
Enable [SQL support](http://druid.io/docs/latest/querying/sql.html#configuration) on the broker and set:
|
|
722
|
+
|
|
723
|
+
```yml
|
|
724
|
+
data_sources:
|
|
725
|
+
my_source:
|
|
726
|
+
adapter: druid
|
|
727
|
+
url: http://hostname:8082
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
Use a [read-only role](https://druid.apache.org/docs/latest/development/extensions-core/druid-basic-security.html).
|
|
731
|
+
|
|
732
|
+
### Elasticsearch
|
|
733
|
+
|
|
734
|
+
Add [elasticsearch](https://github.com/elastic/elasticsearch-ruby) to your Gemfile and set:
|
|
735
|
+
|
|
736
|
+
```yml
|
|
737
|
+
data_sources:
|
|
738
|
+
my_source:
|
|
739
|
+
adapter: elasticsearch
|
|
740
|
+
url: http://user:password@hostname:9200
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
Use a [read-only role](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-privileges.html).
|
|
744
|
+
|
|
745
|
+
### Google BigQuery
|
|
746
|
+
|
|
747
|
+
Add [google-cloud-bigquery](https://github.com/GoogleCloudPlatform/google-cloud-ruby/tree/master/google-cloud-bigquery) to your Gemfile and set:
|
|
748
|
+
|
|
749
|
+
```yml
|
|
750
|
+
data_sources:
|
|
751
|
+
my_source:
|
|
752
|
+
adapter: bigquery
|
|
753
|
+
project: your-project
|
|
754
|
+
keyfile: path/to/keyfile.json
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
### IBM DB2 and Informix
|
|
758
|
+
|
|
759
|
+
Add [ibm_db](https://github.com/ibmdb/ruby-ibmdb) to your Gemfile and set:
|
|
760
|
+
|
|
761
|
+
```yml
|
|
762
|
+
data_sources:
|
|
763
|
+
my_source:
|
|
764
|
+
url: ibm-db://user:password@hostname:50000/database
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
Use a [read-only user](https://www.ibm.com/support/pages/creating-read-only-database-permissions-user).
|
|
768
|
+
|
|
769
|
+
### InfluxDB
|
|
770
|
+
|
|
771
|
+
Add [influxdb](https://github.com/influxdata/influxdb-ruby) to your Gemfile and set:
|
|
772
|
+
|
|
773
|
+
```yml
|
|
774
|
+
data_sources:
|
|
775
|
+
my_source:
|
|
776
|
+
adapter: influxdb
|
|
777
|
+
url: http://user:password@hostname:8086/database
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
Use a [read-only user](https://docs.influxdata.com/influxdb/v1.8/administration/authentication_and_authorization/). Supports [InfluxQL](https://docs.influxdata.com/influxdb/v1.8/query_language/explore-data/).
|
|
781
|
+
|
|
782
|
+
### MySQL
|
|
783
|
+
|
|
784
|
+
Add [mysql2](https://github.com/brianmario/mysql2) to your Gemfile (if it’s not there) and set:
|
|
785
|
+
|
|
786
|
+
```yml
|
|
787
|
+
data_sources:
|
|
788
|
+
my_source:
|
|
789
|
+
url: mysql2://user:password@hostname:3306/database
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
Use a [read-only user](#mysql).
|
|
793
|
+
|
|
794
|
+
### Neo4j
|
|
795
|
+
|
|
796
|
+
Add [neo4j-core](https://github.com/neo4jrb/neo4j-core) to your Gemfile and set:
|
|
797
|
+
|
|
798
|
+
```yml
|
|
799
|
+
data_sources:
|
|
800
|
+
my_source:
|
|
801
|
+
adapter: neo4j
|
|
802
|
+
url: http://user:password@hostname:7474
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
Use a [read-only user](https://neo4j.com/docs/cypher-manual/current/access-control/manage-privileges/).
|
|
806
|
+
|
|
807
|
+
### OpenSearch
|
|
808
|
+
|
|
809
|
+
Add [opensearch-ruby](https://github.com/opensearch-project/opensearch-ruby) to your Gemfile and set:
|
|
810
|
+
|
|
811
|
+
```yml
|
|
812
|
+
data_sources:
|
|
813
|
+
my_source:
|
|
814
|
+
adapter: opensearch
|
|
815
|
+
url: http://user:password@hostname:9200
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
Use a [read-only user](https://opensearch.org/docs/latest/security-plugin/access-control/permissions/).
|
|
819
|
+
|
|
820
|
+
### Oracle
|
|
821
|
+
|
|
822
|
+
Add [activerecord-oracle_enhanced-adapter](https://github.com/rsim/oracle-enhanced) and [ruby-oci8](https://github.com/kubo/ruby-oci8) to your Gemfile and set:
|
|
823
|
+
|
|
824
|
+
```yml
|
|
825
|
+
data_sources:
|
|
826
|
+
my_source:
|
|
827
|
+
url: oracle-enhanced://user:password@hostname:1521/database
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
Use a [read-only user](https://docs.oracle.com/cd/B19306_01/network.102/b14266/authoriz.htm).
|
|
831
|
+
|
|
832
|
+
### PostgreSQL
|
|
833
|
+
|
|
834
|
+
Add [pg](https://github.com/ged/ruby-pg) to your Gemfile (if it’s not there) and set:
|
|
835
|
+
|
|
836
|
+
```yml
|
|
837
|
+
data_sources:
|
|
838
|
+
my_source:
|
|
839
|
+
url: postgres://user:password@hostname:5432/database
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
Use a [read-only user](#postgresql).
|
|
843
|
+
|
|
844
|
+
### Presto
|
|
845
|
+
|
|
846
|
+
Add [presto-client](https://github.com/treasure-data/presto-client-ruby) to your Gemfile and set:
|
|
847
|
+
|
|
848
|
+
```yml
|
|
849
|
+
data_sources:
|
|
850
|
+
my_source:
|
|
851
|
+
url: presto://user@hostname:8080/catalog
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
Use a [read-only user](https://prestodb.io/docs/current/security/built-in-system-access-control.html).
|
|
855
|
+
|
|
856
|
+
### Salesforce
|
|
857
|
+
|
|
858
|
+
Add [restforce](https://github.com/restforce/restforce) to your Gemfile and set:
|
|
859
|
+
|
|
860
|
+
```yml
|
|
861
|
+
data_sources:
|
|
862
|
+
my_source:
|
|
863
|
+
adapter: salesforce
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
And set the appropriate environment variables:
|
|
867
|
+
|
|
868
|
+
```sh
|
|
869
|
+
SALESFORCE_USERNAME="username"
|
|
870
|
+
SALESFORCE_PASSWORD="password"
|
|
871
|
+
SALESFORCE_SECURITY_TOKEN="security token"
|
|
872
|
+
SALESFORCE_CLIENT_ID="client id"
|
|
873
|
+
SALESFORCE_CLIENT_SECRET="client secret"
|
|
874
|
+
SALESFORCE_API_VERSION="41.0"
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
Use a read-only user. Supports [SOQL](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql.htm).
|
|
878
|
+
|
|
879
|
+
### Socrata Open Data API (SODA)
|
|
880
|
+
|
|
881
|
+
Set:
|
|
882
|
+
|
|
883
|
+
```yml
|
|
884
|
+
data_sources:
|
|
885
|
+
my_source:
|
|
886
|
+
adapter: soda
|
|
887
|
+
url: https://soda.demo.socrata.com/resource/4tka-6guv.json
|
|
888
|
+
app_token: ...
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
Supports [SoQL](https://dev.socrata.com/docs/functions/).
|
|
892
|
+
|
|
893
|
+
### Snowflake
|
|
894
|
+
|
|
895
|
+
First, install ODBC. For Homebrew, use:
|
|
896
|
+
|
|
897
|
+
```sh
|
|
898
|
+
brew install unixodbc
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
For Ubuntu, use:
|
|
902
|
+
|
|
903
|
+
```sh
|
|
904
|
+
sudo apt-get install unixodbc-dev
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
For Heroku, use the [Apt buildpack](https://github.com/heroku/heroku-buildpack-apt) and create an `Aptfile` with:
|
|
908
|
+
|
|
909
|
+
```text
|
|
910
|
+
unixodbc-dev
|
|
911
|
+
https://sfc-repo.snowflakecomputing.com/odbc/linux/2.21.5/snowflake-odbc-2.21.5.x86_64.deb
|
|
912
|
+
```
|
|
913
|
+
|
|
914
|
+
> This installs the driver at `/app/.apt/usr/lib/snowflake/odbc/lib/libSnowflake.so`
|
|
915
|
+
|
|
916
|
+
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:
|
|
917
|
+
|
|
918
|
+
```yml
|
|
919
|
+
data_sources:
|
|
920
|
+
my_source:
|
|
921
|
+
adapter: snowflake
|
|
922
|
+
conn_str: Driver=/path/to/libSnowflake.so;uid=user;pwd=password;server=host.snowflakecomputing.com
|
|
923
|
+
```
|
|
924
|
+
|
|
925
|
+
Use a [read-only role](https://docs.snowflake.com/en/user-guide/security-access-control-configure.html).
|
|
926
|
+
|
|
927
|
+
### SQLite
|
|
928
|
+
|
|
929
|
+
Add [sqlite3](https://github.com/sparklemotion/sqlite3-ruby) to your Gemfile and set:
|
|
930
|
+
|
|
931
|
+
```yml
|
|
932
|
+
data_sources:
|
|
933
|
+
my_source:
|
|
934
|
+
url: sqlite3:path/to/database.sqlite3
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
### SQL Server
|
|
938
|
+
|
|
939
|
+
Add [tiny_tds](https://github.com/rails-sqlserver/tiny_tds) and [activerecord-sqlserver-adapter](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter) to your Gemfile and set:
|
|
940
|
+
|
|
941
|
+
```yml
|
|
942
|
+
data_sources:
|
|
943
|
+
my_source:
|
|
944
|
+
url: sqlserver://user:password@hostname:1433/database
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
Use a [read-only user](https://docs.microsoft.com/en-us/sql/relational-databases/security/authentication-access/getting-started-with-database-engine-permissions?view=sql-server-ver15).
|
|
948
|
+
|
|
949
|
+
## Creating an Adapter
|
|
950
|
+
|
|
951
|
+
Create an adapter for any data store with:
|
|
952
|
+
|
|
953
|
+
```ruby
|
|
954
|
+
class FooAdapter < Blazer::Adapters::BaseAdapter
|
|
955
|
+
# code goes here
|
|
956
|
+
end
|
|
957
|
+
|
|
958
|
+
Blazer.register_adapter "foo", FooAdapter
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
See the [Presto adapter](https://github.com/ankane/blazer/blob/master/lib/blazer/adapters/presto_adapter.rb) for a good example. Then use:
|
|
962
|
+
|
|
963
|
+
```yml
|
|
964
|
+
data_sources:
|
|
965
|
+
my_source:
|
|
966
|
+
adapter: foo
|
|
967
|
+
url: http://user:password@hostname:9200/
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
## Query Permissions
|
|
971
|
+
|
|
972
|
+
Blazer supports a basic permissions model.
|
|
973
|
+
|
|
974
|
+
1. Queries without a name are unlisted
|
|
975
|
+
2. Queries whose name starts with `#` are only listed to the creator
|
|
976
|
+
3. Queries whose name starts with `*` can only be edited by the creator
|
|
977
|
+
|
|
978
|
+
## Learn SQL
|
|
979
|
+
|
|
980
|
+
Have team members who want to learn SQL? Here are a few great, free resources.
|
|
981
|
+
|
|
982
|
+
- [The Data School](https://dataschool.com/learn-sql/)
|
|
983
|
+
- [SQLBolt](https://sqlbolt.com/)
|
|
984
|
+
|
|
985
|
+
## Useful Tools
|
|
986
|
+
|
|
987
|
+
For an easy way to group by day, week, month, and more with correct time zones, check out [Groupdate.sql](https://github.com/ankane/groupdate.sql).
|
|
988
|
+
|
|
989
|
+
## Standalone Version
|
|
990
|
+
|
|
991
|
+
Looking for a standalone version? Check out [Ghost Blazer](https://github.com/buren/ghost_blazer).
|
|
992
|
+
|
|
993
|
+
## Performance
|
|
994
|
+
|
|
995
|
+
By default, queries take up a request while they are running. To run queries asynchronously, add to your config:
|
|
996
|
+
|
|
997
|
+
```yml
|
|
998
|
+
async: true
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
**Note:** Requires caching to be enabled. If you have multiple web processes, your app must use a centralized cache store like Memcached or Redis.
|
|
1002
|
+
|
|
1003
|
+
```ruby
|
|
1004
|
+
config.cache_store = :mem_cache_store
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
## Archiving
|
|
1008
|
+
|
|
1009
|
+
Archive queries that haven’t been viewed in over 90 days.
|
|
1010
|
+
|
|
1011
|
+
```sh
|
|
1012
|
+
rake blazer:archive_queries
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
## Content Security Policy
|
|
1016
|
+
|
|
1017
|
+
If views are stuck with a `Loading...` message, there might be a problem with strict CSP settings in your app. This can be checked with Firefox or Chrome dev tools. You can allow Blazer to override these settings for its controllers with:
|
|
1018
|
+
|
|
1019
|
+
```yml
|
|
1020
|
+
override_csp: true
|
|
1021
|
+
```
|
|
1022
|
+
|
|
1023
|
+
## Upgrading
|
|
1024
|
+
|
|
1025
|
+
### 3.0
|
|
1026
|
+
|
|
1027
|
+
Maps now use Mapbox GL JS v1 instead of Mapbox.js, which affects Mapbox billing.
|
|
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
|
+
## History
|
|
1075
|
+
|
|
1076
|
+
View the [changelog](https://github.com/ankane/blazer/blob/master/CHANGELOG.md)
|
|
1077
|
+
|
|
1078
|
+
## Thanks
|
|
1079
|
+
|
|
1080
|
+
Blazer uses a number of awesome open source projects, including [Rails](https://github.com/rails/rails/), [Vue.js](https://github.com/vuejs/vue), [jQuery](https://github.com/jquery/jquery), [Bootstrap](https://github.com/twbs/bootstrap), [Selectize](https://github.com/brianreavis/selectize.js), [StickyTableHeaders](https://github.com/jmosbech/StickyTableHeaders), [Stupid jQuery Table Sort](https://github.com/joequery/Stupid-Table-Plugin), and [Date Range Picker](https://github.com/dangrossman/bootstrap-daterangepicker).
|
|
1081
|
+
|
|
1082
|
+
Demo data from [MovieLens](https://grouplens.org/datasets/movielens/).
|
|
1083
|
+
|
|
1084
|
+
## Want to Make Blazer Better?
|
|
1085
|
+
|
|
1086
|
+
That’s awesome! Here are a few ways you can help:
|
|
1087
|
+
|
|
1088
|
+
- [Report bugs](https://github.com/ankane/blazer/issues)
|
|
1089
|
+
- Fix bugs and [submit pull requests](https://github.com/ankane/blazer/pulls)
|
|
1090
|
+
- Write, clarify, or fix documentation
|
|
1091
|
+
- Suggest or add new features
|
|
1092
|
+
|
|
1093
|
+
Check out the [dev app](https://github.com/ankane/blazer-dev) to get started.
|