Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error with composite PK #830

Open
fragkakis opened this issue Feb 23, 2024 · 7 comments
Open

Error with composite PK #830

fragkakis opened this issue Feb 23, 2024 · 7 comments

Comments

@fragkakis
Copy link
Contributor

fragkakis commented Feb 23, 2024

I have trouble importing data to a table with a composite PK. Here is the scenario that can reproduce this in Postgres:

# frozen_string_literal: true

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  git_source(:github) { |repo| "https://github.com/#{repo}.git" }

  gem "rails", "~> 7.1.3"
  gem 'activerecord-import'
  gem "pg"
end

require "active_record"
require "minitest/autorun"
require "logger"

db_properties = {
  adapter: "postgresql",
  host: "localhost",
  username: "postgres",
  password: "postgres",
  database: "books"
}

ActiveRecord::Base.establish_connection(db_properties)
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :authors, force: true do |t|
    t.string :name
  end

  execute <<-SQL
    DROP SEQUENCE IF EXISTS book_id_seq;    
    CREATE SEQUENCE book_id_seq
        AS integer
        START WITH 1
        INCREMENT BY 1
        NO MINVALUE
        NO MAXVALUE
        CACHE 1;

    DROP TABLE IF EXISTS books; 
    CREATE TABLE books (
        id bigint DEFAULT nextval('book_id_seq'::regclass) NOT NULL,
        title character varying,
        author_id bigint
     );

    ALTER TABLE ONLY books ADD CONSTRAINT fk_rails_040a418131 FOREIGN KEY (author_id) REFERENCES authors(id);
  SQL
end

class Author < ActiveRecord::Base
  has_many :books, query_constraints: [:id, :author_id], inverse_of: :author
end

class Book < ActiveRecord::Base
  self.primary_key = %i[id author_id]
  belongs_to :author
end

author = Author.create!(name: "Foo Barson")

books = []
2.times do |i|
  books << Book.new(author_id: author.id, title: "book #{i}")
end
Book.import books

The error I am getting is:

/Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-7.1.3.2/lib/active_record/connection_adapters/abstract/quoting.rb:29:in `quote': can't quote Array (TypeError)

        else raise TypeError, "can't quote #{value.class.name}"
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-7.1.3.2/lib/active_record/connection_adapters/postgresql/quoting.rb:69:in `quote'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-7.1.3.2/lib/active_record/connection_adapters/postgresql/schema_statements.rb:258:in `serial_sequence'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-7.1.3.2/lib/active_record/connection_adapters/postgresql/schema_statements.rb:250:in `default_sequence_name'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-7.1.3.2/lib/active_record/model_schema.rb:377:in `reset_sequence_name'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-7.1.3.2/lib/active_record/model_schema.rb:369:in `sequence_name'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-import-1.5.1/lib/activerecord-import/import.rb:1027:in `block (2 levels) in values_sql_for_columns_and_attributes'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-import-1.5.1/lib/activerecord-import/import.rb:1023:in `each'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-import-1.5.1/lib/activerecord-import/import.rb:1023:in `each_with_index'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-import-1.5.1/lib/activerecord-import/import.rb:1023:in `each'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-import-1.5.1/lib/activerecord-import/import.rb:1023:in `map'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-import-1.5.1/lib/activerecord-import/import.rb:1023:in `block in values_sql_for_columns_and_attributes'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-import-1.5.1/lib/activerecord-import/import.rb:1022:in `map'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-import-1.5.1/lib/activerecord-import/import.rb:1022:in `values_sql_for_columns_and_attributes'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-import-1.5.1/lib/activerecord-import/import.rb:815:in `import_without_validations_or_callbacks'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-import-1.5.1/lib/activerecord-import/import.rb:771:in `import_with_validations'
	from /Users/markosfragkakis/.rvm/gems/ruby-3.2.2/gems/activerecord-import-1.5.1/lib/activerecord-import/import.rb:702:in `import_helper'
	... 5 levels...
3.2.2 :118 > 
3.2.2 :119 > 

Please note that the import is successful if I do it using a hash, like so:

books = []
2.times do |i|
  books << {author_id: author.id, title: "book #{i}"}
end
Book.import books
D, [2024-02-23T12:18:10.094993 #6681] DEBUG -- :   Book Create Many (5.6ms)  INSERT INTO "books" ("author_id","title") VALUES (3,'book 0'),(3,'book 1') RETURNING "id", "author_id"
 => #<struct ActiveRecord::Import::Result failed_instances=[], num_inserts=1, ids=[[5, 3], [6, 3]], results=[]> 
3.2.2 :135 > 
3.2.2 :136 > Book.last
D, [2024-02-23T12:18:13.930261 #6681] DEBUG -- :   Book Load (2.8ms)  SELECT "books".* FROM "books" ORDER BY "books"."id" DESC, "books"."author_id" DESC LIMIT $1  [["LIMIT", 1]]
 => #<Book:0x000000010a852950 id: 6, title: "book 1", author_id: 3> 
3.2.2 :137 > 
@kunalvashistordway
Copy link

I am also facing same issue any solution you found on this

@fragkakis
Copy link
Contributor Author

@kunalvashistordway Importing with columns and hashes works.

Unfortunately, our codebase needs to use models, because we manually invoke active record callbacks.

But if you don't I guess you consider switching to hashes.

@jkowens
Copy link
Collaborator

jkowens commented Mar 4, 2024

Support for Rails 7.1 built-in composite primary keys needs to be added.

@kzacharakis
Copy link

Our platform's major upgrade is currently blocked due to this bug. Is there any plan for fix?

@jkowens
Copy link
Collaborator

jkowens commented Apr 11, 2024

Contributions from the community are accepted, but I don't expect this to be added any time soon. I would suggest migrating to the built-in ActiveRecord upsert if you are using composite primary keys.

@fragkakis
Copy link
Contributor Author

Opened PR #837

@jkowens
Copy link
Collaborator

jkowens commented Apr 27, 2024

Resolved by #837. Thanks @fragkakis 🎉 🙌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants