improvement: support access syntax

This commit is contained in:
Zach Daniel 2022-02-07 16:48:36 -05:00
parent 079eb2e08d
commit e2bd3c5aec
11 changed files with 176 additions and 9 deletions

View file

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

View file

@ -4,7 +4,7 @@ defmodule AshPostgres.Expr do
alias Ash.Filter alias Ash.Filter
alias Ash.Query.{BooleanExpression, Not, Ref} alias Ash.Query.{BooleanExpression, Not, Ref}
alias Ash.Query.Operator.IsNil alias Ash.Query.Operator.IsNil
alias Ash.Query.Function.{Ago, Contains, If} alias Ash.Query.Function.{Ago, Contains, GetPath, If}
alias AshPostgres.Functions.{Fragment, TrigramSimilarity, Type} alias AshPostgres.Functions.{Fragment, TrigramSimilarity, Type}
require Ecto.Query require Ecto.Query
@ -88,6 +88,33 @@ defmodule AshPostgres.Expr do
Ecto.Query.dynamic(datetime_add(^DateTime.utc_now(), ^left * -1, ^to_string(right))) Ecto.Query.dynamic(datetime_add(^DateTime.utc_now(), ^left * -1, ^to_string(right)))
end end
defp do_dynamic_expr(
query,
%GetPath{arguments: [left, right], embedded?: pred_embedded?},
bindings,
embedded?,
type
) do
path = Enum.map(right, &to_string/1)
do_dynamic_expr(
query,
%Fragment{
embedded?: pred_embedded?,
arguments: [
raw: "(",
expr: left,
raw: " #> ",
expr: path,
raw: ")"
]
},
bindings,
embedded?,
type
)
end
defp do_dynamic_expr( defp do_dynamic_expr(
query, query,
%Contains{arguments: [left, %Ash.CiString{} = right], embedded?: pred_embedded?}, %Contains{arguments: [left, %Ash.CiString{} = right], embedded?: pred_embedded?},
@ -125,9 +152,9 @@ defmodule AshPostgres.Expr do
%Fragment{ %Fragment{
embedded?: pred_embedded?, embedded?: pred_embedded?,
arguments: [ arguments: [
raw: "strpos(", raw: "strpos((",
expr: left, expr: left,
raw: ", ", raw: "), ",
expr: right, expr: right,
raw: ") > 0" raw: ") > 0"
] ]

View file

@ -1521,7 +1521,7 @@ defmodule AshPostgres.MigrationGenerator do
def get_snapshots(resource, all_resources) do def get_snapshots(resource, all_resources) do
Code.ensure_compiled!(AshPostgres.repo(resource)) Code.ensure_compiled!(AshPostgres.repo(resource))
if AshPostgres.polymorphic?(resource) do if AshPostgres.polymorphic?(resource) do
all_resources all_resources
|> Enum.flat_map(&Ash.Resource.Info.relationships/1) |> Enum.flat_map(&Ash.Resource.Info.relationships/1)

View file

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

View file

@ -1,5 +1,5 @@
%{ %{
"ash": {:hex, :ash, "1.50.16", "11fb1d4f761b9e9cf3e6d5f5910a330381cb0c5e35b574d207f20f06afbb9faa", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8.0", [hex: :ets, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.3.5", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: false]}, {:timex, ">= 3.0.0", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "47813d5da2f209fc98f55a793777ec9f24a02dcd386898d3716ed919ac212818"}, "ash": {:hex, :ash, "1.50.19", "83d7c9ad840602bb0b02aa06545cdac7fa4cc6b09ad0510d2cbc2454466125ae", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8.0", [hex: :ets, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.3.5", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.9", [hex: :sourceror, repo: "hexpm", optional: false]}, {:timex, ">= 3.0.0", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "04a0c442a98efc4774e55fbfa46cde5769ad22efb56e288e712edde9c9b7a90a"},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"},
"certifi": {:hex, :certifi, "2.8.0", "d4fb0a6bb20b7c9c3643e22507e42f356ac090a1dcea9ab99e27e0376d695eba", [:rebar3], [], "hexpm", "6ac7efc1c6f8600b08d625292d4bbf584e14847ce1b6b5c44d983d273e1097ea"}, "certifi": {:hex, :certifi, "2.8.0", "d4fb0a6bb20b7c9c3643e22507e42f356ac090a1dcea9ab99e27e0376d695eba", [:rebar3], [], "hexpm", "6ac7efc1c6f8600b08d625292d4bbf584e14847ce1b6b5c44d983d273e1097ea"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
@ -21,7 +21,7 @@
"excoveralls": {:hex, :excoveralls, "0.13.0", "4e1b7cc4e0351d8d16e9be21b0345a7e165798ee5319c7800b9138ce17e0b38e", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "fe2a56c8909564e2e6764765878d7d5e141f2af3bc8ff3b018a68ee2a218fced"}, "excoveralls": {:hex, :excoveralls, "0.13.0", "4e1b7cc4e0351d8d16e9be21b0345a7e165798ee5319c7800b9138ce17e0b38e", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "fe2a56c8909564e2e6764765878d7d5e141f2af3bc8ff3b018a68ee2a218fced"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"getopt": {:hex, :getopt, "1.0.1", "c73a9fa687b217f2ff79f68a3b637711bb1936e712b521d8ce466b29cbf7808a", [:rebar3], [], "hexpm", "53e1ab83b9ceb65c9672d3e7a35b8092e9bdc9b3ee80721471a161c10c59959c"}, "getopt": {:hex, :getopt, "1.0.1", "c73a9fa687b217f2ff79f68a3b637711bb1936e712b521d8ce466b29cbf7808a", [:rebar3], [], "hexpm", "53e1ab83b9ceb65c9672d3e7a35b8092e9bdc9b3ee80721471a161c10c59959c"},
"gettext": {:hex, :gettext, "0.19.0", "6909d61b38bb33339558f128f8af5913d5d5fe304a770217bf352b1620fb7ec4", [:mix], [], "hexpm", "3f7a274f52ebda9bb6655dfeda3d6b0dc4537ae51ce41dcccc7f73ca7379ad5e"}, "gettext": {:hex, :gettext, "0.19.1", "564953fd21f29358e68b91634799d9d26989f8d039d7512622efb3c3b1c97892", [:mix], [], "hexpm", "10c656c0912b8299adba9b061c06947511e3f109ab0d18b44a866a4498e77222"},
"git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"},
"git_ops": {:hex, :git_ops, "2.4.5", "185a724dfde3745edd22f7571d59c47a835cf54ded67e9ccbc951920b7eec4c2", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e323a5b01ad53bc8c19c3a444be3e61ed7803ecd2e95530446ae9327d0143ecc"}, "git_ops": {:hex, :git_ops, "2.4.5", "185a724dfde3745edd22f7571d59c47a835cf54ded67e9ccbc951920b7eec4c2", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e323a5b01ad53bc8c19c3a444be3e61ed7803ecd2e95530446ae9327d0143ecc"},
"hackney": {:hex, :hackney, "1.18.0", "c4443d960bb9fba6d01161d01cd81173089686717d9490e5d3606644c48d121f", [:rebar3], [{:certifi, "~>2.8.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "9afcda620704d720db8c6a3123e9848d09c87586dc1c10479c42627b905b5c5e"}, "hackney": {:hex, :hackney, "1.18.0", "c4443d960bb9fba6d01161d01cd81173089686717d9490e5d3606644c48d121f", [:rebar3], [{:certifi, "~>2.8.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "9afcda620704d720db8c6a3123e9848d09c87586dc1c10479c42627b905b5c5e"},
@ -38,6 +38,7 @@
"postgrex": {:hex, :postgrex, "0.16.1", "f94628a32c571266f53cd1e5fca705e626e2417bf1eee6f868985d14e874160a", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "6b225df32c857b9430619dbe30200a7ae664e23415a771ae9209396ee8eeee64"}, "postgrex": {:hex, :postgrex, "0.16.1", "f94628a32c571266f53cd1e5fca705e626e2417bf1eee6f868985d14e874160a", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "6b225df32c857b9430619dbe30200a7ae664e23415a771ae9209396ee8eeee64"},
"providers": {:hex, :providers, "1.8.1", "70b4197869514344a8a60e2b2a4ef41ca03def43cfb1712ecf076a0f3c62f083", [:rebar3], [{:getopt, "1.0.1", [hex: :getopt, repo: "hexpm", optional: false]}], "hexpm", "e45745ade9c476a9a469ea0840e418ab19360dc44f01a233304e118a44486ba0"}, "providers": {:hex, :providers, "1.8.1", "70b4197869514344a8a60e2b2a4ef41ca03def43cfb1712ecf076a0f3c62f083", [:rebar3], [{:getopt, "1.0.1", [hex: :getopt, repo: "hexpm", optional: false]}], "hexpm", "e45745ade9c476a9a469ea0840e418ab19360dc44f01a233304e118a44486ba0"},
"sobelow": {:hex, :sobelow, "0.10.2", "00e91208046d3b434f9f08779fe0ca7c6d6595b7fa33b289e792dffa6dde8081", [:mix], [], "hexpm", "e30fc994330cf6f485c1c4f2fb7c4b2d403557d0e101c6e5329fd17a58e55a7e"}, "sobelow": {:hex, :sobelow, "0.10.2", "00e91208046d3b434f9f08779fe0ca7c6d6595b7fa33b289e792dffa6dde8081", [:mix], [], "hexpm", "e30fc994330cf6f485c1c4f2fb7c4b2d403557d0e101c6e5329fd17a58e55a7e"},
"sourceror": {:hex, :sourceror, "0.10.0", "a6a85d8acc874df59bedb7497374f8f7517e4d54a5805da903ff31aaee14a1a7", [:mix], [], "hexpm", "ddd94d23d96ac949696616eb89cecac977dfed7ecdfac6bbd3f83617e4daea28"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"}, "telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"},
"timex": {:hex, :timex, "3.7.6", "502d2347ec550e77fdf419bc12d15bdccd31266bb7d925b30bf478268098282f", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "a296327f79cb1ec795b896698c56e662ed7210cc9eb31f0ab365eb3a62e2c589"}, "timex": {:hex, :timex, "3.7.6", "502d2347ec550e77fdf419bc12d15bdccd31266bb7d925b30bf478268098282f", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "a296327f79cb1ec795b896698c56e662ed7210cc9eb31f0ab365eb3a62e2c589"},

View file

@ -0,0 +1,57 @@
{
"attributes": [
{
"allow_nil?": false,
"default": "fragment(\"uuid_generate_v4()\")",
"generated?": false,
"name": "id",
"primary_key?": true,
"references": null,
"size": null,
"type": "uuid"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"name": "first_name",
"primary_key?": false,
"references": null,
"size": null,
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"name": "last_name",
"primary_key?": false,
"references": null,
"size": null,
"type": "text"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"name": "bio",
"primary_key?": false,
"references": null,
"size": null,
"type": "map"
}
],
"base_filter": null,
"check_constraints": [],
"custom_indexes": [],
"has_create_action": true,
"hash": "19AEE20A027B64FBA25A86974080E72C7B5B4FBB85005325F2F36BA580E32346",
"identities": [],
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"repo": "Elixir.AshPostgres.TestRepo",
"table": "authors"
}

View file

@ -0,0 +1,21 @@
defmodule AshPostgres.TestRepo.Migrations.MigrateResources2 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
alter table(:authors) do
add :bio, :map
end
end
def down do
alter table(:authors) do
remove :bio
end
end
end

View file

@ -59,6 +59,19 @@ defmodule AshPostgres.CalculationTest do
|> Api.read!() |> Api.read!()
end end
test "calculations can refer to embedded attributes" do
author =
Author
|> Ash.Changeset.for_create(:create, %{bio: %{title: "Mr.", bio: "Bones"}})
|> Api.create!()
assert %{title: "Mr."} =
Author
|> Ash.Query.filter(id == ^author.id)
|> Ash.Query.load(:title)
|> Api.read_one!()
end
test "calculations can be used in related filters" do test "calculations can be used in related filters" do
post = post =
Post Post

View file

@ -1,6 +1,6 @@
defmodule AshPostgres.FilterTest do defmodule AshPostgres.FilterTest do
use AshPostgres.RepoCase, async: false use AshPostgres.RepoCase, async: false
alias AshPostgres.Test.{Api, Comment, Post} alias AshPostgres.Test.{Api, Author, Comment, Post}
require Ash.Query require Ash.Query
@ -263,6 +263,43 @@ defmodule AshPostgres.FilterTest do
end end
end end
describe "accessing embeds" do
setup do
Author
|> Ash.Changeset.for_create(:create, bio: %{title: "Dr.", bio: "Strange"})
|> Api.create!()
Author
|> Ash.Changeset.for_create(:create,
bio: %{title: "Highlander", bio: "There can be only one."}
)
|> Api.create!()
:ok
end
test "works using simple equality" do
assert [%{bio: %{title: "Dr."}}] =
Author
|> Ash.Query.filter(bio[:title] == "Dr.")
|> Api.read!()
end
test "works using an expression" do
assert [%{bio: %{title: "Highlander"}}] =
Author
|> Ash.Query.filter(contains(type(bio[:bio], :string), "only one."))
|> Api.read!()
end
test "calculations that use embeds can be filtered on" do
assert [%{bio: %{title: "Dr."}}] =
Author
|> Ash.Query.filter(title == "Dr.")
|> Api.read!()
end
end
describe "basic expressions" do describe "basic expressions" do
test "basic expressions work" do test "basic expressions work" do
Post Post

View file

@ -12,9 +12,11 @@ defmodule AshPostgres.Test.Author do
uuid_primary_key(:id, writable?: true) uuid_primary_key(:id, writable?: true)
attribute(:first_name, :string) attribute(:first_name, :string)
attribute(:last_name, :string) attribute(:last_name, :string)
attribute(:bio, AshPostgres.Test.Bio)
end end
calculations do calculations do
calculate(:title, :string, expr(bio[:title]))
calculate(:full_name, :string, expr(first_name <> " " <> last_name)) calculate(:full_name, :string, expr(first_name <> " " <> last_name))
calculate( calculate(

View file

@ -0,0 +1,9 @@
defmodule AshPostgres.Test.Bio do
@moduledoc false
use Ash.Resource, data_layer: :embedded
attributes do
attribute(:title, :string)
attribute(:bio, :string)
end
end