module Sequel::Postgres::AutoParameterizeDuplicateQueryDetection

  1. lib/sequel/extensions/pg_auto_parameterize_duplicate_query_detection.rb

Enable detecting duplicate queries inside a block

Methods

Public Class

  1. extended

Public Instance

  1. detect_duplicate_queries
  2. execute
  3. ignore_duplicate_queries

Public Class methods

extended(db)
[show source]
   # File lib/sequel/extensions/pg_auto_parameterize_duplicate_query_detection.rb
62 def self.extended(db)
63   db.instance_exec do
64     @duplicate_query_detection_contexts = {}
65     @duplicate_query_detection_mutex = Mutex.new
66   end
67 end

Public Instance methods

detect_duplicate_queries(opts=OPTS, &block)

Run the duplicate query detector during the block. Options:

:backtrace_filter

Regexp used to filter the displayed backtrace.

:handler

If present, called with hash of duplicate query information, instead of raising or warning.

:warn

Always warn instead of raising for duplicate queries.

Note that if you nest calls to this method, only the top level call will respect the passed options.

[show source]
    # File lib/sequel/extensions/pg_auto_parameterize_duplicate_query_detection.rb
122 def detect_duplicate_queries(opts=OPTS, &block)
123   current = Sequel.current
124   if state = duplicate_query_recorder_state(current)
125     return change_duplicate_query_recorder_state(state, true, &block)
126   end
127 
128   @duplicate_query_detection_mutex.synchronize do
129     @duplicate_query_detection_contexts[current] = [true, Hash.new(0)]
130   end
131 
132   begin
133     yield
134   rescue Exception => e
135     raise
136   ensure
137     _, queries = @duplicate_query_detection_mutex.synchronize do
138       @duplicate_query_detection_contexts.delete(current)
139     end
140     queries.delete_if{|_,v| v < 2}
141 
142     unless queries.empty?
143       if handler = opts[:handler]
144         handler.call(queries)
145       else
146         backtrace_filter = opts[:backtrace_filter]
147         backtrace_filter_note = backtrace_filter ? " (filtered)" : ""
148         query_info = queries.map do |k,v|
149           backtrace = k[1]
150           backtrace = backtrace.grep(backtrace_filter) if backtrace_filter
151           "times:#{v}\nsql:#{k[0]}\nbacktrace#{backtrace_filter_note}:\n#{backtrace.join("\n")}\n"
152         end
153         message = "duplicate queries detected:\n\n#{query_info.join("\n")}"
154 
155         if e || opts[:warn]
156           warn(message)
157         else
158           raise DuplicateQueries.new(message, queries)
159         end
160       end
161     end
162   end
163 end
execute(sql, opts=OPTS, &block)

Record each query executed so duplicates can be detected, if queries are being recorded.

[show source]
   # File lib/sequel/extensions/pg_auto_parameterize_duplicate_query_detection.rb
85 def execute(sql, opts=OPTS, &block)
86   record, queries = duplicate_query_recorder_state
87 
88   if record
89     queries[[sql.is_a?(Symbol) ? sql : sql.to_s, caller].freeze] += 1
90   end
91 
92   super
93 end
ignore_duplicate_queries(&block)

Ignore (do not record) queries inside given block. This can be useful in situations where you want to run your entire test suite with duplicate query detection, but you have duplicate queries in some parts of your application where it is not trivial to use a different approach. You can mark those specific sections with ignore_duplicate_queries, and still get duplicate query detection for the rest of the application.

[show source]
    # File lib/sequel/extensions/pg_auto_parameterize_duplicate_query_detection.rb
102 def ignore_duplicate_queries(&block)
103   if state = duplicate_query_recorder_state
104     change_duplicate_query_recorder_state(state, false, &block)
105   else
106     # If we are not inside a detect_duplicate_queries block, there is
107     # no need to do anything, since we are not recording queries.
108     yield
109   end
110 end