33require 'ar_query_matchers/queries/create_counter'
44require 'ar_query_matchers/queries/load_counter'
55require 'ar_query_matchers/queries/update_counter'
6+ require 'ar_query_matchers/queries/field_counter'
67require 'bigdecimal'
78
89module ArQueryMatchers
@@ -225,6 +226,60 @@ def failure_text
225226 end
226227 end
227228
229+ class FieldModels
230+ # The following will succeed:
231+ #
232+ # expect {
233+ # WcRiskClass.last.update_attributes(id: 9999)
234+ # WcRiskClass.last.update_attributes(id: 1234)
235+ # }.to query_by_field(
236+ # 'id' => [9999, 1234],
237+ # )
238+ #
239+ RSpec ::Matchers . define ( :query_by_field ) do |expected = { } |
240+ include MatcherConfiguration
241+ include MatcherErrors
242+
243+ # Convert the map of expected values to a Hash of all arrays
244+ expected = expected . map { |k , v | [ k , v . kind_of? ( Array ) ? v : [ v ] ] } . to_h
245+
246+ match do |block |
247+ @query_stats = Queries ::FieldCounter . instrument ( &block )
248+ expected == @query_stats . query_values
249+ end
250+
251+ def failure_text
252+ expectation_failed_message ( 'query_by' , true )
253+ end
254+ end
255+
256+ # The following will succeed:
257+ #
258+ # expect {
259+ # WcRiskClass.last.update_attributes(id: 9999)
260+ # WcRiskClass.last.update_attributes(id: 1234)
261+ # }.to query_by_field_at_least(
262+ # 'id' => 9999,
263+ # )
264+ #
265+ RSpec ::Matchers . define ( :query_by_field_at_least ) do |expected = { } |
266+ include MatcherConfiguration
267+ include MatcherErrors
268+
269+ # Convert the map of expected values to a Hash of all arrays
270+ _expected = expected . map { |k , v | [ k , v . kind_of? ( Array ) ? v : [ v ] ] } . to_h
271+
272+ match do |block |
273+ @query_stats = Queries ::FieldCounter . instrument ( &block )
274+ _expected == @query_stats . query_values . select { |k , v | _expected . keys . include? ( k ) }
275+ end
276+
277+ def failure_text
278+ expectation_failed_message ( 'query_by' , true , true )
279+ end
280+ end
281+ end
282+
228283 # Shared methods that are included in the matchers.
229284 # They configure it and ensure we get consistent and human readable error messages
230285 module MatcherConfiguration
@@ -249,16 +304,26 @@ module MatcherErrors
249304 # Show the difference between expected and actual values with one value
250305 # per line. This is done by hand because as of this writing the author
251306 # doesn't understand how RSpec does its nice hash diff printing.
252- def difference ( keys )
307+ def difference ( keys , values_only = false )
253308 max_key_length = keys . reduce ( 0 ) { |max , key | [ max , key . size ] . max }
254309
255310 keys . map do |key |
256- left = expected . fetch ( key , 0 )
257- right = @query_stats . queries . fetch ( key , { } ) . fetch ( :count , 0 )
311+ left = expected . fetch ( key , values_only ? [ ] : 0 )
312+ right = @query_stats . queries . fetch ( key , { } )
313+ if values_only
314+ left = [ left ] if not left . kind_of? ( Array )
315+ right = right . fetch ( :values , [ ] )
316+ else
317+ right = right . fetch ( :count , 0 )
318+ end
258319
259- diff = "#{ '+' if right > left } #{ right - left } "
320+ if values_only
321+ "#{ key . rjust ( max_key_length , ' ' ) } – expected: #{ left } , got: #{ right } "
322+ else
323+ diff = "#{ '+' if right > left } #{ right - left } "
324+ "#{ key . rjust ( max_key_length , ' ' ) } – expected: #{ left } , got: #{ right } (#{ diff } )"
325+ end
260326
261- "#{ key . rjust ( max_key_length , ' ' ) } – expected: #{ left } , got: #{ right } (#{ diff } )"
262327 end . compact
263328 end
264329
@@ -281,10 +346,24 @@ def no_queries_fail_message(crud_operation)
281346 "Expected ActiveRecord to not #{ crud_operation } any records, got #{ @query_stats . query_counts } \n \n Where unexpected queries came from:\n \n #{ source_lines ( @query_stats . query_counts . keys ) . join ( "\n " ) } "
282347 end
283348
284- def expectation_failed_message ( crud_operation )
349+ def expectation_failed_message ( crud_operation , values_only = false , subset = false )
350+ if values_only
351+ _expected = expected . map { |k , v | [ k , v . kind_of? ( Array ) ? v : [ v ] ] } . to_h
352+ expected = _expected
353+ end
285354 all_model_names = expected . keys + @query_stats . queries . keys
286- model_names_with_wrong_count = all_model_names . reject { |key | expected [ key ] == @query_stats . queries [ key ] [ :count ] } . uniq
287- "Expected ActiveRecord to #{ crud_operation } #{ expected } , got #{ @query_stats . query_counts } \n Expectations that differed:\n #{ difference ( model_names_with_wrong_count ) . join ( "\n " ) } \n \n Where unexpected queries came from:\n \n #{ source_lines ( model_names_with_wrong_count ) . join ( "\n " ) } "
355+ if values_only
356+ model_names_with_wrong_count = all_model_names . reject { |key |
357+ if subset && !expected [ key ] . nil?
358+ ( expected [ key ] - @query_stats . queries [ key ] [ :values ] ) . empty?
359+ else
360+ @query_stats . queries [ key ] [ :values ] == expected [ key ]
361+ end
362+ } . uniq
363+ else
364+ model_names_with_wrong_count = all_model_names . reject { |key | expected [ key ] == @query_stats . queries [ key ] [ :count ] } . uniq
365+ end
366+ "Expected ActiveRecord to #{ crud_operation } #{ expected } , got #{ values_only ? @query_stats . query_values : @query_stats . query_counts } \n Expectations that differed:\n #{ difference ( model_names_with_wrong_count , values_only ) . join ( "\n " ) } \n \n Where unexpected queries came from:\n \n #{ source_lines ( model_names_with_wrong_count ) . join ( "\n " ) } "
288367 end
289368 end
290369 end
0 commit comments