Skip to content

Commit 0ceddef

Browse files
committed
WIP 20250516-1049
1 parent 73d6f6c commit 0ceddef

File tree

4 files changed

+187
-114
lines changed

4 files changed

+187
-114
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ ash_random_params-*.tar
2121

2222
# Temporary files, for example, from tests.
2323
/tmp/
24+
*.code-workspace

lib/random/default_random.ex

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ defmodule AshRandomParams.DefaultRandom do
4141
tag_value = type_info |> Keyword.fetch!(:tag_value)
4242
attr_names = subtype |> Ash.Resource.Info.attributes() |> Enum.map(& &1.name)
4343

44+
# primary_create = subtype |> Ash.Resource.Info.primary_action(:create)
45+
4446
subtype
4547
|> Ash.Changeset.for_create(:fac_rec, %{}, ash_opts)
4648
|> Ash.create!(ash_opts)
@@ -54,24 +56,42 @@ defmodule AshRandomParams.DefaultRandom do
5456
constraints |> Keyword.fetch!(:one_of) |> Enum.random()
5557
end
5658

57-
def random(%{type: Ash.Type.Integer}, _opts, _context), do: 123_456
58-
def random(%{type: Ash.Type.Decimal}, _opts, _context), do: Decimal.new("123456.789")
59+
def random(%{type: Ash.Type.Integer}, _opts, _context), do: random_int()
60+
61+
def random(%{type: Ash.Type.Decimal}, _opts, _context),
62+
do: Decimal.new("#{random_int()}.#{random_int()}")
63+
5964
def random(%{type: Ash.Type.Boolean}, _opts, _context), do: [true, false] |> Enum.random()
6065
def random(%{type: Ash.Type.Map}, _opts, _context), do: %{}
6166

62-
def random(%{type: Ash.Type.Date}, _opts, _context), do: Date.utc_today()
63-
def random(%{type: Ash.Type.UtcDatetime}, _opts, _context), do: DateTime.utc_now()
64-
def random(%{type: Ash.Type.UtcDatetimeUsec}, _opts, _context), do: DateTime.utc_now()
65-
def random(%{type: Ash.Type.DateTime}, _opts, _context), do: DateTime.utc_now()
67+
def random(%{type: Ash.Type.Date}, _opts, _context),
68+
do: random_date_time() |> DateTime.to_date()
69+
70+
def random(%{type: Ash.Type.UtcDatetime}, _opts, _context), do: random_date_time()
71+
def random(%{type: Ash.Type.UtcDatetimeUsec}, _opts, _context), do: random_date_time()
72+
def random(%{type: Ash.Type.DateTime}, _opts, _context), do: random_date_time()
6673

6774
def random(%{type: Ash.Type.String, name: name}, _opts, _context),
68-
do: "#{name}-#{:rand.uniform(1_000_000_000_000)}"
75+
do: "#{name}-#{random_int()}"
6976

7077
def random(%{type: Ash.Type.CiString, name: name}, _opts, _context),
71-
do: "#{name}-#{:rand.uniform(1_000_000_000_000)}"
78+
do: "#{name}-#{random_int()}"
7279

7380
def random(%{name: name, type: type} = attr_or_arg, opts, context) do
7481
{attr_or_arg, opts, context} |> dbg()
75-
raise "Cannot make random value for #{name} of #{type}"
82+
raise "Cannot make random value for name: #{name}, type: #{type}"
83+
end
84+
85+
# Private
86+
87+
@year_seconds 365 * 24 * 60 * 60
88+
89+
defp random_date_time() do
90+
DateTime.utc_now()
91+
|> DateTime.add(:rand.uniform(20 * @year_seconds) - 10 * @year_seconds, :second)
92+
end
93+
94+
defp random_int() do
95+
:rand.uniform(1_000_000_000_000)
7696
end
7797
end

lib/transformer.ex

Lines changed: 57 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -66,53 +66,70 @@ defmodule AshRandomParams.Transformer do
6666
init_keys = init_params |> Map.keys()
6767
union_keys = tagged_unions |> Map.values()
6868

69-
new_attrs =
70-
Ash.Resource.Info.attributes(resource)
71-
|> Enum.filter(&(&1.name in action.accept))
72-
|> Enum.reject(&(&1.name in init_keys))
73-
|> Enum.reject(&(&1.name in union_keys))
74-
|> Enum.reject(&(&1.name in exclude))
75-
|> Enum.reject(&(&1.allow_nil? and &1.name not in include))
76-
77-
belongs_to_names =
69+
belongs_to_attrs =
7870
resource
7971
|> Ash.Resource.Info.relationships()
8072
|> Enum.flat_map(fn
81-
%BelongsTo{name: name, source_attribute: src_attr} -> [name, src_attr]
73+
%BelongsTo{source_attribute: src_attr} -> [src_attr]
8274
_ -> []
8375
end)
8476

85-
new_args =
86-
action.arguments
87-
|> Enum.reject(&(&1.name in belongs_to_names))
88-
|> Enum.reject(&(&1.name in init_keys))
89-
|> Enum.reject(&(&1.name in union_keys))
90-
|> Enum.reject(&(&1.name in exclude))
91-
|> Enum.reject(&(&1.allow_nil? and &1.name not in include))
92-
93-
new_params =
94-
(new_attrs ++ new_args)
95-
|> Map.new(fn %{name: name, default: default} = attr_or_arg ->
96-
value =
97-
case default do
98-
nil ->
99-
random_mod.random(attr_or_arg, random_opts, %{random: random, action_context: ctx})
100-
101-
default when is_function(default, 0) ->
102-
default.()
103-
104-
default ->
105-
default
106-
end
107-
108-
{name, value}
109-
end)
77+
rel_names =
78+
resource
79+
|> Ash.Resource.Info.relationships()
80+
|> Enum.map(& &1.name)
11081

111-
result_params =
112-
(action.accept ++ Enum.map(action.arguments, & &1.name))
113-
|> Map.new(fn name -> {name, nil} end)
114-
|> Map.merge(init_params)
115-
|> Map.merge(new_params)
82+
accepted_attrs =
83+
Ash.Resource.Info.attributes(resource)
84+
|> Enum.filter(&(&1.name in action.accept))
85+
86+
candidates = accepted_attrs ++ action.arguments
87+
88+
placeholder =
89+
candidates
90+
|> then(fn attr_or_args ->
91+
if action.type == :create do
92+
attr_or_args
93+
else
94+
attr_or_args
95+
|> Enum.reject(&(&1.name in rel_names))
96+
|> Enum.reject(&(&1.name in belongs_to_attrs))
97+
end
98+
end)
99+
|> Map.new(&{&1.name, nil})
100+
101+
generated_params =
102+
(
103+
fields_by_unfill =
104+
candidates
105+
|> Enum.reject(&(&1.name in rel_names))
106+
|> Enum.reject(&(&1.name in belongs_to_attrs))
107+
|> Enum.reject(&(&1.name in union_keys))
108+
|> Enum.reject(&(&1.name in exclude))
109+
|> Enum.reject(& &1.allow_nil?)
110+
111+
fields_by_fill = candidates |> Enum.filter(&(&1.name in include))
112+
113+
(fields_by_unfill ++ fields_by_fill)
114+
|> Enum.reject(&(&1.name in init_keys))
115+
|> Map.new(fn %{name: name, default: default} = attr_or_arg ->
116+
value =
117+
case default do
118+
nil ->
119+
random_mod.random(attr_or_arg, random_opts, %{random: random, action_context: ctx})
120+
121+
default when is_function(default, 0) ->
122+
default.()
123+
124+
default ->
125+
default
126+
end
127+
128+
{name, value}
129+
end)
130+
)
131+
132+
result_params = placeholder |> Map.merge(init_params) |> Map.merge(generated_params)
116133

117134
union_params =
118135
tagged_unions

test/ash_random_params_test.exs

Lines changed: 100 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule AshRandomParamsTest do
22
use ExUnit.Case, async: true
33

4-
alias __MODULE__.{Random, Post, Domain}
4+
alias __MODULE__.{Random, Post, Author, Domain}
55

66
defmodule Post do
77
use Ash.Resource, domain: Domain, data_layer: Ash.DataLayer.Ets, extensions: [AshRandomParams]
@@ -24,11 +24,35 @@ defmodule AshRandomParamsTest do
2424
defaults [:read, :destroy, create: :*, update: :*]
2525
end
2626

27+
relationships do
28+
belongs_to :author, Author, allow_nil?: false, public?: true
29+
end
30+
2731
random_params do
2832
random Random
2933
end
3034
end
3135

36+
defmodule Author do
37+
use Ash.Resource, domain: Domain, data_layer: Ash.DataLayer.Ets
38+
39+
ets do
40+
private? true
41+
end
42+
43+
attributes do
44+
uuid_primary_key :id
45+
end
46+
47+
relationships do
48+
has_many :posts, Post, public?: true
49+
end
50+
51+
actions do
52+
defaults [:read, :destroy, create: :*, update: :*]
53+
end
54+
end
55+
3256
defmodule Random do
3357
use AshRandomParams.Random
3458

@@ -48,93 +72,104 @@ defmodule AshRandomParamsTest do
4872

4973
resources do
5074
resource Post
75+
resource Author
5176
end
5277
end
5378

5479
test "with no options" do
55-
assert {:ok, ret} =
80+
assert %{
81+
author_id: nil,
82+
req_str: "req_str-" <> _,
83+
opt_str: nil,
84+
req_int: 777,
85+
opt_int: nil
86+
} =
87+
params =
5688
Post
5789
|> Ash.ActionInput.for_action(
5890
:random_params,
5991
%{
6092
action: :create
6193
}
6294
)
63-
|> Ash.run_action()
95+
|> Ash.run_action!()
6496

65-
assert ret.req_str |> String.starts_with?("req_str-")
66-
assert ret.opt_str == nil
67-
assert ret.req_int == 777
68-
assert ret.opt_int == nil
97+
refute params |> Map.has_key?(:author)
6998
end
7099

71-
test "with init_params" do
72-
assert {:ok, ret} =
73-
Post
74-
|> Ash.ActionInput.for_action(
75-
:random_params,
76-
%{
77-
action: :create,
78-
init_params: %{
79-
req_int: 123
100+
describe "options" do
101+
test "with init_params" do
102+
assert %{
103+
author_id: nil,
104+
req_str: "req_str-" <> _,
105+
opt_str: nil,
106+
req_int: 123_456,
107+
opt_int: nil
108+
} =
109+
Post
110+
|> Ash.ActionInput.for_action(
111+
:random_params,
112+
%{
113+
action: :create,
114+
init_params: %{
115+
req_int: 123_456
116+
}
80117
}
81-
}
82-
)
83-
|> Ash.run_action()
84-
85-
assert ret.req_str |> String.starts_with?("req_str-")
86-
assert ret.opt_str == nil
87-
assert ret.req_int == 123
88-
assert ret.opt_int == nil
89-
end
90-
91-
test "with include" do
92-
assert {:ok, ret} =
93-
Post
94-
|> Ash.ActionInput.for_action(
95-
:random_params,
96-
%{
97-
action: :create,
98-
include: [:opt_str]
99-
}
100-
)
101-
|> Ash.run_action()
102-
103-
assert ret.req_str |> String.starts_with?("req_str-")
104-
assert ret.opt_str |> String.starts_with?("opt_str-")
105-
assert ret.req_int == 777
106-
assert ret.opt_int == nil
107-
end
118+
)
119+
|> Ash.run_action!()
120+
end
108121

109-
test "with exclude" do
110-
assert {:ok, ret} =
111-
Post
112-
|> Ash.ActionInput.for_action(
113-
:random_params,
114-
%{
115-
action: :create,
116-
exclude: [:req_str]
117-
}
118-
)
119-
|> Ash.run_action()
122+
test "with include" do
123+
assert %{
124+
author_id: nil,
125+
req_str: "req_str-" <> _,
126+
opt_str: "opt_str-" <> _,
127+
req_int: 777,
128+
opt_int: nil
129+
} =
130+
Post
131+
|> Ash.ActionInput.for_action(
132+
:random_params,
133+
%{
134+
action: :create,
135+
include: [:opt_str]
136+
}
137+
)
138+
|> Ash.run_action!()
139+
end
120140

121-
assert ret.req_str == nil
122-
assert ret.opt_str == nil
123-
assert ret.req_int == 777
124-
assert ret.opt_int == nil
141+
test "with exclude" do
142+
assert %{
143+
author_id: nil,
144+
req_str: nil,
145+
opt_str: nil,
146+
req_int: 777,
147+
opt_int: nil
148+
} =
149+
Post
150+
|> Ash.ActionInput.for_action(
151+
:random_params,
152+
%{
153+
action: :create,
154+
exclude: [:req_str]
155+
}
156+
)
157+
|> Ash.run_action!()
158+
end
125159
end
126160

127161
test "code interface" do
128-
assert {:ok, ret} =
129-
Post.random_params(
162+
assert %{
163+
author_id: nil,
164+
req_str: "req_str-" <> _,
165+
opt_str: "opt_str-" <> _,
166+
req_int: 777,
167+
opt_int: nil
168+
} =
169+
Post.random_params!(
130170
:create,
131171
%{},
132172
%{include: [:opt_str]}
133173
)
134-
135-
assert ret.req_str |> String.starts_with?("req_str-")
136-
assert ret.opt_str |> String.starts_with?("opt_str-")
137-
assert ret.req_int == 777
138-
assert ret.opt_int == nil
139174
end
140175
end

0 commit comments

Comments
 (0)