sql-jarvis 1.8.0 → 1.9.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,67 @@
1
+ module Blazer
2
+ module Adapters
3
+ class DruidAdapter < BaseAdapter
4
+ TIMESTAMP_REGEX = /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\z/
5
+
6
+ def run_statement(statement, comment)
7
+ columns = []
8
+ rows = []
9
+ error = nil
10
+
11
+ header = {"Content-Type" => "application/json", "Accept" => "application/json"}
12
+ timeout = data_source.timeout ? data_source.timeout.to_i : 300
13
+ data = {
14
+ query: statement,
15
+ context: {
16
+ timeout: timeout * 1000
17
+ }
18
+ }
19
+
20
+ uri = URI.parse("#{settings["url"]}/druid/v2/sql/")
21
+ http = Net::HTTP.new(uri.host, uri.port)
22
+ http.read_timeout = timeout
23
+
24
+ begin
25
+ response = JSON.parse(http.post(uri.request_uri, data.to_json, header).body)
26
+ if response.is_a?(Hash)
27
+ error = response["errorMessage"] || "Unknown error: #{response.inspect}"
28
+ if error.include?("timed out")
29
+ error = Blazer::TIMEOUT_MESSAGE
30
+ end
31
+ else
32
+ columns = (response.first || {}).keys
33
+ rows = response.map { |r| r.values }
34
+
35
+ # Druid doesn't return column types
36
+ # and no timestamp type in JSON
37
+ rows.each do |row|
38
+ row.each_with_index do |v, i|
39
+ if v.is_a?(String) && TIMESTAMP_REGEX.match(v)
40
+ row[i] = Time.parse(v)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ rescue => e
46
+ error = e.message
47
+ end
48
+
49
+ [columns, rows, error]
50
+ end
51
+
52
+ def tables
53
+ result = data_source.run_statement("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA NOT IN ('INFORMATION_SCHEMA') ORDER BY TABLE_NAME")
54
+ result.rows.map(&:first)
55
+ end
56
+
57
+ def schema
58
+ result = data_source.run_statement("SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, ORDINAL_POSITION FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA NOT IN ('INFORMATION_SCHEMA') ORDER BY 1, 2")
59
+ 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]} }} }
60
+ end
61
+
62
+ def preview_statement
63
+ "SELECT * FROM {table} LIMIT 10"
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,73 @@
1
+ module Blazer
2
+ module Adapters
3
+ class SnowflakeAdapter < SqlAdapter
4
+ def initialize(data_source)
5
+ @data_source = data_source
6
+
7
+ @@registered ||= begin
8
+ require "active_record/connection_adapters/odbc_adapter"
9
+ require "odbc_adapter/adapters/postgresql_odbc_adapter"
10
+
11
+ ODBCAdapter.register(/snowflake/, ODBCAdapter::Adapters::PostgreSQLODBCAdapter) do
12
+ # Explicitly turning off prepared statements as they are not yet working with
13
+ # snowflake + the ODBC ActiveRecord adapter
14
+ def prepared_statements
15
+ false
16
+ end
17
+
18
+ # Quoting needs to be changed for snowflake
19
+ def quote_column_name(name)
20
+ name.to_s
21
+ end
22
+
23
+ private
24
+
25
+ # Override dbms_type_cast to get the values encoded in UTF-8
26
+ def dbms_type_cast(columns, values)
27
+ int_column = {}
28
+ columns.each_with_index do |c, i|
29
+ int_column[i] = c.type == 3 && c.scale == 0
30
+ end
31
+
32
+ float_column = {}
33
+ columns.each_with_index do |c, i|
34
+ float_column[i] = c.type == 3 && c.scale != 0
35
+ end
36
+
37
+ values.each do |row|
38
+ row.each_index do |idx|
39
+ val = row[idx]
40
+ if val
41
+ if int_column[idx]
42
+ row[idx] = val.to_i
43
+ elsif float_column[idx]
44
+ row[idx] = val.to_f
45
+ elsif val.is_a?(String)
46
+ row[idx] = val.force_encoding('UTF-8')
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ @connection_model =
56
+ Class.new(Blazer::Connection) do
57
+ def self.name
58
+ "Blazer::Connection::SnowflakeAdapter#{object_id}"
59
+ end
60
+ if data_source.settings["conn_str"]
61
+ establish_connection(adapter: "odbc", conn_str: data_source.settings["conn_str"])
62
+ elsif data_source.settings["dsn"]
63
+ establish_connection(adapter: "odbc", dsn: data_source.settings["dsn"])
64
+ end
65
+ end
66
+ end
67
+
68
+ def cancel(run_id)
69
+ # todo
70
+ end
71
+ end
72
+ end
73
+ end
@@ -4,24 +4,13 @@ module Blazer
4
4
  class DataSource
5
5
  extend Forwardable
6
6
 
7
- attr_reader :id, :settings, :adapter, :adapter_instance
7
+ attr_reader :id, :settings
8
8
 
9
9
  def_delegators :adapter_instance, :schema, :tables, :preview_statement, :reconnect, :cost, :explain, :cancel
10
10
 
11
11
  def initialize(id, settings)
12
12
  @id = id
13
13
  @settings = settings
14
-
15
- unless settings["url"] || Rails.env.development? || ["bigquery", "athena"].include?(settings["adapter"])
16
- raise Blazer::Error, "Empty url for data source: #{id}"
17
- end
18
-
19
- @adapter_instance =
20
- if Blazer.adapters[adapter]
21
- Blazer.adapters[adapter].new(self)
22
- else
23
- raise Blazer::Error, "Unknown adapter"
24
- end
25
14
  end
26
15
 
27
16
  def adapter
@@ -101,7 +90,6 @@ module Blazer
101
90
  end
102
91
 
103
92
  def run_statement(statement, options = {})
104
- run_id = options[:run_id]
105
93
  async = options[:async]
106
94
  result = nil
107
95
  if cache_mode != "off"
@@ -154,9 +142,23 @@ module Blazer
154
142
 
155
143
  protected
156
144
 
145
+ def adapter_instance
146
+ @adapter_instance ||= begin
147
+ unless settings["url"] || Rails.env.development? || ["bigquery", "athena", "snowflake"].include?(settings["adapter"])
148
+ raise Blazer::Error, "Empty url for data source: #{id}"
149
+ end
150
+
151
+ unless Blazer.adapters[adapter]
152
+ raise Blazer::Error, "Unknown adapter"
153
+ end
154
+
155
+ Blazer.adapters[adapter].new(self)
156
+ end
157
+ end
158
+
157
159
  def run_statement_helper(statement, comment, run_id)
158
160
  start_time = Time.now
159
- columns, rows, error = @adapter_instance.run_statement(statement, comment)
161
+ columns, rows, error = adapter_instance.run_statement(statement, comment)
160
162
  duration = Time.now - start_time
161
163
 
162
164
  cache_data = nil
@@ -165,7 +167,7 @@ module Blazer
165
167
  cache_data = Marshal.dump([columns, rows, error, cache ? Time.now : nil]) rescue nil
166
168
  end
167
169
 
168
- if cache && cache_data && @adapter_instance.cachable?(statement)
170
+ if cache && cache_data && adapter_instance.cachable?(statement)
169
171
  Blazer.cache.write(statement_cache_key(statement), cache_data, expires_in: cache_expires_in.to_f * 60)
170
172
  end
171
173
 
@@ -183,7 +185,7 @@ module Blazer
183
185
  def detect_adapter
184
186
  schema = settings["url"].to_s.split("://").first
185
187
  case schema
186
- when "mongodb", "presto"
188
+ when "mongodb", "presto", "cassandra"
187
189
  schema
188
190
  else
