Skip to content

Commit b7b5758

Browse files
committed
improvement: update to the latest ash
improvement: remove the need to dynamically expand fragments
1 parent 435d521 commit b7b5758

File tree

8 files changed

+70
-232
lines changed

8 files changed

+70
-232
lines changed

.check.exs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
## all available options with default values (see `mix check` docs for description)
33
# parallel: true,
44
# skipped: true,
5-
5+
retry: false,
66
## list of tools (see `mix check` docs for defaults)
77
tools: [
88
## curated tools may be disabled (e.g. the check for compilation warnings)

.github/workflows/elixir.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
matrix:
1919
otp: ["24"]
2020
elixir: ["1.14.0"]
21-
ash: ["2.0.0-rc.10"]
21+
ash: ["2.0.0-rc.14"]
2222
pg_version: ["13"]
2323
env:
2424
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

lib/aggregate.ex

+18-85
Original file line numberDiff line numberDiff line change
@@ -149,77 +149,26 @@ defmodule AshPostgres.Aggregate do
149149
{in_aggregates, in_body} =
150150
Enum.split_with(dynamics, fn {load, _name, _dynamic} -> is_nil(load) end)
151151

152-
query =
153-
if query.select do
154-
query
152+
aggs =
153+
in_body
154+
|> Map.new(fn {load, _, dynamic} ->
155+
{load, dynamic}
156+
end)
157+
158+
aggs =
159+
if Enum.empty?(in_aggregates) do
160+
aggs
155161
else
156-
Ecto.Query.select_merge(query, %{})
162+
Map.put(
163+
aggs,
164+
:aggregates,
165+
Map.new(in_aggregates, fn {_, name, dynamic} ->
166+
{name, dynamic}
167+
end)
168+
)
157169
end
158170

159-
{exprs, new_params, count} =
160-
Enum.reduce(
161-
in_body,
162-
{[], Enum.reverse(query.select.params), Enum.count(query.select.params)},
163-
fn {load, _, dynamic}, {exprs, params, count} ->
164-
{expr, new_params, count} =
165-
Ecto.Query.Builder.Dynamic.partially_expand(
166-
:select,
167-
query,
168-
dynamic,
169-
params,
170-
count
171-
)
172-
173-
{[{load, expr} | exprs], new_params, count}
174-
end
175-
)
176-
177-
query = %{
178-
query
179-
| select: %{
180-
query.select
181-
| expr: {:merge, [], [query.select.expr, {:%{}, [], Enum.reverse(exprs)}]}
182-
}
183-
}
184-
185-
add_aggregates_in_aggregates(query, in_aggregates, new_params, count)
186-
end
187-
188-
defp add_aggregates_in_aggregates(query, [], params, _count),
189-
do: %{query | select: %{query.select | params: Enum.reverse(params)}}
190-
191-
defp add_aggregates_in_aggregates(
192-
%{select: %{expr: expr} = select} = query,
193-
in_aggregates,
194-
params,
195-
count
196-
) do
197-
{exprs, new_params, _} =
198-
Enum.reduce(
199-
in_aggregates,
200-
{[], params, count},
201-
fn {_, name, dynamic}, {exprs, params, count} ->
202-
{expr, new_params, count} =
203-
Ecto.Query.Builder.Dynamic.partially_expand(
204-
:select,
205-
query,
206-
dynamic,
207-
params,
208-
count
209-
)
210-
211-
{[{name, expr} | exprs], new_params, count}
212-
end
213-
)
214-
215-
%{
216-
query
217-
| select: %{
218-
select
219-
| expr: {:merge, [], [expr, {:%{}, [], [aggregates: {:%{}, [], Enum.reverse(exprs)}]}]},
220-
params: Enum.reverse(new_params)
221-
}
222-
}
171+
Ecto.Query.select_merge(query, ^aggs)
223172
end
224173

225174
def agg_subquery_for_lateral_join(
@@ -608,23 +557,7 @@ defmodule AshPostgres.Aggregate do
608557
Ecto.Query.select(query, %{})
609558
end
610559

611-
{expr, new_params, _} =
612-
Ecto.Query.Builder.Dynamic.partially_expand(
613-
:select,
614-
query,
615-
casted,
616-
Enum.reverse(query.select.params),
617-
Enum.count(query.select.params)
618-
)
619-
620-
%{
621-
query
622-
| select: %{
623-
query.select
624-
| expr: {:merge, [], [query.select.expr, {:%{}, [], [{aggregate_name, expr}]}]},
625-
params: Enum.reverse(new_params)
626-
}
627-
}
560+
Ecto.Query.select_merge(query, ^%{aggregate_name => casted})
628561
end
629562

630563
defp aggregate_subquery(

lib/calculation.ex

+17-67
Original file line numberDiff line numberDiff line change
@@ -36,75 +36,25 @@ defmodule AshPostgres.Calculation do
3636
{in_calculations, in_body} =
3737
Enum.split_with(dynamics, fn {load, _name, _dynamic} -> is_nil(load) end)
3838

39-
query =
40-
if query.select do
41-
query
39+
calcs =
40+
in_body
41+
|> Map.new(fn {load, _, dynamic} ->
42+
{load, dynamic}
43+
end)
44+
45+
calcs =
46+
if Enum.empty?(in_calculations) do
47+
calcs
4248
else
43-
Ecto.Query.select(query, %{})
49+
Map.put(
50+
calcs,
51+
:calculations,
52+
Map.new(in_calculations, fn {_, name, dynamic} ->
53+
{name, dynamic}
54+
end)
55+
)
4456
end
4557

46-
{exprs, new_params, _} =
47-
Enum.reduce(
48-
in_body,
49-
{[], Enum.reverse(query.select.params), Enum.count(query.select.params)},
50-
fn {load, _, dynamic}, {exprs, params, count} ->
51-
{expr, new_params, count} =
52-
Ecto.Query.Builder.Dynamic.partially_expand(
53-
:select,
54-
query,
55-
dynamic,
56-
params,
57-
count
58-
)
59-
60-
{[{load, expr} | exprs], new_params, count}
61-
end
62-
)
63-
64-
query = %{
65-
query
66-
| select: %{
67-
query.select
68-
| expr: {:merge, [], [query.select.expr, {:%{}, [], Enum.reverse(exprs)}]},
69-
params: Enum.reverse(new_params)
70-
}
71-
}
72-
73-
add_calculations_in_calculations(query, in_calculations)
74-
end
75-
76-
defp add_calculations_in_calculations(query, []), do: query
77-
78-
defp add_calculations_in_calculations(
79-
%{select: %{expr: expr} = select} = query,
80-
in_calculations
81-
) do
82-
{exprs, new_params, _} =
83-
Enum.reduce(
84-
in_calculations,
85-
{[], Enum.reverse(query.select.params), Enum.count(query.select.params)},
86-
fn {_, name, dynamic}, {exprs, params, count} ->
87-
{expr, new_params, count} =
88-
Ecto.Query.Builder.Dynamic.partially_expand(
89-
:select,
90-
query,
91-
dynamic,
92-
params,
93-
count
94-
)
95-
96-
{[{name, expr} | exprs], new_params, count}
97-
end
98-
)
99-
100-
%{
101-
query
102-
| select: %{
103-
select
104-
| expr:
105-
{:merge, [], [expr, {:%{}, [], [calculations: {:%{}, [], Enum.reverse(exprs)}]}]},
106-
params: Enum.reverse(new_params)
107-
}
108-
}
58+
Ecto.Query.select_merge(query, ^calcs)
10959
end
11060
end

lib/expr.ex

+20-67
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ defmodule AshPostgres.Expr do
44
alias Ash.Filter
55
alias Ash.Query.{BooleanExpression, Exists, Not, Ref}
66
alias Ash.Query.Operator.IsNil
7-
alias Ash.Query.Function.{Ago, Contains, GetPath, If, Length}
8-
alias AshPostgres.Functions.{Fragment, TrigramSimilarity, Type}
7+
alias Ash.Query.Function.{Ago, Contains, GetPath, If, Length, Type}
8+
alias AshPostgres.Functions.{Fragment, TrigramSimilarity}
99

1010
require Ecto.Query
1111

@@ -47,22 +47,8 @@ defmodule AshPostgres.Expr do
4747
arg1 = do_dynamic_expr(query, arg1, bindings, pred_embedded? || embedded?)
4848
arg2 = do_dynamic_expr(query, arg2, bindings, pred_embedded? || embedded?)
4949

50-
do_dynamic_expr(
51-
query,
52-
%Fragment{
53-
embedded?: pred_embedded?,
54-
arguments: [
55-
raw: "similarity(",
56-
expr: arg1,
57-
raw: ", ",
58-
expr: arg2,
59-
raw: ")"
60-
]
61-
},
62-
bindings,
63-
embedded?,
64-
type
65-
)
50+
Ecto.Query.dynamic(fragment("similarity(?, ?)", ^arg1, ^arg2))
51+
|> maybe_type(type, query)
6652
end
6753

6854
defp do_dynamic_expr(
@@ -330,38 +316,20 @@ defmodule AshPostgres.Expr do
330316
{params, fragment_data, _} =
331317
Enum.reduce(arguments, {[], [], 0}, fn
332318
{:raw, str}, {params, fragment_data, count} ->
333-
{params, fragment_data ++ [{:raw, str}], count}
319+
{params, [{:raw, str} | fragment_data], count}
334320

335321
{:casted_expr, dynamic}, {params, fragment_data, count} ->
336-
{expr, new_params, new_count} =
337-
Ecto.Query.Builder.Dynamic.partially_expand(
338-
:select,
339-
query,
340-
dynamic,
341-
params,
342-
count
343-
)
344-
345-
{new_params, fragment_data ++ [{:expr, expr}], new_count}
322+
{[{dynamic, :any} | params], [{:expr, {:^, [], [count]}} | fragment_data], count + 1}
346323

347324
{:expr, expr}, {params, fragment_data, count} ->
348325
dynamic = do_dynamic_expr(query, expr, bindings, pred_embedded? || embedded?)
349326

350-
{expr, new_params, new_count} =
351-
Ecto.Query.Builder.Dynamic.partially_expand(
352-
:select,
353-
query,
354-
dynamic,
355-
params,
356-
count
357-
)
358-
359-
{new_params, fragment_data ++ [{:expr, expr}], new_count}
327+
{[{dynamic, :any} | params], [{:expr, {:^, [], [count]}} | fragment_data], count + 1}
360328
end)
361329

362330
frag_dynamic = %Ecto.Query.DynamicExpr{
363331
fun: fn _query ->
364-
{{:fragment, [], fragment_data}, Enum.reverse(params), []}
332+
{{:fragment, [], Enum.reverse(fragment_data)}, Enum.reverse(params), [], %{}}
365333
end,
366334
binding: [],
367335
file: __ENV__.file,
@@ -694,40 +662,16 @@ defmodule AshPostgres.Expr do
694662

695663
defp do_dynamic_expr(
696664
query,
697-
%Type{arguments: [arg1, arg2], embedded?: pred_embedded?} = type_expr,
698-
bindings,
699-
embedded?,
700-
_type
701-
) do
702-
arg1 = do_dynamic_expr(query, arg1, bindings, false)
703-
arg2 = do_dynamic_expr(query, arg2, bindings, pred_embedded? || embedded?)
704-
type = AshPostgres.Types.parameterized_type(arg2, [])
705-
validate_type!(query, type, type_expr)
706-
707-
if type do
708-
Ecto.Query.dynamic(type(^arg1, ^type))
709-
else
710-
raise "Attempted to explicitly cast to a type that has `cast_in_query?` configured to `false`, or for which a type could not be determined."
711-
end
712-
end
713-
714-
defp do_dynamic_expr(
715-
query,
716-
%Type{arguments: [arg1, arg2, constraints], embedded?: pred_embedded?} = type_expr,
665+
%Type{arguments: [arg1, arg2, constraints]} = type_expr,
717666
bindings,
718-
embedded?,
667+
_embedded?,
719668
_type
720669
) do
721670
arg1 = do_dynamic_expr(query, arg1, bindings, false)
722-
arg2 = do_dynamic_expr(query, arg2, bindings, pred_embedded? || embedded?)
723671
type = AshPostgres.Types.parameterized_type(arg2, constraints)
724672
validate_type!(query, type, type_expr)
725673

726-
if type do
727-
Ecto.Query.dynamic(type(^arg1, ^type))
728-
else
729-
raise "Attempted to explicitly cast to a type that has `cast_in_query?` configured to `false`, or for which a type could not be determined."
730-
end
674+
Ecto.Query.dynamic(type(^arg1, ^type))
731675
end
732676

733677
defp do_dynamic_expr(
@@ -871,6 +815,15 @@ defmodule AshPostgres.Expr do
871815
end
872816
end
873817

818+
defp maybe_type(dynamic, nil, _query), do: dynamic
819+
820+
defp maybe_type(dynamic, type, query) do
821+
type = AshPostgres.Types.parameterized_type(type, [])
822+
validate_type!(query, type, type)
823+
824+
Ecto.Query.dynamic(type(^dynamic, ^type))
825+
end
826+
874827
defp maybe_sanitize_list(value) do
875828
if is_list(value) do
876829
Enum.map(value, fn value ->

lib/migration_generator/migration_generator.ex

+5-3
Original file line numberDiff line numberDiff line change
@@ -1947,9 +1947,11 @@ defmodule AshPostgres.MigrationGenerator do
19471947
constraint.attribute
19481948
|> List.wrap()
19491949
|> Enum.map(fn attribute ->
1950-
resource
1951-
|> Ash.Resource.Info.attribute(attribute)
1952-
|> Map.get(:source)
1950+
attr =
1951+
resource
1952+
|> Ash.Resource.Info.attribute(attribute)
1953+
1954+
attr.source || attr.name
19531955
end)
19541956

19551957
%{

mix.exs

+3-3
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,11 @@ defmodule AshPostgres.MixProject do
134134
# Run "mix help deps" to learn about dependencies.
135135
defp deps do
136136
[
137-
{:ecto_sql, "~> 3.8"},
138-
{:ecto, "~> 3.8"},
137+
{:ecto_sql, "~> 3.9"},
138+
{:ecto, "~> 3.9"},
139139
{:jason, "~> 1.0"},
140140
{:postgrex, ">= 0.0.0"},
141-
{:ash, ash_version("~> 2.0.0-rc.11")},
141+
{:ash, ash_version("~> 2.0.0-rc.14")},
142142
{:git_ops, "~> 2.4.5", only: :dev},
143143
{:ex_doc, "~> 0.22", only: :dev, runtime: false},
144144
{:ex_check, "~> 0.14", only: :dev},

0 commit comments

Comments
 (0)