DEV Community

Pau Riosa
Pau Riosa

Posted on

How does Ecto.Schema's `has_one/3` works?

The problem

I have two schemas, coffees and orders wherein I want to get the recent completed order from each coffees

First solution

defmodule Schemas.Coffee do
    # ... more code
    has_many :completed_orders, Schemas.Order

    def coffee_query(coffee_id) do
        from c in __MODULE__,
            where: c.id == coffee_id,
            preload: [completed_orders: Orders.completed_order],
            limit: 1
    end
end

defmodule Schemas.Order do
    # ... more code

    @completed_status :completed

    def completed_order_query() do
        from o in __MODULE__,
            where: o.status in ^@completed_status,
            order_by: [desc: o.updated_at] 
    end
end

defmodule Contexts.Coffees do
    # more code

    def get_recent_completed_coffee_order(coffee_id) do
     coffee = coffee_id
              |> Schemas.Coffee.coffee_query()
              |> Repo.one

        List.first(coffee.completed_orders)
    end
end
Enter fullscreen mode Exit fullscreen mode
  • Based from the setup, I can actually get the completed_orders of coffees but the only downside for me is that the preload will return a list

  • Since it will return a list , that will result into another process for me just to get the recent completed order.

Then, has_one/3 came into my life

defmodule Schemas.Coffee do
    # ... more code
    has_one :completed_order, Schemas.Order,
        where: [status: :completed],
        preload_order: [desc: :updated_at]

    def coffee_query(coffee_id) do
        from c in __MODULE__,
            where: c.id == ^coffee_id
            preload: [:completed_order],
            limit: 1
    end
end

defmodule Contexts.Coffees do
    # more code

    def get_recent_completed_coffee_order(coffee_id) do
        coffee_id
        |> Schemas.Coffee.coffee_query()
        |> Repo.one
        |> Map.get(:completed_order, nil)
    end
end
Enter fullscreen mode Exit fullscreen mode

What's the magic behind this scheme?

How does has_one/3 works?

Indicates a one-to-one association with another schema

From the current situation, coffee belongs_to order. As a result, coffee has_many orders, but I only need one result to return coming from the orders schema to identify if the coffee order is completed already.

Using has\_one/3\ I was able to achieve what I want.

  • has_one/3 - indicates a one-to-one association with another schema.

  • where - indicates a Filtering associations to get my specific items.

  • preload_order - Sets the default order_by of the association, and since I am using has_one/3 Ecto set a query LIMIT set to one .

[see has_one/3 on docs](https://hexdocs.pm/ecto/Ecto.Schema.html#has_one/3)

Happy Coding

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay