From 511a745fecd944d0e7834bd3434f017ede766475 Mon Sep 17 00:00:00 2001 From: Mpampis Kostas Date: Thu, 27 Oct 2022 12:47:33 +0300 Subject: [PATCH] Add min_n_queries & ignore_pauses config options --- README.md | 3 +++ lib/prosopite.rb | 12 ++++++++++-- test/test_queries.rb | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 77b9e2b..a94cc0e 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ Or install it yourself as: The preferred type of notifications can be configured with: +* `Prosopite.min_n_queries`: Minimum number of N queries to report per N+1 case. Defaults to 2. * `Prosopite.raise = true`: Raise warnings as exceptions * `Prosopite.rails_logger = true`: Send warnings to the Rails log * `Prosopite.prosopite_logger = true`: Send warnings to `log/prosopite.log` @@ -269,6 +270,8 @@ end Prosopite.finish ``` +Pauses can be ignored with `Prosopite.ignore_pauses = true` in case you want to remember their N+1 queries. + An example of when you might use this is if you are [testing Active Jobs inline](https://guides.rubyonrails.org/testing.html#testing-jobs), and don't want to run Prosopite on background job code, just foreground app code. In that case you could write an [Active Job callback](https://edgeguides.rubyonrails.org/active_job_basics.html#callbacks) that pauses the scan while the job is running. diff --git a/lib/prosopite.rb b/lib/prosopite.rb index 84db702..c5be410 100644 --- a/lib/prosopite.rb +++ b/lib/prosopite.rb @@ -10,7 +10,9 @@ class << self :prosopite_logger, :custom_logger, :allow_stack_paths, - :ignore_queries + :ignore_queries, + :ignore_pauses, + :min_n_queries def allow_list=(value) puts "Prosopite.allow_list= is deprecated. Use Prosopite.allow_stack_paths= instead." @@ -29,6 +31,8 @@ def scan tc[:prosopite_query_caller] = {} @allow_stack_paths ||= [] + @ignore_pauses ||= false + @min_n_queries ||= 2 tc[:prosopite_scan] = true @@ -48,6 +52,10 @@ def tc end def pause + if @ignore_pauses + return block_given? ? yield : nil + end + if block_given? begin previous = tc[:prosopite_scan] @@ -83,7 +91,7 @@ def create_notifications tc[:prosopite_notifications] = {} tc[:prosopite_query_counter].each do |location_key, count| - if count > 1 + if count >= @min_n_queries fingerprints = tc[:prosopite_query_holder][location_key].map do |q| begin fingerprint(q) diff --git a/test/test_queries.rb b/test/test_queries.rb index 26b1668..4b3508b 100644 --- a/test/test_queries.rb +++ b/test/test_queries.rb @@ -124,6 +124,25 @@ def test_pause_with_no_error_after_resume assert_no_n_plus_ones end + def test_pause_with_ignore_pauses + # 20 chairs, 4 legs each + chairs = create_list(:chair, 20) + chairs.each { |c| create_list(:leg, 4, chair: c) } + + Prosopite.ignore_pauses = true + Prosopite.scan + + Prosopite.pause + Chair.last(20).each do |c| + c.legs.last + end + + Prosopite.resume + Prosopite.ignore_pauses = false + + assert_n_plus_one + end + def test_pause_with_error_after_resume # 20 chairs, 4 legs each chairs = create_list(:chair, 20) @@ -348,6 +367,20 @@ def test_ignore_queries_with_incorrect_query_match assert_n_plus_one end + def test_min_n_queries + chairs = create_list(:chair, 4) + chairs.each { |c| create_list(:leg, 4, chair: c) } + + Prosopite.min_n_queries = 5 + + Prosopite.scan + Chair.last(4).each do |c| + c.legs.last + end + + assert_no_n_plus_ones + end + private def assert_n_plus_one assert_raises(Prosopite::NPlusOneQueriesError) do