FIX: Bad encoding in InlineEncoder

FIX: Bad encoding in InlineEncoder

When multiple params shared a prefix inline encoder could fail leading to an incorrect gsub

Fixes #41

diff --git a/CHANGELOG b/CHANGELOG
index 88d48d5..8b79454 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,8 @@
+Pending:
+
+- FIX: when multiple params shared a prefix inline encoder may work in unexpected ways
+- FEATURE: add sql_literal for injecting sql in sql builder
+
 2021-03-22 - 1.1.3
 
 - DEV: reduce coupling of internal interfaces and allow or cleaner override of prepared connections
diff --git a/lib/mini_sql/inline_param_encoder.rb b/lib/mini_sql/inline_param_encoder.rb
index 84c6ddb..7b860cc 100644
--- a/lib/mini_sql/inline_param_encoder.rb
+++ b/lib/mini_sql/inline_param_encoder.rb
@@ -20,7 +20,11 @@ module MiniSql
     def encode_hash(sql, hash)
       sql = sql.dup
 
-      hash.each do |k, v|
+      # longest key first for gsub to work
+      # in an expected way
+      hash.sort do |(k, _), (k1, _)|
+        k1.to_s.length <=> k.to_s.length
+      end.each do |k, v|
         sql.gsub!(":#{k}") do
           # ignore ::int and stuff like that
           # $` is previous to match
diff --git a/test/mini_sql/inline_param_encoder_test.rb b/test/mini_sql/inline_param_encoder_test.rb
index 3dfbe35..883deb1 100644
--- a/test/mini_sql/inline_param_encoder_test.rb
+++ b/test/mini_sql/inline_param_encoder_test.rb
@@ -10,6 +10,11 @@ module MiniSql
       @encoder = InlineParamEncoder.new(@connection)
     end
 
+    def test_duplicate_arg_encoding
+      result = @encoder.encode("select :arg2, :arg20", arg2: 1, arg20: 2)
+      assert_equal("select 1, 2", result)
+    end
+
     def test_basic_encoding
       result = @encoder.encode("select :int::int", int: 22)
       assert_equal("select 22::int", result)

GitHub sha: 98e0830c0a58ce73005761dc52e8e6a1c1052805

1 Like