mirror of
https://github.com/ash-project/ash_postgres.git
synced 2024-09-19 13:03:14 +12:00
improvement: add custom migration types, and repo level override
This commit is contained in:
parent
ab89e0e4ae
commit
af97c549c5
7 changed files with 165 additions and 10 deletions
|
@ -14,6 +14,7 @@ locals_without_parens = [
|
|||
index: 2,
|
||||
message: 1,
|
||||
migrate?: 1,
|
||||
migration_types: 1,
|
||||
name: 1,
|
||||
on_delete: 1,
|
||||
on_update: 1,
|
||||
|
|
|
@ -24,6 +24,11 @@ defmodule AshPostgres do
|
|||
Extension.get_entities(resource, [:postgres, :references])
|
||||
end
|
||||
|
||||
@doc "A keyword list of customized migration types"
|
||||
def migration_types(resource) do
|
||||
Extension.get_opt(resource, [:postgres], :migration_types, nil, true)
|
||||
end
|
||||
|
||||
@doc "The configured check_constraints for a resource"
|
||||
def check_constraints(resource) do
|
||||
Extension.get_entities(resource, [:postgres, :check_constraints])
|
||||
|
|
|
@ -237,6 +237,12 @@ defmodule AshPostgres.DataLayer do
|
|||
doc:
|
||||
"Whether or not to include this resource in the generated migrations with `mix ash.generate_migrations`"
|
||||
],
|
||||
migration_types: [
|
||||
type: :keyword_list,
|
||||
default: [],
|
||||
doc:
|
||||
"A keyword list of attribute names to the ecto migration type that should be used for that attribute. Only necessary if you need to override the defaults."
|
||||
],
|
||||
base_filter_sql: [
|
||||
type: :string,
|
||||
doc:
|
||||
|
|
|
@ -344,9 +344,22 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
|> Enum.map(fn {attr, i} -> Map.put(attr, :order, i) end)
|
||||
|> Enum.group_by(& &1.name)
|
||||
|> Enum.map(fn {name, attributes} ->
|
||||
size =
|
||||
attributes
|
||||
|> Enum.map(& &1.size)
|
||||
|> Enum.filter(& &1)
|
||||
|> case do
|
||||
[] ->
|
||||
nil
|
||||
|
||||
sizes ->
|
||||
Enum.max(sizes)
|
||||
end
|
||||
|
||||
%{
|
||||
name: name,
|
||||
type: merge_types(Enum.map(attributes, & &1.type), name, table),
|
||||
size: size,
|
||||
default: merge_defaults(Enum.map(attributes, & &1.default)),
|
||||
allow_nil?: Enum.any?(attributes, & &1.allow_nil?) || Enum.count(attributes) < count,
|
||||
generated?: Enum.any?(attributes, & &1.generated?),
|
||||
|
@ -1643,11 +1656,32 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
|> Enum.map(fn attribute ->
|
||||
default = default(attribute, repo)
|
||||
|
||||
type =
|
||||
AshPostgres.migration_types(resource)[attribute.name] || migration_type(attribute.type)
|
||||
|
||||
type =
|
||||
if :erlang.function_exported(repo, :override_migration_type, 1) do
|
||||
repo.override_migration_type(type)
|
||||
else
|
||||
type
|
||||
end
|
||||
|
||||
{type, size} =
|
||||
case type do
|
||||
{:varchar, size} ->
|
||||
{:varchar, size}
|
||||
|
||||
{:binary, size} ->
|
||||
{:binary, size}
|
||||
|
||||
other ->
|
||||
{other, nil}
|
||||
end
|
||||
|
||||
attribute
|
||||
|> Map.put(:default, default)
|
||||
|> Map.update!(:type, fn type ->
|
||||
migration_type(type)
|
||||
end)
|
||||
|> Map.put(:size, size)
|
||||
|> Map.put(:type, type)
|
||||
end)
|
||||
|> Enum.map(fn attribute ->
|
||||
references = find_reference(resource, table, attribute)
|
||||
|
@ -1788,17 +1822,25 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
snapshot
|
||||
|> Map.update!(:attributes, fn attributes ->
|
||||
Enum.map(attributes, fn attribute ->
|
||||
%{attribute | type: sanitize_type(attribute.type)}
|
||||
%{attribute | type: sanitize_type(attribute.type, attribute[:size])}
|
||||
end)
|
||||
end)
|
||||
|> Jason.encode!(pretty: true)
|
||||
end
|
||||
|
||||
defp sanitize_type({:array, type}) do
|
||||
["array", sanitize_type(type)]
|
||||
defp sanitize_type({:array, type}, size) do
|
||||
["array", sanitize_type(type, size)]
|
||||
end
|
||||
|
||||
defp sanitize_type(type) do
|
||||
defp sanitize_type(:varchar, size) when not is_nil(size) do
|
||||
["varchar", size]
|
||||
end
|
||||
|
||||
defp sanitize_type(:binary, size) when not is_nil(size) do
|
||||
["binary", size]
|
||||
end
|
||||
|
||||
defp sanitize_type(type, _) do
|
||||
type
|
||||
end
|
||||
|
||||
|
@ -1856,9 +1898,24 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
end
|
||||
|
||||
defp load_attribute(attribute, table) do
|
||||
type = load_type(attribute.type)
|
||||
|
||||
{type, size} =
|
||||
case type do
|
||||
{:varchar, size} ->
|
||||
{:varchar, size}
|
||||
|
||||
{:binary, size} ->
|
||||
{:binary, size}
|
||||
|
||||
other ->
|
||||
{other, nil}
|
||||
end
|
||||
|
||||
attribute
|
||||
|> Map.update!(:type, &load_type/1)
|
||||
|> Map.update!(:name, &String.to_atom/1)
|
||||
|> Map.put(:type, type)
|
||||
|> Map.put(:size, size)
|
||||
|> Map.put_new(:default, "nil")
|
||||
|> Map.update!(:default, &(&1 || "nil"))
|
||||
|> Map.update!(:references, fn
|
||||
|
@ -1897,6 +1954,14 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
{:array, load_type(type)}
|
||||
end
|
||||
|
||||
defp load_type(["varchar", size]) do
|
||||
{:varchar, size}
|
||||
end
|
||||
|
||||
defp load_type(["binary", size]) do
|
||||
{:binary, size}
|
||||
end
|
||||
|
||||
defp load_type(type) do
|
||||
String.to_atom(type)
|
||||
end
|
||||
|
|
|
@ -86,6 +86,11 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
"with: [#{source_attribute}: :#{destination_attribute}], match: :full"
|
||||
end
|
||||
|
||||
size =
|
||||
if attribute[:size] do
|
||||
"size: #{attribute[:size]}"
|
||||
end
|
||||
|
||||
[
|
||||
"add #{inspect(attribute.name)}",
|
||||
"references(:#{table}",
|
||||
|
@ -95,7 +100,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
on_delete(reference),
|
||||
on_update(reference)
|
||||
on_update(reference),
|
||||
size
|
||||
],
|
||||
")",
|
||||
maybe_add_default(attribute.default),
|
||||
|
@ -117,6 +123,11 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
} = reference
|
||||
} = attribute
|
||||
}) do
|
||||
size =
|
||||
if attribute[:size] do
|
||||
"size: #{attribute[:size]}"
|
||||
end
|
||||
|
||||
[
|
||||
"add #{inspect(attribute.name)}",
|
||||
"references(:#{table}",
|
||||
|
@ -125,6 +136,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
"prefix: \"public\"",
|
||||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
size,
|
||||
on_delete(reference),
|
||||
on_update(reference)
|
||||
],
|
||||
|
@ -145,11 +157,17 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
}
|
||||
} = attribute
|
||||
}) do
|
||||
size =
|
||||
if attribute.size do
|
||||
"size: #{attribute.size}"
|
||||
end
|
||||
|
||||
[
|
||||
"add #{inspect(attribute.name)}",
|
||||
inspect(attribute.type),
|
||||
maybe_add_default(attribute.default),
|
||||
maybe_add_primary_key(attribute.primary_key?),
|
||||
size,
|
||||
maybe_add_null(attribute.allow_nil?)
|
||||
]
|
||||
|> join()
|
||||
|
@ -167,6 +185,11 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
} = reference
|
||||
} = attribute
|
||||
}) do
|
||||
size =
|
||||
if attribute[:size] do
|
||||
"size: #{attribute[:size]}"
|
||||
end
|
||||
|
||||
[
|
||||
"add #{inspect(attribute.name)}",
|
||||
"references(:#{table}",
|
||||
|
@ -175,6 +198,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
"prefix: prefix()",
|
||||
size,
|
||||
on_delete(reference),
|
||||
on_update(reference)
|
||||
],
|
||||
|
@ -197,6 +221,11 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
} = reference
|
||||
} = attribute
|
||||
}) do
|
||||
size =
|
||||
if attribute[:size] do
|
||||
"size: #{attribute[:size]}"
|
||||
end
|
||||
|
||||
[
|
||||
"add #{inspect(attribute.name)}",
|
||||
"references(:#{table}",
|
||||
|
@ -205,6 +234,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
"prefix: \"public\"",
|
||||
size,
|
||||
on_delete(reference),
|
||||
on_update(reference)
|
||||
],
|
||||
|
@ -221,6 +251,11 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
%{references: %{table: table, destination_field: destination_field} = reference} =
|
||||
attribute
|
||||
}) do
|
||||
size =
|
||||
if attribute[:size] do
|
||||
"size: #{attribute[:size]}"
|
||||
end
|
||||
|
||||
[
|
||||
"add #{inspect(attribute.name)}",
|
||||
"references(:#{table}",
|
||||
|
@ -228,6 +263,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
"column: #{inspect(destination_field)}",
|
||||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
size,
|
||||
on_delete(reference),
|
||||
on_update(reference)
|
||||
],
|
||||
|
@ -260,11 +296,17 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
end
|
||||
|
||||
def up(%{attribute: attribute}) do
|
||||
size =
|
||||
if attribute[:size] do
|
||||
"size: #{attribute[:size]}"
|
||||
end
|
||||
|
||||
[
|
||||
"add #{inspect(attribute.name)}",
|
||||
"#{inspect(attribute.type)}",
|
||||
maybe_add_null(attribute.allow_nil?),
|
||||
maybe_add_default(attribute.default),
|
||||
size,
|
||||
maybe_add_primary_key(attribute.primary_key?)
|
||||
]
|
||||
|> join()
|
||||
|
@ -342,10 +384,16 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
} = reference
|
||||
} = attribute
|
||||
) do
|
||||
size =
|
||||
if attribute[:size] do
|
||||
"size: #{attribute[:size]}"
|
||||
end
|
||||
|
||||
join([
|
||||
"references(:#{table}, column: #{inspect(destination_field)}",
|
||||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
size,
|
||||
"prefix: prefix()",
|
||||
on_delete(reference),
|
||||
on_update(reference),
|
||||
|
@ -369,11 +417,17 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
"with: [#{source_attribute}: :#{destination_attribute}], match: :full"
|
||||
end
|
||||
|
||||
size =
|
||||
if attribute[:size] do
|
||||
"size: #{attribute[:size]}"
|
||||
end
|
||||
|
||||
join([
|
||||
"references(:#{table}, column: #{inspect(destination_field)}",
|
||||
with_match,
|
||||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
size,
|
||||
on_delete(reference),
|
||||
on_update(reference),
|
||||
")"
|
||||
|
@ -390,10 +444,16 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
} = reference
|
||||
} = attribute
|
||||
) do
|
||||
size =
|
||||
if attribute[:size] do
|
||||
"size: #{attribute[:size]}"
|
||||
end
|
||||
|
||||
join([
|
||||
"references(:#{table}, column: #{inspect(destination_field)}, prefix: \"public\"",
|
||||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
size,
|
||||
on_delete(reference),
|
||||
on_update(reference),
|
||||
")"
|
||||
|
@ -410,10 +470,16 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
} = reference
|
||||
} = attribute
|
||||
) do
|
||||
size =
|
||||
if attribute[:size] do
|
||||
"size: #{attribute[:size]}"
|
||||
end
|
||||
|
||||
join([
|
||||
"references(:#{table}, column: #{inspect(destination_field)}",
|
||||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
size,
|
||||
on_delete(reference),
|
||||
on_update(reference),
|
||||
")"
|
||||
|
|
|
@ -35,6 +35,8 @@ defmodule AshPostgres.Repo do
|
|||
@callback migrations_path() :: String.t()
|
||||
@doc "The default prefix(postgres schema) to use when building queries"
|
||||
@callback default_prefix() :: String.t()
|
||||
@doc "Allows overriding a given migration type for *all* fields, for example if you wanted to always use :timestamptz for :utc_datetime fields"
|
||||
@callback override_migration_type(atom) :: atom
|
||||
|
||||
defmacro __using__(opts) do
|
||||
quote bind_quoted: [opts: opts] do
|
||||
|
@ -48,6 +50,7 @@ defmodule AshPostgres.Repo do
|
|||
def tenant_migrations_path, do: nil
|
||||
def migrations_path, do: nil
|
||||
def default_prefix, do: "public"
|
||||
def override_migration_type(type), do: type
|
||||
|
||||
def all_tenants do
|
||||
raise """
|
||||
|
@ -77,7 +80,8 @@ defmodule AshPostgres.Repo do
|
|||
installed_extensions: 0,
|
||||
all_tenants: 0,
|
||||
tenant_migrations_path: 0,
|
||||
default_prefix: 0
|
||||
default_prefix: 0,
|
||||
override_migration_type: 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -67,6 +67,10 @@ defmodule AshPostgres.MigrationGeneratorTest do
|
|||
end)
|
||||
|
||||
defposts do
|
||||
postgres do
|
||||
migration_types second_title: {:varchar, 16}
|
||||
end
|
||||
|
||||
identities do
|
||||
identity(:title, [:title])
|
||||
end
|
||||
|
@ -74,6 +78,7 @@ defmodule AshPostgres.MigrationGeneratorTest do
|
|||
attributes do
|
||||
uuid_primary_key(:id)
|
||||
attribute(:title, :string)
|
||||
attribute(:second_title, :string)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -116,6 +121,9 @@ defmodule AshPostgres.MigrationGeneratorTest do
|
|||
# the migration adds other attributes
|
||||
assert file_contents =~ ~S[add :title, :text]
|
||||
|
||||
# the migration adds custom attributes
|
||||
assert file_contents =~ ~S[add :second_title, :varchar, size: 16]
|
||||
|
||||
# the migration creates unique_indexes based on the identities of the resource
|
||||
assert file_contents =~ ~S{create unique_index(:posts, [:title], name: "posts_title_index")}
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue