feat: support cast_in_query?/0 and source

This commit is contained in:
Zach Daniel 2022-02-14 11:39:50 -05:00
parent e6ff1d8b4b
commit 97bd185c17
8 changed files with 88 additions and 41 deletions

View file

@ -18,7 +18,7 @@ jobs:
matrix:
otp: ["23"]
elixir: ["1.11.0"]
ash: ["master", "1.50.20"]
ash: ["master", "1.51.0"]
pg_version: ["9.6", "11"]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -229,14 +229,14 @@ defmodule AshPostgres.MigrationGenerator do
end
defp add_order_to_operation(%{attribute: attribute} = op, attributes) do
order = Enum.find_index(attributes, &(&1.name == attribute.name))
order = Enum.find_index(attributes, &(&1.source == attribute.source))
attribute = Map.put(attribute, :order, order)
%{op | attribute: attribute}
end
defp add_order_to_operation(%{new_attribute: attribute} = op, attributes) do
order = Enum.find_index(attributes, &(&1.name == attribute.name))
order = Enum.find_index(attributes, &(&1.source == attribute.source))
attribute = Map.put(attribute, :order, order)
%{op | new_attribute: attribute}
@ -330,7 +330,7 @@ defmodule AshPostgres.MigrationGenerator do
new_snapshot
| attributes:
Enum.map(new_snapshot.attributes, fn attribute ->
if attribute.name in primary_key do
if attribute.source in primary_key do
%{attribute | primary_key?: true}
else
%{attribute | primary_key?: false}
@ -346,8 +346,8 @@ defmodule AshPostgres.MigrationGenerator do
attributes
|> Enum.with_index()
|> Enum.map(fn {attr, i} -> Map.put(attr, :order, i) end)
|> Enum.group_by(& &1.name)
|> Enum.map(fn {name, attributes} ->
|> Enum.group_by(& &1.source)
|> Enum.map(fn {source, attributes} ->
size =
attributes
|> Enum.map(& &1.size)
@ -361,13 +361,13 @@ defmodule AshPostgres.MigrationGenerator do
end
%{
name: name,
type: merge_types(Enum.map(attributes, & &1.type), name, table),
source: source,
type: merge_types(Enum.map(attributes, & &1.type), source, 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?),
references: merge_references(Enum.map(attributes, & &1.references), name, table),
references: merge_references(Enum.map(attributes, & &1.references), source, table),
primary_key?: false,
order: attributes |> Enum.map(& &1.order) |> Enum.min()
}
@ -534,7 +534,7 @@ defmodule AshPostgres.MigrationGenerator do
defp pkey_names(attributes) do
attributes
|> Enum.filter(& &1.primary_key?)
|> Enum.map(& &1.name)
|> Enum.map(& &1.source)
|> Enum.sort()
end
@ -1263,12 +1263,12 @@ defmodule AshPostgres.MigrationGenerator do
defp attribute_operations(snapshot, old_snapshot, opts) do
attributes_to_add =
Enum.reject(snapshot.attributes, fn attribute ->
Enum.find(old_snapshot.attributes, &(&1.name == attribute.name))
Enum.find(old_snapshot.attributes, &(&1.source == attribute.source))
end)
attributes_to_remove =
Enum.reject(old_snapshot.attributes, fn attribute ->
Enum.find(snapshot.attributes, &(&1.name == attribute.name))
Enum.find(snapshot.attributes, &(&1.source == attribute.source))
end)
{attributes_to_add, attributes_to_remove, attributes_to_rename} =
@ -1278,7 +1278,7 @@ defmodule AshPostgres.MigrationGenerator do
snapshot.attributes
|> Enum.map(fn attribute ->
{attribute,
Enum.find(old_snapshot.attributes, &(&1.name == attribute.name && &1 != attribute))}
Enum.find(old_snapshot.attributes, &(&1.source == attribute.source && &1 != attribute))}
end)
|> Enum.filter(&elem(&1, 1))
@ -1439,7 +1439,7 @@ defmodule AshPostgres.MigrationGenerator do
defp resolve_renames(_table, [], removing, _opts), do: {[], removing, []}
defp resolve_renames(table, [adding], [removing], opts) do
if renaming_to?(table, removing.name, adding.name, opts) do
if renaming_to?(table, removing.source, adding.source, opts) do
{[], [], [{adding, removing}]}
else
{[adding], [removing], []}
@ -1476,9 +1476,9 @@ defmodule AshPostgres.MigrationGenerator do
defp renaming?(table, removing, opts) do
if opts.no_shell? do
raise "Unimplemented: cannot determine: Are you renaming #{table}.#{removing.name}? without shell input"
raise "Unimplemented: cannot determine: Are you renaming #{table}.#{removing.source}? without shell input"
else
Mix.shell().yes?("Are you renaming #{table}.#{removing.name}?")
Mix.shell().yes?("Are you renaming #{table}.#{removing.source}?")
end
end
@ -1491,7 +1491,7 @@ defmodule AshPostgres.MigrationGenerator do
defp get_new_attribute(adding, tries) do
name =
Mix.shell().prompt(
"What are you renaming it to?: #{Enum.map_join(adding, ", ", & &1.name)}"
"What are you renaming it to?: #{Enum.map_join(adding, ", ", & &1.source)}"
)
name =
@ -1501,7 +1501,7 @@ defmodule AshPostgres.MigrationGenerator do
nil
end
case Enum.find(adding, &(to_string(&1.name) == name)) do
case Enum.find(adding, &(to_string(&1.source) == name)) do
nil -> get_new_attribute(adding, tries - 1)
new_attribute -> new_attribute
end
@ -1546,7 +1546,12 @@ defmodule AshPostgres.MigrationGenerator do
end)
|> Map.update!(:attributes, fn attributes ->
Enum.map(attributes, fn attribute ->
if attribute.name == relationship.destination_field do
destination_field_source =
relationship.destination
|> Ash.Resource.Info.attribute(relationship.destination_field)
|> Map.get(:source)
if attribute.source == destination_field_source do
source_attribute =
Ash.Resource.Info.attribute(relationship.source, relationship.source_field)
@ -1657,7 +1662,9 @@ defmodule AshPostgres.MigrationGenerator do
resource
|> Ash.Resource.Info.attributes()
|> Enum.map(&Map.take(&1, [:name, :type, :default, :allow_nil?, :generated?, :primary_key?]))
|> Enum.map(
&Map.take(&1, [:name, :source, :type, :default, :allow_nil?, :generated?, :primary_key?])
)
|> Enum.map(fn attribute ->
default = default(attribute, repo)
@ -1687,6 +1694,7 @@ defmodule AshPostgres.MigrationGenerator do
|> Map.put(:default, default)
|> Map.put(:size, size)
|> Map.put(:type, type)
|> Map.delete(:name)
end)
|> Enum.map(fn attribute ->
references = find_reference(resource, table, attribute)
@ -1697,9 +1705,15 @@ defmodule AshPostgres.MigrationGenerator do
defp find_reference(resource, table, attribute) do
Enum.find_value(Ash.Resource.Info.relationships(resource), fn relationship ->
if attribute.name == relationship.source_field && relationship.type == :belongs_to &&
source_field_name =
relationship.source
|> Ash.Resource.Info.attribute(relationship.source_field)
|> Map.get(:source)
if attribute.source == source_field_name && relationship.type == :belongs_to &&
foreign_key?(relationship) do
configured_reference = configured_reference(resource, table, attribute.name, relationship)
configured_reference =
configured_reference(resource, table, attribute.source, relationship)
%{
destination_field: relationship.destination_field,
@ -1917,8 +1931,14 @@ defmodule AshPostgres.MigrationGenerator do
{other, nil}
end
attribute =
if Map.has_key?(attribute, :name) do
Map.put(attribute, :source, String.to_atom(attribute.name))
else
Map.update!(attribute, :source, &String.to_atom/1)
end
attribute
|> Map.update!(:name, &String.to_atom/1)
|> Map.put(:type, type)
|> Map.put(:size, size)
|> Map.put_new(:default, "nil")
@ -1936,7 +1956,10 @@ defmodule AshPostgres.MigrationGenerator do
|> Map.put_new(:on_update, nil)
|> Map.update!(:on_delete, &(&1 && String.to_atom(&1)))
|> Map.update!(:on_update, &(&1 && String.to_atom(&1)))
|> Map.put(:name, Map.get(references, :name) || "#{table}_#{attribute.name}_fkey")
|> Map.put(
:name,
Map.get(references, :name) || "#{table}_#{attribute.source}_fkey"
)
|> Map.put_new(:multitenancy, %{
attribute: nil,
strategy: nil,

View file

@ -92,7 +92,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
end
[
"add #{inspect(attribute.name)}",
"add #{inspect(attribute.source)}",
"references(:#{table}",
[
"column: #{inspect(destination_field)}",
@ -129,7 +129,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
end
[
"add #{inspect(attribute.name)}",
"add #{inspect(attribute.source)}",
"references(:#{table}",
[
"column: #{inspect(destination_field)}",
@ -163,7 +163,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
end
[
"add #{inspect(attribute.name)}",
"add #{inspect(attribute.source)}",
inspect(attribute.type),
maybe_add_default(attribute.default),
maybe_add_primary_key(attribute.primary_key?),
@ -191,7 +191,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
end
[
"add #{inspect(attribute.name)}",
"add #{inspect(attribute.source)}",
"references(:#{table}",
[
"column: #{inspect(destination_field)}",
@ -227,7 +227,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
end
[
"add #{inspect(attribute.name)}",
"add #{inspect(attribute.source)}",
"references(:#{table}",
[
"column: #{inspect(destination_field)}",
@ -257,7 +257,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
end
[
"add #{inspect(attribute.name)}",
"add #{inspect(attribute.source)}",
"references(:#{table}",
[
"column: #{inspect(destination_field)}",
@ -277,7 +277,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
def up(%{attribute: %{type: :bigint, default: "nil", generated?: true} = attribute}) do
[
"add #{inspect(attribute.name)}",
"add #{inspect(attribute.source)}",
":bigserial",
maybe_add_null(attribute.allow_nil?),
maybe_add_primary_key(attribute.primary_key?)
@ -287,7 +287,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
def up(%{attribute: %{type: :integer, default: "nil", generated?: true} = attribute}) do
[
"add #{inspect(attribute.name)}",
"add #{inspect(attribute.source)}",
":serial",
maybe_add_null(attribute.allow_nil?),
maybe_add_primary_key(attribute.primary_key?)
@ -302,7 +302,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
end
[
"add #{inspect(attribute.name)}",
"add #{inspect(attribute.source)}",
"#{inspect(attribute.type)}",
maybe_add_null(attribute.allow_nil?),
maybe_add_default(attribute.default),
@ -370,7 +370,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
inspect(attribute.type)
end
"modify #{inspect(attribute.name)}, #{type_or_reference}#{alter_opts(attribute, old_attribute)}"
"modify #{inspect(attribute.source)}, #{type_or_reference}#{alter_opts(attribute, old_attribute)}"
end
defp reference(
@ -533,11 +533,11 @@ defmodule AshPostgres.MigrationGenerator.Operation do
]
def up(%{old_attribute: old_attribute, new_attribute: new_attribute, table: table}) do
"rename table(:#{table}), #{inspect(old_attribute.name)}, to: #{inspect(new_attribute.name)}"
"rename table(:#{table}), #{inspect(old_attribute.source)}, to: #{inspect(new_attribute.source)}"
end
def down(%{new_attribute: old_attribute, old_attribute: new_attribute, table: table}) do
"rename table(:#{table}), #{inspect(old_attribute.name)}, to: #{inspect(new_attribute.name)}"
"rename table(:#{table}), #{inspect(old_attribute.source)}, to: #{inspect(new_attribute.source)}"
end
end
@ -549,19 +549,19 @@ defmodule AshPostgres.MigrationGenerator.Operation do
"""
# Attribute removal has been commented out to avoid data loss. See the migration generator documentation for more
# If you uncomment this, be sure to also uncomment the corresponding attribute *addition* in the `down` migration
# remove #{inspect(attribute.name)}
# remove #{inspect(attribute.source)}
"""
end
def up(%{attribute: attribute}) do
"remove #{inspect(attribute.name)}"
"remove #{inspect(attribute.source)}"
end
def down(%{attribute: attribute, multitenancy: multitenancy, commented?: true}) do
prefix = """
# This is the `down` migration of the statement:
#
# remove #{inspect(attribute.name)}
# remove #{inspect(attribute.source)}
#
"""

View file

@ -13,7 +13,11 @@ defmodule AshPostgres.Types do
def parameterized_type(type, constraints) do
if Ash.Type.ash_type?(type) do
parameterized_type(Ash.Type.ecto_type(type), constraints)
if Ash.Type.cast_in_query?(type) do
parameterized_type(Ash.Type.ecto_type(type), constraints)
else
:any
end
else
if is_atom(type) && :erlang.function_exported(type, :type, 1) do
{:parameterized, type, constraints || []}

View file

@ -97,7 +97,7 @@ defmodule AshPostgres.MixProject do
{:ecto, github: "elixir-ecto/ecto", branch: "master", override: true},
{:jason, "~> 1.0"},
{:postgrex, ">= 0.0.0"},
{:ash, ash_version("~> 1.50 and >= 1.50.20")},
{:ash, ash_version("~> 1.51 and >= 1.51.0")},
{:git_ops, "~> 2.4.5", only: :dev},
{:ex_doc, "~> 0.22", only: :dev, runtime: false},
{:ex_check, "~> 0.11.0", only: :dev},

View file

@ -419,6 +419,17 @@ defmodule AshPostgres.FilterTest do
|> Ash.Query.filter(status_enum == ^"open")
|> Api.read_one!()
end
test "it allows simple filtering without casting" do
Post
|> Ash.Changeset.new(status_enum_no_cast: "open")
|> Api.create!()
assert %{status_enum_no_cast: :open} =
Post
|> Ash.Query.filter(status_enum_no_cast == ^"open")
|> Api.read_one!()
end
end
describe "atom filters" do

View file

@ -53,6 +53,7 @@ defmodule AshPostgres.Test.Post do
attribute(:decimal, :decimal, default: Decimal.new(0))
attribute(:status, AshPostgres.Test.Types.Status)
attribute(:status_enum, AshPostgres.Test.Types.StatusEnum)
attribute(:status_enum_no_cast, AshPostgres.Test.Types.StatusEnumNoCast, source: :status_enum)
create_timestamp(:created_at)
end

View file

@ -0,0 +1,8 @@
defmodule AshPostgres.Test.Types.StatusEnumNoCast do
@moduledoc false
use Ash.Type.Enum, values: [:open, :closed]
def storage_type, do: :status
def cast_in_query?, do: false
end