Skip to content

fix: List.wrap geo_types in constraint error formatter#13

Open
matt-beanland wants to merge 1 commit into
bcksl:mainfrom
matt-beanland:fix/geo-types-list-wrap-formatter
Open

fix: List.wrap geo_types in constraint error formatter#13
matt-beanland wants to merge 1 commit into
bcksl:mainfrom
matt-beanland:fix/geo-types-list-wrap-formatter

Conversation

@matt-beanland

@matt-beanland matt-beanland commented May 27, 2026

Copy link
Copy Markdown

Problem

apply_constraint/2 accepts the geo_types constraint as either a bare atom or a list — it List.wraps the value before matching:

defp apply_constraint({:geo_types, geo_types}, {%struct{} = value, errs}) do
  if Enum.any?(List.wrap(geo_types), &(struct in [&1, geo_type_aliases()[&1]])) do
    {value, errs}
  else
    {value, [constraint_error_geo_types(geo_types, value) | errs]}
  end
end

But the error formatter doesn't wrap:

defp constraint_error_geo_types(geo_types, value) do
  [
    message: "must be a struct with type among: %{types}, got: %{value}",
    types: Enum.map_join(geo_types, ", ", &inspect/1),  # <- crashes on bare atom
    value: value
  ]
end

So when a constraint is declared with the bare-atom form — which both the docs and the existing test fixture use:

argument :point, :geo_any, constraints: [geo_types: :point]

…and a non-matching Geo struct hits the error path, the formatter raises:

** (Protocol.UndefinedError) protocol Enumerable not implemented for type Atom.
   Got value: :point

The accept path works (the struct passes), so this only surfaces when validation fails with a bare-atom geo_types.

Fix

List.wrap/1 the formatter's input so both the bare-atom and list forms render:

types: Enum.map_join(List.wrap(geo_types), ", ", &inspect/1),

Test

Adds a regression test under the existing "Argument constraints: geo_types: [:point]" describe block. Constraint.create_point/1 is declared with geo_types: :point (bare atom); given a non-Point Geo struct (a LINESTRING), it now returns {:error, _} cleanly instead of raising in the formatter.


Discovered while adopting AshGeo as the spatial type surface for ash_neo4j (a Neo4j Ash.DataLayer). Happy to adjust to fit your preferences.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed geometry constraint validation error messages to handle both single and multiple geometry type specifications consistently without crashes.

Review Change Stack

`apply_constraint/2` accepts `geo_types` as either a bare atom or a
list (it `List.wrap`s before matching), but `constraint_error_geo_types/2`
calls `Enum.map_join(geo_types, ", ", &inspect/1)` on the raw value.
When a constraint is declared with the bare-atom form
(`constraints: [geo_types: :point]`, which the docs and the existing
test fixtures both use) and a non-matching Geo struct triggers the
error path, the formatter crashes:

    ** (Protocol.UndefinedError) protocol Enumerable not implemented
       for type Atom. Got value: :point

`List.wrap/1` on the formatter's input makes both forms work.

Adds a regression test: Constraint.create_point/1 (declared with the
bare-atom `geo_types: :point`) given a non-Point Geo struct now returns
{:error, _} cleanly instead of raising.
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c99bf4c1-fe9a-4101-b0e0-1f155109d8e4

📥 Commits

Reviewing files that changed from the base of the PR and between c002217 and 87eca22.

📒 Files selected for processing (2)
  • lib/ash_geo/geometry.ex
  • test/ash_geo_test.exs

📝 Walkthrough

Walkthrough

This PR fixes a bug in the constraint error message formatter that crashed when geo_types was a bare atom instead of a list. The fix wraps geo_types with List.wrap/1 before formatting, and adds a regression test to verify that providing wrong-shaped geometry returns an error gracefully.

Changes

Geometry constraint error formatting

Layer / File(s) Summary
Error formatter robustness and test
lib/ash_geo/geometry.ex, test/ash_geo_test.exs
The constraint_error_geo_types/2 function now uses List.wrap/1 to normalize geo_types before joining, handling both single values and lists. A regression test confirms that providing a LINESTRING where a Geo.Point is expected returns an error without crashing the formatter.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

A tiny fix with careful care, 🐰
When atoms hide in lists so rare,
List.wrap ensures the message flows,
No crashes now—the error shows! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: List.wrap geo_types in constraint error formatter' directly and accurately describes the main change—wrapping geo_types with List.wrap in the error formatter to handle both atom and list forms.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@matt-beanland

Copy link
Copy Markdown
Author

@zachdaniel or @bcksl is ash_geo being actively maintained?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant