Packages
pow
1.0.21
1.0.39
1.0.38
1.0.37
1.0.36
1.0.35
1.0.34
1.0.33
1.0.32
1.0.31
1.0.30
1.0.29
1.0.28
1.0.27
1.0.26
1.0.25
1.0.24
1.0.23
1.0.22
1.0.21
1.0.20
1.0.19
1.0.18
1.0.17
1.0.16
1.0.15
1.0.14
1.0.13
1.0.12
1.0.11
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-rc.4
1.0.0-rc.3
1.0.0-rc.2
1.0.0-rc.1
1.0.0-rc.0
0.1.0-rc.1
0.1.0-alpha.8
0.1.0-alpha.7
retired
0.1.0-alpha.6
0.1.0-alpha.5
0.1.0-alpha.4
0.1.0-alpha.3
0.1.0-alpha.2
0.1.0-alpha.1
0.1.0-alpha
Robust user authentication solution
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/pow/ecto/schema/migration.ex
defmodule Pow.Ecto.Schema.Migration do
@moduledoc """
Generates schema migration content.
## Configuration options
* `:repo` - the ecto repo to use. This value defaults to the derrived
context base repo from the `context_base` argument in `gen/2`.
* `:table` - the ecto table name, defaults to "users".
* `:attrs` - list of attributes, defaults to the results from
`Pow.Ecto.Schema.Fields.attrs/1`.
* `:indexes` - list of indexes, defaults to the results from
`Pow.Ecto.Schema.Fields.indexes/1`.
"""
alias Pow.{Config, Ecto.Schema.Fields}
@template """
defmodule <%= inspect schema.repo %>.Migrations.<%= schema.migration_name %> do
use Ecto.Migration
def change do
create table(:<%= schema.table %><%= if schema.binary_id do %>, primary_key: false<% end %>) do
<%= if schema.binary_id do %> add :id, :binary_id, primary_key: true
<% end %><%= for {k, v} <- schema.attrs do %> add <%= inspect k %>, <%= inspect v %><%= schema.migration_defaults[k] %>
<% end %><%= for {_, i, _, s} <- schema.assocs do %> add <%= if(String.ends_with?(inspect(i), "_id"), do: inspect(i), else: inspect(i) <> "_id") %>, references(<%= inspect(s) %>, on_delete: :nothing<%= if schema.binary_id do %>, type: :binary_id<% end %>)
<% end %>
timestamps()
end
<%= for index <- schema.indexes do %>
<%= index %><% end %>
end
end
"""
@doc """
Generates migration file content.
"""
@spec gen(map()) :: binary()
def gen(schema) do
EEx.eval_string(unquote(@template), schema: schema)
end
@doc """
Generates migration schema map.
"""
@spec new(atom(), binary(), Config.t()) :: map()
def new(context_base, schema_plural, config \\ []) do
repo = Config.get(config, :repo, Module.concat([context_base, "Repo"]))
attrs = Config.get(config, :attrs, Fields.attrs(config))
indexes = Config.get(config, :indexes, Fields.indexes(config))
migration_name = name(schema_plural)
schema(context_base, repo, schema_plural, migration_name, attrs, indexes, binary_id: config[:binary_id])
end
defp name(schema_plural), do: "Create#{Macro.camelize(schema_plural)}"
@doc """
Generates a schema map to be used with the schema template.
"""
@spec schema(atom(), atom(), binary(), binary(), list(), list(), Keyword.t()) :: map()
def schema(context_base, repo, table, migration_name, attrs, indexes, opts) do
migration_attrs = migration_attrs(attrs)
binary_id = opts[:binary_id]
migration_defaults = defaults(migration_attrs)
{assocs, attrs} = partition_attrs(context_base, migration_attrs)
indexes = migration_indexes(indexes, table)
%{
migration_name: migration_name,
repo: repo,
table: table,
binary_id: binary_id,
attrs: attrs,
migration_defaults: migration_defaults,
assocs: assocs,
indexes: indexes
}
end
defp migration_attrs(attrs) do
attrs
|> Enum.reject(&is_virtual?/1)
|> Enum.map(&to_migration_attr/1)
end
defp is_virtual?({_name, _type}), do: false
defp is_virtual?({_name, _type, defaults}) do
Keyword.get(defaults, :virtual, false)
end
defp to_migration_attr({name, type}) do
{name, type, ""}
end
defp to_migration_attr({name, type, []}) do
to_migration_attr({name, type})
end
defp to_migration_attr({name, type, defaults}) do
defaults = Enum.map_join(defaults, ", ", fn {k, v} -> "#{k}: #{v}" end)
{name, type, ", #{defaults}"}
end
defp defaults(attrs) do
Enum.map(attrs, fn {key, _value, defaults} ->
{key, defaults}
end)
end
defp partition_attrs(context_base, attrs) do
{assocs, attrs} =
Enum.split_with(attrs, fn
{_, {:references, _}, _} -> true
_ -> false
end)
attrs = Enum.map(attrs, fn {key_id, type, _defaults} -> {key_id, type} end)
assocs =
Enum.map(assocs, fn {key_id, {:references, source}, _} ->
key = String.replace(Atom.to_string(key_id), "_id", "")
context = Macro.camelize(source)
schema = Macro.camelize(key)
module = Module.concat([context_base, context, schema])
{String.to_atom(key), key_id, inspect(module), source}
end)
{assocs, attrs}
end
defp migration_indexes(indexes, table) do
Enum.map(indexes, &to_migration_index(table, &1))
end
defp to_migration_index(table, {key_or_keys, true}),
do: "create unique_index(:#{table}, #{inspect(List.wrap(key_or_keys))})"
end