blazer 3.1.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c920d16bb8d06df36944b4fb3b5af8b416e8e630205cd02de9db7babce6ea23
4
- data.tar.gz: d9020c24eedecf00ee2b1ba6f1bd5bfc90d7b9c08b173561a89cfcff20b83791
3
+ metadata.gz: 885d7856adf62794335bea7227c9d3f7047ca8c07bae46bb3ebe0e889433b4cf
4
+ data.tar.gz: e6943b3a9d84ad8fe818ff82ec167dfad16d00f9449c9429a7d05067fcbab48f
5
5
  SHA512:
6
- metadata.gz: 4c8a438f50c796301e4c8d342c6cc52280f3a77fcfe9bb608acc7042e85cfcdf296173e44cd8223c5bfc87f15b9a8d4126606fe145d9a8c8b2a7aed3eba617e7
7
- data.tar.gz: 5b8538fa4bff96e674b04e26f2ab7fee1c7cd7559c3946069476e53db3d8fa62ffe305828689456309e2900f747e1081f0be22772acc0fc63d98da425161f2e7
6
+ metadata.gz: 6cb9bdb7cafb7e4c6dff3e9a19e9c5c4450650fc69b805f84f041ab4fe2173982d349bd023fab6d395e36e324010aaed94606ec38c6fd384e1ebda33a0a7d27c
7
+ data.tar.gz: d17d30c3c3a816a26c16f2b6eb383acb94df09f162bb9e05f19d51e865a6efec8f01c5f376fcf6dfdb62814426b35934ac824d4c119ef0b5d84cd86a489779b5
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## 3.2.1 (2025-03-21)
2
+
3
+ - Added thousands separator to charts
4
+ - Improved i18n for charts
5
+ - Fixed leading zeros in variables
6
+
7
+ ## 3.2.0 (2025-02-23)
8
+
9
+ - Added support for Trino
10
+ - Added support for `neo4j-ruby-driver` gem
11
+ - Fixed types for SQLite
12
+ - Fixed table preview and schema page for SQLite
13
+
1
14
  ## 3.1.0 (2024-10-14)
2
15
 
3
16
  - Fixed error when Propshaft is installed but not used
@@ -446,3 +459,20 @@ There was no 1.8.1 release.
446
459
  - Added support for Rails 4.2
447
460
  - Fixed error with `mysql2` adapter
448
461
  - Added `user_class` option
462
+
463
+ ## 0.0.4 (2014-11-19)
464
+
465
+ - Added timeout
466
+
467
+ ## 0.0.3 (2014-10-08)
468
+
469
+ - Made editor bigger
470
+
471
+ ## 0.0.2 (2014-10-01)
472
+
473
+ - Added query to audits
474
+ - Added `user_name` option
475
+
476
+ ## 0.0.1 (2014-09-30)
477
+
478
+ - First release
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014-2024 Andrew Kane
1
+ Copyright (c) 2014-2025 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -4,7 +4,7 @@ Explore your data with SQL. Easily create charts and dashboards, and share them
4
4
 
5
5
  [Try it out](https://blazer.dokkuapp.com)
6
6
 
7
- [![Screenshot](https://blazer.dokkuapp.com/assets/blazer-a10baa40fef1ca2f5bb25fc97bcf261a6a54192fb1ad0f893c0f562b8c7c4697.png)](https://blazer.dokkuapp.com)
7
+ [![Screenshot](https://blazer.dokkuapp.com/assets/blazer-176c595c.png)](https://blazer.dokkuapp.com)
8
8
 
9
9
  Blazer is also available as a [Docker image](https://github.com/ankane/blazer-docker).
10
10
 
@@ -71,7 +71,7 @@ Be sure to set a host in `config/environments/production.rb` for emails to work.
71
71
  config.action_mailer.default_url_options = {host: "blazer.dokkuapp.com"}
72
72
  ```
73
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.
74
+ Schedule checks to run (with cron, Solid Queue, [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
75
 
76
76
  ```sh
77
77
  rake blazer:run_checks SCHEDULE="5 minutes"
@@ -94,6 +94,24 @@ Here’s what it looks like with cron.
94
94
  0 8 * * * rake blazer:send_failing_checks
95
95
  ```
96
96
 
97
+ For Solid Queue, update `config/recurring.yml`.
98
+
99
+ ```yml
100
+ production:
101
+ blazer_run_checks_5_minutes:
102
+ command: "Blazer.run_checks(schedule: '5 minutes')"
103
+ schedule: every 5 minutes
104
+ blazer_run_checks_1_hour:
105
+ command: "Blazer.run_checks(schedule: '1 hour')"
106
+ schedule: every hour
107
+ blazer_run_checks_1_day:
108
+ command: "Blazer.run_checks(schedule: '1 day')"
109
+ schedule: every day at 7:30am
110
+ blazer_send_failing_checks:
111
+ command: "Blazer.send_failing_checks"
112
+ schedule: every day at 8am
113
+ ```
114
+
97
115
  For Slack notifications, create an [incoming webhook](https://slack.com/apps/A0F7XDUAZ-incoming-webhooks) and set:
98
116
 
99
117
  ```sh
@@ -125,7 +143,7 @@ end
125
143
 
126
144
  ### Other
127
145
 
128
- Specify a `before_action` method to run in `blazer.yml`.
146
+ Specify a `before_action` method to run in `config/blazer.yml`.
129
147
 
130
148
  ```yml
131
149
  before_action_method: require_admin
@@ -136,7 +154,7 @@ You can define this method in your `ApplicationController`.
136
154
  ```ruby
137
155
  def require_admin
138
156
  # depending on your auth, something like...
139
- redirect_to root_path unless current_user && current_user.admin?
157
+ redirect_to main_app.root_path unless current_user && current_user.admin?
140
158
  end
141
159
  ```
142
160
 
@@ -158,7 +176,7 @@ ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO blazer;
158
176
  COMMIT;
159
177
  ```
160
178
 
161
- ### MySQL
179
+ ### MySQL and MariaDB
162
180
 
163
181
  Create a user with read-only permissions:
164
182
 
@@ -213,7 +231,7 @@ SELECT * FROM users WHERE occupation_id = {occupation_id}
213
231
 
214
232
  Instead of remembering each occupation’s id, users can select occupations by name.
215
233
 
216
- Add a smart variable with:
234
+ Add a smart variable in `config/blazer.yml` with:
217
235
 
218
236
  ```yml
219
237
  smart_variables:
@@ -431,24 +449,22 @@ anomaly_checks: prophet
431
449
 
432
450
  ### Trend
433
451
 
434
- [Trend](https://trendapi.org/) uses an external service by default, but you can run it on your own infrastructure as well.
435
-
436
452
  Add [trend](https://github.com/ankane/trend) to your Gemfile:
437
453
 
438
454
  ```ruby
439
455
  gem "trend"
440
456
  ```
441
457
 
442
- And add to `config/blazer.yml`:
458
+ Set the URL to the [API](https://github.com/ankane/trend-api) in an initializer:
443
459
 
444
- ```yml
445
- anomaly_checks: trend
460
+ ```ruby
461
+ Trend.url = "http://localhost:8000"
446
462
  ```
447
463
 
448
- For the [self-hosted API](https://github.com/ankane/trend-api), create an initializer with:
464
+ And add to `config/blazer.yml`:
449
465
 
450
- ```ruby
451
- Trend.url = "http://localhost:8000"
466
+ ```yml
467
+ anomaly_checks: trend
452
468
  ```
453
469
 
454
470
  ### AnomalyDetection.rb
@@ -487,24 +503,22 @@ forecasting: prophet
487
503
 
488
504
  ### Trend
489
505
 
490
- [Trend](https://trendapi.org/) uses an external service by default, but you can run it on your own infrastructure as well.
491
-
492
506
  Add [trend](https://github.com/ankane/trend) to your Gemfile:
493
507
 
494
508
  ```ruby
495
509
  gem "trend"
496
510
  ```
497
511
 
498
- And add to `config/blazer.yml`:
512
+ Set the URL to the [API](https://github.com/ankane/trend-api) in an initializer:
499
513
 
500
- ```yml
501
- forecasting: trend
514
+ ```ruby
515
+ Trend.url = "http://localhost:8000"
502
516
  ```
503
517
 
504
- For the [self-hosted API](https://github.com/ankane/trend-api), create an initializer with:
518
+ And add to `config/blazer.yml`:
505
519
 
506
- ```ruby
507
- Trend.url = "http://localhost:8000"
520
+ ```yml
521
+ forecasting: trend
508
522
  ```
509
523
 
510
524
  ## Uploads
@@ -566,15 +580,15 @@ data_sources:
566
580
  - [Google BigQuery](#google-bigquery)
567
581
  - [IBM DB2 and Informix](#ibm-db2-and-informix)
568
582
  - [InfluxDB](#influxdb)
569
- - [MySQL](#mysql-1)
583
+ - [MySQL and MariaDB](#mysql-and-mariadb-1)
570
584
  - [Neo4j](#neo4j)
571
585
  - [OpenSearch](#opensearch)
572
586
  - [Oracle](#oracle)
573
587
  - [PostgreSQL](#postgresql-1)
574
- - [Presto](#presto)
588
+ - [Presto and Trino](#presto-and-trino)
575
589
  - [Salesforce](#salesforce)
576
- - [Socrata Open Data API (SODA)](#socrata-open-data-api-soda)
577
590
  - [Snowflake](#snowflake)
591
+ - [Socrata Open Data API (SODA)](#socrata-open-data-api-soda)
578
592
  - [SQLite](#sqlite)
579
593
  - [SQL Server](#sql-server)
580
594
 
@@ -639,11 +653,11 @@ Here’s an example IAM policy:
639
653
  }
640
654
  ```
641
655
 
642
- You also need to configure [S3 permissions](https://aws.amazon.com/premiumsupport/knowledge-center/access-denied-athena/).
656
+ You also need to configure [S3 permissions](https://repost.aws/knowledge-center/access-denied-athena).
643
657
 
644
658
  ### Amazon Redshift
645
659
 
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:
660
+ Add [activerecord7-redshift-adapter-pennylane](https://github.com/pennylane-hq/activerecord-adapter-redshift) to your Gemfile and set:
647
661
 
648
662
  ```yml
649
663
  data_sources:
@@ -706,7 +720,7 @@ Use a read-only user. Requires the [Thrift server](https://spark.apache.org/docs
706
720
 
707
721
  ### Cassandra
708
722
 
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:
723
+ Add [cassandra-driver](https://github.com/datastax/ruby-driver) and [sorted_set](https://github.com/knu/sorted_set) to your Gemfile and set:
710
724
 
711
725
  ```yml
712
726
  data_sources:
@@ -718,7 +732,7 @@ Use a [read-only role](https://docs.datastax.com/en/cql-oss/3.3/cql/cql_using/us
718
732
 
719
733
  ### Druid
720
734
 
721
- Enable [SQL support](http://druid.io/docs/latest/querying/sql.html#configuration) on the broker and set:
735
+ Enable [SQL support](https://druid.apache.org/docs/latest/querying/sql) on the broker and set:
722
736
 
723
737
  ```yml
724
738
  data_sources:
@@ -744,7 +758,7 @@ Use a [read-only role](https://www.elastic.co/guide/en/elasticsearch/reference/c
744
758
 
745
759
  ### Google BigQuery
746
760
 
747
- Add [google-cloud-bigquery](https://github.com/GoogleCloudPlatform/google-cloud-ruby/tree/master/google-cloud-bigquery) to your Gemfile and set:
761
+ Add [google-cloud-bigquery](https://github.com/GoogleCloudPlatform/google-cloud-ruby/tree/main/google-cloud-bigquery) to your Gemfile and set:
748
762
 
749
763
  ```yml
750
764
  data_sources:
@@ -779,7 +793,7 @@ data_sources:
779
793
 
780
794
  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
795
 
782
- ### MySQL
796
+ ### MySQL and MariaDB
783
797
 
784
798
  Add [mysql2](https://github.com/brianmario/mysql2) to your Gemfile (if it’s not there) and set:
785
799
 
@@ -789,17 +803,17 @@ data_sources:
789
803
  url: mysql2://user:password@hostname:3306/database
790
804
  ```
791
805
 
792
- Use a [read-only user](#mysql).
806
+ Use a [read-only user](#mysql-and-mariadb).
793
807
 
794
808
  ### Neo4j
795
809
 
796
- Add [neo4j-core](https://github.com/neo4jrb/neo4j-core) to your Gemfile and set:
810
+ Add [neo4j-ruby-driver](https://github.com/neo4jrb/neo4j-ruby-driver) to your Gemfile and set:
797
811
 
798
812
  ```yml
799
813
  data_sources:
800
814
  my_source:
801
815
  adapter: neo4j
802
- url: http://user:password@hostname:7474
816
+ url: bolt://user:password@hostname:7687/database
803
817
  ```
804
818
 
805
819
  Use a [read-only user](https://neo4j.com/docs/cypher-manual/current/access-control/manage-privileges/).
@@ -841,17 +855,19 @@ data_sources:
841
855
 
842
856
  Use a [read-only user](#postgresql).
843
857
 
844
- ### Presto
858
+ ### Presto and Trino
845
859
 
846
- Add [presto-client](https://github.com/treasure-data/presto-client-ruby) to your Gemfile and set:
860
+ Add [presto-client](https://github.com/treasure-data/trino-client-ruby/tree/v0.6.5) or [trino-client](https://github.com/treasure-data/trino-client-ruby) to your Gemfile and set:
847
861
 
848
862
  ```yml
849
863
  data_sources:
850
864
  my_source:
851
865
  url: presto://user@hostname:8080/catalog
866
+ # or
867
+ url: trino://user@hostname:8080/catalog
852
868
  ```
853
869
 
854
- Use a [read-only user](https://prestodb.io/docs/current/security/built-in-system-access-control.html).
870
+ Use a read-only user for [Presto](https://prestodb.io/docs/current/security/built-in-system-access-control.html) or [Trino](https://trino.io/docs/current/security/built-in-system-access-control.html).
855
871
 
856
872
  ### Salesforce
857
873
 
@@ -876,20 +892,6 @@ SALESFORCE_API_VERSION="41.0"
876
892
 
877
893
  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
894
 
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
895
  ### Snowflake
894
896
 
895
897
  First, install ODBC. For Homebrew, use:
@@ -913,7 +915,7 @@ https://sfc-repo.snowflakecomputing.com/odbc/linux/2.21.5/snowflake-odbc-2.21.5.
913
915
 
914
916
  > This installs the driver at `/app/.apt/usr/lib/snowflake/odbc/lib/libSnowflake.so`
915
917
 
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:
918
+ Then, download the [Snowflake ODBC driver](https://docs.snowflake.com/developer-guide/odbc/odbc-download). Add [odbc_adapter](https://github.com/localytics/odbc_adapter) to your Gemfile and set:
917
919
 
918
920
  ```yml
919
921
  data_sources:
@@ -924,6 +926,20 @@ data_sources:
924
926
 
925
927
  Use a [read-only role](https://docs.snowflake.com/en/user-guide/security-access-control-configure.html).
926
928
 
929
+ ### Socrata Open Data API (SODA)
930
+
931
+ Set:
932
+
933
+ ```yml
934
+ data_sources:
935
+ my_source:
936
+ adapter: soda
937
+ url: https://soda.demo.socrata.com/resource/4tka-6guv.json
938
+ app_token: ...
939
+ ```
940
+
941
+ Supports [SoQL](https://dev.socrata.com/docs/functions/).
942
+
927
943
  ### SQLite
928
944
 
929
945
  Add [sqlite3](https://github.com/sparklemotion/sqlite3-ruby) to your Gemfile and set:
@@ -986,10 +1002,6 @@ Have team members who want to learn SQL? Here are a few great, free resources.
986
1002
 
987
1003
  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
1004
 
989
- ## Standalone Version
990
-
991
- Looking for a standalone version? Check out [Ghost Blazer](https://github.com/buren/ghost_blazer).
992
-
993
1005
  ## Performance
994
1006
 
995
1007
  By default, queries take up a request while they are running. To run queries asynchronously, add to your config:
@@ -26,8 +26,15 @@ module Blazer
26
26
  end
27
27
 
28
28
  def index
29
- set_queries
30
- render json: @queries
29
+ respond_to do |format|
30
+ format.html do
31
+ redirect_to root_path
32
+ end
33
+ format.json do
34
+ set_queries
35
+ render json: @queries
36
+ end
37
+ end
31
38
  end
32
39
 
33
40
  def new
@@ -225,6 +232,9 @@ module Blazer
225
232
 
226
233
  def set_data_source
227
234
  @data_source = Blazer.data_sources[params[:data_source]]
235
+ rescue Blazer::Error => e
236
+ raise unless e.message.start_with?("Unknown data source:")
237
+ render plain: "Unknown data source", status: :not_found
228
238
  end
229
239
 
230
240
  def continue_run
@@ -4,7 +4,7 @@
4
4
  <% if @only_chart %>
5
5
  <p class="text-muted">Select variables</p>
6
6
  <% else %>
7
- <div class="alert alert-info">Can’t preview queries with variables...yet!</div>
7
+ <div class="alert alert-info">Can’t preview queries with variables</div>
8
8
  <% end %>
9
9
  <% elsif @cohort_analysis %>
10
10
  <% if @cohort_error %>
@@ -46,7 +46,7 @@
46
46
  <% chart_id = SecureRandom.hex %>
47
47
  <% column_types = @result.column_types %>
48
48
  <% chart_type = @result.chart_type %>
49
- <% chart_options = {id: chart_id} %>
49
+ <% chart_options = {id: chart_id, thousands: t("number.format.delimiter"), decimal: t("number.format.separator")} %>
50
50
  <% if ["line", "line2"].include?(chart_type) %>
51
51
  <% chart_options.merge!(min: nil) %>
52
52
  <% end %>
@@ -165,7 +165,7 @@
165
165
  <% end %>
166
166
  <% end %>
167
167
 
168
- <% if v2 = (@smart_values[k] || {})[v.nil? ? v : v.to_s] %>
168
+ <% if (v2 = @smart_values.dig(k, v&.to_s)) %>
169
169
  <div class="text-muted"><%= v2 %></div>
170
170
  <% end %>
171
171
  </td>
@@ -13,7 +13,7 @@
13
13
  <thead>
14
14
  <tr>
15
15
  <th colspan="2">
16
- <% if table[:schema] != "public" %><%= table[:schema] %>.<% end %><%= table[:table] %>
16
+ <% if table[:schema] && table[:schema] != "public" %><%= table[:schema] %>.<% end %><%= table[:table] %>
17
17
  </th>
18
18
  </tr>
19
19
  </thead>
@@ -7,14 +7,20 @@ module Blazer
7
7
  error = nil
8
8
 
9
9
  begin
10
- result = session.query("#{statement} /*#{comment}*/", bind_params)
11
- columns = result.columns.map(&:to_s)
12
- rows = []
13
- result.each do |row|
14
- rows << columns.map do |c|
15
- v = row.send(c)
16
- v = v.properties if v.respond_to?(:properties)
17
- v
10
+ if bolt?
11
+ result = session.run("#{statement} /*#{comment}*/", bind_params).to_a
12
+ columns = result.any? ? result.first.keys.map(&:to_s) : []
13
+ rows = result.map(&:values)
14
+ else
15
+ result = session.query("#{statement} /*#{comment}*/", bind_params)
16
+ columns = result.columns.map(&:to_s)
17
+ rows = []
18
+ result.each do |row|
19
+ rows << columns.map do |c|
20
+ v = row.send(c)
21
+ v = v.properties if v.respond_to?(:properties)
22
+ v
23
+ end
18
24
  end
19
25
  end
20
26
  rescue => e
@@ -26,8 +32,13 @@ module Blazer
26
32
  end
27
33
 
28
34
  def tables
29
- result = session.query("CALL db.labels()")
30
- result.rows.map(&:first)
35
+ if bolt?
36
+ result = session.run("CALL db.labels()").to_a
37
+ result.map { |r| r.values.first }
38
+ else
39
+ result = session.query("CALL db.labels()")
40
+ result.rows.map(&:first)
41
+ end
31
42
  end
32
43
 
33
44
  def preview_statement
@@ -52,10 +63,27 @@ module Blazer
52
63
 
53
64
  def session
54
65
  @session ||= begin
55
- require "neo4j/core/cypher_session/adaptors/http"
56
- http_adaptor = Neo4j::Core::CypherSession::Adaptors::HTTP.new(settings["url"])
57
- Neo4j::Core::CypherSession.new(http_adaptor)
66
+ if bolt?
67
+ uri = URI.parse(settings["url"])
68
+ auth = Neo4j::Driver::AuthTokens.basic(uri.user, uri.password)
69
+ database = uri.path.delete_prefix("/")
70
+ uri.user = nil
71
+ uri.password = nil
72
+ uri.path = ""
73
+ Neo4j::Driver::GraphDatabase.driver(uri, auth).session(database: database)
74
+ else
75
+ require "neo4j/core/cypher_session/adaptors/http"
76
+ http_adaptor = Neo4j::Core::CypherSession::Adaptors::HTTP.new(settings["url"])
77
+ Neo4j::Core::CypherSession.new(http_adaptor)
78
+ end
79
+ end
80
+ end
81
+
82
+ def bolt?
83
+ if !defined?(@bolt)
84
+ @bolt = settings["url"].start_with?("bolt")
58
85
  end
86
+ @bolt
59
87
  end
60
88
  end
61
89
  end
@@ -40,7 +40,8 @@ module Blazer
40
40
  @client ||= begin
41
41
  uri = URI.parse(settings["url"])
42
42
  query = uri.query ? CGI.parse(uri.query) : {}
43
- Presto::Client.new(
43
+ cls = uri.scheme == "trino" ? Trino::Client : Presto::Client
44
+ cls.new(
44
45
  server: "#{uri.host}:#{uri.port}",
45
46
  catalog: uri.path.to_s.delete_prefix("/"),
46
47
  schema: query["schema"] || "public",
@@ -21,19 +21,30 @@ module Blazer
21
21
  error = nil
22
22
 
23
23
  begin
24
- result = nil
25
- in_transaction do
24
+ types = []
25
+ in_transaction do |connection|
26
26
  set_timeout(data_source.timeout) if data_source.timeout
27
27
  binds = bind_params.map { |v| ActiveRecord::Relation::QueryAttribute.new(nil, v, ActiveRecord::Type::Value.new) }
28
- result = connection_model.connection.select_all("#{statement} /*#{comment}*/", nil, binds)
28
+ if sqlite?
29
+ type_map = connection.send(:type_map)
30
+ connection.raw_connection.prepare("#{statement} /*#{comment}*/") do |stmt|
31
+ stmt.bind_params(connection.send(:type_casted_binds, binds))
32
+ columns = stmt.columns
33
+ rows = stmt.to_a
34
+ types = stmt.types.map { |t| type_map.lookup(t) }
35
+ end
36
+ else
37
+ result = connection.select_all("#{statement} /*#{comment}*/", nil, binds)
38
+ columns = result.columns
39
+ rows = result.rows
40
+ if result.column_types.any?
41
+ types = columns.size.times.map { |i| result.column_types[i] }
42
+ end
43
+ end
29
44
  end
30
45
 
31
- columns = result.columns
32
- rows = result.rows
33
-
34
46
  # cast values
35
- if result.column_types.any?
36
- types = columns.map { |c| result.column_types[c] }
47
+ if types.any?
37
48
  rows =
38
49
  rows.map do |row|
39
50
  row.map.with_index do |v, i|
@@ -60,7 +71,12 @@ module Blazer
60
71
  end
61
72
 
62
73
  def tables
63
- sql = add_schemas("SELECT table_schema, table_name FROM information_schema.tables")
74
+ sql =
75
+ if sqlite?
76
+ "SELECT NULL, name FROM sqlite_master WHERE type IN ('table', 'view') ORDER BY name"
77
+ else
78
+ add_schemas("SELECT table_schema, table_name FROM information_schema.tables")
79
+ end
64
80
  result = data_source.run_statement(sql, refresh_cache: true)
65
81
  if postgresql? || redshift? || snowflake?
66
82
  result.rows.sort_by { |r| [r[0] == default_schema ? "" : r[0], r[1]] }.map do |row|
@@ -84,7 +100,12 @@ module Blazer
84
100
  end
85
101
 
86
102
  def schema
87
- sql = add_schemas("SELECT table_schema, table_name, column_name, data_type, ordinal_position FROM information_schema.columns")
103
+ sql =
104
+ if sqlite?
105
+ "SELECT NULL, t.name, c.name, c.type, c.cid FROM sqlite_master t INNER JOIN pragma_table_info(t.name) c WHERE t.type IN ('table', 'view')"
106
+ else
107
+ add_schemas("SELECT table_schema, table_name, column_name, data_type, ordinal_position FROM information_schema.columns")
108
+ end
88
109
  result = data_source.run_statement(sql)
89
110
  result.rows.group_by { |r| [r[0], r[1]] }.map { |k, vs| {schema: k[0], table: k[1], columns: vs.sort_by { |v| v[2] }.map { |v| {name: v[2], data_type: v[3]} }} }.sort_by { |t| [t[:schema] == default_schema ? "" : t[:schema], t[:table]] }
90
111
  end
@@ -274,6 +295,8 @@ module Blazer
274
295
  "public"
275
296
  elsif sqlserver?
276
297
  "dbo"
298
+ elsif sqlite?
299
+ nil
277
300
  elsif connection_model.respond_to?(:connection_db_config)
278
301
  connection_model.connection_db_config.database
279
302
  else
@@ -302,8 +325,7 @@ module Blazer
302
325
  if postgresql? || redshift?
303
326
  execute("SET #{use_transaction? ? "LOCAL " : ""}statement_timeout = #{timeout.to_i * 1000}")
304
327
  elsif mysql?
305
- # use send as this method is private in Rails 4.2
306
- mariadb = connection_model.connection.send(:mariadb?) rescue false
328
+ mariadb = connection_model.connection.mariadb? rescue false
307
329
  if mariadb
308
330
  execute("SET max_statement_time = #{timeout.to_i * 1000}")
309
331
  else
@@ -319,14 +341,14 @@ module Blazer
319
341
  end
320
342
 
321
343
  def in_transaction
322
- connection_model.connection_pool.with_connection do
344
+ connection_model.connection_pool.with_connection do |connection|
323
345
  if use_transaction?
324
346
  connection_model.transaction do
325
- yield
347
+ yield connection
326
348
  raise ActiveRecord::Rollback
327
349
  end
328
350
  else
329
- yield
351
+ yield connection
330
352
  end
331
353
  end
332
354
  end
@@ -15,3 +15,4 @@ Blazer.register_adapter "soda", Blazer::Adapters::SodaAdapter
15
15
  Blazer.register_adapter "spark", Blazer::Adapters::SparkAdapter
16
16
  Blazer.register_adapter "sql", Blazer::Adapters::SqlAdapter
17
17
  Blazer.register_adapter "snowflake", Blazer::Adapters::SnowflakeAdapter
18
+ Blazer.register_adapter "trino", Blazer::Adapters::PrestoAdapter
@@ -256,7 +256,7 @@ module Blazer
256
256
  def detect_adapter
257
257
  scheme = settings["url"].to_s.split("://").first
258
258
  case scheme
259
- when "presto", "cassandra", "ignite"
259
+ when "presto", "trino", "cassandra", "ignite"
260
260
  scheme
261
261
  else
262
262
  "sql"
@@ -34,7 +34,10 @@ module Blazer
34
34
 
35
35
  unless value.is_a?(ActiveSupport::TimeWithZone)
36
36
  if value.match?(/\A\d+\z/)
37
- value = value.to_i
37
+ # check no leading zeros (when not zero)
38
+ if value == value.to_i.to_s
39
+ value = value.to_i
40
+ end
38
41
  elsif value.match?(/\A\d+\.\d+\z/)
39
42
  value = value.to_f
40
43
  end
@@ -1,3 +1,3 @@
1
1
  module Blazer
2
- VERSION = "3.1.0"
2
+ VERSION = "3.2.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blazer
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-10-15 00:00:00.000000000 Z
10
+ date: 2025-03-22 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: railties
@@ -30,14 +29,14 @@ dependencies:
30
29
  requirements:
31
30
  - - ">="
32
31
  - !ruby/object:Gem::Version
33
- version: '6.1'
32
+ version: '7'
34
33
  type: :runtime
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - ">="
39
38
  - !ruby/object:Gem::Version
40
- version: '6.1'
39
+ version: '7'
41
40
  - !ruby/object:Gem::Dependency
42
41
  name: chartkick
43
42
  requirement: !ruby/object:Gem::Requirement
@@ -80,7 +79,6 @@ dependencies:
80
79
  - - ">="
81
80
  - !ruby/object:Gem::Version
82
81
  version: '0'
83
- description:
84
82
  email: andrew@ankane.org
85
83
  executables: []
86
84
  extensions: []
@@ -236,7 +234,6 @@ homepage: https://github.com/ankane/blazer
236
234
  licenses:
237
235
  - MIT
238
236
  metadata: {}
239
- post_install_message:
240
237
  rdoc_options: []
241
238
  require_paths:
242
239
  - lib
@@ -251,8 +248,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
251
248
  - !ruby/object:Gem::Version
252
249
  version: '0'
253
250
  requirements: []
254
- rubygems_version: 3.5.16
255
- signing_key:
251
+ rubygems_version: 3.6.2
256
252
  specification_version: 4
257
253
  summary: Explore your data with SQL. Easily create charts and dashboards, and share
258
254
  them with your team.