diff --git a/README.md b/README.md index 45823dc..5e9b4c8 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ expect { nil }.to_not query_database expect { User.last }.to query_database 1 expect { User.create }.to query_database 3.times -# Assert specific queries: +# Assert a specific query list: expect { User.last }.to query_database ["User Load"] expect { User.create!.update(name: "Jane") }.to query_database [ @@ -33,6 +33,14 @@ expect { User.create!.update(name: "Jane") }.to query_database [ "User Update", "TRANSACTION", ] + +# Assert a specific query summary: +expect { User.create!.update(name: "Jane") }.to query_database( + { + insert: { users: 1 }, + update: { users: 1 }, + } +) ``` ## Alternatives diff --git a/lib/rspec/sql.rb b/lib/rspec/sql.rb index b384bb6..4602e13 100644 --- a/lib/rspec/sql.rb +++ b/lib/rspec/sql.rb @@ -3,6 +3,8 @@ require "active_support" require "rspec" +require_relative "sql/query_summary" + module RSpec module Sql; end @@ -18,6 +20,8 @@ module Sql; end @queries.size == expected.size elsif expected.is_a?(Array) query_names == expected + elsif expected.is_a?(Hash) + query_summary == expected else raise "What are you expecting?" end @@ -52,6 +56,10 @@ def query_descriptions @queries.map { |q| "#{q[:name]} #{q[:sql]}" } end + def query_summary + Sql::QuerySummary.new(@queries).summary + end + def scribe_queries(&) queries = [] diff --git a/lib/rspec/sql/query_summary.rb b/lib/rspec/sql/query_summary.rb new file mode 100644 index 0000000..9d6d038 --- /dev/null +++ b/lib/rspec/sql/query_summary.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module RSpec + module Sql + class QuerySummary + QUERY_TYPES = [:delete, :insert, :select, :update].freeze + + attr_reader :summary + + def initialize(queries) + @summary = {} + queries.each do |payload| + type = get_type(payload[:sql]) + next if QUERY_TYPES.exclude?(type) || pg_query?(payload[:sql]) + + table = get_table(payload[:sql]) + @summary[type] ||= {} + @summary[type][table] ||= 0 + @summary[type][table] += 1 + end + end + + private + + def get_table(sql) + sql_parts = sql.split + case get_type(sql) + when :insert + sql_parts[2] + when :update + sql_parts[1] + else + table_index = sql_parts.index("FROM") + sql_parts[table_index + 1] + end.gsub(/(\\|")/, "").to_sym + end + + def get_type(sql) + sql.split[0].downcase.to_sym + end + + def pg_query?(sql) + sql.include?("SELECT a.attname") || sql.include?("pg_attribute") + end + end + end +end diff --git a/rspec-sql.gemspec b/rspec-sql.gemspec index 83fbd1b..59e0455 100644 --- a/rspec-sql.gemspec +++ b/rspec-sql.gemspec @@ -3,7 +3,7 @@ Gem::Specification.new do |s| s.version = "0.0.0" s.summary = "RSpec::Sql matcher" s.description = "RSpec matcher for database queries." - s.authors = ["Maikel Linke"] + s.authors = ["Maikel Linke", "Open Food Network contributors"] s.email = "maikel@openfoodnetwork.org.au" s.files = Dir["lib/**/*.rb"] s.homepage = "https://github.com/openfoodfoundation/rspec-sql" diff --git a/spec/lib/rspec/sql_spec.rb b/spec/lib/rspec/sql_spec.rb index 7178458..ab1110c 100644 --- a/spec/lib/rspec/sql_spec.rb +++ b/spec/lib/rspec/sql_spec.rb @@ -57,4 +57,13 @@ "TRANSACTION", ] end + + it "expects a summary of queries" do + expect { User.create!.update(name: "Jane") }.to query_database( + { + insert: { users: 1 }, + update: { users: 1 }, + } + ) + end end