-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Questions on approach taken #8
Comments
@RobStallion great questions! (as always!) |
@RobStallion do you feel that your questions have been answered satisfactorily? 💭 |
@RobStallion you are not being "dense"; |
Macros vs Regular functionsSay we have our defmodule AppendOnly do
def insert_logic(changeset) do
...
def update_logic(changeset) do
...
def one_logic(struct) do
...
def all_logic(struct) do
...
end And say we have the following modules with defmodule Address do
def insert(struct), do: struct |> Address.changeset() |> AppendOnly.insert_logic() |> Repo.insert()
def update(struct), do: struct |> Address.changeset() |> AppendOnly.update_logic() |> Repo.insert()
def one, do: Address |> AppendOnly.one_logic() |> Repo.one()
def all, do: Address |> AppendOnly.all_logic() |> Repo.all()
end defmodule Customer do
def insert(struct), do: struct |> Customer.changeset() |> AppendOnly.insert_logic() |> Repo.insert()
def update(struct), do: struct |> Customer.changeset() |> AppendOnly.update_logic() |> Repo.insert()
def one, do: Customer |> AppendOnly.one_logic() |> Repo.one()
def all, do: Customer |> AppendOnly.all_logic() |> Repo.all()
end Where, for example, the Address.insert(%Address{address: "1600 Pennsylvania Avenue NW", state: "Washington"}) Obviously this is WET code and needs to be cleaned up. When refactoring here, the only thing that needs to remain the same is that the Regular functions refactor approachAs you say @RobStallion, one approach is to pass in the module into the (after a refactor of defmodule Address do
def insert(struct), do: AppendOnly.insert(Address, struct)
def update(struct), do: AppendOnly.update(Address, struct)
def one, do: AppendOnly.one(Address)
def all, do: AppendOnly.all(Address)
end Change 1Lets say that we now wanted to add a
to every module you wish to add it to. and add a delete function to the Change 2Lets say that we now want to change the behaviour of the defmodule Address do
def insert(struct), do: struct |> something_else() |> Repo.insert
def update(struct), do: AppendOnly.update(Address, struct)
def one, do: AppendOnly.one(Address)
def all, do: AppendOnly.all(Address)
end Macro refactor approachAnother approach is to construct the Once this is configured we could set up the defmodule Address do
use AppendOnly
end One really nice thing about macros is that it can reference the module where it is being We repeat as little code as possible in each module following our Change 1We would now like to add a We would simply add a Change 2We would now like to override the We would simply add our new
Comparing the two approachesThe initial code setup for a module following the append only pattern is a lot cleaner using macros. Change 1Adding a Change 2The difference here between the two approaches isn't much, there is the same amount of code added, but one difference could be that the macro approach is far less cluttered by other functions which we don't want to override. In short, I think that the |
Hello, complete elixir n00b chiming in. Thanks so much for this and all the other great repos on Elixir that you have created. I tripped over
with the typo
Finding this typo was very hard because the
This did produce much more sensible error messages because it doesn't allow the addition of new properties, but I'm curious if there are reasons that doing each attribute separately in a map.puts makes more sense |
@mischa-s nice typo catch 👍 I think you may be on to a potential code smell, nice work Another way of updating a key and throw a an error if the So, item
|> Map.put(:id, nil)
|> Map.put(:insterted, nil)
|> Map.put(:updated_at, nil)
|> __MODULE__.changeset(attrs)
|> Repo.insert() Could be: %{ item | id: nil, insterted: nil, updated_at: nil }
|> __MODULE__.changeset(attrs)
|> Repo.insert() The typo would have thrown the following error:
|
@samhstn the way you suggested looks great, so easy to read 😸 |
Why is everything done using macros? We could achieve the same result by making them regular functions which takes the relevant module as an argument. Is there any benefits of one approach vs the other?
Is the insert function just allowing the user to skip the step where they call the relevant changeset function? Is this a good idea?
The
get
andget_by
functions seem to just call theirRepo
equivalents. Are they needed?
The text was updated successfully, but these errors were encountered: