improvement: handle UUID types better

This commit is contained in:
Zach Daniel 2022-10-17 08:40:32 -05:00
parent fb8a13f33d
commit 5222e1e755
4 changed files with 130 additions and 6 deletions

View file

@ -662,16 +662,15 @@ defmodule AshPostgres.Expr do
defp do_dynamic_expr(
query,
%Type{arguments: [arg1, arg2, constraints]} = type_expr,
%Type{arguments: [arg1, arg2, constraints]},
bindings,
_embedded?,
embedded?,
_type
) do
arg1 = do_dynamic_expr(query, arg1, bindings, false)
arg2 = Ash.Type.get_type(arg2)
arg1 = maybe_uuid_to_binary(arg2, arg1, arg1)
type = AshPostgres.Types.parameterized_type(arg2, constraints)
validate_type!(query, type, type_expr)
Ecto.Query.dynamic(type(^arg1, ^type))
do_dynamic_expr(query, arg1, bindings, embedded?, type)
end
defp do_dynamic_expr(
@ -795,10 +794,29 @@ defmodule AshPostgres.Expr do
defp do_dynamic_expr(query, value, _bindings, false, type) do
value = maybe_sanitize_list(value)
type = AshPostgres.Types.parameterized_type(type, [])
validate_type!(query, type, value)
Ecto.Query.dynamic(type(^value, ^type))
end
defp maybe_uuid_to_binary({:array, type}, value, _original_value) when is_list(value) do
Enum.map(value, &maybe_uuid_to_binary(type, &1, &1))
end
defp maybe_uuid_to_binary(type, value, original_value)
when type in [
Ash.Type.UUID.EctoType,
:uuid
] and is_binary(value) do
case Ecto.UUID.dump(value) do
{:ok, encoded} -> encoded
_ -> original_value
end
end
defp maybe_uuid_to_binary(_type, _value, original_value), do: original_value
defp validate_type!(query, type, context) do
case type do
{:parameterized, Ash.Type.CiStringWrapper.EctoType, _} ->

View file

@ -0,0 +1,77 @@
{
"attributes": [
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": true,
"references": {
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "post_links_source_post_id_fkey",
"on_delete": null,
"on_update": null,
"schema": "public",
"table": "posts"
},
"size": null,
"source": "source_post_id",
"type": "uuid"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": true,
"references": {
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "post_links_destination_post_id_fkey",
"on_delete": null,
"on_update": null,
"schema": "public",
"table": "posts"
},
"size": null,
"source": "destination_post_id",
"type": "uuid"
}
],
"base_filter": null,
"check_constraints": [],
"custom_indexes": [],
"custom_statements": [],
"has_create_action": true,
"hash": "D5A5182C6A632C61F04477975186F608E1B6FA336CE6DAF40DBEF8A4E5689DB4",
"identities": [
{
"base_filter": null,
"index_name": "post_links_unique_link_index",
"keys": [
"source_post_id",
"destination_post_id"
],
"name": "unique_link"
}
],
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"repo": "Elixir.AshPostgres.TestRepo",
"schema": null,
"table": "post_links"
}

View file

@ -0,0 +1,21 @@
defmodule AshPostgres.TestRepo.Migrations.MigrateResources3 do
@moduledoc """
Updates resources based on their most recent snapshots.
This file was autogenerated with `mix ash_postgres.generate_migrations`
"""
use Ecto.Migration
def up do
create unique_index(:post_links, [:source_post_id, :destination_post_id],
name: "post_links_unique_link_index"
)
end
def down do
drop_if_exists unique_index(:post_links, [:source_post_id, :destination_post_id],
name: "post_links_unique_link_index"
)
end
end

View file

@ -27,4 +27,12 @@ defmodule AshPostgres.Test.TypeTest do
|> Ash.Query.filter(fragment("(?)[1] > (?)[2]", point, point))
|> Api.read!()
end
test "uuids can be used as strings in fragments" do
uuid = Ash.UUID.generate()
Post
|> Ash.Query.filter(fragment("? = ?", id, type(^uuid, :uuid)))
|> Api.read!()
end
end