quote-sql 0.0.4 โ 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +10 -2
- data/lib/quote_sql/quoter.rb +14 -6
- data/lib/quote_sql/test.rb +70 -54
- data/lib/quote_sql/version.rb +1 -1
- data/lib/quote_sql.rb +3 -3
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: cb47e85b4c7c4e1f945748295390c9e1bd49b7e0ba5291e0f7310058f6f91ddc
         | 
| 4 | 
            +
              data.tar.gz: 0f5bde1afc31eb573bb3e24727b530bf5909048284114d45c56c1b24a63e97aa
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 6596b9bb50ee373030e401dcb9d0067ae31857b6467fdd7b0341e21b3dcbe8fb0e78714ec24f56615618bbf965849307474a4030978e6c98d2d728166e235151
         | 
| 7 | 
            +
              data.tar.gz: f38366de3e2227835fd11f512a9c9d2a99d130d896a17f6b0a58788dd8ed7ebd13f46682992b762e2d50f09716c3bd5654d525dc4b03f350d3a52cc6b19b322e
         | 
    
        data/README.md
    CHANGED
    
    | @@ -9,13 +9,15 @@ I created this library while coding for different projects, and had lots of Here | |
| 9 9 |  | 
| 10 10 | 
             
            My strategy is to segment SQL Queries in readable junks, which can be individually tested and then combine their sql to the final query.
         | 
| 11 11 |  | 
| 12 | 
            -
            QuoteSql is used in production, but is still bleeding edge - and there is not a fully sync between doc and code.
         | 
| 13 | 
            -
             | 
| 14 12 | 
             
            If you think QuoteSql is interesting, let's chat!
         | 
| 15 13 | 
             
            Also if you have problems using it, just drop me a note.
         | 
| 16 14 |  | 
| 17 15 | 
             
            Best Martin
         | 
| 18 16 |  | 
| 17 | 
            +
            ## Caveats & Notes
         | 
| 18 | 
            +
            - QuoteSql is used in production, but is still bleeding edge - and there is not a fully sync between doc and code.
         | 
| 19 | 
            +
            - Just for my examples and in the docs, I'm using for Yajl for JSON parsing, and changed in my environments the standard parse output to *symbolized keys*. 
         | 
| 20 | 
            +
             | 
| 19 21 | 
             
            ## Examples
         | 
| 20 22 | 
             
            ### Simple quoting
         | 
| 21 23 | 
             
            `QuoteSql.new("SELECT %field").quote(field: "abc").to_sql`
         | 
| @@ -119,6 +121,12 @@ with optional array dimension | |
| 119 121 | 
             
              - +String+ value will become the expression, the key the AS {result: "SUM(*)"} => SUM(*) AS result
         | 
| 120 122 | 
             
              - +Proc+ are executed with the +QuoteSQL::Quoter+ object as parameter and added as raw SQL
         | 
| 121 123 |  | 
| 124 | 
            +
            ## Executing
         | 
| 125 | 
            +
            ### Getting the results
         | 
| 126 | 
            +
            ### Binds
         | 
| 127 | 
            +
              `v = {a: 1, b: "foo", c: true};QuoteSQL(%q{Select * From %x_json}, x_json: 1, x_casts: {a: "int", b: "text", c: "boolean"}).result(v.to_json)`
         | 
| 128 | 
            +
              => Select * From json_to_recordset($1) AS "x"("a" int,"b" text,"c" boolean) => [{a: 1, b: "foo", c: true}]
         | 
| 129 | 
            +
             | 
| 122 130 | 
             
            ## Shortcuts and functions
         | 
| 123 131 | 
             
            - `QuoteSQL("select %abc", abc: 1)` == `QuoteSql.new("select %abc").quote(abc: 1)`
         | 
| 124 132 | 
             
            - when you have in your initializer `String.include QuoteSql::Extension` you can do e.g. `"select %abc".quote_sql(abc: 1)`
         | 
    
        data/lib/quote_sql/quoter.rb
    CHANGED
    
    | @@ -37,9 +37,13 @@ class QuoteSql | |
| 37 37 | 
             
                def ident_columns(name = nil)
         | 
| 38 38 | 
             
                  item = columns(name || self.name)
         | 
| 39 39 | 
             
                  unless item
         | 
| 40 | 
            -
                     | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 40 | 
            +
                    unless item = casts(name || self.name)&.keys
         | 
| 41 | 
            +
                      if (table = self.table(name || self.name))&.respond_to? :column_names
         | 
| 42 | 
            +
                        item = table.column_names
         | 
| 43 | 
            +
                      else
         | 
| 44 | 
            +
                        raise ArgumntError, "No columns, casts or table given for #{name}" unless table&.respond_to? :column_names
         | 
| 45 | 
            +
                      end
         | 
| 46 | 
            +
                    end
         | 
| 43 47 | 
             
                  end
         | 
| 44 48 | 
             
                  if item.is_a?(Array)
         | 
| 45 49 | 
             
                    if item.all? { _1.respond_to?(:name) }
         | 
| @@ -143,11 +147,15 @@ class QuoteSql | |
| 143 147 | 
             
                  casts = self.casts(name)
         | 
| 144 148 | 
             
                  columns = self.columns(name) || casts&.keys
         | 
| 145 149 | 
             
                  column_cast = columns&.map { "#{QuoteSql.quote_column_name(_1)} #{casts&.dig(_1) || "TEXT"}" }
         | 
| 146 | 
            -
                   | 
| 147 | 
            -
             | 
| 150 | 
            +
                  if item.is_a? Integer
         | 
| 151 | 
            +
                    rv = "$#{item}"
         | 
| 152 | 
            +
                  else
         | 
| 153 | 
            +
                    item = [item].flatten.compact.as_json.map { _1.slice(*columns.map(&:to_s)) }
         | 
| 154 | 
            +
                    rv = "'#{item.to_json.gsub(/'/, "''")}'"
         | 
| 155 | 
            +
                  end
         | 
| 156 | 
            +
                  Raw.sql "json_to_recordset(#{rv}) AS #{QuoteSql.quote_column_name name}(#{column_cast.join(',')})"
         | 
| 148 157 | 
             
                end
         | 
| 149 158 |  | 
| 150 | 
            -
             | 
| 151 159 | 
             
                def data_values(item = @quotable)
         | 
| 152 160 | 
             
                  item = Array(item).compact
         | 
| 153 161 | 
             
                  column_names = columns(name)
         | 
    
        data/lib/quote_sql/test.rb
    CHANGED
    
    | @@ -1,59 +1,5 @@ | |
| 1 1 | 
             
            class QuoteSql::Test
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              def all
         | 
| 4 | 
            -
                @success = []
         | 
| 5 | 
            -
                @fail = []
         | 
| 6 | 
            -
                private_methods(false).grep(/^test_/).each { run(_1, true) }
         | 
| 7 | 
            -
                @success.each { STDOUT.puts(*_1, nil) }
         | 
| 8 | 
            -
                @fail.each { STDOUT.puts(*_1, nil) }
         | 
| 9 | 
            -
                puts
         | 
| 10 | 
            -
              end
         | 
| 11 | 
            -
             | 
| 12 | 
            -
              def run(name, all = false)
         | 
| 13 | 
            -
                name = name.to_s.sub(/^test_/, "")
         | 
| 14 | 
            -
                rv = ["๐งช #{name}"]
         | 
| 15 | 
            -
                @expected = nil
         | 
| 16 | 
            -
                @test = send("test_#{name}")
         | 
| 17 | 
            -
                if sql.gsub(/\s+/, "")&.downcase&.strip == expected&.gsub(/\s+/, "")&.downcase&.strip
         | 
| 18 | 
            -
                  tables = @test.tables.to_h { [[_1, "table"].compact.join("_"), _2] }
         | 
| 19 | 
            -
                  columns = @test.instance_variable_get(:@columns).to_h { [[_1, "columns"].compact.join("_"), _2] }
         | 
