Module: QueryGuard::Core::FindingBuilders

Defined in:
lib/query_guard/core/finding_builders.rb

Overview

Factory builders for common finding types. Provides convenient methods to create well-structured findings without manually specifying all parameters.

Example:

finding = FindingBuilders.slow_query(
query,
duration_ms: 250.5,
threshold_ms: 100.0
)

Class Method Summary collapse

Class Method Details

.build(analyzer_name:, rule_name:, **opts) ⇒ Object

Generic builder for custom findings



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/query_guard/core/finding_builders.rb', line 93

def self.build(analyzer_name:, rule_name:, **opts)
  Finding.new(
    analyzer_name: analyzer_name,
    rule_name: rule_name,
    severity: opts[:severity] || :warn,
    title: opts[:title],
    description: opts[:description],
    message: opts[:message],
    sql: opts[:sql],
    metadata: opts[:metadata] || {},
    recommendations: opts[:recommendations] || [],
    query: opts[:query],
    file_path: opts[:file_path],
    line_number: opts[:line_number]
  )
end

.migration_risk(migration_file:, issue:, **opts) ⇒ Object

Migration-related finding (prepared for Phase 2)



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/query_guard/core/finding_builders.rb', line 111

def self.migration_risk(migration_file:, issue:, **opts)
  Finding.new(
    analyzer_name: :migration_safety,
    rule_name: opts[:rule_name] || :unsafe_operation,
    severity: opts[:severity] || :error,
    title: opts[:title] || "Migration Risk Detected",
    description: opts[:description] || "Migration may cause data loss or downtime.",
    message: issue,
    file_path: migration_file,
    line_number: opts[:line_number],
    metadata: opts[:metadata] || {},
    recommendations: opts[:recommendations] || [
      "Review migration carefully before deploying",
      "Test on a staging environment",
      "Consider phased rollout for large tables"
    ]
  )
end

.pattern_detected(query, pattern_type:, **opts) ⇒ Object

Pattern matching finding (prepared for future analyzers)



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/query_guard/core/finding_builders.rb', line 131

def self.pattern_detected(query, pattern_type:, **opts)
  Finding.new(
    analyzer_name: opts[:analyzer_name] || :pattern_detector,
    rule_name: opts[:rule_name] || :pattern_detected,
    severity: opts[:severity] || :info,
    title: opts[:title] || "Pattern Detected",
    description: opts[:description] || "A query pattern was detected.",
    message: opts[:message] || "#{pattern_type} pattern detected",
    sql: query&.sql,
    metadata: {
      pattern_type: pattern_type,
      **(opts[:metadata] || {})
    },
    recommendations: opts[:recommendations] || [],
    query: query,
    file_path: opts[:file_path],
    line_number: opts[:line_number]
  )
end

.select_star(query, **opts) ⇒ Object

SELECT * finding



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/query_guard/core/finding_builders.rb', line 68

def self.select_star(query, **opts)
  Finding.new(
    analyzer_name: :select_star,
    rule_name: :select_star_detected,
    severity: opts[:severity] || :warn,
    title: "SELECT * Used",
    description: "Query uses SELECT * instead of specifying columns.",
    message: "SELECT * detected in query",
    sql: query&.sql,
    metadata: {
      sql: query&.sql
    },
    recommendations: [
      "Specify only required columns explicitly",
      "Reduces bandwidth and improves query efficiency",
      "Makes schema changes less error-prone",
      "Enables better query optimization by the database"
    ],
    query: query,
    file_path: opts[:file_path],
    line_number: opts[:line_number]
  )
end

.slow_query(query, duration_ms:, threshold_ms:, **opts) ⇒ Object

Slow query finding



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/query_guard/core/finding_builders.rb', line 17

def self.slow_query(query, duration_ms:, threshold_ms:, **opts)
  Finding.new(
    analyzer_name: :slow_query,
    rule_name: :duration_exceeded,
    severity: opts[:severity] || :warn,
    title: "Slow Query Detected",
    description: "Query execution time exceeded the configured threshold.",
    message: "Query took #{duration_ms.round(2)}ms (limit: #{threshold_ms}ms)",
    sql: query&.sql,
    metadata: {
      duration_ms: duration_ms,
      threshold_ms: threshold_ms
    },
    recommendations: [
      "Add indexes on frequently queried columns",
      "Review and optimize the query logic",
      "Consider using pagination for large result sets",
      "Check database statistics"
    ],
    query: query,
    file_path: opts[:file_path],
    line_number: opts[:line_number]
  )
end

.too_many_queries(count:, limit:, total_duration_ms:, **opts) ⇒ Object

Too many queries finding



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/query_guard/core/finding_builders.rb', line 43

def self.too_many_queries(count:, limit:, total_duration_ms:, **opts)
  Finding.new(
    analyzer_name: :query_count,
    rule_name: :count_exceeded,
    severity: opts[:severity] || :warn,
    title: "Too Many Queries",
    description: "Request executed more queries than the configured limit.",
    message: "Executed #{count} queries (limit: #{limit})",
    metadata: {
      count: count,
      limit: limit,
      total_duration_ms: total_duration_ms
    },
    recommendations: [
      "Use eager loading (N+1 query prevention)",
      "Consolidate multiple queries into one",
      "Use database-level aggregations where possible",
      "Consider caching results"
    ],
    file_path: opts[:file_path],
    line_number: opts[:line_number]
  )
end