Skip to content

Commit

Permalink
manage raw where clause with array as param (#1044)
Browse files Browse the repository at this point in the history
* manage raw where clause with array as param

* ameba fun...
  • Loading branch information
davidepaolotua authored Jun 16, 2024
1 parent c1729f3 commit 3a27ebb
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 14 deletions.
50 changes: 42 additions & 8 deletions spec/avram/query_builder_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,48 @@ describe Avram::QueryBuilder do
query.statement.should eq "SELECT * FROM users WHERE name = $1 AND age > $2"
end

it "accepts raw where clauses" do
query = new_query
.where(Avram::Where::Raw.new("name = ?", "Mikias"))
.where(Avram::Where::Raw.new("age > ?", 26))
.where(Avram::Where::Raw.new("age < ?", args: [30]))
.limit(1)
query.statement.should eq "SELECT * FROM users WHERE name = 'Mikias' AND age > 26 AND age < 30 LIMIT 1"
query.args.empty?.should be_true
describe "accepts raw clauses" do
it "substituting binding parameters" do
query = new_query
.where(Avram::Where::Raw.new("name = ?", "Mikias"))
.where(Avram::Where::Raw.new("age > ?", 26))
.where(Avram::Where::Raw.new("age < ?", args: [30]))
.limit(1)
query.statement.should eq "SELECT * FROM users WHERE name = 'Mikias' AND age > 26 AND age < 30 LIMIT 1"
query.args.empty?.should be_true
end

it "escaping elements to prevent sql injections" do
expected = <<-SQL
SELECT * FROM users WHERE name = 'aloha'';--'
SQL
query = new_query.where(Avram::Where::Raw.new("name = ?", "aloha';--"))
query.statement.should eq expected
end

it "correctly managing input arrays" do
expected = <<-SQL
SELECT * FROM users WHERE tags && '{"ruby","crystal"}'
SQL
query = new_query.where(Avram::Where::Raw.new("tags && ?", ["ruby", "crystal"]))
query.statement.should eq expected
end

it "preventing sql injections with arrays (1)" do
expected = <<-SQL
SELECT * FROM users WHERE tags && '{"ruby","crystal';--"}'
SQL
query = new_query.where(Avram::Where::Raw.new("tags && ?", ["ruby", "crystal';--"]))
query.statement.should eq expected
end

it "preventing sql injections with arrays (2)" do
expected = <<-SQL
SELECT * FROM users WHERE tags && '{"ruby","crystal\\"}';--"}'
SQL
query = new_query.where(Avram::Where::Raw.new("tags && ?", ["ruby", "crystal\"}';--"]))
query.statement.should eq expected
end
end

it "can be ordered" do
Expand Down
24 changes: 18 additions & 6 deletions src/avram/where.cr
Original file line number Diff line number Diff line change
Expand Up @@ -446,14 +446,26 @@ module Avram::Where

private def build_clause(statement, bind_vars)
bind_vars.each do |arg|
if arg.is_a?(String) || arg.is_a?(Slice(UInt8))
escaped = PG::EscapeHelper.escape_literal(arg)
else
escaped = arg
end
statement = statement.sub('?', escaped)
encoded_arg = prepare_for_execution(arg)
statement = statement.sub('?', encoded_arg)
end
statement
end

private def prepare_for_execution(value)
if value.is_a?(Array)
"'#{PQ::Param.encode_array(value)}'"
else
escape_if_needed(value)
end
end

private def escape_if_needed(value)
if value.is_a?(String) || value.is_a?(Slice(UInt8))
PG::EscapeHelper.escape_literal(value)
else
value
end
end
end
end

0 comments on commit 3a27ebb

Please sign in to comment.