Skip to content

Commit

Permalink
Add query summary matching
Browse files Browse the repository at this point in the history
This has been copied from the openfoodnetwork repository and adapted
slightly. It also needed one little fix.

This approach is quite different to our previous one and I'm wondering
if we use `User` and `Create` instead of `users` and `insert` to stay on
the higher level of Active Record. But for now this is can be a simple
replacement for the openfoodnetwork spec helper and we can evolve it
from there.
  • Loading branch information
mkllnk committed Feb 29, 2024
1 parent b3a6238 commit db75acb
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 2 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 [
Expand All @@ -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
Expand Down
8 changes: 8 additions & 0 deletions lib/rspec/sql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require "active_support"
require "rspec"

require_relative "sql/query_summary"

module RSpec
module Sql; end

Expand All @@ -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
Expand Down Expand Up @@ -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 = []

Expand Down
47 changes: 47 additions & 0 deletions lib/rspec/sql/query_summary.rb
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion rspec-sql.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
9 changes: 9 additions & 0 deletions spec/lib/rspec/sql_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit db75acb

Please sign in to comment.