ensql 0.6.0 → 0.6.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/.github/workflows/lint.yml +52 -0
- data/.github/workflows/specs.yml +59 -0
- data/.yardopts +2 -0
- data/CHANGELOG.md +32 -2
- data/Gemfile +8 -14
- data/Gemfile.lock +10 -3
- data/README.md +124 -64
- data/ensql.gemspec +17 -11
- data/gemfiles/maintained.gemfile +22 -0
- data/gemfiles/maintained.gemfile.lock +81 -0
- data/gemfiles/minimum.gemfile +26 -0
- data/gemfiles/minimum.gemfile.lock +76 -0
- data/lib/ensql.rb +5 -65
- data/lib/ensql/active_record_adapter.rb +77 -33
- data/lib/ensql/adapter.rb +50 -12
- data/lib/ensql/error.rb +6 -0
- data/lib/ensql/load_sql.rb +39 -0
- data/lib/ensql/pool_wrapper.rb +21 -0
- data/lib/ensql/postgres_adapter.rb +177 -0
- data/lib/ensql/sequel_adapter.rb +79 -30
- data/lib/ensql/sql.rb +14 -13
- data/lib/ensql/transaction.rb +57 -0
- data/lib/ensql/version.rb +7 -5
- data/perf/adapter_benchmark.rb +102 -0
- metadata +93 -5
    
        data/ensql.gemspec
    CHANGED
    
    | @@ -3,15 +3,15 @@ | |
| 3 3 | 
             
            require_relative "lib/ensql/version"
         | 
| 4 4 |  | 
| 5 5 | 
             
            Gem::Specification.new do |spec|
         | 
| 6 | 
            -
              spec.name | 
| 7 | 
            -
              spec.version | 
| 8 | 
            -
              spec.authors | 
| 9 | 
            -
              spec.email | 
| 10 | 
            -
             | 
| 11 | 
            -
              spec.summary | 
| 12 | 
            -
              spec.description | 
| 13 | 
            -
              spec.homepage | 
| 14 | 
            -
              spec.license | 
| 6 | 
            +
              spec.name = "ensql"
         | 
| 7 | 
            +
              spec.version = Ensql::VERSION
         | 
| 8 | 
            +
              spec.authors = ["Daniel Fone"]
         | 
| 9 | 
            +
              spec.email = ["daniel@fone.net.nz"]
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              spec.summary = "Write SQL the safe and simple way"
         | 
| 12 | 
            +
              spec.description = "Escape your ORM and embrace the power and simplicity of writing plain SQL again."
         | 
| 13 | 
            +
              spec.homepage = "https://github.com/danielfone/ensql"
         | 
| 14 | 
            +
              spec.license = "MIT"
         | 
| 15 15 | 
             
              spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
         | 
| 16 16 |  | 
| 17 17 | 
             
              # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
         | 
| @@ -25,8 +25,14 @@ Gem::Specification.new do |spec| | |
| 25 25 | 
             
              spec.files = Dir.chdir(File.expand_path(__dir__)) do
         | 
