blazer 2.2.8 → 2.4.2
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 +25 -0
- data/LICENSE.txt +1 -1
- data/README.md +131 -168
- data/app/assets/stylesheets/blazer/application.css +4 -0
- data/app/controllers/blazer/base_controller.rb +8 -0
- data/app/controllers/blazer/dashboards_controller.rb +2 -0
- data/app/controllers/blazer/queries_controller.rb +119 -3
- data/app/controllers/blazer/uploads_controller.rb +147 -0
- data/app/models/blazer/query.rb +9 -2
- data/app/models/blazer/upload.rb +11 -0
- data/app/models/blazer/uploads_connection.rb +7 -0
- data/app/views/blazer/_nav.html.erb +3 -0
- data/app/views/blazer/checks/_form.html.erb +1 -1
- data/app/views/blazer/checks/index.html.erb +3 -0
- data/app/views/blazer/dashboards/_form.html.erb +1 -1
- data/app/views/blazer/dashboards/show.html.erb +1 -1
- 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/docs.html.erb +6 -0
- data/app/views/blazer/queries/home.html.erb +3 -0
- data/app/views/blazer/queries/run.html.erb +15 -17
- data/app/views/blazer/queries/show.html.erb +1 -1
- 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/config/routes.rb +5 -0
- data/lib/blazer.rb +24 -0
- data/lib/blazer/adapters/base_adapter.rb +8 -0
- data/lib/blazer/adapters/druid_adapter.rb +3 -3
- data/lib/blazer/adapters/hive_adapter.rb +45 -0
- data/lib/blazer/adapters/ignite_adapter.rb +54 -0
- data/lib/blazer/adapters/spark_adapter.rb +9 -0
- data/lib/blazer/adapters/sql_adapter.rb +64 -1
- data/lib/blazer/data_source.rb +2 -2
- data/lib/blazer/version.rb +1 -1
- data/lib/generators/blazer/templates/config.yml.tt +6 -0
- data/lib/generators/blazer/templates/install.rb.tt +1 -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 +9 -0
- metadata +18 -32
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
</button>
|
|
11
11
|
<ul class="dropdown-menu">
|
|
12
12
|
<li><%= link_to "Home", root_path %></li>
|
|
13
|
+
<% if Blazer.uploads? %>
|
|
14
|
+
<li><%= link_to "Uploads", uploads_path %></li>
|
|
15
|
+
<% end %>
|
|
13
16
|
<li role="separator" class="divider"></li>
|
|
14
17
|
<li><%= link_to "New Query", new_query_path %></li>
|
|
15
18
|
<li><%= link_to "New Dashboard", new_dashboard_path %></li>
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<% end %>
|
|
32
32
|
|
|
33
33
|
<script>
|
|
34
|
-
<%= blazer_js_var "queries", Blazer::Query.named.order(:name).select("id, name").map { |q| {text: q.name, value: q.id} } %>
|
|
34
|
+
<%= blazer_js_var "queries", Blazer::Query.active.named.order(:name).select("id, name").map { |q| {text: q.name, value: q.id} } %>
|
|
35
35
|
<%= blazer_js_var "dashboardQueries", @queries || @dashboard.dashboard_queries.order(:position).map(&:query) %>
|
|
36
36
|
|
|
37
37
|
var app = new Vue({
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
</div>
|
|
40
40
|
</div>
|
|
41
41
|
<script>
|
|
42
|
-
<%= blazer_js_var "data", {statement: @statements[i], query_id: query.id, data_source: query.data_source, only_chart: true} %>
|
|
42
|
+
<%= blazer_js_var "data", {statement: @statements[i], query_id: query.id, data_source: query.data_source, only_chart: true, cohort_period: params[:cohort_period]} %>
|
|
43
43
|
|
|
44
44
|
runQuery(data, function (data) {
|
|
45
45
|
$("#chart-<%= i %>").html(data)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<% if @cached_at || @just_cached %>
|
|
2
|
+
<p class="text-muted" style="float: right;">
|
|
3
|
+
<% if @cached_at %>
|
|
4
|
+
Cached <%= time_ago_in_words(@cached_at, include_seconds: true) %> ago
|
|
5
|
+
<% elsif params[:query_id] %>
|
|
6
|
+
Cached just now
|
|
7
|
+
<% if @data_source.cache_mode == "slow" %>
|
|
8
|
+
(over <%= "%g" % @data_source.cache_slow_threshold %>s)
|
|
9
|
+
<% end %>
|
|
10
|
+
<% end %>
|
|
11
|
+
|
|
12
|
+
<% if @query && params[:query_id] %>
|
|
13
|
+
<%= link_to "Refresh", refresh_query_path(@query, variable_params(@query)), method: :post %>
|
|
14
|
+
<% end %>
|
|
15
|
+
</p>
|
|
16
|
+
<% end %>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<% unless @only_chart %>
|
|
2
|
+
<%= render partial: "caching" %>
|
|
3
|
+
<p class="text-muted" style="margin-bottom: 10px;">
|
|
4
|
+
<%= pluralize(@rows.size, "cohort") %>
|
|
5
|
+
</p>
|
|
6
|
+
<% end %>
|
|
7
|
+
<% if @rows.any? %>
|
|
8
|
+
<div class="results-container">
|
|
9
|
+
<table class="table results-table">
|
|
10
|
+
<thead>
|
|
11
|
+
<tr>
|
|
12
|
+
<th style="min-width: 100px;">Cohort</th>
|
|
13
|
+
<% 12.times do |i| %>
|
|
14
|
+
<th style="width: 7.5%; text-align: right;"><%= @conversion_period.titleize %> <%= i + 1 %></th>
|
|
15
|
+
<% end %>
|
|
16
|
+
</tr>
|
|
17
|
+
</thead>
|
|
18
|
+
<tbody>
|
|
19
|
+
<% @rows.each do |row| %>
|
|
20
|
+
<tr>
|
|
21
|
+
<td>
|
|
22
|
+
<%= row[0] %>
|
|
23
|
+
<div style="font-size: 12px; color: #999;"><%= row[1] == 1 ? "1 user" : "#{number_with_delimiter(row[1])} users" %></div>
|
|
24
|
+
</td>
|
|
25
|
+
<% 12.times do |i| %>
|
|
26
|
+
<td style="text-align: right;">
|
|
27
|
+
<% num = row[i + 2] %>
|
|
28
|
+
<% if num %>
|
|
29
|
+
<% denom = row[1] %>
|
|
30
|
+
<% if denom > 0 %>
|
|
31
|
+
<%= (100.0 * num / denom).round %>%
|
|
32
|
+
<% else %>
|
|
33
|
+
-
|
|
34
|
+
<% end %>
|
|
35
|
+
<div style="font-size: 12px; color: #999;"><%= number_with_delimiter(num) %></div>
|
|
36
|
+
<% else %>
|
|
37
|
+
-
|
|
38
|
+
<% end %>
|
|
39
|
+
</td>
|
|
40
|
+
<% end %>
|
|
41
|
+
</tr>
|
|
42
|
+
<% end %>
|
|
43
|
+
</tbody>
|
|
44
|
+
</table>
|
|
45
|
+
</div>
|
|
46
|
+
<% elsif @only_chart %>
|
|
47
|
+
<p class="text-muted">No cohorts</p>
|
|
48
|
+
<% end %>
|
|
@@ -129,3 +129,9 @@
|
|
|
129
129
|
</table>
|
|
130
130
|
|
|
131
131
|
<p>Use the column name <code>target</code> to draw a line for goals.</p>
|
|
132
|
+
|
|
133
|
+
<% if @data_source.supports_cohort_analysis? %>
|
|
134
|
+
<h2>Cohort Analysis</h2>
|
|
135
|
+
|
|
136
|
+
<p>Create a query with the comment <code>/* cohort analysis */</code>. The result should have columns named <code>user_id</code> and <code>conversion_time</code> and optionally <code>cohort_time</code>.</p>
|
|
137
|
+
<% end %>
|
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
</button>
|
|
20
20
|
<ul class="dropdown-menu">
|
|
21
21
|
<li><%= link_to "Checks", checks_path %></li>
|
|
22
|
+
<% if Blazer.uploads? %>
|
|
23
|
+
<li><%= link_to "Uploads", uploads_path %></li>
|
|
24
|
+
<% end %>
|
|
22
25
|
<li role="separator" class="divider"></li>
|
|
23
26
|
<li><%= link_to "New Dashboard", new_dashboard_path %></li>
|
|
24
27
|
<li><%= link_to "New Check", new_check_path %></li>
|
|
@@ -6,25 +6,20 @@
|
|
|
6
6
|
<% else %>
|
|
7
7
|
<div class="alert alert-info">Can’t preview queries with variables...yet!</div>
|
|
8
8
|
<% end %>
|
|
9
|
+
<% elsif @cohort_analysis %>
|
|
10
|
+
<% if @cohort_error %>
|
|
11
|
+
<div class="alert alert-info"><%= @cohort_error %></div>
|
|
12
|
+
<% else %>
|
|
13
|
+
<%= render partial: "cohorts" %>
|
|
14
|
+
<% end %>
|
|
9
15
|
<% else %>
|
|
10
16
|
<% unless @only_chart %>
|
|
11
|
-
|
|
12
|
-
<p class="text-muted" style="float: right;">
|
|
13
|
-
<% if @cached_at %>
|
|
14
|
-
Cached <%= time_ago_in_words(@cached_at, include_seconds: true) %> ago
|
|
15
|
-
<% elsif params[:query_id] %>
|
|
16
|
-
Cached just now
|
|
17
|
-
<% if @data_source.cache_mode == "slow" %>
|
|
18
|
-
(over <%= "%g" % @data_source.cache_slow_threshold %>s)
|
|
19
|
-
<% end %>
|
|
20
|
-
<% end %>
|
|
21
|
-
|
|
22
|
-
<% if @query && params[:query_id] %>
|
|
23
|
-
<%= link_to "Refresh", refresh_query_path(@query, variable_params(@query)), method: :post %>
|
|
24
|
-
<% end %>
|
|
25
|
-
</p>
|
|
26
|
-
<% end %>
|
|
17
|
+
<%= render partial: "caching" %>
|
|
27
18
|
<p class="text-muted" style="margin-bottom: 10px;">
|
|
19
|
+
<% if @row_limit && @rows.size > @row_limit %>
|
|
20
|
+
First
|
|
21
|
+
<% @rows = @rows.first(@row_limit) %>
|
|
22
|
+
<% end %>
|
|
28
23
|
<%= pluralize(@rows.size, "row") %>
|
|
29
24
|
|
|
30
25
|
<% @checks.select(&:state).each do |check| %>
|
|
@@ -43,6 +38,9 @@
|
|
|
43
38
|
<% if @forecast_error %>
|
|
44
39
|
<div class="alert alert-danger"><%= @forecast_error %></div>
|
|
45
40
|
<% end %>
|
|
41
|
+
<% if @cohort_error %>
|
|
42
|
+
<div class="alert alert-info"><%= @cohort_error %></div>
|
|
43
|
+
<% end %>
|
|
46
44
|
<% if @rows.any? %>
|
|
47
45
|
<% values = @rows.first %>
|
|
48
46
|
<% chart_id = SecureRandom.hex %>
|
|
@@ -147,7 +145,7 @@
|
|
|
147
145
|
<% elsif @columns == ["PLAN"] && @data_source.adapter == "druid" %>
|
|
148
146
|
<pre><code><%= @rows[0][0] %></code></pre>
|
|
149
147
|
<% else %>
|
|
150
|
-
<table class="table results-table"
|
|
148
|
+
<table class="table results-table">
|
|
151
149
|
<thead>
|
|
152
150
|
<tr>
|
|
153
151
|
<% @columns.each_with_index do |key, i| %>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<%= link_to "Fork", new_query_path(variable_params(@query).merge(fork_query_id: @query.id, data_source: @query.data_source, name: @query.name)), class: "btn btn-info" %>
|
|
15
15
|
|
|
16
16
|
<% if !@error && @success %>
|
|
17
|
-
<%= button_to "Download", run_queries_path(query_id: @query.id, format: "csv", forecast: params[:forecast]), params: {statement: @statement}, class: "btn btn-primary" %>
|
|
17
|
+
<%= button_to "Download", run_queries_path(query_id: @query.id, format: "csv", forecast: params[:forecast], cohort_period: params[:cohort_period]), params: {statement: @statement}, class: "btn btn-primary" %>
|
|
18
18
|
<% end %>
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<%= form_for @upload, html: {class: "small-form"} do |f| %>
|
|
2
|
+
<% if @upload.errors.any? %>
|
|
3
|
+
<div class="alert alert-danger"><%= @upload.errors.full_messages.first %></div>
|
|
4
|
+
<% elsif !@upload.persisted? %>
|
|
5
|
+
<p>Create a database table from a CSV file. The table will be created in the <code><%= Blazer.settings["uploads"]["schema"] %></code> schema.</p>
|
|
6
|
+
<% end %>
|
|
7
|
+
|
|
8
|
+
<div class="form-group">
|
|
9
|
+
<%= f.label :table %>
|
|
10
|
+
<%= f.text_field :table, class: "form-control" %>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="form-group">
|
|
13
|
+
<%= f.label :description %>
|
|
14
|
+
<%= f.text_area :description, placeholder: "Optional", style: "height: 60px;", class: "form-control" %>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="form-group">
|
|
17
|
+
<%= f.label :file %>
|
|
18
|
+
<%= f.file_field :file, accept: "text/csv", style: "margin-top: 6px; margin-bottom: 21px;" %>
|
|
19
|
+
</div>
|
|
20
|
+
<p>
|
|
21
|
+
<% if @upload.persisted? %>
|
|
22
|
+
<%= link_to "Delete", upload_path(@upload), method: :delete, "data-confirm" => "Are you sure?", class: "btn btn-danger" %>
|
|
23
|
+
<% end %>
|
|
24
|
+
<%= f.submit "Save", class: "btn btn-success" %>
|
|
25
|
+
<%= link_to "Back", :back, class: "btn btn-link" %>
|
|
26
|
+
</p>
|
|
27
|
+
<% end %>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<% blazer_title "Uploads" %>
|
|
2
|
+
|
|
3
|
+
<div id="header">
|
|
4
|
+
<div class="pull-right" style="line-height: 34px;">
|
|
5
|
+
<div class="btn-group">
|
|
6
|
+
<%= link_to "New Upload", new_upload_path, class: "btn btn-info" %>
|
|
7
|
+
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
8
|
+
<span class="caret"></span>
|
|
9
|
+
<span class="sr-only">Toggle Dropdown</span>
|
|
10
|
+
</button>
|
|
11
|
+
<ul class="dropdown-menu">
|
|
12
|
+
<li><%= link_to "Home", root_path %></li>
|
|
13
|
+
<li><%= link_to "Checks", checks_path %></li>
|
|
14
|
+
<li role="separator" class="divider"></li>
|
|
15
|
+
<li><%= link_to "New Query", new_query_path %></li>
|
|
16
|
+
<li><%= link_to "New Dashboard", new_dashboard_path %></li>
|
|
17
|
+
<li><%= link_to "New Check", new_check_path %></li>
|
|
18
|
+
</ul>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<input id="search" type="text" placeholder="Start typing a table or person" style="width: 300px; display: inline-block;" class="search form-control" />
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<table id="uploads" class="table">
|
|
26
|
+
<thead>
|
|
27
|
+
<tr>
|
|
28
|
+
<th>Table</th>
|
|
29
|
+
<th style="width: 60%;"></th>
|
|
30
|
+
<% if Blazer.user_class %>
|
|
31
|
+
<th style="width: 20%; text-align: right;">Mastermind</th>
|
|
32
|
+
<% end%>
|
|
33
|
+
</tr>
|
|
34
|
+
</thead>
|
|
35
|
+
<tbody>
|
|
36
|
+
<% @uploads.each do |upload| %>
|
|
37
|
+
<tr>
|
|
38
|
+
<td><%= link_to upload.table, edit_upload_path(upload) %></td>
|
|
39
|
+
<td><%= truncate(upload.description, length: 100, separator: " ") %></td>
|
|
40
|
+
<% if Blazer.user_class %>
|
|
41
|
+
<td class="creator"><%= blazer_user && upload.creator == blazer_user ? "You" : upload.creator.try(Blazer.user_name) %></td>
|
|
42
|
+
<% end %>
|
|
43
|
+
</tr>
|
|
44
|
+
<% end %>
|
|
45
|
+
</tbody>
|
|
46
|
+
</table>
|
|
47
|
+
|
|
48
|
+
<script>
|
|
49
|
+
$("#search").on("keyup", function() {
|
|
50
|
+
var value = $(this).val().toLowerCase()
|
|
51
|
+
$("#uploads tbody tr").filter( function() {
|
|
52
|
+
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
|
|
53
|
+
})
|
|
54
|
+
}).focus()
|
|
55
|
+
</script>
|
data/config/routes.rb
CHANGED
data/lib/blazer.rb
CHANGED
|
@@ -18,12 +18,15 @@ require "blazer/adapters/cassandra_adapter"
|
|
|
18
18
|
require "blazer/adapters/drill_adapter"
|
|
19
19
|
require "blazer/adapters/druid_adapter"
|
|
20
20
|
require "blazer/adapters/elasticsearch_adapter"
|
|
21
|
+
require "blazer/adapters/hive_adapter"
|
|
22
|
+
require "blazer/adapters/ignite_adapter"
|
|
21
23
|
require "blazer/adapters/influxdb_adapter"
|
|
22
24
|
require "blazer/adapters/mongodb_adapter"
|
|
23
25
|
require "blazer/adapters/neo4j_adapter"
|
|
24
26
|
require "blazer/adapters/presto_adapter"
|
|
25
27
|
require "blazer/adapters/salesforce_adapter"
|
|
26
28
|
require "blazer/adapters/soda_adapter"
|
|
29
|
+
require "blazer/adapters/spark_adapter"
|
|
27
30
|
require "blazer/adapters/sql_adapter"
|
|
28
31
|
require "blazer/adapters/snowflake_adapter"
|
|
29
32
|
|
|
@@ -32,6 +35,7 @@ require "blazer/engine"
|
|
|
32
35
|
|
|
33
36
|
module Blazer
|
|
34
37
|
class Error < StandardError; end
|
|
38
|
+
class UploadError < Error; end
|
|
35
39
|
class TimeoutNotSupported < Error; end
|
|
36
40
|
|
|
37
41
|
class << self
|
|
@@ -206,6 +210,23 @@ module Blazer
|
|
|
206
210
|
slack_webhook_url.present?
|
|
207
211
|
end
|
|
208
212
|
|
|
213
|
+
def self.uploads?
|
|
214
|
+
settings.key?("uploads")
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def self.uploads_connection
|
|
218
|
+
raise "Empty url for uploads" unless settings.dig("uploads", "url")
|
|
219
|
+
Blazer::UploadsConnection.connection
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def self.uploads_schema
|
|
223
|
+
settings.dig("uploads", "schema") || "uploads"
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def self.uploads_table_name(name)
|
|
227
|
+
uploads_connection.quote_table_name("#{uploads_schema}.#{name}")
|
|
228
|
+
end
|
|
229
|
+
|
|
209
230
|
def self.adapters
|
|
210
231
|
@adapters ||= {}
|
|
211
232
|
end
|
|
@@ -221,11 +242,14 @@ Blazer.register_adapter "cassandra", Blazer::Adapters::CassandraAdapter
|
|
|
221
242
|
Blazer.register_adapter "drill", Blazer::Adapters::DrillAdapter
|
|
222
243
|
Blazer.register_adapter "druid", Blazer::Adapters::DruidAdapter
|
|
223
244
|
Blazer.register_adapter "elasticsearch", Blazer::Adapters::ElasticsearchAdapter
|
|
245
|
+
Blazer.register_adapter "hive", Blazer::Adapters::HiveAdapter
|
|
246
|
+
Blazer.register_adapter "ignite", Blazer::Adapters::IgniteAdapter
|
|
224
247
|
Blazer.register_adapter "influxdb", Blazer::Adapters::InfluxdbAdapter
|
|
225
248
|
Blazer.register_adapter "neo4j", Blazer::Adapters::Neo4jAdapter
|
|
226
249
|
Blazer.register_adapter "presto", Blazer::Adapters::PrestoAdapter
|
|
227
250
|
Blazer.register_adapter "mongodb", Blazer::Adapters::MongodbAdapter
|
|
228
251
|
Blazer.register_adapter "salesforce", Blazer::Adapters::SalesforceAdapter
|
|
229
252
|
Blazer.register_adapter "soda", Blazer::Adapters::SodaAdapter
|
|
253
|
+
Blazer.register_adapter "spark", Blazer::Adapters::SparkAdapter
|
|
230
254
|
Blazer.register_adapter "sql", Blazer::Adapters::SqlAdapter
|
|
231
255
|
Blazer.register_adapter "snowflake", Blazer::Adapters::SnowflakeAdapter
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Blazer
|
|
2
|
+
module Adapters
|
|
3
|
+
class HiveAdapter < BaseAdapter
|
|
4
|
+
def run_statement(statement, comment)
|
|
5
|
+
columns = []
|
|
6
|
+
rows = []
|
|
7
|
+
error = nil
|
|
8
|
+
|
|
9
|
+
begin
|
|
10
|
+
result = client.execute("#{statement} /*#{comment}*/")
|
|
11
|
+
columns = result.any? ? result.first.keys : []
|
|
12
|
+
rows = result.map(&:values)
|
|
13
|
+
rescue => e
|
|
14
|
+
error = e.message
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
[columns, rows, error]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def tables
|
|
21
|
+
client.execute("SHOW TABLES").map { |r| r["tab_name"] }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def preview_statement
|
|
25
|
+
"SELECT * FROM {table} LIMIT 10"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
protected
|
|
29
|
+
|
|
30
|
+
def client
|
|
31
|
+
@client ||= begin
|
|
32
|
+
uri = URI.parse(settings["url"])
|
|
33
|
+
Hexspace::Client.new(
|
|
34
|
+
host: uri.host,
|
|
35
|
+
port: uri.port,
|
|
36
|
+
username: uri.user,
|
|
37
|
+
password: uri.password,
|
|
38
|
+
database: uri.path.sub(/\A\//, ""),
|
|
39
|
+
mode: uri.scheme.to_sym
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Blazer
|
|
2
|
+
module Adapters
|
|
3
|
+
class IgniteAdapter < BaseAdapter
|
|
4
|
+
def run_statement(statement, comment)
|
|
5
|
+
columns = []
|
|
6
|
+
rows = []
|
|
7
|
+
error = nil
|
|
8
|
+
|
|
9
|
+
begin
|
|
10
|
+
result = client.query("#{statement} /*#{comment}*/", schema: default_schema, statement_type: :select, timeout: data_source.timeout)
|
|
11
|
+
columns = result.any? ? result.first.keys : []
|
|
12
|
+
rows = result.map(&:values)
|
|
13
|
+
rescue => e
|
|
14
|
+
error = e.message
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
[columns, rows, error]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def preview_statement
|
|
21
|
+
"SELECT * FROM {table} LIMIT 10"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def tables
|
|
25
|
+
sql = "SELECT table_schema, table_name FROM information_schema.tables WHERE table_schema NOT IN ('INFORMATION_SCHEMA', 'SYS')"
|
|
26
|
+
result = data_source.run_statement(sql)
|
|
27
|
+
result.rows.reject { |row| row[1].start_with?("__") }.map do |row|
|
|
28
|
+
(row[0] == default_schema ? row[1] : "#{row[0]}.#{row[1]}").downcase
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# TODO figure out error
|
|
33
|
+
# Table `__T0` can be accessed only within Ignite query context.
|
|
34
|
+
# def schema
|
|
35
|
+
# sql = "SELECT table_schema, table_name, column_name, data_type, ordinal_position FROM information_schema.columns WHERE table_schema NOT IN ('INFORMATION_SCHEMA', 'SYS')"
|
|
36
|
+
# result = data_source.run_statement(sql)
|
|
37
|
+
# 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]] }
|
|
38
|
+
# end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def default_schema
|
|
43
|
+
"PUBLIC"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def client
|
|
47
|
+
@client ||= begin
|
|
48
|
+
uri = URI(settings["url"])
|
|
49
|
+
Ignite::Client.new(host: uri.host, port: uri.port, username: uri.user, password: uri.password)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|