blazer 2.4.7 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://github.com/ankane/blazer/workflows/build/badge.svg?branch=master)](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
|