Skip to content

Commit

Permalink
Merge pull request #201 from TalentBox/183-handle-bound-variables-and…
Browse files Browse the repository at this point in the history
…-prepared-statement

183 handle bound variables and prepared statement
  • Loading branch information
JonathanTron authored Dec 18, 2023
2 parents a94425a + e27f5ac commit c3def71
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 15 deletions.
8 changes: 1 addition & 7 deletions lib/sequel_rails/railties/log_subscriber.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,7 @@ def sql(event)

name = format('%s (%.1fms)', payload[:name], event.duration)
sql = payload[:sql].squeeze(' ')
binds = nil

unless (payload[:binds] || []).empty?
binds = ' ' + payload[:binds].map do |col, v|
[col.name, v]
end.inspect
end
binds = " #{payload[:binds].inspect}" unless (payload[:binds] || []).empty?

if odd?
name = color(name, :cyan, :bold => true)
Expand Down
131 changes: 123 additions & 8 deletions spec/lib/sequel_rails/railties/log_subscriber_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,6 @@ def set_logger(logger) # rubocop:disable AccessorMethodName
end
after { teardown }

it 'logs queries, runtime and count' do
expect(described_class.count).to eq 0
User.all
wait
expect(@logger.logged(:debug).last).to match(/SELECT \* FROM ("|`)users("|`)/)
expect(described_class.count).to be > 0
end

it 'does not log query when logger level is not debug, but track runtime and count' do
expect(described_class.count).to eq 0
@logger.level = defined?(Logger::Severity) ? Logger::Severity::INFO : :info
Expand All @@ -30,4 +22,127 @@ def set_logger(logger) # rubocop:disable AccessorMethodName
expect(@logger.logged(:debug).size).to eq 0
expect(described_class.count).to be > 0
end

describe 'for postgresql', :postgres do
it 'logs queries, runtime and count' do
expect(described_class.count).to eq 0
User.all
User.where(:id => 1).select_map(:id)
wait
expect(@logger.logged(:debug)[-2]).to match(/SELECT \* FROM "users"/)
expect(@logger.logged(:debug)[-1]).to match(/SELECT "id" FROM "users" WHERE \("id" = 1\)/)
expect(described_class.count).to be > 0
end

it 'works with bound variables' do
ds = Sequel::Model.db[:users].where(:id => :$id)
ds.call(:select, :id => 1)
wait
expect(@logger.logged(:debug).last).to match(
/SELECT \* FROM "users" WHERE \("id" = \$1\) \[1\]/
)
expect(described_class.count).to be > 0
end

it 'works with prepared statements' do
ds = Sequel::Model.db[:users].where(:id => :$id).prepare(:select, :users_by_id)
ds.call(:id => 1)
wait
expect(@logger.logged(:debug)[-2]).to match(
/PREPARE users_by_id AS SELECT \* FROM "users" WHERE \("id" = \$1\)/
)
expect(@logger.logged(:debug)[-1]).to match(
/EXECUTE users_by_id \[1\]/
)
expect(described_class.count).to be > 0
end
end

describe 'for mysql', :mysql do
it 'logs queries, runtime and count' do
expect(described_class.count).to eq 0
User.all
User.where(:id => 1).select_map(:id)
wait
expect(@logger.logged(:debug)[-2]).to match(/SELECT \* FROM `users`/)
expect(@logger.logged(:debug)[-1]).to match(/SELECT `id` FROM `users` WHERE \(`id` = 1\)/)
expect(described_class.count).to be > 0
end

it 'works with plain queries', :mysql do
Sequel::Model.db[:users].where(:id => 1).to_a
wait
expect(@logger.logged(:debug).last).to match(
/SELECT \* FROM `users` WHERE \(`id` = 1\)/
)
expect(described_class.count).to be > 0
end

it 'works with bound variables' do
ds = Sequel::Model.db[:users].where(:id => :$id)
ds.call(:select, :id => 1)
wait
expect(@logger.logged(:debug).last).to match(
/Executing SELECT \* FROM `users` WHERE \(`id` = \?\) \[1\]/
)
expect(described_class.count).to be > 0
end

it 'works with prepared statements' do
ds = Sequel::Model.db[:users].where(:id => :$id).prepare(:select, :users_by_id)
ds.call(:id => 1)
wait
expect(@logger.logged(:debug)[-2]).to match(
/Preparing users_by_id: SELECT \* FROM `users` WHERE \(`id` = \?\)/
)
expect(@logger.logged(:debug)[-1]).to match(
/Executing users_by_id \[1\]/
)
expect(described_class.count).to be > 0
end
end

describe 'for sqlite', :sqlite do
it 'logs queries, runtime and count' do
expect(described_class.count).to eq 0
User.all
User.where(:id => 1).select_map(:id)
wait
expect(@logger.logged(:debug)[-2]).to match(/SELECT \* FROM `users`/)
expect(@logger.logged(:debug)[-1]).to match(/SELECT `id` FROM `users` WHERE \(`id` = 1\)/)
expect(described_class.count).to be > 0
end

it 'works with plain queries', :mysql do
Sequel::Model.db[:users].where(:id => 1).to_a
wait
expect(@logger.logged(:debug).last).to match(
/SELECT \* FROM `users` WHERE \(`id` = 1\)/
)
expect(described_class.count).to be > 0
end

it 'works with bound variables' do
ds = Sequel::Model.db[:users].where(:id => :$id)
ds.call(:select, :id => 1)
wait
expect(@logger.logged(:debug).last).to match(
/SELECT \* FROM `users` WHERE \(`id` = :id\) {"id"=>1}/
)
expect(described_class.count).to be > 0
end

it 'works with prepared statements' do
ds = Sequel::Model.db[:users].where(:id => :$id).prepare(:select, :users_by_id)
ds.call(:id => 1)
wait
expect(@logger.logged(:debug)[-2]).to match(
/PREPARE users_by_id: SELECT \* FROM `users` WHERE \(`id` = :id\)/
)
expect(@logger.logged(:debug)[-1]).to match(
/EXECUTE users_by_id {"id"=>1}/
)
expect(described_class.count).to be > 0
end
end
end

0 comments on commit c3def71

Please sign in to comment.