Class: RailsPulse::Query

Inherits:
ApplicationRecord show all
Includes:
Taggable
Defined in:
app/models/rails_pulse/query.rb

Constant Summary

Constants included from Taggable

Taggable::MAX_TAG_LENGTH, Taggable::TAG_NAME_REGEX

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Taggable

#add_tag, #has_tag?, #remove_tag, #tag_list, #tag_list=

Class Method Details

.ransackable_associations(auth_object = nil) ⇒ Object



31
32
33
# File 'app/models/rails_pulse/query.rb', line 31

def self.ransackable_associations(auth_object = nil)
  %w[operations]
end

.ransackable_attributes(auth_object = nil) ⇒ Object



27
28
29
# File 'app/models/rails_pulse/query.rb', line 27

def self.ransackable_attributes(auth_object = nil)
  %w[id normalized_sql average_query_time_ms execution_count total_time_consumed performance_status occurred_at]
end

Instance Method Details

#analysis_statusObject



112
113
114
115
116
# File 'app/models/rails_pulse/query.rb', line 112

def analysis_status
  return "not_analyzed" unless analyzed?
  return "needs_update" if needs_reanalysis?
  "current"
end

#analyzed?Boolean

Analysis helper methods

Returns:

  • (Boolean)


94
95
96
# File 'app/models/rails_pulse/query.rb', line 94

def analyzed?
  analyzed_at.present?
end

#critical_issues_countObject



124
125
126
# File 'app/models/rails_pulse/query.rb', line 124

def critical_issues_count
  issues_by_severity["critical"]&.count || 0
end

#ensure_analyzed!Object



85
86
87
88
89
90
91
# File 'app/models/rails_pulse/query.rb', line 85

def ensure_analyzed!
  return if analyzed?
  QueryAnalysisService.analyze_query(id)
  reload
rescue => e
  RailsPulse.logger.warn("[Query] Auto-analysis failed for query #{id}: #{e.message}")
end

#generate_hashed_sqlObject



140
141
142
143
# File 'app/models/rails_pulse/query.rb', line 140

def generate_hashed_sql
  require "digest"
  self.hashed_sql = Digest::MD5.hexdigest(normalized_sql)
end

#has_recent_operations?Boolean

Returns:

  • (Boolean)


98
99
100
# File 'app/models/rails_pulse/query.rb', line 98

def has_recent_operations?
  operations.where("occurred_at > ?", 48.hours.ago).exists?
end

#issues_by_severityObject



118
119
120
121
122
# File 'app/models/rails_pulse/query.rb', line 118

def issues_by_severity
  return {} unless analyzed? && issues.present?

  issues.group_by { |issue| issue["severity"] || "unknown" }
end

#n_plus_one_groups(ops) ⇒ Object



78
79
80
81
82
83
# File 'app/models/rails_pulse/query.rb', line 78

def n_plus_one_groups(ops)
  ops
    .reject { |op| op.repeated_query_group.nil? }
    .group_by(&:repeated_query_group)
    .transform_values { |group| group.map(&:repetition_count).compact.max }
end

#needs_reanalysis?Boolean

Returns:

  • (Boolean)


102
103
104
105
106
107
108
109
110
# File 'app/models/rails_pulse/query.rb', line 102

def needs_reanalysis?
  return true unless analyzed?

  # Check if there are new operations since analysis
  last_operation_time = operations.maximum(:occurred_at)
  return false unless last_operation_time

  last_operation_time > analyzed_at
end

#recent_operationsObject



70
71
72
73
74
75
76
# File 'app/models/rails_pulse/query.rb', line 70

def recent_operations
  operations
    .where("occurred_at > ?", 30.days.ago)
    .order(occurred_at: :desc)
    .limit(500)
    .to_a
end

#to_breadcrumbObject



132
133
134
# File 'app/models/rails_pulse/query.rb', line 132

def to_breadcrumb
  normalized_sql.to_s.truncate(60)
end

#to_sObject



136
137
138
# File 'app/models/rails_pulse/query.rb', line 136

def to_s
  id
end

#warning_issues_countObject



128
129
130
# File 'app/models/rails_pulse/query.rb', line 128

def warning_issues_count
  issues_by_severity["warning"]&.count || 0
end