rom-rb / rom-factory

Data generator with support for persistence backends
MIT License
83 stars 42 forks source link

Associations in traits persists multiple times #91

Open S1azZy opened 3 months ago

S1azZy commented 3 months ago

Describe the bug

If you make a belongs_to association inside trait, it will be created 2 times. This causes an error if there is a uniqueness check. I have written a test for an example.

On version 0.10.2 it works correct.

To Reproduce

# frozen_string_literal: true

RSpec.describe ROM::Factory do
  include_context "database"

  subject(:factories) do
    ROM::Factory.configure do |config|
      config.rom = rom
    end
  end

  before do
    conn.create_table?(:book_types) do
      primary_key :id
      column :type, String, null: false

      index :type, unique: true
    end

    conn.create_table?(:books) do
      primary_key :id
      foreign_key :book_type_id, :book_types, index: true
    end

    conf.relation(:book_types) do
      schema(infer: true) do
        associations do
          has_many :books
        end
      end
    end

    conf.relation(:books) do
      schema(infer: true) do
        associations do
          belongs_to :book_type
        end
      end
    end

    rom.gateways[:default].use_logger(Logger.new($stdout))
  end

  context "trait with associations" do
    it "creates book type only once" do
      factories.define(:book) do |f|
        f.trait :with_type do |t|
          t.association(:book_type)
        end
      end

      factories.define(:book_type) do |f|
        f.type { "NOT_UNIQUE" }
      end

      factories[:book, :with_type]
      expect(rom.relations[:book_types].count).to eq(1)
    end
  end

  after do
    conn.drop_table?(:books)
    conn.drop_table?(:book_types)
  end
end

And the error

I, [2024-07-22T16:45:11.954139 #19499]  INFO -- : (0.002133s) INSERT INTO "book_types" ("type") VALUES ('NOT_UNIQUE') RETURNING "book_types"."id", "book_types"."type"
E, [2024-07-22T16:45:11.955342 #19499] ERROR -- : PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "book_types_type_index"
DETAILS:  Key (type)=(NOT_UNIQUE) already exists.: INSERT INTO "book_types" ("type") VALUES ('NOT_UNIQUE') RETURNING "book_types"."id", "book_types"."type"
I, [2024-07-22T16:45:11.964446 #19499]  INFO -- : (0.008830s) DROP TABLE IF EXISTS "books"
I, [2024-07-22T16:45:11.970889 #19499]  INFO -- : (0.006384s) DROP TABLE IF EXISTS "book_types"
F

Failures:

  1) ROM::Factory trait with associations creates book type only once
     Failure/Error:
       result = relation
         .with(auto_struct: !tuple_evaluator.has_associations?)
         .command(:create)
         .call(attrs)

     ROM::SQL::UniqueConstraintError:
       PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "book_types_type_index"
       DETAILS:  Key (type)=(NOT_UNIQUE) already exists.
     # ./lib/rom/factory/builder/persistable.rb:48:in `persist'
     # ./lib/rom/factory/builder/persistable.rb:28:in `create'
     # ./lib/rom/factory/attributes/association.rb:82:in `call'
     # ./lib/rom/factory/tuple_evaluator.rb:186:in `block in evaluate_associations'
     # ./lib/rom/factory/attribute_registry.rb:22:in `each'
     # ./lib/rom/factory/attribute_registry.rb:22:in `each'
     # ./lib/rom/factory/tuple_evaluator.rb:178:in `each_with_object'
     # ./lib/rom/factory/tuple_evaluator.rb:178:in `evaluate_associations'
     # ./lib/rom/factory/tuple_evaluator.rb:149:in `evaluate'
     # ./lib/rom/factory/tuple_evaluator.rb:59:in `defaults'
     # ./lib/rom/factory/tuple_evaluator.rb:173:in `evaluate_traits'
     # ./lib/rom/factory/tuple_evaluator.rb:150:in `evaluate'
     # ./lib/rom/factory/tuple_evaluator.rb:59:in `defaults'
     # ./lib/rom/factory/builder.rb:37:in `tuple'
     # ./lib/rom/factory/builder/persistable.rb:27:in `create'
     # ./lib/rom/factory/factories.rb:171:in `[]'
     # ./spec/integration/rom/association_trait_spec.rb:56:in `block (3 levels) in <top (required)>'
     # ------------------
     # --- Caused by: ---
     # PG::UniqueViolation:
     #   ERROR:  duplicate key value violates unique constraint "book_types_type_index"
     #   DETAILS:  Key (type)=(NOT_UNIQUE) already exists.
     #   ./lib/rom/factory/builder/persistable.rb:48:in `persist'

Expected behavior

Associations in traits should be created only 1 time.

My environment

solnic commented 3 months ago

Thanks for reporting this! I'll look into it.