| 26 26 | 
             
                `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
         | 
| 27 27 | 
             
              end
         | 
| 28 | 
            -
              spec.bindir | 
| 29 | 
            -
              spec.executables | 
| 28 | 
            +
              spec.bindir = "exe"
         | 
| 29 | 
            +
              spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
         | 
| 30 30 | 
             
              spec.require_paths = ["lib"]
         | 
| 31 31 |  | 
| 32 | 
            +
              spec.add_dependency "connection_pool", ">= 0.9.3", "<3"
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              spec.add_development_dependency "rake", "~> 13.0"
         | 
| 35 | 
            +
              spec.add_development_dependency "rspec", "~> 3.0"
         | 
| 36 | 
            +
              spec.add_development_dependency "simplecov", "~> 0.21.2"
         | 
| 37 | 
            +
              spec.add_development_dependency "yard", "~> 0.9.26"
         | 
| 32 38 | 
             
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # This specifies the oldest maintained versions of our dependencies
         | 
| 5 | 
            +
            #
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            source "https://rubygems.org"
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ruby "~> 2.5.0"
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            # Specify your gem's dependencies in ensql.gemspec
         | 
| 12 | 
            +
            gemspec path: "../"
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            # Optional runtime dependencies
         | 
| 15 | 
            +
            group :adapters do
         | 
| 16 | 
            +
              require_relative "../lib/ensql/version"
         | 
| 17 | 
            +
              gem "activerecord", "~> 5.2.0"
         | 
| 18 | 
            +
              gem "sequel", "~> 5.9"
         | 
| 19 | 
            +
              gem "sqlite3"
         | 
| 20 | 
            +
              gem "pg"
         | 
| 21 | 
            +
              gem "sequel_pg"
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,81 @@ | |
| 1 | 
            +
            PATH
         | 
| 2 | 
            +
              remote: ..
         | 
| 3 | 
            +
              specs:
         | 
| 4 | 
            +
                ensql (0.6.5)
         | 
| 5 | 
            +
                  connection_pool (>= 0.9.3, < 3)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            GEM
         | 
| 8 | 
            +
              remote: https://rubygems.org/
         | 
| 9 | 
            +
              specs:
         | 
| 10 | 
            +
                activemodel (5.2.4.5)
         | 
| 11 | 
            +
                  activesupport (= 5.2.4.5)
         | 
| 12 | 
            +
                activerecord (5.2.4.5)
         | 
| 13 | 
            +
                  activemodel (= 5.2.4.5)
         | 
| 14 | 
            +
                  activesupport (= 5.2.4.5)
         | 
| 15 | 
            +
                  arel (>= 9.0)
         | 
| 16 | 
            +
                activesupport (5.2.4.5)
         | 
| 17 | 
            +
                  concurrent-ruby (~> 1.0, >= 1.0.2)
         | 
| 18 | 
            +
                  i18n (>= 0.7, < 2)
         | 
| 19 | 
            +
                  minitest (~> 5.1)
         | 
| 20 | 
            +
                  tzinfo (~> 1.1)
         | 
| 21 | 
            +
                arel (9.0.0)
         | 
| 22 | 
            +
                concurrent-ruby (1.1.8)
         | 
| 23 | 
            +
                connection_pool (2.2.3)
         | 
| 24 | 
            +
                diff-lcs (1.4.4)
         | 
| 25 | 
            +
                docile (1.3.5)
         | 
| 26 | 
            +
                i18n (1.8.9)
         | 
| 27 | 
            +
                  concurrent-ruby (~> 1.0)
         | 
| 28 | 
            +
                minitest (5.14.4)
         | 
| 29 | 
            +
                pg (1.2.3)
         | 
| 30 | 
            +
                rake (13.0.3)
         | 
| 31 | 
            +
                rspec (3.10.0)
         | 
| 32 | 
            +
                  rspec-core (~> 3.10.0)
         | 
| 33 | 
            +
                  rspec-expectations (~> 3.10.0)
         | 
| 34 | 
            +
                  rspec-mocks (~> 3.10.0)
         | 
| 35 | 
            +
                rspec-core (3.10.1)
         | 
| 36 | 
            +
                  rspec-support (~> 3.10.0)
         | 
| 37 | 
            +
                rspec-expectations (3.10.1)
         | 
| 38 | 
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 39 | 
            +
                  rspec-support (~> 3.10.0)
         | 
| 40 | 
            +
                rspec-mocks (3.10.2)
         | 
| 41 | 
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 42 | 
            +
                  rspec-support (~> 3.10.0)
         | 
| 43 | 
            +
                rspec-support (3.10.2)
         | 
| 44 | 
            +
                sequel (5.42.0)
         | 
| 45 | 
            +
                sequel_pg (1.14.0)
         | 
| 46 | 
            +
                  pg (>= 0.18.0, != 1.2.0)
         | 
| 47 | 
            +
                  sequel (>= 4.38.0)
         | 
| 48 | 
            +
                simplecov (0.21.2)
         | 
| 49 | 
            +
                  docile (~> 1.1)
         | 
| 50 | 
            +
                  simplecov-html (~> 0.11)
         | 
| 51 | 
            +
                  simplecov_json_formatter (~> 0.1)
         | 
| 52 | 
            +
                simplecov-html (0.12.3)
         | 
| 53 | 
            +
                simplecov_json_formatter (0.1.2)
         | 
| 54 | 
            +
                sqlite3 (1.4.2)
         | 
| 55 | 
            +
                thread_safe (0.3.6)
         | 
| 56 | 
            +
                tzinfo (1.2.9)
         | 
| 57 | 
            +
                  thread_safe (~> 0.1)
         | 
| 58 | 
            +
                yard (0.9.26)
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            PLATFORMS
         | 
| 61 | 
            +
              ruby
         | 
| 62 | 
            +
              x86_64-darwin-18
         | 
| 63 | 
            +
              x86_64-linux
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            DEPENDENCIES
         | 
| 66 | 
            +
              activerecord (~> 5.2.0)
         | 
| 67 | 
            +
              ensql!
         | 
| 68 | 
            +
              pg
         | 
| 69 | 
            +
              rake (~> 13.0)
         | 
| 70 | 
            +
              rspec (~> 3.0)
         | 
| 71 | 
            +
              sequel (~> 5.9)
         | 
| 72 | 
            +
              sequel_pg
         | 
| 73 | 
            +
              simplecov (~> 0.21.2)
         | 
| 74 | 
            +
              sqlite3
         | 
| 75 | 
            +
              yard (~> 0.9.26)
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            RUBY VERSION
         | 
| 78 | 
            +
               ruby 2.5.8p224
         | 
| 79 | 
            +
             | 
| 80 | 
            +
            BUNDLED WITH
         | 
| 81 | 
            +
               2.2.9
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # This specifies the oldest compatible versions of our dependencies
         | 
| 5 | 
            +
            #
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            source "https://rubygems.org"
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ruby "2.4.0"
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            # Specify your gem's dependencies in ensql.gemspec
         | 
| 12 | 
            +
            gemspec path: "../"
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            # Downgrade simplecov for ruby 2.4 compat
         | 
| 15 | 
            +
            gem "simplecov", "~> 0.18.5"
         | 
| 16 | 
            +
            gem "connection_pool", "0.9.3"
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            # Optional runtime dependencies
         | 
| 19 | 
            +
            group :adapters do
         | 
| 20 | 
            +
              require_relative "../lib/ensql/version"
         | 
| 21 | 
            +
              gem "activerecord", Ensql::SUPPORTED_ACTIVERECORD_VERSIONS.to_s.scan(/\d+.\d+/).first
         | 
| 22 | 
            +
              gem "sequel", Ensql::SUPPORTED_SEQUEL_VERSIONS.to_s.scan(/\d+.\d+/).first
         | 
| 23 | 
            +
              gem "sqlite3", "~> 1.3.6" # AR version constraint
         | 
| 24 | 
            +
              gem "pg", Ensql::SUPPORTED_PG_VERSIONS.to_s.scan(/\d+.\d+/).first
         | 
| 25 | 
            +
              gem "sequel_pg"
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,76 @@ | |
| 1 | 
            +
            PATH
         | 
| 2 | 
            +
              remote: ..
         | 
| 3 | 
            +
              specs:
         | 
| 4 | 
            +
                ensql (0.6.5)
         | 
| 5 | 
            +
                  connection_pool (>= 0.9.3, < 3)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            GEM
         | 
| 8 | 
            +
              remote: https://rubygems.org/
         | 
| 9 | 
            +
              specs:
         | 
| 10 | 
            +
                activemodel (5.0.0)
         | 
| 11 | 
            +
                  activesupport (= 5.0.0)
         | 
| 12 | 
            +
                activerecord (5.0.0)
         | 
| 13 | 
            +
                  activemodel (= 5.0.0)
         | 
| 14 | 
            +
                  activesupport (= 5.0.0)
         | 
| 15 | 
            +
                  arel (~> 7.0)
         | 
| 16 | 
            +
                activesupport (5.0.0)
         | 
| 17 | 
            +
                  concurrent-ruby (~> 1.0, >= 1.0.2)
         | 
| 18 | 
            +
                  i18n (~> 0.7)
         | 
| 19 | 
            +
                  minitest (~> 5.1)
         | 
| 20 | 
            +
                  tzinfo (~> 1.1)
         | 
| 21 | 
            +
                arel (7.1.4)
         | 
| 22 | 
            +
                concurrent-ruby (1.1.8)
         | 
| 23 | 
            +
                connection_pool (0.9.3)
         | 
| 24 | 
            +
                diff-lcs (1.4.4)
         | 
| 25 | 
            +
                docile (1.3.5)
         | 
| 26 | 
            +
                i18n (0.9.5)
         | 
| 27 | 
            +
                  concurrent-ruby (~> 1.0)
         | 
| 28 | 
            +
                minitest (5.14.4)
         | 
| 29 | 
            +
                pg (0.19.0)
         | 
| 30 | 
            +
                rake (13.0.3)
         | 
| 31 | 
            +
                rspec (3.10.0)
         | 
| 32 | 
            +
                  rspec-core (~> 3.10.0)
         | 
| 33 | 
            +
                  rspec-expectations (~> 3.10.0)
         | 
| 34 | 
            +
                  rspec-mocks (~> 3.10.0)
         | 
| 35 | 
            +
                rspec-core (3.10.1)
         | 
| 36 | 
            +
                  rspec-support (~> 3.10.0)
         | 
| 37 | 
            +
                rspec-expectations (3.10.1)
         | 
| 38 | 
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 39 | 
            +
                  rspec-support (~> 3.10.0)
         | 
| 40 | 
            +
                rspec-mocks (3.10.2)
         | 
| 41 | 
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         | 
| 42 | 
            +
                  rspec-support (~> 3.10.0)
         | 
| 43 | 
            +
                rspec-support (3.10.2)
         | 
| 44 | 
            +
                sequel (5.9.0)
         | 
| 45 | 
            +
                sequel_pg (1.14.0)
         | 
| 46 | 
            +
                  pg (>= 0.18.0, != 1.2.0)
         | 
| 47 | 
            +
                  sequel (>= 4.38.0)
         | 
| 48 | 
            +
                simplecov (0.18.5)
         | 
| 49 | 
            +
                  docile (~> 1.1)
         | 
| 50 | 
            +
                  simplecov-html (~> 0.11)
         | 
| 51 | 
            +
                simplecov-html (0.12.3)
         | 
| 52 | 
            +
                sqlite3 (1.3.13)
         | 
| 53 | 
            +
                thread_safe (0.3.6)
         | 
| 54 | 
            +
                tzinfo (1.2.9)
         | 
| 55 | 
            +
                  thread_safe (~> 0.1)
         | 
| 56 | 
            +
                yard (0.9.26)
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            PLATFORMS
         | 
| 59 | 
            +
              x86_64-darwin-18
         | 
| 60 | 
            +
              x86_64-linux
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            DEPENDENCIES
         | 
| 63 | 
            +
              activerecord (= 5.0)
         | 
| 64 | 
            +
              connection_pool (= 0.9.3)
         | 
| 65 | 
            +
              ensql!
         | 
| 66 | 
            +
              pg (= 0.19)
         | 
| 67 | 
            +
              rake (~> 13.0)
         | 
| 68 | 
            +
              rspec (~> 3.0)
         | 
| 69 | 
            +
              sequel (= 5.9)
         | 
| 70 | 
            +
              sequel_pg
         | 
| 71 | 
            +
              simplecov (~> 0.18.5)
         | 
| 72 | 
            +
              sqlite3 (~> 1.3.6)
         | 
| 73 | 
            +
              yard (~> 0.9.26)
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            BUNDLED WITH
         | 
| 76 | 
            +
               2.2.9
         | 
    
        data/lib/ensql.rb
    CHANGED
    
    | @@ -1,7 +1,10 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require_relative "ensql/version"
         | 
| 4 | 
            +
            require_relative "ensql/adapter"
         | 
| 4 5 | 
             
            require_relative "ensql/sql"
         | 
| 6 | 
            +
            require_relative "ensql/transaction"
         | 
| 7 | 
            +
            require_relative "ensql/load_sql"
         | 
| 5 8 |  | 
| 6 9 | 
             
            #
         | 
| 7 10 | 
             
            # Primary interface for loading, interpolating and executing SQL statements
         | 
| @@ -24,46 +27,13 @@ require_relative "ensql/sql" | |
| 24 27 | 
             
            #     Ensql.sql('select * from users where id = %{id}', id: 1).first_row # => { "id" => 1, "email" => "test@example.com" }
         | 
| 25 28 | 
             
            #
         | 
| 26 29 | 
             
            module Ensql
         | 
| 27 | 
            -
              # Wrapper for errors raised by Ensql
         | 
| 28 | 
            -
              class Error < StandardError; end
         | 
| 29 | 
            -
             | 
| 30 30 | 
             
              class << self
         | 
| 31 | 
            -
             | 
| 32 31 | 
             
                # (see SQL)
         | 
| 33 32 | 
             
                # @return [Ensql::SQL] SQL statement
         | 
| 34 | 
            -
                def sql(sql, params={})
         | 
| 33 | 
            +
                def sql(sql, params = {})
         | 
| 35 34 | 
             
                  SQL.new(sql, params)
         | 
| 36 35 | 
             
                end
         | 
| 37 36 |  | 
| 38 | 
            -
                # Path to search for *.sql queries in, defaults to "sql/". For example, if
         | 
| 39 | 
            -
                # {sql_path} is set to 'app/queries', `load_sql('users/active')` will read
         | 
| 40 | 
            -
                # 'app/queries/users/active.sql'.
         | 
| 41 | 
            -
                # @see .load_sql
         | 
| 42 | 
            -
                #
         | 
| 43 | 
            -
                # @example
         | 
| 44 | 
            -
                #   Ensql.sql_path = Rails.root.join('app/queries')
         | 
| 45 | 
            -
                #
         | 
| 46 | 
            -
                def sql_path
         | 
| 47 | 
            -
                  @sql_path ||= 'sql'
         | 
| 48 | 
            -
                end
         | 
| 49 | 
            -
                attr_writer :sql_path
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                # Load SQL from a file within {sql_path}. This is the recommended way to
         | 
| 52 | 
            -
                # manage SQL in a non-trivial project. For details of how to write
         | 
| 53 | 
            -
                # interpolation placeholders, see {SQL}.
         | 
| 54 | 
            -
                #
         | 
| 55 | 
            -
                # @see .sql_path=
         | 
| 56 | 
            -
                # @return [Ensql::SQL]
         | 
| 57 | 
            -
                #
         | 
| 58 | 
            -
                # @example
         | 
| 59 | 
            -
                #   Ensql.load_sql('users/activity', report_params)
         | 
| 60 | 
            -
                #   Ensql.load_sql(:upsert_users, imported_users_attrs)
         | 
| 61 | 
            -
                #
         | 
| 62 | 
            -
                def load_sql(name, params={})
         | 
| 63 | 
            -
                  path = File.join(sql_path, "#{name}.sql")
         | 
| 64 | 
            -
                  SQL.new(File.read(path), params, name)
         | 
| 65 | 
            -
                end
         | 
| 66 | 
            -
             | 
| 67 37 | 
             
                # Convenience method to interpolate and run the supplied SQL on the current
         | 
| 68 38 | 
             
                # adapter.
         | 
| 69 39 | 
             
                # @return [void]
         | 
| @@ -72,38 +42,8 @@ module Ensql | |
| 72 42 | 
             
                #   Ensql.run("DELETE FROM users WHERE id = %{id}", id: user.id)
         | 
| 73 43 | 
             
                #   Ensql.run("ALTER TABLE test RENAME TO old_test")
         | 
| 74 44 | 
             
                #
         | 
| 75 | 
            -
                def run(sql, params={})
         | 
| 45 | 
            +
                def run(sql, params = {})
         | 
| 76 46 | 
             
                  SQL.new(sql, params).run
         | 
| 77 47 | 
             
                end
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                # Connection adapter to use. Must implement the interface defined in
         | 
| 80 | 
            -
                # {Ensql::Adapter}. If not specified, it will try to autoload an adapter
         | 
| 81 | 
            -
                # based on the availability of Sequel or ActiveRecord, in that order.
         | 
| 82 | 
            -
                #
         | 
| 83 | 
            -
                # @example
         | 
| 84 | 
            -
                #     require 'sequel'
         | 
| 85 | 
            -
                #     Ensql.adapter # => Ensql::SequelAdapter
         | 
| 86 | 
            -
                #     Ensql.adapter = Ensql::ActiveRecordAdapter # override adapter
         | 
| 87 | 
            -
                #     Ensql.adapter = CustomMSSQLAdapater # supply your own adapter
         | 
| 88 | 
            -
                #
         | 
| 89 | 
            -
                def adapter
         | 
| 90 | 
            -
                  @adapter ||= autoload_adapter
         | 
| 91 | 
            -
                end
         | 
| 92 | 
            -
                attr_writer :adapter
         | 
| 93 | 
            -
             | 
| 94 | 
            -
              private
         | 
| 95 | 
            -
             | 
| 96 | 
            -
                def autoload_adapter
         | 
| 97 | 
            -
                  if defined? Sequel
         | 
| 98 | 
            -
                    require_relative 'ensql/sequel_adapter'
         | 
| 99 | 
            -
                    SequelAdapter
         | 
| 100 | 
            -
                  elsif defined? ActiveRecord
         | 
| 101 | 
            -
                    require_relative 'ensql/active_record_adapter'
         | 
| 102 | 
            -
                    ActiveRecordAdapter
         | 
| 103 | 
            -
                  else
         | 
| 104 | 
            -
                    raise Error, "Couldn't autodetect an adapter, please specify manually."
         | 
| 105 | 
            -
                  end
         | 
| 106 | 
            -
                end
         | 
| 107 | 
            -
             | 
| 108 48 | 
             
              end
         | 
| 109 49 | 
             
            end
         | 
| @@ -1,60 +1,104 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require_relative  | 
| 4 | 
            -
            require_relative  | 
| 3 | 
            +
            require_relative "version"
         | 
| 4 | 
            +
            require_relative "adapter"
         | 
| 5 | 
            +
            require_relative "pool_wrapper"
         | 
| 5 6 |  | 
| 6 7 | 
             
            # Ensure our optional dependency has a compatible version
         | 
| 7 | 
            -
            gem  | 
| 8 | 
            -
            require  | 
| 8 | 
            +
            gem "activerecord", Ensql::SUPPORTED_ACTIVERECORD_VERSIONS
         | 
| 9 | 
            +
            require "active_record"
         | 
| 9 10 |  | 
| 10 11 | 
             
            module Ensql
         | 
| 11 12 | 
             
              #
         | 
| 12 | 
            -
              #  | 
| 13 | 
            -
              # ActiveRecord connection to be configured and | 
| 14 | 
            -
              #  | 
| 13 | 
            +
              # Wraps an ActiveRecord connection pool to implement the {Adapter} interface
         | 
| 14 | 
            +
              # for ActiveRecord. Requires an ActiveRecord connection to be configured and
         | 
| 15 | 
            +
              # established. By default, uses the connection pool on ActiveRecord::Base.
         | 
| 16 | 
            +
              # Other pools can be passed to the constructor.
         | 
| 15 17 | 
             
              #
         | 
| 16 18 | 
             
              # @example
         | 
| 17 19 | 
             
              #   require 'active_record'
         | 
| 18 20 | 
             
              #   ActiveRecord::Base.establish_connection(adapter: 'postgresql', database: 'mydb')
         | 
| 19 | 
            -
              #   Ensql.adapter = Ensql::ActiveRecordAdapter
         | 
| 21 | 
            +
              #   Ensql.adapter = Ensql::ActiveRecordAdapter.new
         | 
| 22 | 
            +
              #   # Use database configuration for the Widget model instead
         | 
| 23 | 
            +
              #   Ensql.adapter = Ensql::ActiveRecordAdapter.new(Widget)
         | 
| 20 24 | 
             
              #
         | 
| 21 | 
            -
              # @see  | 
| 22 | 
            -
              # @see ACTIVERECORD_VERSION Required gem version
         | 
| 25 | 
            +
              # @see SUPPORTED_ACTIVERECORD_VERSIONS
         | 
| 23 26 | 
             
              #
         | 
| 24 | 
            -
               | 
| 25 | 
            -
                 | 
| 26 | 
            -
             | 
| 27 | 
            -
                #  | 
| 28 | 
            -
                 | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 27 | 
            +
              class ActiveRecordAdapter
         | 
| 28 | 
            +
                include Adapter
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                # Wrap the raw connections from an Active Record connection pool. This
         | 
| 31 | 
            +
                # allows us to safely checkout the underlying database connection for use in
         | 
| 32 | 
            +
                # a database specific adapter.
         | 
| 33 | 
            +
                #
         | 
| 34 | 
            +
                #     Ensql.adapter = MySqliteAdapter.new(ActiveRecordAdapter.pool)
         | 
| 35 | 
            +
                #
         | 
| 36 | 
            +
                # @param base [Class] an ActiveRecord class to source connections from
         | 
| 37 | 
            +
                # @return [PoolWrapper] a pool adapter for raw connections
         | 
| 38 | 
            +
                def self.pool(base = ActiveRecord::Base)
         | 
| 39 | 
            +
                  PoolWrapper.new do |client_block|
         | 
| 40 | 
            +
                    base.connection_pool.with_connection { |connection| client_block.call connection.raw_connection }
         | 
| 35 41 | 
             
                  end
         | 
| 36 42 | 
             
                end
         | 
| 37 43 |  | 
| 38 | 
            -
                #  | 
| 39 | 
            -
                 | 
| 40 | 
            -
                   | 
| 44 | 
            +
                # Support deprecated class method interface
         | 
| 45 | 
            +
                class << self
         | 
| 46 | 
            +
                  require "forwardable"
         | 
| 47 | 
            +
                  extend Forwardable
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  delegate [:literalize, :run, :fetch_count, :fetch_each_row, :fetch_rows, :fetch_first_column, :fetch_first_field, :fetch_first_row] => :new
         | 
| 41 50 | 
             
                end
         | 
| 42 51 |  | 
| 43 | 
            -
                #  | 
| 44 | 
            -
                def  | 
| 45 | 
            -
                   | 
| 52 | 
            +
                # @param base [Class] an ActiveRecord class to source connections from
         | 
| 53 | 
            +
                def initialize(base = ActiveRecord::Base)
         | 
| 54 | 
            +
                  @base = base
         | 
| 46 55 | 
             
                end
         | 
| 47 56 |  | 
| 48 | 
            -
                #  | 
| 49 | 
            -
                def  | 
| 50 | 
            -
                   | 
| 57 | 
            +
                # @visibility private
         | 
| 58 | 
            +
                def fetch_rows(sql)
         | 
| 59 | 
            +
                  fetch_each_row(sql).to_a
         | 
| 51 60 | 
             
                end
         | 
| 52 61 |  | 
| 53 | 
            -
                 | 
| 54 | 
            -
             | 
| 62 | 
            +
                # @visibility private
         | 
| 63 | 
            +
                def fetch_each_row(sql, &block)
         | 
| 64 | 
            +
                  return to_enum(:fetch_each_row, sql) unless block
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  result = with_connection { |c| c.exec_query(sql) }
         | 
| 67 | 
            +
                  # AR populates `column_types` with the types of any columns that haven't
         | 
| 68 | 
            +
                  # already been type casted by pg decoders. If present, we need to
         | 
| 69 | 
            +
                  # deserialize them now.
         | 
| 70 | 
            +
                  if result.column_types.any?
         | 
| 71 | 
            +
                    result.each { |row| yield deserialize_types(row, result.column_types) }
         | 
| 72 | 
            +
                  else
         | 
| 73 | 
            +
                    result.each(&block)
         | 
| 74 | 
            +
                  end
         | 
| 55 75 | 
             
                end
         | 
| 56 76 |  | 
| 57 | 
            -
                 | 
| 77 | 
            +
                # @visibility private
         | 
| 78 | 
            +
                def run(sql)
         | 
| 79 | 
            +
                  with_connection { |c| c.execute(sql) }
         | 
| 80 | 
            +
                  nil
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                # @visibility private
         | 
| 84 | 
            +
                def fetch_count(sql)
         | 
| 85 | 
            +
                  with_connection { |c| c.exec_update(sql) }
         | 
| 86 | 
            +
                end
         | 
| 58 87 |  | 
| 88 | 
            +
                # @visibility private
         | 
| 89 | 
            +
                def literalize(value)
         | 
| 90 | 
            +
                  with_connection { |c| c.quote(value) }
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                private
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                def with_connection(&block)
         | 
| 96 | 
            +
                  @base.connection_pool.with_connection(&block)
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                def deserialize_types(row, column_types)
         | 
| 100 | 
            +
                  column_types.each { |column, type| row[column] = type.deserialize(row[column]) }
         | 
| 101 | 
            +
                  row
         | 
| 102 | 
            +
                end
         | 
| 59 103 | 
             
              end
         | 
| 60 104 | 
             
            end
         |