Class: RailsPulse::Query
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
.bulk_find_or_create(norm_map) ⇒ Object
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
# File 'app/models/rails_pulse/query.rb', line 27
def self.bulk_find_or_create(norm_map)
return {} if norm_map.empty?
id_map = where(hashed_sql: norm_map.keys).pluck(:hashed_sql, :id).to_h
missing = norm_map.reject { |h, _| id_map.key?(h) }
unless missing.empty?
now = Time.current
insert_all(missing.map { |h, n| { hashed_sql: h, normalized_sql: n, created_at: now, updated_at: now } })
id_map.merge!(where(hashed_sql: missing.keys).pluck(:hashed_sql, :id).to_h)
end
id_map
end
|
.ransackable_associations(auth_object = nil) ⇒ Object
46
47
48
|
# File 'app/models/rails_pulse/query.rb', line 46
def self.ransackable_associations(auth_object = nil)
%w[operations]
end
|
.ransackable_attributes(auth_object = nil) ⇒ Object
42
43
44
|
# File 'app/models/rails_pulse/query.rb', line 42
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_status ⇒ Object
127
128
129
130
131
|
# File 'app/models/rails_pulse/query.rb', line 127
def analysis_status
return "not_analyzed" unless analyzed?
return "needs_update" if needs_reanalysis?
"current"
end
|
#analyzed? ⇒ Boolean
109
110
111
|
# File 'app/models/rails_pulse/query.rb', line 109
def analyzed?
analyzed_at.present?
end
|
#critical_issues_count ⇒ Object
139
140
141
|
# File 'app/models/rails_pulse/query.rb', line 139
def critical_issues_count
issues_by_severity["critical"]&.count || 0
end
|
#ensure_analyzed! ⇒ Object
100
101
102
103
104
105
106
|
# File 'app/models/rails_pulse/query.rb', line 100
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_sql ⇒ Object
155
156
157
158
|
# File 'app/models/rails_pulse/query.rb', line 155
def generate_hashed_sql
require "digest"
self.hashed_sql = Digest::MD5.hexdigest(normalized_sql)
end
|
#has_recent_operations? ⇒ Boolean
113
114
115
|
# File 'app/models/rails_pulse/query.rb', line 113
def has_recent_operations?
operations.where("occurred_at > ?", 48.hours.ago).exists?
end
|
#issues_by_severity ⇒ Object
133
134
135
136
137
|
# File 'app/models/rails_pulse/query.rb', line 133
def issues_by_severity
return {} unless analyzed? && issues.present?
issues.group_by { |issue| issue["severity"] || "unknown" }
end
|
#n_plus_one_groups(ops) ⇒ Object
93
94
95
96
97
98
|
# File 'app/models/rails_pulse/query.rb', line 93
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
117
118
119
120
121
122
123
124
125
|
# File 'app/models/rails_pulse/query.rb', line 117
def needs_reanalysis?
return true unless analyzed?
last_operation_time = operations.maximum(:occurred_at)
return false unless last_operation_time
last_operation_time > analyzed_at
end
|
#recent_operations ⇒ Object
85
86
87
88
89
90
91
|
# File 'app/models/rails_pulse/query.rb', line 85
def recent_operations
operations
.where("occurred_at > ?", 30.days.ago)
.order(occurred_at: :desc)
.limit(500)
.to_a
end
|
#to_breadcrumb ⇒ Object
147
148
149
|
# File 'app/models/rails_pulse/query.rb', line 147
def to_breadcrumb
normalized_sql.to_s.truncate(60)
end
|
#to_s ⇒ Object
151
152
153
|
# File 'app/models/rails_pulse/query.rb', line 151
def to_s
id
end
|
#warning_issues_count ⇒ Object
143
144
145
|
# File 'app/models/rails_pulse/query.rb', line 143
def warning_issues_count
issues_by_severity["warning"]&.count || 0
end
|