azrael

azrael

Hi,

I am working on a first elixir project and I am struggling quite a lot with the many_to_many association. I have got it sort-of working using the auto-generated link table, however it does not seem to be checking for uniqueness on the link succesfully.

defmodule KevinCadleFantasyGame.Lineup do
  use Ecto.Schema
  import Ecto.Changeset

  alias KevinCadleFantasyGame.{Player, Repo, Lineup}

  schema "lineups" do
    many_to_many :players, Player,
      join_through: "lineup_players", unique: true

    timestamps()
  end

  @doc false
  def changeset(lineup, attrs) do
    player_ids = if Map.has_key?(attrs, :player_ids), do: attrs.player_ids, else: []
    players = Player.by_ids(player_ids)

    lineup
    |> Repo.preload(:players)
    |> cast(attrs, [:id])
    |> put_assoc(:players, players)
    |> unique_constraint(:players)
    |> validate_required([])
  end


  def create_or_update(params) do
    cs = changeset(%Lineup{}, params)

    if cs.valid? do
      Repo.insert!(cs,
        on_conflict: :nothing,
        conflict_target: :id
        )
    else
      cs
    end
  end
end

and the migration:

defmodule KevinCadleFantasyGame.Repo.Migrations.CreateLineups do
  use Ecto.Migration

  def change do
    create table(:lineups) do

      timestamps()
    end


    create table("lineup_players", primary_key: false) do
      add :player_id, references(:players)
      add :lineup_id, references(:lineups)
    end

    create unique_index(:lineup_players, [:player_id, :lineup_id])
  end
end

With a non-unique link it is giving me a postgres error due to a failure of uniqueness constraint, which is fine, but ideally I’d probably like it to be caught on the changset. What am i doing wrong?

Thanks,

Az

Showing Posts 1 to 2

kokolegorille

kokolegorille

Hello and welcome, You might give a name to your constraint…

create unique_index(:lineup_players, [:player_id, :lineup_id], name: :my_constraint)

and use it like this

|> unique_constraint(:players, name: :my_constraint)
azrael

azrael OP

I had tried that, it doesn’t seem to make any difference. With renamed to unique_lineup_players (rather than the previous default of lineup_players_player_id_lineup_id_index), i still get the postgrex error:

** (Postgrex.Error) ERROR 23505 (unique_violation) duplicate key value violates unique constraint "unique_lineup_players"

    table: lineup_players
    constraint: unique_lineup_players

Key (player_id, lineup_id)=(309, 10) already exists.
    (ecto_sql 3.8.3) lib/ecto/adapters/sql.ex:932: Ecto.Adapters.SQL.raise_sql_call_error/1
    (ecto_sql 3.8.3) lib/ecto/adapters/sql.ex:822: Ecto.Adapters.SQL.insert_all/9
    (ecto 3.8.4) lib/ecto/repo/schema.ex:58: Ecto.Repo.Schema.do_insert_all/7
    (ecto 3.8.4) lib/ecto/association.ex:1330: Ecto.Association.ManyToMany.on_repo_change/5
    (ecto 3.8.4) lib/ecto/association.ex:572: anonymous fn/8 in Ecto.Association.on_repo_change/7
    (elixir 1.13.4) lib/enum.ex:2396: Enum."-reduce/3-lists^foldl/2-0-"/3
    (ecto 3.8.4) lib/ecto/association.ex:568: Ecto.Association.on_repo_change/7
    (elixir 1.13.4) lib/enum.ex:2396: Enum."-reduce/3-lists^foldl/2-0-"/3
    (ecto 3.8.4) lib/ecto/association.ex:532: Ecto.Association.on_repo_change/4
    (ecto 3.8.4) lib/ecto/repo/schema.ex:905: Ecto.Repo.Schema.process_children/5
    (ecto 3.8.4) lib/ecto/repo/schema.ex:985: anonymous fn/3 in Ecto.Repo.Schema.wrap_in_transaction/6
    (ecto_sql 3.8.3) lib/ecto/adapters/sql.ex:1222: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
    (db_connection 2.4.2) lib/db_connection.ex:1562: DBConnection.run_transaction/4
    (ecto 3.8.4) lib/ecto/repo/schema.ex:269: Ecto.Repo.Schema.insert!/4

I can also see that it doesn’t query the link table at all, so its not clear how it ever would work:

[debug] QUERY OK source="players" db=0.0ms idle=1766.0ms
SELECT p0."id", p0."name", p0."headshot_url", p0."team_short_name", p0."position", p0."inserted_at", p0."updated_at" FROM "players" AS p0 WHERE (p0."id" = ANY($1)) [[309]]←[90m
↳ KevinCadleFantasyGame.Lineup.changeset/2, at: lib/kevin_cadle_fantasy_game/lineup.ex:17
[debug] QUERY OK db=0.0ms idle=1766.0ms
begin []←[90m
↳ :erl_eval.do_apply/6, at: erl_eval.erl:680
[debug] QUERY OK db=0.0ms
INSERT INTO "lineups" ("id","inserted_at","updated_at") VALUES ($1,$2,$3) ON CONFLICT ("id") DO NOTHING [10, ~N[2022-08-30 12:28:28], ~N[2022-08-30 12:28:28]]←[90m
↳ :erl_eval.do_apply/6, at: erl_eval.erl:680
[debug] QUERY ERROR db=0.0ms
INSERT INTO "lineup_players" ("lineup_id","player_id") VALUES ($1,$2) [10, 309]←[90m
↳ :erl_eval.do_apply/6, at: erl_eval.erl:680
[debug] QUERY OK db=0.0ms
rollback []←[90m
↳ :erl_eval.do_apply/6, at: erl_eval.erl:680
— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews