Foreign key reference naming and Ash.Generator

On my resource I have:
references do
reference :region, name: "FK_dfwoyi1w884tqx68rctmbut4u"
...snip...
references do
reference :region, name: "FK_dfwoyi1w884tqx68rctmbut4u"
...snip...
Using an invalid region_id in a seed I get this error:
** (Ash.Error.Unknown)
Unknown Error

* ** (Ecto.ConstraintError) constraint error when attempting to insert struct:

* "FK_dfwoyi1w884tqx68rctmbut4u" (foreign_key_constraint)
** (Ash.Error.Unknown)
Unknown Error

* ** (Ecto.ConstraintError) constraint error when attempting to insert struct:

* "FK_dfwoyi1w884tqx68rctmbut4u" (foreign_key_constraint)
Are FKs combined with seed_generate in Ash.Generator not supposed to work? The error says that:
* "outcrop_region_id_fkey" (foreign_key_constraint)
* "outcrop_region_id_fkey" (foreign_key_constraint)
Is defined on the changeset, which makes it seem like the foreign key is not applied as it should.
Solution:
regression perhaps? want a failing pr submitted to ash_postgres?
Jump to solution
6 Replies
ZachDaniel
ZachDaniel4mo ago
🤔 not sure I'm pretty sure that goes down the code path that should add foreign key constraints etc.
Oliver
OliverOP4mo ago
weird Currently waiting on an output from an LLM simulating this through project_eval (it is a HUGE resource with like forty validated columns), then we'll see if it works on the Ash.create! codepath or not I get the same error with Ash.create!()
Solution
Oliver
Oliver4mo ago
regression perhaps? want a failing pr submitted to ash_postgres?
Oliver
OliverOP4mo ago
*a failing test PR yup, fails on ash_postgres too but just to align expectations here, I would expect a reference with a name: "some name here" to end up as an error with invalid attribute or something instead of the error saying that I can add foreign_key_constraint/3
Result of creating comment with invalid post_id: {:error,
%Ash.Error.Unknown{
bread_crumbs: ["Error returned from: AshPostgres.Test.Comment.create"],
changeset: "#Changeset<>",
errors: [
%Ash.Error.Unknown.UnknownError{
error: "** (Ecto.ConstraintError) constraint error when attempting to insert struct:\n\n * \"special_name_fkey\" (foreign_key_constraint)\n\nIf you would like to stop this constraint violation from raising an\nexception and instead add it as an error to your changeset, please\ncall `foreign_key_constraint/3` on your changeset with the constraint\n`:name` as an option.\n\nThe changeset defined the following constraints:\n\n * \"comments_id_fkey\" (foreign_key_constraint)\n * \"comments_id_fkey\" (foreign_key_constraint)\n * \"comments_id_fkey\" (foreign_key_constraint)\n * \"comments_id_fkey\" (foreign_key_constraint)\n * \"comments_author_id_fkey\" (foreign_key_constraint)\n * \"comments_post_id_fkey\" (foreign_key_constraint)\n * \"comments_id_fkey\" (foreign_key_constraint)\n * \"comments_pkey\" (unique_constraint)\n",
field: nil,
value: nil,
splode: Ash.Error,
bread_crumbs: ["Error returned from: AshPostgres.Test.Comment.create"],
vars: [],
path: [],
stacktrace: #Splode.Stacktrace<>,
class: :unknown
}
]
}}
Result of creating comment with invalid post_id: {:error,
%Ash.Error.Unknown{
bread_crumbs: ["Error returned from: AshPostgres.Test.Comment.create"],
changeset: "#Changeset<>",
errors: [
%Ash.Error.Unknown.UnknownError{
error: "** (Ecto.ConstraintError) constraint error when attempting to insert struct:\n\n * \"special_name_fkey\" (foreign_key_constraint)\n\nIf you would like to stop this constraint violation from raising an\nexception and instead add it as an error to your changeset, please\ncall `foreign_key_constraint/3` on your changeset with the constraint\n`:name` as an option.\n\nThe changeset defined the following constraints:\n\n * \"comments_id_fkey\" (foreign_key_constraint)\n * \"comments_id_fkey\" (foreign_key_constraint)\n * \"comments_id_fkey\" (foreign_key_constraint)\n * \"comments_id_fkey\" (foreign_key_constraint)\n * \"comments_author_id_fkey\" (foreign_key_constraint)\n * \"comments_post_id_fkey\" (foreign_key_constraint)\n * \"comments_id_fkey\" (foreign_key_constraint)\n * \"comments_pkey\" (unique_constraint)\n",
field: nil,
value: nil,
splode: Ash.Error,
bread_crumbs: ["Error returned from: AshPostgres.Test.Comment.create"],
vars: [],
path: [],
stacktrace: #Splode.Stacktrace<>,
class: :unknown
}
]
}}
from:
test "named reference results in properly applied foreign_key_constraint/3 on the underlying changeset" do
# Create a comment with an invalid post_id
result =
AshPostgres.Test.Comment
|> Ash.Changeset.for_create(:create, %{
title: "Test Comment",
# This post doesn't exist
post_id: Ash.UUID.generate()
})
|> Ash.create()

IO.inspect(result, label: "Result of creating comment with invalid post_id")
end
test "named reference results in properly applied foreign_key_constraint/3 on the underlying changeset" do
# Create a comment with an invalid post_id
result =
AshPostgres.Test.Comment
|> Ash.Changeset.for_create(:create, %{
title: "Test Comment",
# This post doesn't exist
post_id: Ash.UUID.generate()
})
|> Ash.create()

IO.inspect(result, label: "Result of creating comment with invalid post_id")
end
ZachDaniel
ZachDaniel4mo ago
Correct
Oliver
OliverOP4mo ago
ok I will submit a failing PR for now, I have to go but I'll set claude code churning on it just for fun considering how well it went with ash_graphql 😛
in test file @test/references_test.exs there is a test that writes a comment with a random uuid. It tries to insert a
@test/support/resources/comment.ex from the test modules. However the reference name set on post in the comment module is
not used to put a foreign_key_constraint on comment.post for that special name. Analyze the codebase and find out where
foreign key constraints are applied based on the references + references.reference dsl. You can look for code referencing
`references` + `references.references`, probably implemented in spark dsl. Most likely there is also some code defining
foreign_key_constraint. The code to analyze lives in the lib/ folder. Documentation you might need to understand the system
better can be found in the documentation/ folder. Think really hard, then make a plan using the TodoWriter and show me an
oerview in a debugging.md file in the root folder of this project. The expected outcome of the failing test would be an
InvalidAttribute error instead of the ash unknown error it gets now.
in test file @test/references_test.exs there is a test that writes a comment with a random uuid. It tries to insert a
@test/support/resources/comment.ex from the test modules. However the reference name set on post in the comment module is
not used to put a foreign_key_constraint on comment.post for that special name. Analyze the codebase and find out where
foreign key constraints are applied based on the references + references.reference dsl. You can look for code referencing
`references` + `references.references`, probably implemented in spark dsl. Most likely there is also some code defining
foreign_key_constraint. The code to analyze lives in the lib/ folder. Documentation you might need to understand the system
better can be found in the documentation/ folder. Think really hard, then make a plan using the TodoWriter and show me an
oerview in a debugging.md file in the root folder of this project. The expected outcome of the failing test would be an
InvalidAttribute error instead of the ash unknown error it gets now.
crossing fingers 😄 Gotta say, this looks very promising so far:
✻ Thinking…

Perfect! This is exactly what I was looking for. This code is in add_related_foreign_key_constraints, which checks if there's
a custom reference defined and uses its name if present (line 2641-2642).

However, looking back at the add_my_foreign_key_constraints function (lines 2681-2701), it doesn't check for custom reference
names - it always uses the default pattern.

This is the bug! The add_my_foreign_key_constraints function should be checking for custom reference names just like
add_related_foreign_key_constraints does.
✻ Thinking…

Perfect! This is exactly what I was looking for. This code is in add_related_foreign_key_constraints, which checks if there's
a custom reference defined and uses its name if present (line 2641-2642).

However, looking back at the add_my_foreign_key_constraints function (lines 2681-2701), it doesn't check for custom reference
names - it always uses the default pattern.

This is the bug! The add_my_foreign_key_constraints function should be checking for custom reference names just like
add_related_foreign_key_constraints does.
🤯
⏺ Update Todos
⎿  ☒ Implement fix in add_my_foreign_key_constraints to check for custom reference names
☐ Run the test to verify the fix works
☐ Run full test suite to ensure no regressions

⏺ Bash(mix test test/references_test.exs:109 --trace)
⎿  Compiling 67 files (.ex)
Generated ash_postgres app
Running ExUnit with seed: 762839, max_cases: 1
… +36 lines (ctrl+r to expand)

⏺ Great! The fix is working. The test now shows the expected Ash.Error.Invalid with InvalidAttribute error instead of the
Ash.Error.Unknown error. The foreign key constraint with the custom name "special_name_fkey" is now being properly recognized
and handled.

⏺ Update Todos
⎿  ☒ Implement fix in add_my_foreign_key_constraints to check for custom reference names
☒ Run the test to verify the fix works
☐ Run full test suite to ensure no regressions

⏺ Bash(mix test)
⎿  Running…
⏺ Update Todos
⎿  ☒ Implement fix in add_my_foreign_key_constraints to check for custom reference names
☐ Run the test to verify the fix works
☐ Run full test suite to ensure no regressions

⏺ Bash(mix test test/references_test.exs:109 --trace)
⎿  Compiling 67 files (.ex)
Generated ash_postgres app
Running ExUnit with seed: 762839, max_cases: 1
… +36 lines (ctrl+r to expand)

⏺ Great! The fix is working. The test now shows the expected Ash.Error.Invalid with InvalidAttribute error instead of the
Ash.Error.Unknown error. The foreign key constraint with the custom name "special_name_fkey" is now being properly recognized
and handled.

⏺ Update Todos
⎿  ☒ Implement fix in add_my_foreign_key_constraints to check for custom reference names
☒ Run the test to verify the fix works
☐ Run full test suite to ensure no regressions

⏺ Bash(mix test)
⎿  Running…

Did you find this page helpful?