189
191
  "sql"
data/lib/blazer/engine.rb CHANGED
@@ -11,21 +11,23 @@ module Blazer
11
11
  Blazer.audit = Blazer.settings.key?("audit") ? Blazer.settings["audit"] : true
12
12
  Blazer.user_name = Blazer.settings["user_name"] if Blazer.settings["user_name"]
13
13
  Blazer.from_email = Blazer.settings["from_email"] if Blazer.settings["from_email"]
14
- Blazer.before_action = Blazer.settings["before_action"] if Blazer.settings["before_action"]
15
-
16
- Blazer.user_class ||= Blazer.settings.key?("user_class") ? Blazer.settings["user_class"] : (User rescue nil)
17
- Blazer.user_method = Blazer.settings["user_method"]
18
- if Blazer.user_class
19
- Blazer.user_method ||= "current_#{Blazer.user_class.to_s.downcase.singularize}"
20
- end
21
-
14
+ Blazer.before_action = Blazer.settings["before_action_method"] if Blazer.settings["before_action_method"]
22
15
  Blazer.check_schedules = Blazer.settings["check_schedules"] if Blazer.settings.key?("check_schedules")
16
+
23
17
  if Blazer.settings.key?("mapbox_access_token")
24
18
  Blazer.mapbox_access_token = Blazer.settings["mapbox_access_token"]
25
19
  elsif ENV["MAPBOX_ACCESS_TOKEN"].present?
26
20
  Blazer.mapbox_access_token = ENV["MAPBOX_ACCESS_TOKEN"]
27
21
  end
28
22
 
23
+ if Blazer.settings.key?('assignees')
24
+ data_source = Blazer.data_sources['main']
25
+ statement = Blazer.settings['assignees']
26
+ Blazer.assignees = (Blazer::RunStatement.new.perform(data_source, statement, {}).rows rescue [])
27
+ else
28
+ Blazer.assignees = []
29
+ end
30
+
29
31
  if Blazer.user_class
30
32
  options = Blazer::BELONGS_TO_OPTIONAL.merge(class_name: Blazer.user_class.to_s)
31
33
  Blazer::Query.belongs_to :creator, options
@@ -1,3 +1,3 @@
1
1
  module Blazer
2
- VERSION = "1.8.0"
2
+ VERSION = "1.9.6"
3
3
  end
@@ -3,7 +3,6 @@
3
3
  data_sources:
4
4
  main:
5
5
  url: <%%= ENV["BLAZER_DATABASE_URL"] %>
6
- mapbox_access_token: <%%= ENV["MAPBOX_ACCESS_TOKEN"] %>
7
6
 
8
7
  # statement timeout, in seconds
9
8
  # none by default
@@ -48,13 +47,15 @@ audit: true
48
47
  # method name for the display name
49
48
  # user_name: name
50
49
 
51
- # optional auth method to use as a before_action (default: nil)
52
- # before_action: :authenticate!
50
+ # custom before_action to use for auth
51
+ # before_action_method: require_admin
53
52
 
54
53
  # email to send checks from
55
54
  # from_email: blazer@example.org
56
55
 
57
- # mapbox_access_token: ''
56
+ mapbox_access_token: <%= ENV["MAPBOX_ACCESS_TOKEN"] %>
57
+
58
+ #assignees: 'SELECT id, name FROM users ORDER BY id ASC'
58
59
 
59
60
  check_schedules:
60
61
  - "1 day"
@@ -6,6 +6,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version
6
6
  t.text :description
7
7
  t.text :statement
8
8
  t.string :data_source
9
+ t.string :assignee_ids
9
10
  t.timestamps null: false
10
11
  end
11
12
 
@@ -1,6 +1,6 @@
1
1
  namespace :blazer do
2
2
  desc "run checks"
3
- task :run_checks, [:schedule] => :environment do |t, args|
3
+ task :run_checks, [:schedule] => :environment do |_, args|
4
4
  Blazer.run_checks(schedule: args[:schedule] || ENV["SCHEDULE"])
