diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8688ff0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,45 @@ +name: CI + +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + ruby-version: ['2.7', '3.0', '3.1', '3.2'] + gemfile: + - "activerecord_6_0" + - "activerecord_6_1" + - "activerecord_7_0" + services: + postgres: + image: postgres + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + env: + BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile + TEST_DATABASE_USER: postgres + TEST_DATABASE_PASSWORD: postgres + TEST_DATABASE_HOST: localhost + TEST_DATABASE: postgres + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby ${{ matrix.ruby-version }} + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + ruby-version: ${{ matrix.ruby-version }} + - name: Install dependencies + run: bundle install + - name: Run tests + run: bundle exec rake \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4054c74..f370f7d 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ pkg ## PROJECT::SPECIFIC Gemfile.lock +gemfiles/*.gemfile.lock diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3413056..0000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: ruby -rvm: - - 2.6.5 - - 2.7.1 -before_install: - - sudo apt-get update - - sudo apt-get --yes remove postgresql\* - - sudo apt-get install -y postgresql-12 postgresql-client-12 - - sudo cp /etc/postgresql/{9.6,12}/main/pg_hba.conf - - sudo service postgresql restart 12 -gemfile: - - gemfiles/activerecord_4.gemfile - - gemfiles/activerecord_5.gemfile - - gemfiles/activerecord_6.gemfile -matrix: - exclude: - - rvm: 2.7.1 - gemfile: gemfiles/activerecord_4.gemfile -services: - - postgresql -before_script: - - psql -c 'create database postgresql_cursor_test;' -U postgres - - psql -c 'CREATE ROLE travis SUPERUSER LOGIN CREATEDB;' -U postgres - - psql -c 'create table products ( id serial primary key, data varchar);' -U postgres -d postgresql_cursor_test - - psql -c 'create table prices ( id serial primary key, data varchar, product_id integer);' -U postgres -d postgresql_cursor_test -addons: - postgresql: '12.3' diff --git a/Appraisals b/Appraisals index 363a882..0efc675 100644 --- a/Appraisals +++ b/Appraisals @@ -1,12 +1,11 @@ -appraise "activerecord-4" do - gem "activerecord", "4.2.11.1" - gem "pg", "~> 0.15" +appraise "activerecord-6-0" do + gem "activerecord", "6.0.6" end -appraise "activerecord-5" do - gem "activerecord", "5.2.3" +appraise "activerecord-6-1" do + gem "activerecord", "6.1.7" end -appraise "activerecord-6" do - gem "activerecord", "6.0.0" +appraise "activerecord-7-0" do + gem "activerecord", "7.0.4" end diff --git a/Rakefile b/Rakefile index 648366d..1047d7c 100644 --- a/Rakefile +++ b/Rakefile @@ -17,9 +17,7 @@ task :console do #IRB.start end -desc "Setup testing database and table" +desc "Setup testing database" task :setup do sh %q(createdb postgresql_cursor_test) - sh %Q - sh %Q end diff --git a/gemfiles/activerecord_5.gemfile b/gemfiles/activerecord_6_0.gemfile similarity index 76% rename from gemfiles/activerecord_5.gemfile rename to gemfiles/activerecord_6_0.gemfile index c8bacf6..fb8adfc 100644 --- a/gemfiles/activerecord_5.gemfile +++ b/gemfiles/activerecord_6_0.gemfile @@ -2,6 +2,6 @@ source "https://rubygems.org" -gem "activerecord", "5.2.3" +gem "activerecord", "6.0.6" gemspec path: "../" diff --git a/gemfiles/activerecord_6.gemfile b/gemfiles/activerecord_6_1.gemfile similarity index 76% rename from gemfiles/activerecord_6.gemfile rename to gemfiles/activerecord_6_1.gemfile index 385b1b2..caa8d4f 100644 --- a/gemfiles/activerecord_6.gemfile +++ b/gemfiles/activerecord_6_1.gemfile @@ -2,6 +2,6 @@ source "https://rubygems.org" -gem "activerecord", "6.0.0" +gem "activerecord", "6.1.7" gemspec path: "../" diff --git a/gemfiles/activerecord_4.gemfile b/gemfiles/activerecord_7_0.gemfile similarity index 64% rename from gemfiles/activerecord_4.gemfile rename to gemfiles/activerecord_7_0.gemfile index 5d186ce..cf49fd4 100644 --- a/gemfiles/activerecord_4.gemfile +++ b/gemfiles/activerecord_7_0.gemfile @@ -2,7 +2,6 @@ source "https://rubygems.org" -gem "activerecord", "4.2.11.1" -gem "pg", "~> 0.15" +gem "activerecord", "7.0.4" gemspec path: "../" diff --git a/lib/postgresql_cursor.rb b/lib/postgresql_cursor.rb index 7b9486e..aacb5f5 100644 --- a/lib/postgresql_cursor.rb +++ b/lib/postgresql_cursor.rb @@ -12,6 +12,6 @@ # ActiveRecord 4.x require 'active_record/connection_adapters/postgresql_adapter' ActiveRecord::Base.extend(PostgreSQLCursor::ActiveRecord::SqlCursor) - ActiveRecord::Relation.send(:include, PostgreSQLCursor::ActiveRecord::Relation::CursorIterators) - ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:include, PostgreSQLCursor::ActiveRecord::ConnectionAdapters::PostgreSQLTypeMap) + ActiveRecord::Relation.include(PostgreSQLCursor::ActiveRecord::Relation::CursorIterators) + ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.include(PostgreSQLCursor::ActiveRecord::ConnectionAdapters::PostgreSQLTypeMap) end diff --git a/lib/postgresql_cursor/cursor.rb b/lib/postgresql_cursor/cursor.rb index fb5905c..370c721 100644 --- a/lib/postgresql_cursor/cursor.rb +++ b/lib/postgresql_cursor/cursor.rb @@ -110,12 +110,8 @@ def each_array(&block) def each_instance(klass = nil, &block) klass ||= @type each_tuple do |row| - if ::ActiveRecord::VERSION::MAJOR < 4 - model = klass.send(:instantiate, row) - else - @column_types ||= column_types - model = klass.send(:instantiate, row, @column_types) - end + @column_types ||= column_types + model = klass.send(:instantiate, row, @column_types) block.call(model) end end @@ -144,12 +140,8 @@ def each_instance_batch(klass = nil, &block) klass ||= @type each_batch do |batch| models = batch.map do |row| - if ::ActiveRecord::VERSION::MAJOR < 4 - klass.send(:instantiate, row) - else - @column_types ||= column_types - klass.send(:instantiate, row, @column_types) - end + @column_types ||= column_types + klass.send(:instantiate, row, @column_types) end block.call(models) end @@ -223,7 +215,6 @@ def cast_types(row) end def column_types - return nil if ::ActiveRecord::VERSION::MAJOR < 4 return @column_types if @column_types types = {} @@ -233,11 +224,7 @@ def column_types fmod = @result.fmod i types[fname] = @connection.get_type_map.fetch(ftype.to_s, fmod) do |oid, mod| # warn "unknown OID: #{fname}(#{oid}, #{mod}) (#{sql})" - if ::ActiveRecord::VERSION::MAJOR <= 4 - ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::Identity.new - else - ::ActiveRecord::Type::Value.new - end + ::ActiveRecord::Type::Value.new end end diff --git a/postgresql_cursor.gemspec b/postgresql_cursor.gemspec index 3950144..f4f35e0 100644 --- a/postgresql_cursor.gemspec +++ b/postgresql_cursor.gemspec @@ -27,14 +27,12 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.require_paths = ["lib"] + spec.required_ruby_version = '>= 2.7' + # Remove this for jruby which should use 'activerecord-jdbcpostgresql-adapter' # spec.add_dependency 'pg' - spec.add_dependency "activerecord", ">= 3.1.0" - # spec.add_dependency 'activerecord', '~> 3.1.0' - # spec.add_dependency 'activerecord', '~> 4.1.0' - # spec.add_dependency 'activerecord', '~> 5.0.0' - # spec.add_dependency 'activerecord', '~> 6.0.0' + spec.add_dependency "activerecord", ">= 6.0" spec.add_development_dependency "irb" spec.add_development_dependency "minitest" diff --git a/test-app/app.rb b/test-app/app.rb index e728d7e..16d3af2 100644 --- a/test-app/app.rb +++ b/test-app/app.rb @@ -9,9 +9,24 @@ require 'active_record' require 'postgresql_cursor' -ActiveRecord::Base.establish_connection( adapter: 'postgresql', +ActiveRecord::Base.establish_connection( + adapter: 'postgresql', database: ENV['TEST_DATABASE'] || 'postgresql_cursor_test', - username: ENV['TEST_USER'] || ENV['USER'] || 'postgresql_cursor') + host: ENV['TEST_DATABASE_HOST'], + username: ENV['TEST_DATABASE_USER'] || ENV['USER'] || 'postgresql_cursor', + password: ENV['TEST_DATABASE_PASSWORD'] +) + +ActiveRecord::Schema.define(version: 0) do + create_table(:products, force: true) do |t| + t.string :data + end + + create_table(:prices, force: true) do |t| + t.string :data + t.integer :product_id + end +end class Product < ActiveRecord::Base def self.generate(max=1_000) diff --git a/test/helper.rb b/test/helper.rb index a4e767f..724d817 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -5,9 +5,24 @@ require 'active_record' require 'postgresql_cursor' -ActiveRecord::Base.establish_connection(adapter: 'postgresql', +ActiveRecord::Base.establish_connection( + adapter: 'postgresql', database: ENV['TEST_DATABASE'] || 'postgresql_cursor_test', - username: ENV['TEST_USER'] || ENV['USER'] || 'postgresql_cursor') + host: ENV['TEST_DATABASE_HOST'], + username: ENV['TEST_DATABASE_USER'] || ENV['USER'] || 'postgresql_cursor', + password: ENV['TEST_DATABASE_PASSWORD'] +) + +ActiveRecord::Schema.define(version: 0) do + create_table(:products, force: true) do |t| + t.string :data + end + + create_table(:prices, force: true) do |t| + t.string :data + t.integer :product_id + end +end class Product < ActiveRecord::Base has_many :prices diff --git a/test/test_postgresql_cursor.rb b/test/test_postgresql_cursor.rb index d62cadf..f0458f9 100644 --- a/test/test_postgresql_cursor.rb +++ b/test/test_postgresql_cursor.rb @@ -141,6 +141,7 @@ def test_batch_exception Product.each_row_batch_by_sql("select * from products") do |r| raise "Oops" end + flunk("Should have thrown an exception") rescue => e assert_equal e.message, "Oops" end @@ -149,16 +150,18 @@ def test_exception_in_failed_transaction Product.each_row_by_sql("select * from products") do |r| Product.connection.execute("select kaboom") end + flunk("Should have thrown an exception") rescue => e - assert_match(/PG::InFailedSqlTransaction/, e.message) + assert_kind_of(PG::UndefinedColumn, root_cause(e)) end def test_batch_exception_in_failed_transaction Product.each_row_batch_by_sql("select * from products") do |r| Product.connection.execute("select kaboom") end + flunk("Should have thrown an exception") rescue => e - assert_match(/PG::InFailedSqlTransaction/, e.message) + assert_kind_of(PG::UndefinedColumn, root_cause(e)) end def test_cursor @@ -225,4 +228,11 @@ def test_relation_association_is_not_loaded cursor = Product.first.prices.each_instance refute cursor.instance_variable_get(:@type).loaded? end + + def root_cause(e) + until e.cause.nil? + e = e.cause + end + e + end end