First I wanto to say that I have been using Elixir professionally for the past couple of months and it has been a great experience :). Thanks to every person that supports the language.
The issue is:
Today, I was trying to do the following : Given a certain type of parameter to a named function, return a certain literal lambda and use it to perform a query. This is because I’m expecting a JSON with a key named “paginate”, that gets “validated” into a map of the form %{"paginate" => %{"page" => page, "page_size" => page_size}} to determine if a query has to be paginated or not. This map is then used as a parameter for a function named query_chooser:
def query_function_chooser(%{"paginate" => %{"page" => page, "page_size" => page_size}}) do
(fn query ->
q_results = Repo.paginate(query, page: page, page_size: page_size)
q_results.entries
end)
end
def query_function_chooser(_) do
(fn query -> Repo.all(query) end)
end
Then, query_function_chooser gets called like this:
def get_items(params) do
func = Utils.query_function_chooser(params)
q =
from(i in Item,
select: i
)
func.(q)
end
And with that code, I get the following error: function Repo.all/1 is undefined (module Repo is not available).
If I call Repo.get or Repo.paginate directly from the body of get_items I don’t get such error.
Actually in this case I don’t think you need the anonymous function, just a function call since you are using pattern matching to chose which function clause. For example:
def maybe_paginate(query, %{"paginate" => %{"page" => page, "page_size" => page_size}}) do
query
|> Repo.paginate(query, page: page, page_size: page_size)
|> Map.get(:entries)
end
def maybe_paginate(query, _) do
Repo.all(query)
end
def get_items(params) do
q =
from(i in Item,
select: i
)
maybe_paginate(q, params)
end
Of course your example might just be a simplification of your use case and I may have misunderstood. And of course it doesn’t address your original question. I assume (but have not verified) that you have alias MyApp.Repo in a scope that is not available inside the anonymous functions. But we would have to see the overall module before jumping too much to conclusion.
Yes, this is actually a simplificaton of my problem, query_function_chooser is supposed to be a general function, imported from another module to determine if a pagination is to be done, or not.
And yes, you are are right about alias MyApp.Repo, but the thing is that the anonymous function is expected to be called/used from one of many ModuleNumber.Repo modules. So, If I want to paginate (or not) on the Module0.Repo or the Module1.Repo , I want to use query_function_chooser like in the get_items example.
Because of that, even If I were to use alias MyApp.Repo, I don’t think It would work, because the function could be called from either Module0 or Module 1 (or Module 2, Module3, etc.). Maybe there is a way to make this work that I’m not aware of?
Ah, ok, now I understand better. In this case you would likely need to pass in the repo you need to the anonymous function as well. For example:
def query_function_chooser(%{"paginate" => %{"page" => page, "page_size" => page_size}}) do
(fn repo, query ->
q_results = repo.paginate(query, page: page, page_size: page_size)
q_results.entries
end)
end
def query_function_chooser(_) do
(fn repo, query -> repo.all(query) end)
end
Then, query_function_chooser gets called like this:
def get_items(params) do
func = Utils.query_function_chooser(params)
q =
from(i in Item,
select: i
)
# Call the function with the relevant repo
func.(MyApp.Repo, q)
end