From b3ac13e760dd46faee9ba08a2ded9e5987ae9270 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Sat, 27 Jul 2024 17:05:46 -0400 Subject: [PATCH] chore: release version v3.3.0 --- CHANGELOG.md | 63 +++++++++++++++++++++++-- lib/ash/expr/expr.ex | 16 +------ lib/ash/type/file/path.ex | 1 + lib/ash/type/file/plug_upload.ex | 1 + lib/mix/tasks/patch/ash.patch.extend.ex | 20 +++++++- mix.exs | 4 +- mix.lock | 6 +-- test/expr_test.exs | 22 +++++++++ 8 files changed, 107 insertions(+), 26 deletions(-) create mode 100644 test/expr_test.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0246a46e..ced3e474 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,20 +2,73 @@ -## [v3.2.6](https://github.com/ash-project/ash/compare/v3.2.5...v3.2.6) (2024-07-22) - +## [v3.3.0](https://github.com/ash-project/ash/compare/v3.2.6...v3.3.0) (2024-07-27) +### Features: +- [`Ash.Type.File`] Add Ash.Type.File (#1337) ### Bug Fixes: -* fallback to `authorize_with` when authorizing bulk destroy actions +- [bulk actions] ensure that statuses are set correctly on bulk actions -* don't refer to non-existent `batch_change/4` +- [bulk actions] properly transfer process context(tracers) for bulk actions + +- [embedded resources] properly display identity/primary key mismatch error on lists of embeds + +- [`Ash.Type.NewType`] apply constraints to NewType even when casting an array (#1341) + +- [`Ash.Query`] pass reuse_values? true when loading in Ash.Query.apply_to/2 (#1346) + +- [code interfaces] honor `skip_unknown_inputs` in code interfaces + +- [notifications] don't gather notifications except for in the top level transaction starter + +- [generic actions] support `skip_unknown_inputs` on generic actions + +- [atomic updates] ensure `changed?` context is set on atomic changesets (we assume it is `true`, its up to extensions to handle) + +- [`Ash.Type.CiString`, `Ash.Type.String`] Update string/ci_string generators to ensure min_length (#1335) + +- [`Ash`] handle `{record, action, input}` types in `Ash.can?` + +- [bulk actions] only call `batch_change` if it is defined, never `change` in bulk create ### Improvements: -* Replace incorrect function_exported?-checks in bulk-actions, add has-defs for change modules (#1330) +- [`mix ash.gen.resource`] better positional argument handling with igniter + +- [`Ash.Expr`] use `:utc_datetime_usec` for `now()` return type + +- [`mix ash.install`] don't install sat solver in initial installation + +- [`Ash.Policy.Authorizer`] validate that a solver exists at compile time when using policies + +- [`Ash.Type.Enum`] Expose type t() on Ash.Type.Enum implementations (#1338) + +- [`Ash.Resource`] add :\* as a valid value in `skip_unknown_inputs` + +- [`Ash.Resource`] add `skip_unknown_inputs` to individual actions + +- [embedded resources] add `skip_unknown_inputs` constraint to embedded resources + +- [embedded resources] automatically fall back to a default domain when working with embeds + +- [`Ash`] handle 3 tuple in `Ash.can?` + +- [`Ash.Error`] add `Ash.Error.error_descriptions` + +## [v3.2.6](https://github.com/ash-project/ash/compare/v3.2.5...v3.2.6) (2024-07-22) + +### Bug Fixes: + +- [bulk actions] fallback to `authorize_with` when authorizing bulk destroy actions + +- [bulk actions] don't refer to non-existent `batch_change/4` + +### Improvements: + +- [bulk actions] Replace incorrect function_exported?-checks in bulk-actions, add has-defs for change modules (#1330) ## [v3.2.5](https://github.com/ash-project/ash/compare/v3.2.4...v3.2.5) (2024-07-22) diff --git a/lib/ash/expr/expr.ex b/lib/ash/expr/expr.ex index 3966695b..3de0bbc4 100644 --- a/lib/ash/expr/expr.ex +++ b/lib/ash/expr/expr.ex @@ -1006,13 +1006,7 @@ defmodule Ash.Expr do {:halt, :error} Ash.Expr.expr?(value) -> - case determine_type(value) do - {:ok, {^type, matched_constraints}} -> - {:cont, Map.update!(acc, :types, &[{type, matched_constraints} | &1])} - - _ -> - {:halt, :error} - end + {:cont, Map.update!(acc, :types, &[{type, constraints} | &1])} true -> {:cont, Map.update!(acc, :types, &[{type, constraints} | &1])} @@ -1024,13 +1018,7 @@ defmodule Ash.Expr do {:halt, :error} Ash.Expr.expr?(value) -> - case determine_type(value) do - {:ok, {^type, matched_constraints}} -> - {:cont, Map.update!(acc, :types, &[{type, matched_constraints} | &1])} - - _ -> - {:halt, :error} - end + {:cont, Map.update!(acc, :types, &[{type, []} | &1])} true -> {:cont, Map.update!(acc, :types, &[{type, []} | &1])} diff --git a/lib/ash/type/file/path.ex b/lib/ash/type/file/path.ex index 67b7e63e..71aa8731 100644 --- a/lib/ash/type/file/path.ex +++ b/lib/ash/type/file/path.ex @@ -7,5 +7,6 @@ defmodule Ash.Type.File.Path do def path(path), do: {:ok, path} @impl Ash.Type.File.Implementation + # sobelow_skip ["Traversal.FileModule"] def open(path, modes), do: File.open(path, modes) end diff --git a/lib/ash/type/file/plug_upload.ex b/lib/ash/type/file/plug_upload.ex index 55428b6d..9f6d390f 100644 --- a/lib/ash/type/file/plug_upload.ex +++ b/lib/ash/type/file/plug_upload.ex @@ -7,6 +7,7 @@ if Code.ensure_loaded?(Plug.Upload) do @impl Ash.Type.File.Implementation def path(%Plug.Upload{path: path}), do: {:ok, path} + # sobelow_skip ["Traversal.FileModule"] @impl Ash.Type.File.Implementation def open(%Plug.Upload{path: path}, options), do: File.open(path, options) end diff --git a/lib/mix/tasks/patch/ash.patch.extend.ex b/lib/mix/tasks/patch/ash.patch.extend.ex index 3aa09f1a..683ed151 100644 --- a/lib/mix/tasks/patch/ash.patch.extend.ex +++ b/lib/mix/tasks/patch/ash.patch.extend.ex @@ -1,4 +1,5 @@ defmodule Mix.Tasks.Ash.Patch.Extend do + @example "mix ash.patch.extend My.Domain.Resource postgres,Ash.Policy.Authorizer" @moduledoc """ Adds an extension or extensions to the domain/resource @@ -23,7 +24,7 @@ defmodule Mix.Tasks.Ash.Patch.Extend do ## Example ```bash - mix ash.patch.extend My.Domain.Resource postgres,Ash.Policy.Authorizer + #{@example} ``` """ @shortdoc "Adds an extension or extensions to the given domain/resource" @@ -31,7 +32,22 @@ defmodule Mix.Tasks.Ash.Patch.Extend do use Igniter.Mix.Task @impl Igniter.Mix.Task - def igniter(igniter, [subject, extensions | argv]) do + def info(_argv, _parent) do + %Igniter.Mix.Task.Info{ + positional: [ + :subject, + extensions: [ + rest: true + ] + ], + example: @example + } + end + + @impl Igniter.Mix.Task + def igniter(igniter, argv) do + {%{subject: subject, extensions: extensions}, argv} = positional_args!(argv) + opts = [ subjects: subject, diff --git a/mix.exs b/mix.exs index 4880e4e6..a8b1b778 100644 --- a/mix.exs +++ b/mix.exs @@ -6,7 +6,7 @@ defmodule Ash.MixProject do A declarative, extensible framework for building Elixir applications. """ - @version "3.2.6" + @version "3.3.0" def project do [ @@ -361,7 +361,7 @@ defmodule Ash.MixProject do {:simple_sat, "~> 0.1 and >= 0.1.1", optional: true}, # Code Generators - {:igniter, "~> 0.3 and >= 0.3.10"}, + {:igniter, "~> 0.3 and >= 0.3.11"}, # Dev/Test dependencies {:eflame, "~> 1.0", only: [:dev, :test]}, diff --git a/mix.lock b/mix.lock index 2758d72c..63717cf0 100644 --- a/mix.lock +++ b/mix.lock @@ -18,11 +18,11 @@ "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, "git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"}, "git_ops": {:hex, :git_ops, "2.6.1", "cc7799a68c26cf814d6d1a5121415b4f5bf813de200908f930b27a2f1fe9dad5", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "ce62d07e41fe993ec22c35d5edb11cf333a21ddaead6f5d9868fcb607d42039e"}, - "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, - "igniter": {:hex, :igniter, "0.3.10", "b264ed66d14f52d8fabbf5cdbcc65ce57ee35cca120066dd24f530dcc943dd48", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:inflex, "~> 2.0", [hex: :inflex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "8cbf5397296cd4d3dcbd7977e8f760190321ceff1d7d393a7bcad373c46f2626"}, + "glob_ex": {:hex, :glob_ex, "0.1.8", "f7ef872877ca2ae7a792ab1f9ff73d9c16bf46ecb028603a8a3c5283016adc07", [:mix], [], "hexpm", "9e39d01729419a60a937c9260a43981440c43aa4cadd1fa6672fecd58241c464"}, + "igniter": {:hex, :igniter, "0.3.11", "1039c38eaf4e3c677712d097e18be96231479c3e9d7d8fd9c04397b1f6d3601d", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:inflex, "~> 2.0", [hex: :inflex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:owl, "~> 0.9", [hex: :owl, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}, {:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: false]}], "hexpm", "1381104faaa5c51b2cc540f185e72d3bbab0ea3eb57348c50af4440c7e469491"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, "iterex": {:hex, :iterex, "0.1.1", "90378a9561ad87da46737dceaf02e68a0b3023746216a4de34a0c509f5f505d4", [:mix], [], "hexpm", "c4f5916a6dbb03aa4c3d5c480069e13075ca6a57bd0c28d643da3891962440ad"}, - "jason": {:hex, :jason, "1.4.3", "d3f984eeb96fe53b85d20e0b049f03e57d075b5acda3ac8d465c969a2536c17b", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "9a90e868927f7c777689baa16d86f4d0e086d968db5c05d917ccff6d443e58a3"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, "makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, diff --git a/test/expr_test.exs b/test/expr_test.exs new file mode 100644 index 00000000..d7cf06ba --- /dev/null +++ b/test/expr_test.exs @@ -0,0 +1,22 @@ +defmodule Ash.Test.ExprTest do + @moduledoc false + use ExUnit.Case, async: true + + import Ash.Expr + + describe "determine_types" do + test "it determines the type of an if statement with complex values" do + {:ok, %func{arguments: args}} = + expr( + if fragment("1") do + string_downcase(type("foo", :string)) + else + error(Foo, %{bar: "baz"}) + end + ) + |> Ash.Filter.hydrate_refs(%{}) + + determine_types(func, args) + end + end +end