123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- require "csv"
- require "chartkick"
- require "blazer/version"
- require "blazer/engine"
- require "blazer/tasks"
- module Blazer
- class << self
- attr_accessor :audit
- attr_reader :time_zone
- attr_accessor :user_name
- attr_accessor :user_class
- attr_accessor :timeout
- attr_accessor :from_email
- end
- self.audit = true
- self.user_name = :name
- self.timeout = 15
- def self.time_zone=(time_zone)
- @time_zone = time_zone.is_a?(ActiveSupport::TimeZone) ? time_zone : ActiveSupport::TimeZone[time_zone.to_s]
- end
- def self.settings
- @settings ||= YAML.load(File.read(Rails.root.join("config", "blazer.yml")))
- end
- def self.linked_columns
- settings["linked_columns"] || {}
- end
- def self.smart_columns
- settings["smart_columns"] || {}
- end
- def self.smart_variables
- settings["smart_variables"] || {}
- end
- def self.run_statement(statement)
- rows = []
- error = nil
- begin
- Blazer::Connection.transaction do
- Blazer::Connection.connection.execute("SET statement_timeout = #{Blazer.timeout * 1000}") if Blazer.timeout && postgresql?
- result = Blazer::Connection.connection.select_all(statement)
- result.each do |untyped_row|
- row = {}
- untyped_row.each do |k, v|
- row[k] = result.column_types.empty? ? v : result.column_types[k].send(:type_cast, v)
- end
- rows << row
- end
- raise ActiveRecord::Rollback
- end
- rescue ActiveRecord::StatementInvalid => e
- error = e.message.sub(/.+ERROR: /, "")
- end
- [rows, error]
- end
- def self.tables
- default_schema = postgresql? ? "public" : Blazer::Connection.connection_config[:database]
- schema = Blazer::Connection.connection_config[:schema] || default_schema
- rows, error = run_statement(Blazer::Connection.send(:sanitize_sql_array, ["SELECT table_name, column_name, ordinal_position, data_type FROM information_schema.columns WHERE table_schema = ?", schema]))
- Hash[rows.group_by { |r| r["table_name"] }.map { |t, f| [t, f.sort_by { |f| f["ordinal_position"] }.map { |f| f.slice("column_name", "data_type") }] }.sort_by { |t, _f| t }]
- end
- def self.postgresql?
- ["PostgreSQL", "Redshift"].include?(Blazer::Connection.connection.adapter_name)
- end
- def self.run_checks
- Blazer::Check.includes(:blazer_query).find_each do |check|
- rows = nil
- error = nil
- tries = 0
- # try 3 times on timeout errors
- begin
- rows, error = run_statement(check.blazer_query.statement)
- tries += 1
- end while error && error.include?("canceling statement due to statement timeout") && tries < 3
- check.update_state(rows, error)
- end
- end
- def self.send_failing_checks
- emails = {}
- Blazer::Check.includes(:blazer_query).where(state: %w[failing error]).find_each do |check|
- check.split_emails.each do |email|
- (emails[email] ||= []) << check
- end
- end
- emails.each do |email, checks|
- Blazer::CheckMailer.failing_checks(email, checks).deliver_later
- end
- end
- end
|