Support non-null HasOne (#3118)
* Rename `Has*Model` to `ActiveHas*` * Support non-null HasOne * Fix E0034 ambiguity: unify HasOne::loaded / ActiveHasOne::set constructors The per-cardinality inherent impls each defined a same-named associated constructor (loaded / set), so the unqualified paths HasOne::loaded and ActiveHasOne::set were ambiguous (E0034) at every call site — the E: EntityTrait where-bound does not disambiguate associated-function path resolution. The crate's own tests and doctests failed to compile as a result. Define loaded / set once on the cardinality-generic impl, dispatching arg-wrapping through IntoHasOneLoaded / IntoActiveHasOneSet helper traits (one impl for the required E case, one for the optional Option<E> case). Bare model -> required, Option<model> -> optional, resolved unambiguously. Also fixes an entity_loader test that passed a bare model to a nullable relation (cake.bakery is HasOne<Option<..>>), which the ambiguity had masked. * Support nested writes for duplicate-target belongs_to; clear() no-op on unset FK Two fixes to nested-ActiveModel save behavior: 1. belongs_to relations that share a target entity with another relation used to silently generate no save/detach code (the action codegen was gated on the target entity being unique), so their nested writes were no-ops. They now always generate: a belongs_to with an explicit relation_enum, or a non-unique target, is keyed by its relation variant via `set_parent_key_for` / `clear_parent_key_for` (the default variant is inferred the same way the loader does); a unique target keeps the entity-keyed path. Fixes e.g. `user_follower` (two belongs_to to `user`). 2. `clear_<field>()` on a nullable belongs_to whose FK column was never set (a freshly-built ActiveModel) returned `DbErr::AttrNotSet`; it is now a no-op, since an unset nullable FK is already effectively clear. Adds `test_belongs_to_duplicate_target` and `test_clear_unset_belongs_to_is_noop`. * Revert now-redundant turbofish to bare HasOne::loaded / ActiveHasOne::set With the E0034 root-cause fix in place, the unqualified constructors resolve unambiguously, so the per-site `::<Option<E>>::` turbofish is no longer needed. Revert it in the doc example, lib test modules, into_active_model bodies, and the integration tests so users see the clean bare-call form. The macro-generated code keeps its explicit turbofish (internal, not user-facing). * Fix ActiveModelEx optional belongs_to clearing * Split HasOne and BelongsTo --------- Co-authored-by: Chris Tsang <chris.2y3@outlook.com>
狐
狐狸 committed
e94a44b27a3a03a174cb15baceed6eb49ea59752
Parent: 324ea7b
Committed by Chris Tsang <chris.2y3@outlook.com>
on 7/12/2026, 6:13:27 PM