| 20 | 
            -
                  rv += [@test.original, { **tables, **columns, **@test.quotes }.inspect, "๐ฏ #{expected}", "โ
 #{sql}"]
         | 
| 21 | 
            -
                  @success << rv if @success
         | 
| 22 | 
            -
                else
         | 
| 23 | 
            -
                  rv += [@test.inspect, "๐ฏ #{expected}", "โ #{sql}"]
         | 
| 24 | 
            -
                  @fail << rv if @fail
         | 
| 25 | 
            -
                end
         | 
| 26 | 
            -
              rescue => exc
         | 
| 27 | 
            -
                rv += [@test.inspect, "๐ฏ #{expected}", "โ #{sql}", exc.message]
         | 
| 28 | 
            -
                @fail << rv if @fail
         | 
| 29 | 
            -
              ensure
         | 
| 30 | 
            -
                STDOUT.puts(*rv) unless @fail or @success
         | 
| 31 | 
            -
              end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
              def expected(v = nil)
         | 
| 34 | 
            -
                @expected ||= v
         | 
| 35 | 
            -
              end
         | 
| 36 | 
            -
             | 
| 37 | 
            -
              def sql
         | 
| 38 | 
            -
                @test.to_sql
         | 
| 39 | 
            -
              end
         | 
| 40 | 
            -
             | 
| 41 | 
            -
              class PseudoActiveRecord
         | 
| 42 | 
            -
                def self.table_name
         | 
| 43 | 
            -
                  "pseudo_active_records"
         | 
| 44 | 
            -
                end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                def self.column_names
         | 
| 47 | 
            -
                  %w(id column1 column2)
         | 
| 48 | 
            -
                end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                def to_qsl
         | 
| 51 | 
            -
                  "SELECT * FROM #{self.class.table_name}"
         | 
| 52 | 
            -
                end
         | 
| 53 | 
            -
              end
         | 
| 54 | 
            -
             | 
| 55 2 | 
             
              private
         | 
| 56 | 
            -
             | 
| 57 3 | 
             
              def test_columns
         | 
| 58 4 | 
             
                expected <<~SQL
         | 
| 59 5 | 
             
                  SELECT x, "a", "b", "c", "d"
         | 
| @@ -189,6 +135,20 @@ class QuoteSql::Test | |
| 189 135 | 
             
                "INSERT INTO users (name, color) SELECT * from %x_json".quote_sql(x_casts: {name: "text", color: "text"}, x_json:)
         | 
| 190 136 | 
             
              end
         | 
| 191 137 |  | 
| 138 | 
            +
              def test_from_json_bind
         | 
| 139 | 
            +
                expected <<~SQL
         | 
| 140 | 
            +
                    Select * From json_to_recordset($1) AS "x"("a" int,"b" text,"c" boolean)
         | 
| 141 | 
            +
                SQL
         | 
| 142 | 
            +
                QuoteSQL("Select * From %x_json", x_json: 1, x_casts: {a: "int", b: "text", c: "boolean"})
         | 
| 143 | 
            +
              end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
              def test_insert_json_bind
         | 
| 146 | 
            +
                expected <<~SQL
         | 
| 147 | 
            +
                     INSERT INTO table ("a","b","c") Select * From json_to_recordset($1) AS "x"("a" int,"b" text,"c" boolean)  
         | 
| 148 | 
            +
                SQL
         | 
| 149 | 
            +
                QuoteSQL("INSERT INTO table (%x_columns) Select * From %x_json", x_json: 1, x_casts: {a: "int", b: "text", c: "boolean"})
         | 
| 150 | 
            +
              end
         | 
| 151 | 
            +
             | 
| 192 152 | 
             
              # def test_q3
         | 
| 193 153 | 
             
              #   expected Arel.sql(<<-SQL)
         | 
| 194 154 | 
             
              #         INSERT INTO "responses" ("id","type","task_id","index","data","parts","value","created_at","updated_at")
         | 
| @@ -212,4 +172,60 @@ class QuoteSql::Test | |
| 212 172 | 
             
              #     )
         | 
| 213 173 | 
             
              # end
         | 
| 214 174 |  | 
| 175 | 
            +
             | 
| 176 | 
            +
              public
         | 
| 177 | 
            +
             | 
| 178 | 
            +
              def all
         | 
| 179 | 
            +
                @success = []
         | 
| 180 | 
            +
                @fail = []
         | 
| 181 | 
            +
                private_methods(false).grep(/^test_/).each { run(_1, true) }
         | 
| 182 | 
            +
                @success.each { STDOUT.puts(*_1, nil) }
         | 
| 183 | 
            +
                @fail.each { STDOUT.puts(*_1, nil) }
         | 
| 184 | 
            +
                puts
         | 
| 185 | 
            +
              end
         | 
| 186 | 
            +
             | 
| 187 | 
            +
              def run(name, all = false)
         | 
| 188 | 
            +
                name = name.to_s.sub(/^test_/, "")
         | 
| 189 | 
            +
                rv = ["๐งช #{name}"]
         | 
| 190 | 
            +
                @expected = nil
         | 
| 191 | 
            +
                @test = send("test_#{name}")
         | 
| 192 | 
            +
                if sql.gsub(/\s+/, "")&.downcase&.strip == expected&.gsub(/\s+/, "")&.downcase&.strip
         | 
| 193 | 
            +
                  tables = @test.tables.to_h { [[_1, "table"].compact.join("_"), _2] }
         | 
| 194 | 
            +
                  columns = @test.instance_variable_get(:@columns).to_h { [[_1, "columns"].compact.join("_"), _2] }
         | 
| 195 | 
            +
                  rv += [
         | 
| 196 | 
            +
                    "QuoteSql.new(\"#{@test.original}\").quote(#{{**tables, **columns, **@test.quotes }.inspect}).to_sql", "๐ฏ #{expected}", "โ
 #{sql}"]
         | 
| 197 | 
            +
                  @success << rv if @success
         | 
| 198 | 
            +
                else
         | 
| 199 | 
            +
                  rv += [@test.inspect, "๐ฏ #{expected}", "โ #{sql}"]
         | 
| 200 | 
            +
                  @fail << rv if @fail
         | 
| 201 | 
            +
                end
         | 
| 202 | 
            +
              rescue => exc
         | 
| 203 | 
            +
                rv += [@test.inspect, "๐ฏ #{expected}", "โ #{sql}", exc.message]
         | 
| 204 | 
            +
                @fail << rv if @fail
         | 
| 205 | 
            +
              ensure
         | 
| 206 | 
            +
                STDOUT.puts(*rv) unless @fail or @success
         | 
| 207 | 
            +
              end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
              def expected(v = nil)
         | 
| 210 | 
            +
                @expected ||= v
         | 
| 211 | 
            +
              end
         | 
| 212 | 
            +
             | 
| 213 | 
            +
              def sql
         | 
| 214 | 
            +
                @test.to_sql
         | 
| 215 | 
            +
              end
         | 
| 216 | 
            +
             | 
| 217 | 
            +
              class PseudoActiveRecord
         | 
| 218 | 
            +
                def self.table_name
         | 
| 219 | 
            +
                  "pseudo_active_records"
         | 
| 220 | 
            +
                end
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                def self.column_names
         | 
| 223 | 
            +
                  %w(id column1 column2)
         | 
| 224 | 
            +
                end
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                def to_qsl
         | 
| 227 | 
            +
                  "SELECT * FROM #{self.class.table_name}"
         | 
| 228 | 
            +
                end
         | 
| 229 | 
            +
              end
         | 
| 230 | 
            +
             | 
| 215 231 | 
             
            end
         | 
    
        data/lib/quote_sql/version.rb
    CHANGED
    
    
    
        data/lib/quote_sql.rb
    CHANGED
    
    | @@ -82,14 +82,14 @@ time(stamp)?(_\\(\d+\\))?(_with(out)?_time_zone)? | |
| 82 82 | 
             
                @sql
         | 
| 83 83 | 
             
              end
         | 
| 84 84 |  | 
| 85 | 
            -
              def result(binds | 
| 85 | 
            +
              def result(*binds, prepare: false, async: false)
         | 
| 86 86 | 
             
                sql = to_sql
         | 
| 87 | 
            -
                if binds.present? and sql.scan(/(?<=\$)\d+/).map(&:to_i).max  | 
| 87 | 
            +
                if binds.present? and sql.scan(/(?<=\$)\d+/).map(&:to_i).max != binds.length
         | 
| 88 88 | 
             
                  raise ArgumentError, "Wrong number of binds"
         | 
| 89 89 | 
             
                end
         | 
| 90 90 | 
             
                _exec(sql, binds, prepare: false, async: false)
         | 
| 91 91 | 
             
              rescue => exc
         | 
| 92 | 
            -
                STDERR.puts exc. | 
| 92 | 
            +
                STDERR.puts exc.inspect, self.inspect
         | 
| 93 93 | 
             
                raise exc
         | 
| 94 94 | 
             
              end
         | 
| 95 95 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: quote-sql
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.5
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Martin Kufner
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2024-02- | 
| 11 | 
            +
            date: 2024-02-27 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: niceql
         |