Skip to content

Instantly share code, notes, and snippets.

@nimish-mehta
Last active January 6, 2017 06:38
Show Gist options
  • Save nimish-mehta/daa78539e5b00914739a335ab5648807 to your computer and use it in GitHub Desktop.
Save nimish-mehta/daa78539e5b00914739a335ab5648807 to your computer and use it in GitHub Desktop.
Alias elixir ecto columns from db columns, by using a separate virtual field per column for reading and writing
# Define a macro to alias columns and collect them
defmodule ColumnAlias do
defmacro __using__(_) do
quote do
Module.register_attribute(__MODULE__, :column_aliases, accumulate: true)
import ColumnAlias, only: [alias_field: 3]
@before_compile ColumnAlias
end
end
defmacro alias_field(name, type, options) do
alias_name = Keyword.get(options, :alias_as)
passable_options = Keyword.delete(options, :alias_as)
quote do
field unquote(name), unquote(type), unquote(passable_options)
field unquote(alias_name), unquote(type), virtual: true
@column_aliases {unquote(alias_name), unquote(name)}
end
end
defmacro __before_compile__(_) do
quote do
def copy_from_aliases(%__MODULE__{} = og_struct, overwrite \\ true) do
Enum.reduce(@column_aliases, og_struct, fn ({alias_name, original_name}, acc) ->
value_to_copy = Map.get(acc, alias_name)
if overwrite || is_nil(Map.get(acc, original_name)) do
Map.put(acc, original_name, value_to_copy)
else
acc
end
end)
end
def copy_to_aliases(%__MODULE__{} = og_struct, overwrite \\ true) do
Enum.reduce(@column_aliases, og_struct, fn ({alias_name, original_name}, acc) ->
value_to_copy = Map.get(acc, original_name)
if overwrite || is_nil(Map.get(acc, alias_name)) do
Map.put(acc, alias_name, value_to_copy)
else
acc
end
end)
end
def __aliases__ do
@column_aliases
end
end
end
end
bb = %PhoenixBlog.Post{aliased_name: 'name', aliased_body: 'body', body: 'real_body'}
%PhoenixBlog.Post{__meta__: #Ecto.Schema.Metadata<:built, "posts">,
aliased_body: 'body', aliased_name: 'name', body: 'real_body', id: nil,
inserted_at: nil, name: nil, updated_at: nil,
user: #Ecto.Association.NotLoaded<association :user is not loaded>,
user_id: nil}
IO.inspect bb.body
'real_body'
# Copy without overwriting
bb = PhoenixBlog.Post.copy_from_aliases bb, false
%PhoenixBlog.Post{__meta__: #Ecto.Schema.Metadata<:built, "posts">,
aliased_body: 'body', aliased_name: 'name', body: 'real_body', id: nil,
inserted_at: nil, name: 'name', updated_at: nil,
user: #Ecto.Association.NotLoaded<association :user is not loaded>,
user_id: nil}
IO.inspect bb.body
'real_body'
bb = PhoenixBlog.Post.copy_from_aliases bb
# Copy with overwriting default option
%PhoenixBlog.Post{__meta__: #Ecto.Schema.Metadata<:built, "posts">,
aliased_body: 'body', aliased_name: 'name', body: 'body', id: nil,
inserted_at: nil, name: 'name', updated_at: nil,
user: #Ecto.Association.NotLoaded<association :user is not loaded>,
user_id: nil}
bb.body
'body'
defmodule PhoenixBlog.Post do
use PhoenixBlog.Web, :model
use ColumnAlias
schema "posts" do
alias_field :name, :string, alias_as: :aliased_name
alias_field :body, :string, alias_as: :aliased_body
belongs_to :user, PhoenixBlog.User
timestamps()
end
@doc """
Builds a changeset based on the `struct` and `params`.
"""
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:name, :body])
|> validate_required([:name, :body])
end
end
@johnnyshields
Copy link

def foo
  return f
end

def foo=(value)
  f = value
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment