ecto icon indicating copy to clipboard operation
ecto copied to clipboard

feat: add preload_order for has_one

Open saveman71 opened this issue 5 months ago • 10 comments

Hello there,

Stumbling on https://elixirforum.com/t/ecto-has-one-sort-association/62923 earlier this afternoon and after considering what adding support for preload_order to the has_one assoc would entail, I gave it a shot.

I know this is probably a solution to a bad architecture, but it could save us the trouble of converting our assoc to an has_many then adding a limit and/or always considering getting the latest object in business logic.

A brief explanation on why we need this:

  • We have Documents

  • Documents can be signed and thus some SigningRequests are attached

  • Only one request is active at any time, we will never show multiple requests in the UI

  • However, some can fail, etc.

  • Up until recently we had the following:

    has_one :signing_request, SigningRequest, where: [state: {:in, [Statuses.created(), Statuses.signed()]}]
    

    Which worked but it hid any failed SigningRequest.

    When noticing this, I didn't thing too much about it and removed the filter. However, since the sort is undefined, in some cases if you have a failed signature and a successful one, it returns the first found, the failed one.

  • To fix this, with preload_order support we could do:

    has_one :signing_request, SigningRequest, preload_order: [desc: :id]
    

    (or on inserted_at, etc.) which would ensure that we always return the latest one, regardless of it's status (if a user chose to overwrite a successful signature, why not)

This PR is meant as an RFC, and the new case is not pretty (its here to avoid Ecto.Association.BelongsTo which doesn't have preload_order). Documentation would follow if accepted.

Made a quick tests and it seems to work for our use case

Cheers!

saveman71 avatar Sep 03 '24 14:09 saveman71