Skip to content

Commit 172d1f4

Browse files
committed
improvement: support atomics as insert values via subqueries
This is hacky, but the only real way to do it rn
1 parent 6034861 commit 172d1f4

1 file changed

Lines changed: 54 additions & 0 deletions

File tree

lib/atomics.ex

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,60 @@ defmodule AshSql.Atomics do
104104
end
105105
end
106106

107+
@doc """
108+
Converts atomics to subquery values suitable for insert_all.
109+
110+
Returns `{:ok, map}` where map contains `{field => subquery}` pairs.
111+
Each subquery returns a single value that can be used as a field value in insert_all.
112+
113+
All changesets in a batch share the same atomics (Ash groups by atomics before dispatch).
114+
"""
115+
def atomics_to_insert_values(_resource, _query, []), do: {:ok, %{}}
116+
117+
def atomics_to_insert_values(resource, query, atomics) do
118+
atomics = type_atomics(query.__ash_bindings__.sql_behaviour, resource, atomics)
119+
120+
Enum.reduce_while(atomics, {:ok, %{}}, fn {field, expr}, {:ok, acc} ->
121+
attribute = Ash.Resource.Info.attribute(resource, field)
122+
123+
expr = unwrap_type(expr)
124+
125+
expr =
126+
if AshSql.Calculation.map_type?(attribute.type, attribute.constraints || []) do
127+
expr
128+
else
129+
maybe_cast_atomic_expr(
130+
expr,
131+
attribute,
132+
query.__ash_bindings__.sql_behaviour,
133+
resource
134+
)
135+
end
136+
137+
type =
138+
case query.__ash_bindings__.sql_behaviour.storage_type(resource, attribute.name) do
139+
nil -> {attribute.type, attribute.constraints}
140+
storage_type -> storage_type
141+
end
142+
143+
case AshSql.Expr.dynamic_expr(query, expr, query.__ash_bindings__, false, type) do
144+
{dynamic, _acc} ->
145+
subquery =
146+
Ecto.Query.from(row in fragment("(VALUES(1))"), select: ^dynamic)
147+
|> Map.put(:__ash_bindings__, query.__ash_bindings__)
148+
149+
{:cont, {:ok, Map.put(acc, field, subquery)}}
150+
151+
other ->
152+
{:halt, other}
153+
end
154+
end)
155+
end
156+
157+
defp unwrap_type(%Ash.Query.Function.Type{arguments: [expr | _]}), do: expr
158+
defp unwrap_type(%Ash.Query.Call{name: :type, args: [expr | _]}), do: expr
159+
defp unwrap_type(expr), do: expr
160+
107161
def set_subquery_prefix(sub_query, query) do
108162
%{
109163
sub_query

0 commit comments

Comments
 (0)