0
votes

I have 3 tables:

  1. categories
  2. subcategories
  3. categorySubcategories

1 category has 0 to many subcategories.

I have this function which gets all entries from categories table and only gets the entries of the subcategories table that belong to the category which has an id of 1:

  def getCategories(conn) do
    categories = all Api.Category
    groceryItemSubcategories = from s in Api.Subcategory,
    join: cs in Api.CategorySubcategory, on: cs.c_id == 1,
    select: %{name: s.name, foo: cs.c_id}
    conn
    |> put_resp_content_type("application/json")
    |> send_resp(200, Poison.encode!(%{categories: categories, groceryItemSubcategories: groceryItemSubcategories}))
  end

giving this error:

23:10:27.169 [error] #PID<0.339.0> running Api.Router terminated
Server: localhost:4000 (http)
Request: GET /categories
** (exit) an exception was raised:
    ** (Poison.EncodeError) unable to encode value: {"subcategories", Api.Subcategory}
        (poison) lib/poison/encoder.ex:383: Poison.Encoder.Any.encode/2
        (poison) lib/poison/encoder.ex:227: anonymous fn/4 in Poison.Encoder.Map.encode/3
        (poison) lib/poison/encoder.ex:228: Poison.Encoder.Map."-encode/3-lists^foldl/2-0-"/3

        (poison) lib/poison/encoder.ex:228: Poison.Encoder.Map.encode/3
        (poison) lib/poison/encoder.ex:227: anonymous fn/4 in Poison.Encoder.Map.encode/3
        (poison) lib/poison/encoder.ex:228: Poison.Encoder.Map."-encode/3-lists^foldl/2-0-"/3

        (poison) lib/poison/encoder.ex:228: Poison.Encoder.Map.encode/3
        (poison) lib/poison.ex:41: Poison.encode!/2

The final answer is this:

  def getCategories(conn) do
    categories = all Api.Category
    groceryItemSubcategories = Api.Repo.all(from s in Api.Subcategory,
    join: cs in Api.CategorySubcategory, on: cs.s_id == s.id,
    join: c in Api.Category, on: c.id == cs.c_id,
    where: c.id == 1,
    select: %{name: s.name, foo: cs.c_id}
    )
    conn
    |> put_resp_content_type("application/json")
    |> send_resp(200, Poison.encode!(%{categories: categories, groceryItemSubcategories: groceryItemSubcategories}))
  end

The part that makes the error go away is wrapping the statement in Api.Repo.All(). Dogbert was really the one who answered it so I'm not wanting to answer this.

1
Poison cannot encode tuples. Try selecting into a map, e.g. select: {s.name, cs.c_id} -> select: %{name: s.name, foo: cs.c_id}. - Dogbert
@Dogbert Thanks. Just posted the error i'm getting when I do that. - BeniaminoBaggins
That's a syntax error. Could you post the whole code that you tried? Probably missing a comma or something somewhere. - Dogbert
@Dogbert I just added the whole function to the bottom of the question. Let me know if you want to see more code. Cheers - BeniaminoBaggins
Oh I meant replace the code on the left of the arrow with the one on the right, not copy the whole thing. - Dogbert

1 Answers

1
votes

There are two main issues with the original code:

  1. You forgot to call Repo.all in the second query.

  2. You're selecting a tuple in the query and then encoding it to JSON. Poison does handle encoding tuples to JSON. You can select a list or map instead, depending on what data structure you want. Here's how to select a map:

    groceryItemSubcategories = Api.Repo.all(from s in Api.Subcategory,
      join: cs in Api.CategorySubcategory, on: cs.s_id == s.id,
      join: c in Api.Category, on: c.id == cs.c_id,
      where: c.id == 1,
      select: %{name: s.name, c_id: cs.c_id})