Class: AndOne::Detection

Inherits:
Object
  • Object
show all
Defined in:
lib/and_one/detection.rb

Overview

Represents a single N+1 detection: the repeated queries, their call site, and metadata.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(queries:, caller_locations:, count:, adapter: nil) ⇒ Detection

Returns a new instance of Detection.



10
11
12
13
14
15
# File 'lib/and_one/detection.rb', line 10

def initialize(queries:, caller_locations:, count:, adapter: nil)
  @queries = queries
  @caller_locations = caller_locations
  @count = count
  @adapter = adapter
end

Instance Attribute Details

#adapterObject (readonly)

Returns the value of attribute adapter.



8
9
10
# File 'lib/and_one/detection.rb', line 8

def adapter
  @adapter
end

#caller_locationsObject (readonly)

Returns the value of attribute caller_locations.



8
9
10
# File 'lib/and_one/detection.rb', line 8

def caller_locations
  @caller_locations
end

#countObject (readonly)

Returns the value of attribute count.



8
9
10
# File 'lib/and_one/detection.rb', line 8

def count
  @count
end

#queriesObject (readonly)

Returns the value of attribute queries.



8
9
10
# File 'lib/and_one/detection.rb', line 8

def queries
  @queries
end

Instance Method Details

#fingerprintObject

A stable fingerprint for this detection, based on the query shape and the target table. Independent of call site so the same N+1 pattern produces the same fingerprint regardless of where it's triggered. For location-specific ignoring, use path: rules in .and_one_ignore.



31
32
33
34
35
36
# File 'lib/and_one/detection.rb', line 31

def fingerprint
  @fingerprint ||= begin
    sql_fp = Fingerprint.generate(sample_query)
    Digest::SHA256.hexdigest("#{sql_fp}:#{table_name}")[0, 12]
  end
end

#fix_locationObject

The frame where the AR relation/collection was likely loaded or iterated. This is the best place to add .includes().



51
52
53
# File 'lib/and_one/detection.rb', line 51

def fix_location
  @fix_location ||= find_fix_location
end

#origin_frameObject

The first frame in the call stack that is application code (not a gem, not ruby stdlib, not and_one itself)



45
46
47
# File 'lib/and_one/detection.rb', line 45

def origin_frame
  @origin_frame ||= find_origin_frame
end

#raw_caller_stringsObject

The raw caller strings (before backtrace cleaning)



39
40
41
# File 'lib/and_one/detection.rb', line 39

def raw_caller_strings
  @raw_caller_strings ||= caller_locations.map(&:to_s)
end

#sample_queryObject

Returns the SQL of the first query as the representative example



18
19
20
# File 'lib/and_one/detection.rb', line 18

def sample_query
  @queries.first
end

#table_nameObject

Attempt to extract the table name from the repeated query



23
24
25
# File 'lib/and_one/detection.rb', line 23

def table_name
  @table_name ||= extract_table_name(sample_query)
end