5
5
  end
6
6
 
Binary file
Binary file
metadata CHANGED
@@ -1,17 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sql-jarvis
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.9.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - ThanhKhoaIT
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-03 00:00:00.000000000 Z
11
+ date: 2018-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: railties
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - ">="
@@ -87,8 +101,11 @@ executables: []
87
101
  extensions: []
88
102
  extra_rdoc_files: []
89
103
  files:
104
+ - ".gitattributes"
105
+ - ".github/ISSUE_TEMPLATE.md"
90
106
  - ".gitignore"
91
107
  - CHANGELOG.md
108
+ - CONTRIBUTING.md
92
109
  - Gemfile
93
110
  - LICENSE.txt
94
111
  - README.md
@@ -120,6 +137,7 @@ files:
120
137
  - app/assets/javascripts/blazer/moment.js
121
138
  - app/assets/javascripts/blazer/queries.js
122
139
  - app/assets/javascripts/blazer/routes.js
140
+ - app/assets/javascripts/blazer/select2.js
123
141
  - app/assets/javascripts/blazer/selectize.js
124
142
  - app/assets/javascripts/blazer/stupidtable.js
125
143
  - app/assets/javascripts/blazer/vue.js
@@ -127,6 +145,7 @@ files:
127
145
  - app/assets/stylesheets/blazer/bootstrap.css.erb
128
146
  - app/assets/stylesheets/blazer/daterangepicker-bs3.css
129
147
  - app/assets/stylesheets/blazer/github.css
148
+ - app/assets/stylesheets/blazer/select2.min.css
130
149
  - app/assets/stylesheets/blazer/selectize.default.css
131
150
  - app/controllers/blazer/base_controller.rb
132
151
  - app/controllers/blazer/checks_controller.rb
@@ -167,10 +186,13 @@ files:
167
186
  - lib/blazer/adapters/athena_adapter.rb
168
187
  - lib/blazer/adapters/base_adapter.rb
169
188
  - lib/blazer/adapters/bigquery_adapter.rb
189
+ - lib/blazer/adapters/cassandra_adapter.rb
170
190
  - lib/blazer/adapters/drill_adapter.rb
191
+ - lib/blazer/adapters/druid_adapter.rb
171
192
  - lib/blazer/adapters/elasticsearch_adapter.rb
172
193
  - lib/blazer/adapters/mongodb_adapter.rb
173
194
  - lib/blazer/adapters/presto_adapter.rb
195
+ - lib/blazer/adapters/snowflake_adapter.rb
174
196
  - lib/blazer/adapters/sql_adapter.rb
175
197
  - lib/blazer/data_source.rb
176
198
  - lib/blazer/detect_anomalies.R
@@ -180,9 +202,11 @@ files:
180
202
  - lib/blazer/run_statement_job.rb
181
203
  - lib/blazer/version.rb
182
204
  - lib/generators/blazer/install_generator.rb
183
- - lib/generators/blazer/templates/config.yml
184
- - lib/generators/blazer/templates/install.rb
205
+ - lib/generators/blazer/templates/config.yml.tt
206
+ - lib/generators/blazer/templates/install.rb.tt
185
207
  - lib/tasks/blazer.rake
208
+ - sql-jarvis-1.9.4.gem
209
+ - sql-jarvis-1.9.5.gem
186
210
  homepage: https://github.com/ThanhKhoaIT/blazer
187
211
  licenses:
188
212
  - MIT
@@ -203,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
203
227
  version: '0'
204
228
  requirements: []
205
229
  rubyforge_project:
206
- rubygems_version: 2.6.11
230
+ rubygems_version: 2.6.14
207
231
  signing_key:
208
232
  specification_version: 4
209
233
  summary: Fork from ankane! Explore your data with SQL. Easily create charts and dashboards,