ash_postgres
ash_postgres copied to clipboard
The changeset does not define a constraint for a custom unique index
Describe the bug
The following custom unique index:
postgres do
# ...
custom_indexes do
index(["provider", "provider_id"], unique: true, where: "archived_at IS NULL and provider_id IS NOT NULL")
end
end
Does not add a constraint on a changeset which results in the exception when inserting a duplicated record:
** (Ecto.ConstraintError) constraint error when attempting to insert struct:
* table_provider_provider_id_index (unique_constraint)
If you would like to stop this constraint violation from raising an
exception and instead add it as an error to your changeset, please
call `unique_constraint/3` on your changeset with the constraint
`:name` as an option.
The changeset defined the following constraints:
* table_user_id_fkey (foreign_key_constraint)
* table_pkey (unique_constraint)
(ecto 3.8.4) lib/ecto/repo/schema.ex:783: anonymous fn/4 in Ecto.Repo.Schema.constraints_to_errors/3
(elixir 1.14.0) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(ecto 3.8.4) lib/ecto/repo/schema.ex:768: Ecto.Repo.Schema.constraints_to_errors/3
(ecto 3.8.4) lib/ecto/repo/schema.ex:749: Ecto.Repo.Schema.apply/4
(ecto 3.8.4) lib/ecto/repo/schema.ex:367: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4
(ash_postgres 1.0.0-rc.5) lib/data_layer.ex:934: AshPostgres.DataLayer.create/2
(ash 2.0.0-rc.7) lib/ash/actions/create.ex:378: anonymous fn/8 in Ash.Actions.Create.as_requests/5
(ash 2.0.0-rc.7) lib/ash/changeset/changeset.ex:1463: Ash.Changeset.run_around_actions/2
(ash 2.0.0-rc.7) lib/ash/actions/create.ex:313: anonymous fn/8 in Ash.Actions.Create.as_requests/5
(ash 2.0.0-rc.7) lib/ash/engine/request.ex:1041: Ash.Engine.Request.do_try_resolve_local/4
(ash 2.0.0-rc.7) lib/ash/engine/request.ex:281: Ash.Engine.Request.do_next/1
(ash 2.0.0-rc.7) lib/ash/engine/request.ex:210: Ash.Engine.Request.next/1
(ash 2.0.0-rc.7) lib/ash/engine/engine.ex:610: Ash.Engine.advance_request/2
(ash 2.0.0-rc.7) lib/ash/engine/engine.ex:535: Ash.Engine.fully_advance_request/2
(ash 2.0.0-rc.7) lib/ash/engine/engine.ex:469: Ash.Engine.do_run_iteration/2
(elixir 1.14.0) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(ash 2.0.0-rc.7) lib/ash/engine/engine.ex:218: Ash.Engine.run_to_completion/1
(ash 2.0.0-rc.7) lib/ash/engine/engine.ex:167: Ash.Engine.do_run/2
(ash 2.0.0-rc.7) lib/ash/engine/engine.ex:88: anonymous fn/2 in Ash.Engine.run/2
(ecto_sql 3.8.3) lib/ecto/adapters/sql.ex:1222: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
Expected behavior All custom unique indexes should add a constraint to the changeset.
** Runtime
- Elixir version 1.14.0
- Erlang version 25.0.4
- ash 2.0.0-rc.7
- ash_admin 0.6.0-rc.1
- ash_graphql 0.20.0-rc.1
- ash_phoenix 1.0.0-rc.0
- ash_postgres 1.0.0-rc.5
🤔 yeah, this is interesting. There is a way to add custom unique indexes to be checked in the changeset. Specifically:
postgres do
unique_index_names {[:provider, :provider_id], "...name of constraint"}
end
But we could likely derive these for custom constraints. The only thing is that we need to have atoms for the fields instead of strings, and we don't necessarily want to assume that every key provided to a custom index already exists as an atom.
So, to do this automatically we'd need to
- make custom_indexes take a list of
atom
for fields instead of strings - add those to the list of unique constraint names to check for.
Fixed in: 059837651d2cee1b717113363b5b9b45a5cbe0a5