11defmodule LiveDebugger.App.Debugger.NodeState.StreamUtils do
22 @ moduledoc """
3- Utilities for extracting and computing Phoenix LiveView stream diffs and state
3+ Utilities for extracting Phoenix LiveView stream diffs and state
44 from render traces.
55 """
66
7- alias LiveDebugger.App.Utils.TermDiffer
8- alias LiveDebugger.App.Utils.TermDiffer.Diff
9- alias LiveDebugger.App.Utils.TermParser
10-
11- @ empty_diff % Diff { type: :map , ins: % { } , del: % { } , diff: % { } }
12-
137 @ doc """
148 Given a tuple of render traces, compute the base stream diff and stream state.
159 """
1610 def build_initial_stream_diff ( { stream_updates , _trace } ) do
1711 stream_traces = extract_stream_traces ( stream_updates )
1812 stream_names = get_stream_names_map ( stream_traces )
1913
20- # base_diff = TermDiffer.diff(%{}, base_stream_state)
21-
22- # {_, initial_term_tree} =
23- # TermParser.update_by_diff(
24- # TermParser.term_to_display_tree(%{}),
25- # base_diff
26- # )
27-
2814 fun_list = collect_updates ( stream_traces )
29- # stream_names = Enum.map (stream_traces, &elem(&1, 0) )
15+ config_list = collect_config ( stream_traces )
3016
31- # dbg({inserts, deletes})
32- # deletes = ensure_delete_keys_present(inserts, deletes)
17+ dbg ( fun_list )
3318
34- # computed_lists = reconstruct_stream_lists(inserts, deletes)
35- # # dbg(computed_lists)
36- # stream_state = build_stream_state_map(computed_lists)
37- # # dbg(stream_state)
38- # final_diff = build_diff_from_computed_lists(computed_lists)
39- # dbg(final_diff)
19+ { fun_list , config_list , stream_names }
20+ end
4021
22+ def compute_diff ( stream_updates ) do
23+ stream_names = get_stream_names_map ( stream_updates )
24+ fun_list = collect_updates ( stream_updates )
4125 { fun_list , stream_names }
4226 end
4327
@@ -49,14 +33,6 @@ defmodule LiveDebugger.App.Debugger.NodeState.StreamUtils do
4933 |> Enum . reject ( & Enum . empty? / 1 )
5034 end
5135
52- defp infer_base_stream_state ( [ ] ) , do: % { }
53-
54- defp infer_base_stream_state ( [ first_trace | _ ] ) do
55- first_trace
56- |> Enum . filter ( fn { _ , val } -> match? ( % Phoenix.LiveView.LiveStream { } , val ) end )
57- |> Map . new ( fn { key , _val } -> { key , [ ] } end )
58- end
59-
6036 defp get_stream_names_map ( updates ) do
6137 updates
6238 |> Enum . flat_map ( fn update ->
@@ -76,21 +52,55 @@ defmodule LiveDebugger.App.Debugger.NodeState.StreamUtils do
7652 update_list
7753 end
7854
55+ defp collect_config ( update_list ) do
56+ update_list =
57+ update_list
58+ |> Enum . map ( & flatten_stream_config ( & 1 ) )
59+ # We only need the first render because config stays the same and cannot be changed
60+ |> Enum . take ( 1 )
61+ |> List . flatten ( )
62+
63+ dbg ( update_list )
64+ update_list
65+ end
66+
7967 def map_stream_entry_to_stream_function ( % Phoenix.LiveView.LiveStream {
8068 name: name ,
8169 inserts: inserts ,
8270 deletes: deletes ,
8371 reset?: reset? ,
84- consumable?: consumable ?
72+ consumable?: _consumable ?
8573 } ) do
8674 [ ]
8775 |> maybe_add_reset ( reset? , name )
88- |> maybe_add_inserts ( inserts , name )
76+ # Reverse to preserve the order of inserts
77+ |> maybe_add_inserts ( Enum . reverse ( inserts ) , name )
8978 |> maybe_add_deletes ( deletes , name )
9079 end
9180
81+ def map_stream_entry_to_stream_config (
82+ % Phoenix.LiveView.LiveStream {
83+ name: name
84+ } ,
85+ config
86+ ) do
87+ [ ]
88+ |> maybe_add_config ( config , name )
89+ end
90+
91+ defp maybe_add_config ( functions , nil , _name ) , do: functions
92+
93+ defp maybe_add_config ( functions , [ dom_id: fun ] , name ) do
94+ functions ++ [ fn socket -> Phoenix.LiveView . stream_configure ( socket , name , dom_id: fun ) end ]
95+ end
96+
9297 defp maybe_add_reset ( functions , true , name ) do
93- functions ++ [ fn socket -> Phoenix.LiveView . stream ( socket , name , [ ] , reset: true ) end ]
98+ functions ++
99+ [
100+ fn socket ->
101+ Phoenix.LiveView . stream ( socket , name , [ ] , reset: true )
102+ end
103+ ]
94104 end
95105
96106 defp maybe_add_reset ( functions , false , _name ) , do: functions
@@ -108,7 +118,7 @@ defmodule LiveDebugger.App.Debugger.NodeState.StreamUtils do
108118 end
109119
110120 defp create_insert_functions ( inserts , name ) do
111- Enum . map ( inserts , fn { dom_id , at , element , limit , update? } ->
121+ Enum . map ( inserts , fn { _dom_id , at , element , limit , update? } ->
112122 fn socket ->
113123 Phoenix.LiveView . stream_insert ( socket , name , element ,
114124 at: at ,
@@ -121,151 +131,36 @@ defmodule LiveDebugger.App.Debugger.NodeState.StreamUtils do
121131
122132 defp create_delete_functions ( deletes , name ) do
123133 Enum . map ( deletes , fn dom_id ->
124- dbg ( dom_id )
125-
126134 fn socket ->
127- Phoenix.LiveView . stream_delete_by_dom_id ( socket , name , dom_id )
135+ # Problem with same_id because ids are reused and element is updated and then deleted
136+ Process . send_after ( self ( ) , { :delete_stream_entry , name , dom_id , socket } , 1 )
137+ socket
128138 end
129139 end )
130140 end
131141
132142 defp flatten_stream_updates ( stream_entry ) do
143+ dbg ( stream_entry )
144+
133145 Enum . flat_map ( stream_entry , fn
134- { stream_name , % Phoenix.LiveView.LiveStream { } = stream } ->
135- dbg ( map_stream_entry_to_stream_function ( stream ) )
146+ { _stream_name , % Phoenix.LiveView.LiveStream { } = stream } ->
136147 map_stream_entry_to_stream_function ( stream )
137148
138149 _ ->
139150 [ ]
140151 end )
141152 end
142153
143- # defp reconstruct_stream_lists(inserts, deletes) do
144- # inserts
145- # |> Enum.map(fn {stream_name, stream_inserts} ->
146- # list = build_stream_list_from_inserts(stream_inserts)
147- # deleted_ids = Map.get(deletes, stream_name, [])
148- # # dbg(list)
149- # # dbg(deleted_ids)
150-
151- # cleaned =
152- # Enum.reduce(deleted_ids, list, fn dom_id, acc ->
153- # List.keydelete(acc, dom_id, 0)
154- # end)
155-
156- # {stream_name, cleaned}
157- # end)
158- # end
154+ defp flatten_stream_config ( stream_entry ) do
155+ configured = Map . get ( stream_entry , :__configured__ )
159156
160- # defp build_stream_list_from_inserts(inserts) do
161- # Enum.reduce(Enum.reverse(inserts), [], fn {dom_id, _, element, _, updated?}, acc ->
162- # if updated? do
163- # List.keyreplace(acc, dom_id, 0, {dom_id, element})
164- # else
165- # List.insert_at(acc, 0, {dom_id, element})
166- # end
167- # end)
168- # end
169-
170- # defp build_stream_state_map(list_map) do
171- # list_map
172- # |> Enum.map(fn {stream_name, list} ->
173- # stream_state =
174- # Enum.with_index(list, fn {dom_id, _val}, idx ->
175- # {dom_id, idx}
176- # end)
177-
178- # {stream_name, stream_state}
179- # end)
180- # |> Map.new()
181- # end
182-
183- # defp build_diff_from_computed_lists(list_map) do
184- # diff_map =
185- # Enum.reduce(list_map, %{}, fn {stream_name, list}, acc ->
186- # inserts =
187- # list
188- # |> Enum.with_index()
189- # |> Enum.into(%{}, fn {{_dom_id, val}, index} ->
190- # {index, val}
191- # end)
192-
193- # # dbg(inserts)
194-
195- # list_diff = %Diff{type: :list, ins: inserts, del: %{}, diff: %{}}
196- # Map.put(acc, stream_name, list_diff)
197- # end)
198-
199- # Map.put(@empty_diff, :diff, diff_map)
200- # end
201-
202- # defp compute_stream_diff_update(inserts, deletes, current_state) do
203- # deleted_ids = MapSet.new(deletes)
204-
205- # cleaned_state =
206- # Enum.reject(current_state, fn {dom_id, _} -> dom_id in deleted_ids end)
207-
208- # reindexed_state =
209- # cleaned_state
210- # |> Enum.with_index()
211- # |> Enum.map(fn {{dom_id, _}, idx} -> {dom_id, idx} end)
212-
213- # deleted_map =
214- # deletes
215- # |> Enum.map(fn dom_id ->
216- # case List.keyfind(current_state, dom_id, 0) do
217- # {^dom_id, idx} -> {idx, :deleted}
218- # _ -> nil
219- # end
220- # end)
221- # |> Enum.reject(&is_nil/1)
222- # |> Enum.into(%{})
223-
224- # {insert_ops, updated_del_map, updated_state} =
225- # Enum.reduce(inserts, {[], %{}, reindexed_state}, fn
226- # {dom_id, index, value, _, true}, {ins_acc, del_acc, state_acc} ->
227- # {_, original_index} = List.keyfind(current_state, dom_id, 0)
228-
229- # updated_del =
230- # if original_index, do: Map.put(del_acc, original_index, :deleted), else: del_acc
231-
232- # # tu cos nie dzila jeszcze i kolejnosc jeszce jak insertujemy pod ten sam domid bez update to tez update xd i
233- # # insert at index jesli jest mniej elementow to na koniec(update)
234- # updated_ins = List.insert_at(ins_acc, index, {dom_id, value})
235- # new_state = List.keyreplace(state_acc, dom_id, 0, {dom_id, index})
236-
237- # {updated_ins, updated_del, new_state}
238-
239- # {dom_id, index, value, _, false}, {ins_acc, del_acc, state_acc} ->
240- # {
241- # List.insert_at(ins_acc, index, {dom_id, value}),
242- # del_acc,
243- # List.insert_at(state_acc, index, {dom_id, index})
244- # }
245- # end)
246-
247- # # dbg(ins_map)
248-
249- # final_state =
250- # updated_state
251- # |> Enum.with_index()
252- # |> Enum.map(fn {{dom_id, _}, idx} -> {dom_id, idx} end)
253-
254- # # dbg({insert_ops, final_state})
255-
256- # ins_map =
257- # insert_ops
258- # |> Enum.map(fn {dom_id, val} ->
259- # {Keyword.fetch!(final_state, dom_id), val}
260- # end)
261- # |> Map.new()
262-
263- # # dbg(ins_map)
157+ Enum . flat_map ( stream_entry , fn
158+ { stream_name , % Phoenix.LiveView.LiveStream { } = stream } ->
159+ name_config = Map . get ( configured , stream_name )
160+ map_stream_entry_to_stream_config ( stream , name_config )
264161
265- # %{
266- # ins: ins_map,
267- # del: Map.merge(deleted_map, updated_del_map),
268- # final_state: final_state
269- # }
270- # end
162+ _ ->
163+ [ ]
164+ end )
165+ end
271166end
0 commit comments