queries_controller.rb 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. module Blazer
  2. class QueriesController < BaseController
  3. before_action :set_query, only: [:show, :edit, :update, :destroy, :refresh]
  4. def home
  5. set_queries(1000)
  6. end
  7. def index
  8. set_queries
  9. render partial: "index", layout: false
  10. end
  11. def new
  12. @query = Blazer::Query.new(
  13. statement: params[:statement],
  14. data_source: params[:data_source],
  15. name: params[:name]
  16. )
  17. if params[:fork_query_id]
  18. @query.statement ||= Blazer::Query.find(params[:fork_query_id]).try(:statement)
  19. end
  20. end
  21. def create
  22. @query = Blazer::Query.new(query_params)
  23. @query.creator = blazer_user if @query.respond_to?(:creator)
  24. if @query.save
  25. redirect_to query_path(@query, variable_params)
  26. else
  27. render :new
  28. end
  29. end
  30. def show
  31. @statement = @query.statement.dup
  32. process_vars(@statement)
  33. @smart_vars = {}
  34. @sql_errors = []
  35. data_source = Blazer.data_sources[@query.data_source]
  36. @bind_vars.each do |var|
  37. query = data_source.smart_variables[var]
  38. if query
  39. rows, error, cached_at = data_source.run_statement(query)
  40. @smart_vars[var] = rows.map { |v| v.values.reverse }
  41. @sql_errors << error if error
  42. end
  43. end
  44. Blazer.transform_statement.call(data_source, @statement) if Blazer.transform_statement
  45. end
  46. def edit
  47. end
  48. def run
  49. @statement = params[:statement]
  50. process_vars(@statement)
  51. @only_chart = params[:only_chart]
  52. if @success
  53. @query = Query.find_by(id: params[:query_id]) if params[:query_id]
  54. data_source = params[:data_source]
  55. data_source = @query.data_source if @query && @query.data_source
  56. @data_source = Blazer.data_sources[data_source]
  57. Blazer.transform_statement.call(@data_source, @statement) if Blazer.transform_statement
  58. # audit
  59. if Blazer.audit
  60. audit = Blazer::Audit.new(statement: @statement)
  61. audit.query = @query
  62. audit.data_source = data_source
  63. audit.user = blazer_user
  64. audit.save!
  65. end
  66. @rows, @error, @cached_at = @data_source.run_statement(@statement, user: blazer_user, query: @query, refresh_cache: params[:check])
  67. if @query && @error != Blazer::TIMEOUT_MESSAGE
  68. @query.checks.each do |check|
  69. check.update_state(@rows, @error)
  70. end
  71. end
  72. @columns = {}
  73. if @rows.any?
  74. @rows.first.each do |key, value|
  75. @columns[key] =
  76. case value
  77. when Integer
  78. "int"
  79. when Float
  80. "float"
  81. else
  82. "string-ins"
  83. end
  84. end
  85. end
  86. @filename = @query.name.parameterize if @query
  87. @min_width_types = (@rows.first || {}).select { |k, v| v.is_a?(Time) || v.is_a?(String) || @data_source.smart_columns[k] }.keys
  88. @boom = {}
  89. @columns.keys.each do |key|
  90. query = @data_source.smart_columns[key]
  91. if query
  92. values = @rows.map { |r| r[key] }.compact.uniq
  93. rows, error, cached_at = @data_source.run_statement(ActiveRecord::Base.send(:sanitize_sql_array, [query.sub("{value}", "(?)"), values]))
  94. @boom[key] = Hash[rows.map(&:values).map { |k, v| [k.to_s, v] }]
  95. end
  96. end
  97. @linked_columns = @data_source.linked_columns
  98. @markers = []
  99. [["latitude", "longitude"], ["lat", "lon"]].each do |keys|
  100. if (keys - (@rows.first || {}).keys).empty?
  101. @markers =
  102. @rows.select do |r|
  103. r[keys.first] && r[keys.last]
  104. end.map do |r|
  105. {
  106. title: r.except(*keys).map{ |k, v| "<strong>#{k}:</strong> #{v}" }.join("<br />").truncate(140),
  107. latitude: r[keys.first],
  108. longitude: r[keys.last]
  109. }
  110. end
  111. end
  112. end
  113. end
  114. respond_to do |format|
  115. format.html do
  116. render layout: false
  117. end
  118. format.csv do
  119. send_data csv_data(@rows), type: "text/csv; charset=utf-8; header=present", disposition: "attachment; filename=\"#{@query ? @query.name.parameterize : 'query'}.csv\""
  120. end
  121. end
  122. end
  123. def refresh
  124. data_source = Blazer.data_sources[@query.data_source]
  125. @statement = @query.statement.dup
  126. process_vars(@statement)
  127. Blazer.transform_statement.call(data_source, @statement) if Blazer.transform_statement
  128. data_source.clear_cache(@statement)
  129. redirect_to query_path(@query, variable_params)
  130. end
  131. def update
  132. if params[:commit] == "Fork"
  133. @query = Blazer::Query.new
  134. @query.creator = blazer_user if @query.respond_to?(:creator)
  135. end
  136. unless @query.editable?(blazer_user)
  137. @query.errors.add(:base, "Sorry, permission denied")
  138. end
  139. if @query.errors.empty? && @query.update(query_params)
  140. redirect_to query_path(@query, variable_params)
  141. else
  142. render :edit
  143. end
  144. end
  145. def destroy
  146. @query.destroy if @query.editable?(blazer_user)
  147. redirect_to root_url
  148. end
  149. def tables
  150. @tables = Blazer.data_sources[params[:data_source]].tables.keys
  151. render partial: "tables", layout: false
  152. end
  153. private
  154. def set_queries(limit = nil)
  155. @my_queries =
  156. if blazer_user
  157. favorite_query_ids = Blazer::Audit.where(user_id: blazer_user.id).where("created_at > ?", 7.days.ago).where("query_id IS NOT NULL").group(:query_id).order("count_all desc").limit(50).count.keys
  158. queries = Blazer::Query.where("name <> ''").where(id: favorite_query_ids).index_by(&:id)
  159. favorite_query_ids.map { |query_id| queries[query_id] }.compact
  160. else
  161. []
  162. end
  163. @queries = Blazer::Query.where("name <> ''").order(:name)
  164. @queries = @queries.where("id NOT IN (?)", @my_queries.map(&:id)) if @my_queries.any?
  165. @queries = @queries.includes(:creator) if Blazer.user_class
  166. @queries = @queries.limit(limit) if limit
  167. @trending_queries = Blazer::Audit.group(:query_id).where("created_at > ?", 2.days.ago).having("COUNT(DISTINCT user_id) >= 3").uniq.count(:user_id)
  168. @checks = Blazer::Check.group(:query_id).count
  169. @dashboards = Blazer::Dashboard.order(:name)
  170. end
  171. def set_query
  172. @query = Blazer::Query.find(params[:id].to_s.split("-").first)
  173. end
  174. def query_params
  175. params.require(:query).permit(:name, :description, :statement, :data_source)
  176. end
  177. def csv_data(rows)
  178. CSV.generate do |csv|
  179. if rows.any?
  180. csv << rows.first.keys
  181. end
  182. rows.each do |row|
  183. csv << row.values.map { |v| v.is_a?(Time) ? v.in_time_zone(Blazer.time_zone) : v }
  184. end
  185. end
  186. end
  187. end
  188. end