blazer 2.4.7 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -0
- data/README.md +89 -49
- data/app/assets/stylesheets/blazer/application.css +1 -0
- data/app/assets/stylesheets/blazer/bootstrap-propshaft.css +10 -0
- data/app/assets/stylesheets/blazer/bootstrap-sprockets.css.erb +10 -0
- data/app/assets/stylesheets/blazer/{bootstrap.css.erb → bootstrap.css} +0 -6
- data/app/controllers/blazer/base_controller.rb +45 -45
- data/app/controllers/blazer/dashboards_controller.rb +4 -11
- data/app/controllers/blazer/queries_controller.rb +28 -48
- data/app/models/blazer/query.rb +8 -2
- data/app/views/blazer/_variables.html.erb +5 -4
- data/app/views/blazer/dashboards/_form.html.erb +1 -1
- data/app/views/blazer/dashboards/show.html.erb +4 -4
- data/app/views/blazer/queries/_caching.html.erb +1 -1
- data/app/views/blazer/queries/_form.html.erb +3 -3
- data/app/views/blazer/queries/run.html.erb +1 -1
- data/app/views/blazer/queries/show.html.erb +12 -7
- data/app/views/layouts/blazer/application.html.erb +7 -2
- data/lib/blazer/adapters/athena_adapter.rb +51 -15
- data/lib/blazer/adapters/base_adapter.rb +16 -1
- data/lib/blazer/adapters/bigquery_adapter.rb +13 -2
- data/lib/blazer/adapters/cassandra_adapter.rb +15 -4
- data/lib/blazer/adapters/drill_adapter.rb +10 -0
- data/lib/blazer/adapters/druid_adapter.rb +36 -1
- data/lib/blazer/adapters/elasticsearch_adapter.rb +19 -4
- data/lib/blazer/adapters/hive_adapter.rb +10 -0
- data/lib/blazer/adapters/ignite_adapter.rb +12 -2
- data/lib/blazer/adapters/influxdb_adapter.rb +22 -10
- data/lib/blazer/adapters/mongodb_adapter.rb +4 -0
- data/lib/blazer/adapters/neo4j_adapter.rb +17 -2
- data/lib/blazer/adapters/opensearch_adapter.rb +52 -0
- data/lib/blazer/adapters/presto_adapter.rb +9 -0
- data/lib/blazer/adapters/salesforce_adapter.rb +5 -0
- data/lib/blazer/adapters/snowflake_adapter.rb +9 -0
- data/lib/blazer/adapters/soda_adapter.rb +9 -0
- data/lib/blazer/adapters/spark_adapter.rb +5 -0
- data/lib/blazer/adapters/sql_adapter.rb +34 -4
- data/lib/blazer/data_source.rb +85 -5
- data/lib/blazer/engine.rb +1 -4
- data/lib/blazer/result.rb +4 -0
- data/lib/blazer/run_statement.rb +7 -3
- data/lib/blazer/run_statement_job.rb +4 -2
- data/lib/blazer/slack_notifier.rb +19 -4
- data/lib/blazer/statement.rb +75 -0
- data/lib/blazer/version.rb +1 -1
- data/lib/blazer.rb +27 -8
- data/lib/generators/blazer/templates/config.yml.tt +1 -1
- data/lib/tasks/blazer.rake +5 -5
- metadata +8 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8bdfc1e428f7e01bf9a06461a5f0143a6e940cd1e3d708ba2bd504132bbaa1db
|
|
4
|
+
data.tar.gz: 729e9a408e7f4fa5203ab4c133800e49087fccf634efcf7c9dd6ca80a610a861
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e6c7a7be80246c1030170a5df95656947b2431cf908bb6d37d668cbe3f57006ef096d63186976c63c683f0e2511873cabb5d2be56e389de331487666ba297dc3
|
|
7
|
+
data.tar.gz: 9feb70216244f77d37357376cd68b9ec85a6d3eeb3c89f3e58196688e81618ca2ae38372e5491e0811bdd7d9e0082317a711040f5782cc54f5d9f99ec57d624a
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
## 2.6.0 (2022-04-20)
|
|
2
|
+
|
|
3
|
+
- Fixed quoting issue with variables
|
|
4
|
+
- Custom adapters now need to specify how to quote variables in queries
|
|
5
|
+
- Added experimental support for Propshaft
|
|
6
|
+
- Fixed error with empty results with InfluxDB
|
|
7
|
+
|
|
8
|
+
## 2.5.0 (2022-01-04)
|
|
9
|
+
|
|
10
|
+
- Added support for Slack OAuth tokens
|
|
11
|
+
- Added experimental support for AnomalyDetection.rb
|
|
12
|
+
- Improved table preview for MySQL
|
|
13
|
+
- Fixed cohort analysis for MySQL
|
|
14
|
+
|
|
15
|
+
## 2.4.8 (2021-12-07)
|
|
16
|
+
|
|
17
|
+
- Added support for OpenSearch
|
|
18
|
+
- Removed `elasticsearch-xpack` dependency for Elasticsearch
|
|
19
|
+
|
|
1
20
|
## 2.4.7 (2021-09-25)
|
|
2
21
|
|
|
3
22
|
- Made Action Mailer optional
|
data/README.md
CHANGED
|
@@ -10,6 +10,8 @@ Blazer is also available as a [Docker image](https://github.com/ankane/blazer-do
|
|
|
10
10
|
|
|
11
11
|
:tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
|
|
12
12
|
|
|
13
|
+
[](https://github.com/ankane/blazer/actions)
|
|
14
|
+
|
|
13
15
|
## Features
|
|
14
16
|
|
|
15
17
|
- **Multiple data sources** - PostgreSQL, MySQL, Redshift, and [many more](#full-list)
|
|
@@ -37,7 +39,7 @@ Blazer is also available as a [Docker image](https://github.com/ankane/blazer-do
|
|
|
37
39
|
Add this line to your application’s Gemfile:
|
|
38
40
|
|
|
39
41
|
```ruby
|
|
40
|
-
gem
|
|
42
|
+
gem "blazer"
|
|
41
43
|
```
|
|
42
44
|
|
|
43
45
|
Run:
|
|
@@ -59,7 +61,7 @@ For production, specify your database:
|
|
|
59
61
|
ENV["BLAZER_DATABASE_URL"] = "postgres://user:password@hostname:5432/database"
|
|
60
62
|
```
|
|
61
63
|
|
|
62
|
-
Blazer tries to protect against queries which modify data
|
|
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).
|
|
63
65
|
|
|
64
66
|
#### Checks (optional)
|
|
65
67
|
|
|
@@ -142,11 +144,9 @@ Be sure to render or redirect for unauthorized users.
|
|
|
142
144
|
|
|
143
145
|
## Permissions
|
|
144
146
|
|
|
145
|
-
Blazer runs each query in a transaction and rolls it back to prevent queries from modifying data. As an additional line of defense, we recommend using a read only user.
|
|
146
|
-
|
|
147
147
|
### PostgreSQL
|
|
148
148
|
|
|
149
|
-
Create a user with read
|
|
149
|
+
Create a user with read-only permissions:
|
|
150
150
|
|
|
151
151
|
```sql
|
|
152
152
|
BEGIN;
|
|
@@ -160,7 +160,7 @@ COMMIT;
|
|
|
160
160
|
|
|
161
161
|
### MySQL
|
|
162
162
|
|
|
163
|
-
Create a user with read
|
|
163
|
+
Create a user with read-only permissions:
|
|
164
164
|
|
|
165
165
|
```sql
|
|
166
166
|
GRANT SELECT, SHOW VIEW ON database_name.* TO blazer@’127.0.0.1′ IDENTIFIED BY ‘secret123‘;
|
|
@@ -169,7 +169,7 @@ FLUSH PRIVILEGES;
|
|
|
169
169
|
|
|
170
170
|
### MongoDB
|
|
171
171
|
|
|
172
|
-
Create a user with read
|
|
172
|
+
Create a user with read-only permissions:
|
|
173
173
|
|
|
174
174
|
```
|
|
175
175
|
db.createUser({user: "blazer", pwd: "password", roles: ["read"]})
|
|
@@ -412,7 +412,7 @@ SELECT users.id AS user_id, orders.created_at AS conversion_time, users.created_
|
|
|
412
412
|
FROM users LEFT JOIN orders ON orders.user_id = users.id
|
|
413
413
|
```
|
|
414
414
|
|
|
415
|
-
This feature requires PostgreSQL or MySQL.
|
|
415
|
+
This feature requires PostgreSQL or MySQL 8.
|
|
416
416
|
|
|
417
417
|
## Anomaly Detection
|
|
418
418
|
|
|
@@ -423,7 +423,7 @@ Blazer supports three different approaches to anomaly detection.
|
|
|
423
423
|
Add [prophet-rb](https://github.com/ankane/prophet) to your Gemfile:
|
|
424
424
|
|
|
425
425
|
```ruby
|
|
426
|
-
gem
|
|
426
|
+
gem "prophet-rb"
|
|
427
427
|
```
|
|
428
428
|
|
|
429
429
|
And add to `config/blazer.yml`:
|
|
@@ -439,7 +439,7 @@ anomaly_checks: prophet
|
|
|
439
439
|
Add [trend](https://github.com/ankane/trend) to your Gemfile:
|
|
440
440
|
|
|
441
441
|
```ruby
|
|
442
|
-
gem
|
|
442
|
+
gem "trend"
|
|
443
443
|
```
|
|
444
444
|
|
|
445
445
|
And add to `config/blazer.yml`:
|
|
@@ -454,46 +454,20 @@ For the [self-hosted API](https://github.com/ankane/trend-api), create an initia
|
|
|
454
454
|
Trend.url = "http://localhost:8000"
|
|
455
455
|
```
|
|
456
456
|
|
|
457
|
-
###
|
|
457
|
+
### AnomalyDetection.rb (experimental)
|
|
458
458
|
|
|
459
|
-
|
|
459
|
+
Add [anomaly_detection](https://github.com/ankane/AnomalyDetection.rb) to your Gemfile:
|
|
460
460
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
```R
|
|
464
|
-
install.packages("remotes")
|
|
465
|
-
remotes::install_github("twitter/AnomalyDetection")
|
|
461
|
+
```ruby
|
|
462
|
+
gem "anomaly_detection"
|
|
466
463
|
```
|
|
467
464
|
|
|
468
465
|
And add to `config/blazer.yml`:
|
|
469
466
|
|
|
470
467
|
```yml
|
|
471
|
-
anomaly_checks:
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
If upgrading from version 1.4 or below, also follow the [upgrade instructions](#15).
|
|
475
|
-
|
|
476
|
-
If you’re on Heroku, follow the additional instructions below.
|
|
477
|
-
|
|
478
|
-
### R on Heroku
|
|
479
|
-
|
|
480
|
-
Add the [R buildpack](https://github.com/virtualstaticvoid/heroku-buildpack-r) to your app.
|
|
481
|
-
|
|
482
|
-
```sh
|
|
483
|
-
heroku buildpacks:add --index 1 https://github.com/virtualstaticvoid/heroku-buildpack-r.git
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
And create an `init.R` with:
|
|
487
|
-
|
|
488
|
-
```r
|
|
489
|
-
if (!"AnomalyDetection" %in% installed.packages()) {
|
|
490
|
-
install.packages("remotes")
|
|
491
|
-
remotes::install_github("twitter/AnomalyDetection")
|
|
492
|
-
}
|
|
468
|
+
anomaly_checks: anomaly_detection
|
|
493
469
|
```
|
|
494
470
|
|
|
495
|
-
Commit and deploy away. The first deploy may take a few minutes.
|
|
496
|
-
|
|
497
471
|
## Forecasting
|
|
498
472
|
|
|
499
473
|
Blazer supports for two different forecasting methods. [Example](https://blazer.dokkuapp.com/queries/18-forecast?forecast=t)
|
|
@@ -502,10 +476,10 @@ A forecast link will appear for queries that return 2 columns with types timesta
|
|
|
502
476
|
|
|
503
477
|
### Prophet
|
|
504
478
|
|
|
505
|
-
Add [prophet](https://github.com/ankane/prophet) to your Gemfile:
|
|
479
|
+
Add [prophet-rb](https://github.com/ankane/prophet) to your Gemfile:
|
|
506
480
|
|
|
507
481
|
```ruby
|
|
508
|
-
gem
|
|
482
|
+
gem "prophet-rb", ">= 0.2.1"
|
|
509
483
|
```
|
|
510
484
|
|
|
511
485
|
And add to `config/blazer.yml`:
|
|
@@ -516,12 +490,12 @@ forecasting: prophet
|
|
|
516
490
|
|
|
517
491
|
### Trend
|
|
518
492
|
|
|
519
|
-
[Trend](https://trendapi.org/) uses an external service.
|
|
493
|
+
[Trend](https://trendapi.org/) uses an external service by default, but you can run it on your own infrastructure as well.
|
|
520
494
|
|
|
521
495
|
Add [trend](https://github.com/ankane/trend) to your Gemfile:
|
|
522
496
|
|
|
523
497
|
```ruby
|
|
524
|
-
gem
|
|
498
|
+
gem "trend"
|
|
525
499
|
```
|
|
526
500
|
|
|
527
501
|
And add to `config/blazer.yml`:
|
|
@@ -530,6 +504,12 @@ And add to `config/blazer.yml`:
|
|
|
530
504
|
forecasting: trend
|
|
531
505
|
```
|
|
532
506
|
|
|
507
|
+
For the [self-hosted API](https://github.com/ankane/trend-api), create an initializer with:
|
|
508
|
+
|
|
509
|
+
```ruby
|
|
510
|
+
Trend.url = "http://localhost:8000"
|
|
511
|
+
```
|
|
512
|
+
|
|
533
513
|
## Uploads
|
|
534
514
|
|
|
535
515
|
Creating database tables from CSV files. [Example](https://blazer.dokkuapp.com/uploads)
|
|
@@ -592,6 +572,7 @@ data_sources:
|
|
|
592
572
|
- [MongoDB](#mongodb-1)
|
|
593
573
|
- [MySQL](#mysql-1)
|
|
594
574
|
- [Neo4j](#neo4j)
|
|
575
|
+
- [OpenSearch](#opensearch)
|
|
595
576
|
- [Oracle](#oracle)
|
|
596
577
|
- [PostgreSQL](#postgresql-1)
|
|
597
578
|
- [Presto](#presto)
|
|
@@ -673,6 +654,8 @@ data_sources:
|
|
|
673
654
|
url: redshift://user:password@hostname:5439/database
|
|
674
655
|
```
|
|
675
656
|
|
|
657
|
+
Use a [read-only user](https://docs.aws.amazon.com/redshift/latest/dg/r_GRANT.html).
|
|
658
|
+
|
|
676
659
|
### Apache Drill
|
|
677
660
|
|
|
678
661
|
Add [drill-sergeant](https://github.com/ankane/drill-sergeant) to your Gemfile and set:
|
|
@@ -684,6 +667,8 @@ data_sources:
|
|
|
684
667
|
url: http://hostname:8047
|
|
685
668
|
```
|
|
686
669
|
|
|
670
|
+
Use a [read-only user](https://drill.apache.org/docs/roles-and-privileges/).
|
|
671
|
+
|
|
687
672
|
### Apache Hive
|
|
688
673
|
|
|
689
674
|
Add [hexspace](https://github.com/ankane/hexspace) to your Gemfile and set:
|
|
@@ -707,6 +692,8 @@ data_sources:
|
|
|
707
692
|
url: ignite://user:password@hostname:10800
|
|
708
693
|
```
|
|
709
694
|
|
|
695
|
+
Use a [read-only user](https://www.gridgain.com/docs/latest/administrators-guide/security/authorization-permissions) (requires a third-party plugin).
|
|
696
|
+
|
|
710
697
|
### Apache Spark
|
|
711
698
|
|
|
712
699
|
Add [hexspace](https://github.com/ankane/hexspace) to your Gemfile and set:
|
|
@@ -730,6 +717,8 @@ data_sources:
|
|
|
730
717
|
url: cassandra://user:password@hostname:9042/keyspace
|
|
731
718
|
```
|
|
732
719
|
|
|
720
|
+
Use a [read-only role](https://docs.datastax.com/en/cql-oss/3.3/cql/cql_using/useSecurePermission.html).
|
|
721
|
+
|
|
733
722
|
### Druid
|
|
734
723
|
|
|
735
724
|
Enable [SQL support](http://druid.io/docs/latest/querying/sql.html#configuration) on the broker and set:
|
|
@@ -741,9 +730,11 @@ data_sources:
|
|
|
741
730
|
url: http://hostname:8082
|
|
742
731
|
```
|
|
743
732
|
|
|
733
|
+
Use a [read-only role](https://druid.apache.org/docs/latest/development/extensions-core/druid-basic-security.html).
|
|
734
|
+
|
|
744
735
|
### Elasticsearch
|
|
745
736
|
|
|
746
|
-
Add [elasticsearch](https://github.com/elastic/elasticsearch-ruby)
|
|
737
|
+
Add [elasticsearch](https://github.com/elastic/elasticsearch-ruby) to your Gemfile and set:
|
|
747
738
|
|
|
748
739
|
```yml
|
|
749
740
|
data_sources:
|
|
@@ -752,6 +743,8 @@ data_sources:
|
|
|
752
743
|
url: http://user:password@hostname:9200
|
|
753
744
|
```
|
|
754
745
|
|
|
746
|
+
Use a [read-only role](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-privileges.html).
|
|
747
|
+
|
|
755
748
|
### Google BigQuery
|
|
756
749
|
|
|
757
750
|
Add [google-cloud-bigquery](https://github.com/GoogleCloudPlatform/google-cloud-ruby/tree/master/google-cloud-bigquery) to your Gemfile and set:
|
|
@@ -774,6 +767,8 @@ data_sources:
|
|
|
774
767
|
url: ibm-db://user:password@hostname:50000/database
|
|
775
768
|
```
|
|
776
769
|
|
|
770
|
+
Use a [read-only user](https://www.ibm.com/support/pages/creating-read-only-database-permissions-user).
|
|
771
|
+
|
|
777
772
|
### InfluxDB
|
|
778
773
|
|
|
779
774
|
Add [influxdb](https://github.com/influxdata/influxdb-ruby) to your Gemfile and set:
|
|
@@ -785,7 +780,7 @@ data_sources:
|
|
|
785
780
|
url: http://user:password@hostname:8086/database
|
|
786
781
|
```
|
|
787
782
|
|
|
788
|
-
Supports [InfluxQL](https://docs.influxdata.com/influxdb/v1.8/query_language/explore-data/)
|
|
783
|
+
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/).
|
|
789
784
|
|
|
790
785
|
### MongoDB
|
|
791
786
|
|
|
@@ -799,6 +794,8 @@ data_sources:
|
|
|
799
794
|
url: mongodb://user:password@hostname:27017/database
|
|
800
795
|
```
|
|
801
796
|
|
|
797
|
+
Use a [read-only user](#mongodb).
|
|
798
|
+
|
|
802
799
|
### MySQL
|
|
803
800
|
|
|
804
801
|
Add [mysql2](https://github.com/brianmario/mysql2) to your Gemfile (if it’s not there) and set:
|
|
@@ -809,6 +806,8 @@ data_sources:
|
|
|
809
806
|
url: mysql2://user:password@hostname:3306/database
|
|
810
807
|
```
|
|
811
808
|
|
|
809
|
+
Use a [read-only user](#mysql).
|
|
810
|
+
|
|
812
811
|
### Neo4j
|
|
813
812
|
|
|
814
813
|
Add [neo4j-core](https://github.com/neo4jrb/neo4j-core) to your Gemfile and set:
|
|
@@ -820,6 +819,21 @@ data_sources:
|
|
|
820
819
|
url: http://user:password@hostname:7474
|
|
821
820
|
```
|
|
822
821
|
|
|
822
|
+
Use a [read-only user](https://neo4j.com/docs/cypher-manual/current/access-control/manage-privileges/).
|
|
823
|
+
|
|
824
|
+
### OpenSearch
|
|
825
|
+
|
|
826
|
+
Add [opensearch-ruby](https://github.com/opensearch-project/opensearch-ruby) to your Gemfile and set:
|
|
827
|
+
|
|
828
|
+
```yml
|
|
829
|
+
data_sources:
|
|
830
|
+
my_source:
|
|
831
|
+
adapter: opensearch
|
|
832
|
+
url: http://user:password@hostname:9200
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
Use a [read-only user](https://opensearch.org/docs/latest/security-plugin/access-control/permissions/).
|
|
836
|
+
|
|
823
837
|
### Oracle
|
|
824
838
|
|
|
825
839
|
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:
|
|
@@ -830,6 +844,8 @@ data_sources:
|
|
|
830
844
|
url: oracle-enhanced://user:password@hostname:1521/database
|
|
831
845
|
```
|
|
832
846
|
|
|
847
|
+
Use a [read-only user](https://docs.oracle.com/cd/B19306_01/network.102/b14266/authoriz.htm).
|
|
848
|
+
|
|
833
849
|
### PostgreSQL
|
|
834
850
|
|
|
835
851
|
Add [pg](https://github.com/ged/ruby-pg) to your Gemfile (if it’s not there) and set:
|
|
@@ -840,6 +856,8 @@ data_sources:
|
|
|
840
856
|
url: postgres://user:password@hostname:5432/database
|
|
841
857
|
```
|
|
842
858
|
|
|
859
|
+
Use a [read-only user](#postgresql).
|
|
860
|
+
|
|
843
861
|
### Presto
|
|
844
862
|
|
|
845
863
|
Add [presto-client](https://github.com/treasure-data/presto-client-ruby) to your Gemfile and set:
|
|
@@ -850,6 +868,8 @@ data_sources:
|
|
|
850
868
|
url: presto://user@hostname:8080/catalog
|
|
851
869
|
```
|
|
852
870
|
|
|
871
|
+
Use a [read-only user](https://prestodb.io/docs/current/security/built-in-system-access-control.html).
|
|
872
|
+
|
|
853
873
|
### Salesforce
|
|
854
874
|
|
|
855
875
|
Add [restforce](https://github.com/restforce/restforce) to your Gemfile and set:
|
|
@@ -871,7 +891,7 @@ SALESFORCE_CLIENT_SECRET="client secret"
|
|
|
871
891
|
SALESFORCE_API_VERSION="41.0"
|
|
872
892
|
```
|
|
873
893
|
|
|
874
|
-
Supports [SOQL](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql.htm)
|
|
894
|
+
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).
|
|
875
895
|
|
|
876
896
|
### Socrata Open Data API (SODA)
|
|
877
897
|
|
|
@@ -885,7 +905,7 @@ data_sources:
|
|
|
885
905
|
app_token: ...
|
|
886
906
|
```
|
|
887
907
|
|
|
888
|
-
Supports [SoQL](https://dev.socrata.com/docs/functions/)
|
|
908
|
+
Supports [SoQL](https://dev.socrata.com/docs/functions/).
|
|
889
909
|
|
|
890
910
|
### Snowflake
|
|
891
911
|
|
|
@@ -919,6 +939,8 @@ data_sources:
|
|
|
919
939
|
conn_str: Driver=/path/to/libSnowflake.so;uid=user;pwd=password;server=host.snowflakecomputing.com
|
|
920
940
|
```
|
|
921
941
|
|
|
942
|
+
Use a [read-only role](https://docs.snowflake.com/en/user-guide/security-access-control-configure.html).
|
|
943
|
+
|
|
922
944
|
### SQLite
|
|
923
945
|
|
|
924
946
|
Add [sqlite3](https://github.com/sparklemotion/sqlite3-ruby) to your Gemfile and set:
|
|
@@ -939,6 +961,8 @@ data_sources:
|
|
|
939
961
|
url: sqlserver://user:password@hostname:1433/database
|
|
940
962
|
```
|
|
941
963
|
|
|
964
|
+
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).
|
|
965
|
+
|
|
942
966
|
## Creating an Adapter
|
|
943
967
|
|
|
944
968
|
Create an adapter for any data store with:
|
|
@@ -1015,6 +1039,22 @@ override_csp: true
|
|
|
1015
1039
|
|
|
1016
1040
|
## Upgrading
|
|
1017
1041
|
|
|
1042
|
+
### 2.6
|
|
1043
|
+
|
|
1044
|
+
Custom adapters now need to specify how to quote variables in queries (there is no longer a default)
|
|
1045
|
+
|
|
1046
|
+
```ruby
|
|
1047
|
+
class FooAdapter < Blazer::Adapters::BaseAdapter
|
|
1048
|
+
def quoting
|
|
1049
|
+
:backslash_escape # single quote strings and convert ' to \' and \ to \\
|
|
1050
|
+
# or
|
|
1051
|
+
:single_quote_escape # single quote strings and convert ' to ''
|
|
1052
|
+
# or
|
|
1053
|
+
->(value) { ... } # custom method
|
|
1054
|
+
end
|
|
1055
|
+
end
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1018
1058
|
### 2.3
|
|
1019
1059
|
|
|
1020
1060
|
To archive queries, create a migration
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Bootstrap v3.4.1 (https://getbootstrap.com/)
|
|
3
|
+
* Copyright 2011-2019 Twitter, Inc.
|
|
4
|
+
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
5
|
+
*/
|
|
6
|
+
@font-face {
|
|
7
|
+
font-family: "Glyphicons Halflings";
|
|
8
|
+
src: url('/blazer/glyphicons-halflings-regular.eot');
|
|
9
|
+
src: url('/blazer/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('/blazer/glyphicons-halflings-regular.woff2') format('woff2'), url('/blazer/glyphicons-halflings-regular.woff') format('woff'), url('/blazer/glyphicons-halflings-regular.ttf') format('truetype'), url('/blazer/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Bootstrap v3.4.1 (https://getbootstrap.com/)
|
|
3
|
+
* Copyright 2011-2019 Twitter, Inc.
|
|
4
|
+
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
5
|
+
*/
|
|
6
|
+
@font-face {
|
|
7
|
+
font-family: "Glyphicons Halflings";
|
|
8
|
+
src: url('<%= font_path("blazer/glyphicons-halflings-regular.eot") %>');
|
|
9
|
+
src: url('<%= font_path("blazer/glyphicons-halflings-regular.eot?#iefix") %>') format('embedded-opentype'), url('<%= font_path("blazer/glyphicons-halflings-regular.woff2") %>') format('woff2'), url('<%= font_path("blazer/glyphicons-halflings-regular.woff") %>') format('woff'), url('<%= font_path("blazer/glyphicons-halflings-regular.ttf") %>') format('truetype'), url('<%= font_path("blazer/glyphicons-halflings-regular.svg#glyphicons_halflingsregular") %>') format('svg');
|
|
10
|
+
}
|
|
@@ -263,11 +263,6 @@ th {
|
|
|
263
263
|
border: 1px solid #ddd !important;
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
|
-
@font-face {
|
|
267
|
-
font-family: "Glyphicons Halflings";
|
|
268
|
-
src: url('<%= font_path("blazer/glyphicons-halflings-regular.eot") %>');
|
|
269
|
-
src: url('<%= font_path("blazer/glyphicons-halflings-regular.eot?#iefix") %>') format('embedded-opentype'), url('<%= font_path("blazer/glyphicons-halflings-regular.woff2") %>') format('woff2'), url('<%= font_path("blazer/glyphicons-halflings-regular.woff") %>') format('woff'), url('<%= font_path("blazer/glyphicons-halflings-regular.ttf") %>') format('truetype'), url('<%= font_path("blazer/glyphicons-halflings-regular.svg#glyphicons_halflingsregular") %>') format('svg');
|
|
270
|
-
}
|
|
271
266
|
.glyphicon {
|
|
272
267
|
position: relative;
|
|
273
268
|
top: 1px;
|
|
@@ -6831,4 +6826,3 @@ button.close {
|
|
|
6831
6826
|
display: none !important;
|
|
6832
6827
|
}
|
|
6833
6828
|
}
|
|
6834
|
-
/*# sourceMappingURL=bootstrap.css.map */
|
|
@@ -32,45 +32,34 @@ module Blazer
|
|
|
32
32
|
|
|
33
33
|
private
|
|
34
34
|
|
|
35
|
-
def process_vars(statement,
|
|
36
|
-
|
|
35
|
+
def process_vars(statement, var_params = nil)
|
|
36
|
+
var_params ||= request.query_parameters
|
|
37
|
+
(@bind_vars ||= []).concat(statement.variables).uniq!
|
|
38
|
+
# update in-place so populated in view and consistent across queries on dashboard
|
|
37
39
|
@bind_vars.each do |var|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if @success
|
|
43
|
-
@bind_vars.each do |var|
|
|
44
|
-
value = params[var].presence
|
|
45
|
-
if value
|
|
46
|
-
if ["start_time", "end_time"].include?(var)
|
|
47
|
-
value = value.to_s.gsub(" ", "+") # fix for Quip bug
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
if var.end_with?("_at")
|
|
51
|
-
begin
|
|
52
|
-
value = Blazer.time_zone.parse(value)
|
|
53
|
-
rescue
|
|
54
|
-
# do nothing
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
if value =~ /\A\d+\z/
|
|
59
|
-
value = value.to_i
|
|
60
|
-
elsif value =~ /\A\d+\.\d+\z/
|
|
61
|
-
value = value.to_f
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
value = Blazer.transform_variable.call(var, value) if Blazer.transform_variable
|
|
65
|
-
statement.gsub!("{#{var}}", ActiveRecord::Base.connection.quote(value))
|
|
40
|
+
if !var_params[var]
|
|
41
|
+
default = statement.data_source.variable_defaults[var]
|
|
42
|
+
# only add if default exists
|
|
43
|
+
var_params[var] = default if default
|
|
66
44
|
end
|
|
67
45
|
end
|
|
46
|
+
runnable = @bind_vars.all? { |v| var_params[v] }
|
|
47
|
+
statement.add_values(var_params) if runnable
|
|
48
|
+
runnable
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def refresh_query(query)
|
|
52
|
+
statement = query.statement_object
|
|
53
|
+
runnable = process_vars(statement)
|
|
54
|
+
cohort_analysis_statement(statement) if statement.cohort_analysis?
|
|
55
|
+
statement.clear_cache if runnable
|
|
68
56
|
end
|
|
69
57
|
|
|
70
58
|
def add_cohort_analysis_vars
|
|
71
59
|
@bind_vars << "cohort_period" unless @bind_vars.include?("cohort_period")
|
|
72
|
-
@smart_vars["cohort_period"] = ["day", "week", "month"]
|
|
73
|
-
|
|
60
|
+
@smart_vars["cohort_period"] = ["day", "week", "month"] if @smart_vars
|
|
61
|
+
# TODO create var_params method
|
|
62
|
+
request.query_parameters["cohort_period"] ||= "week"
|
|
74
63
|
end
|
|
75
64
|
|
|
76
65
|
def parse_smart_variables(var, data_source)
|
|
@@ -94,22 +83,33 @@ module Blazer
|
|
|
94
83
|
[smart_var, error]
|
|
95
84
|
end
|
|
96
85
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
86
|
+
def cohort_analysis_statement(statement)
|
|
87
|
+
@cohort_period = params["cohort_period"] || "week"
|
|
88
|
+
@cohort_period = "week" unless ["day", "week", "month"].include?(@cohort_period)
|
|
89
|
+
|
|
90
|
+
# for now
|
|
91
|
+
@conversion_period = @cohort_period
|
|
92
|
+
@cohort_days =
|
|
93
|
+
case @cohort_period
|
|
94
|
+
when "day"
|
|
95
|
+
1
|
|
96
|
+
when "week"
|
|
97
|
+
7
|
|
98
|
+
when "month"
|
|
99
|
+
30
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
statement.apply_cohort_analysis(period: @cohort_period, days: @cohort_days)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# TODO allow all keys
|
|
106
|
+
# or show error message for disallowed keys
|
|
107
107
|
UNPERMITTED_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]
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
def variable_params(resource)
|
|
109
|
+
def variable_params(resource, var_params = nil)
|
|
111
110
|
permitted_keys = resource.variables - UNPERMITTED_KEYS.map(&:to_s)
|
|
112
|
-
|
|
111
|
+
var_params ||= request.query_parameters
|
|
112
|
+
var_params.slice(*permitted_keys)
|
|
113
113
|
end
|
|
114
114
|
helper_method :variable_params
|
|
115
115
|
|
|
@@ -21,11 +21,8 @@ module Blazer
|
|
|
21
21
|
|
|
22
22
|
def show
|
|
23
23
|
@queries = @dashboard.dashboard_queries.order(:position).preload(:query).map(&:query)
|
|
24
|
-
@statements = []
|
|
25
24
|
@queries.each do |query|
|
|
26
|
-
|
|
27
|
-
process_vars(statement, query.data_source)
|
|
28
|
-
@statements << statement
|
|
25
|
+
@success = process_vars(query.statement_object)
|
|
29
26
|
end
|
|
30
27
|
@bind_vars ||= []
|
|
31
28
|
|
|
@@ -48,7 +45,7 @@ module Blazer
|
|
|
48
45
|
|
|
49
46
|
def update
|
|
50
47
|
if update_dashboard(@dashboard)
|
|
51
|
-
redirect_to dashboard_path(@dashboard, variable_params(@dashboard))
|
|
48
|
+
redirect_to dashboard_path(@dashboard, params: variable_params(@dashboard))
|
|
52
49
|
else
|
|
53
50
|
render_errors @dashboard
|
|
54
51
|
end
|
|
@@ -61,13 +58,9 @@ module Blazer
|
|
|
61
58
|
|
|
62
59
|
def refresh
|
|
63
60
|
@dashboard.queries.each do |query|
|
|
64
|
-
|
|
65
|
-
statement = query.statement.dup
|
|
66
|
-
process_vars(statement, query.data_source)
|
|
67
|
-
Blazer.transform_statement.call(data_source, statement) if Blazer.transform_statement
|
|
68
|
-
data_source.clear_cache(statement)
|
|
61
|
+
refresh_query(query)
|
|
69
62
|
end
|
|
70
|
-
redirect_to dashboard_path(@dashboard, variable_params(@dashboard))
|
|
63
|
+
redirect_to dashboard_path(@dashboard, params: variable_params(@dashboard))
|
|
71
64
|
end
|
|
72
65
|
|
|
73
66
|
private
|