rom-sql icon indicating copy to clipboard operation
rom-sql copied to clipboard

Need to override combine_keys with whatever in order to combine result correctly

Open blelump opened this issue 7 years ago • 0 comments

Using the gist provided below, ROM doesn't combine buildings correctly. The query result is empty even though the SQL query was correct.

[
  #<ROM::Struct::User id=1 login="[email protected]" employee_id=5 buildings=[]>
]

However, if you will modify the association

has_many :buildings, override: true, view: :for_user

and override combine_keys with literally whatever:

has_many :buildings, override: true, view: :for_user, combine_keys: {blah: :blah} # combine_keys: {} is also fine

it will work:

[
  #<ROM::Struct::User id=1 login="[email protected]" employee_id=5 
     buildings=[#<ROM::Struct::Building id=1 name="wew">, #<ROM::Struct::Building id=2 name="weeew">]>
]

Gist to reproduce:

rom = ROM.container(:sql, 'sqlite::memory') do |conf|
  conf.gateways[:default].use_logger(Logger.new($stdout))

  conf.default.create_table(:users) do
    primary_key :id
    column :login, String
  end

  conf.default.create_table(:employees) do
    primary_key :id
    column :name, String, null: false
  end

  conf.default.create_table(:buildings_employees) do
    foreign_key :building_id, :buildings
    foreign_key :employee_id, :employees
  end

  conf.default.create_table(:buildings) do
    primary_key :id
    column :name, String, null: false
  end

  conf.default.create_table(:employees_users) do
    foreign_key :verifable_id, :employees
    foreign_key :user_id, :users
  end

  conf.relation(:users) do
    schema(:users, infer: true) do
      associations do
        has_many :employees_users
        has_many :users, through: :employees_users
        has_many :buildings, override: true, view: :for_user
      end
    end
  end

  conf.relation(:employees) do
    schema(:employees, infer: true) do
      associations do
      end
    end
  end

  conf.relation(:buildings) do
    schema(:buildings, infer: true) do
      associations do
        has_many :buildings_employees
      end
    end

    def for_user(_assoc, users)
      join(:buildings_employees)
        .where(employee_id: users.pluck(:employee_id))
    end
  end

  conf.relation(:buildings_employees) do
    schema(:buildings_employees, infer: true) do
      associations do
        belongs_to :building
        belongs_to :employee
      end
    end
  end

  conf.relation(:employees_users) do
    schema(:employees_users, infer: true) do
      associations do
        belongs_to :user, foreign_key: :user_id
        belongs_to :employee, foreign_key: :verifable_id
      end
    end
  end
end

class UserRepo < ROM::Repository[:users]
  def by_id(id)
    users
      .join(:employees_users)
      .join(:employees, { id: :verifable_id })
      .select_append { |r| r[:employees][:id].as(:employee_id) }
      .combine(:buildings)
      .to_a
  end
end

employee = rom.relations[:employees].changeset(:create, name: 'Jane', id: 5).commit
rom.relations[:employees].changeset(:create, name: 'Jane', id: 8).commit

user = rom.relations[:users]
  .changeset(:create, login: '[email protected]')
  .commit

rom.relations[:employees_users]
  .changeset(:create, user_id: user[:id], verifable_id: employee[:id]).commit

au = rom.relations[:buildings]
  .changeset(:create, employee_id: employee[:id], name: 'wew').commit

au2 = rom.relations[:buildings]
  .changeset(:create, name: 'weeew').commit

rom.relations[:buildings_employees].changeset(
  :create,
  [
    { employee_id: employee[:id], building_id: au[:id] },
    { employee_id: employee[:id], building_id: au2[:id] }
  ]
).commit

repo = UserRepo.new(rom)

user = repo.by_id(1)

Bundled with: rom-sql (2.3.0)

blelump avatar Mar 22 '18 12:03 blelump