@@ -20,6 +20,9 @@ defmodule AlgoraWeb.Admin.CampaignLive do
20
20
21
21
require Logger
22
22
23
+ @ repo_cache_table :campaign_repo_cache
24
+ @ user_cache_table :campaign_user_cache
25
+
23
26
defmodule Campaign do
24
27
@ moduledoc false
25
28
use Ecto.Schema
@@ -45,6 +48,11 @@ defmodule AlgoraWeb.Admin.CampaignLive do
45
48
end
46
49
end
47
50
51
+ def start_link do
52
+ :ets . new ( @ repo_cache_table , [ :named_table , :set , :public ] )
53
+ :ets . new ( @ user_cache_table , [ :named_table , :set , :public ] )
54
+ end
55
+
48
56
@ impl true
49
57
def mount ( _params , _session , socket ) do
50
58
timezone = if ( params = get_connect_params ( socket ) , do: params [ "timezone" ] )
@@ -54,8 +62,6 @@ defmodule AlgoraWeb.Admin.CampaignLive do
54
62
|> assign ( :timezone , timezone )
55
63
|> assign ( :page_title , "Campaign" )
56
64
|> assign ( :form , to_form ( Campaign . changeset ( % Campaign { } ) ) )
57
- |> assign ( :repo_cache , % { } )
58
- |> assign ( :user_cache , % { } )
59
65
|> assign_preview ( ) }
60
66
end
61
67
@@ -271,30 +277,33 @@ defmodule AlgoraWeb.Admin.CampaignLive do
271
277
socket . assigns . csv_data
272
278
|> Enum . map ( & Map . get ( & 1 , "email" ) )
273
279
|> Enum . uniq ( )
280
+ |> Enum . reject ( fn key -> :ets . lookup ( @ user_cache_table , key ) != [ ] end )
274
281
275
- new_cache =
276
- Map . new ( new_keys , fn key ->
277
- user = Accounts . get_user_by_email ( key )
282
+ Enum . each ( new_keys , fn key ->
283
+ user = Accounts . get_user_by_email ( key )
278
284
285
+ timestamp =
279
286
if user do
280
- { key , Util . next_occurrence_of_time ( user . last_active_at || user . inserted_at ) }
287
+ Util . next_occurrence_of_time ( user . last_active_at || user . inserted_at )
281
288
else
282
- { key , Util . next_occurrence_of_time ( Util . random_datetime ( ) ) }
289
+ Util . next_occurrence_of_time ( Util . random_datetime ( ) )
283
290
end
284
- end )
285
291
286
- updated_cache = Map . merge ( socket . assigns . user_cache , new_cache )
292
+ :ets . insert ( @ user_cache_table , { key , timestamp } )
293
+ end )
287
294
288
295
csv_data =
289
- Enum . map ( socket . assigns . csv_data , fn row -> Map . put ( row , "timestamp" , Map . get ( updated_cache , row [ "email" ] ) ) end )
296
+ Enum . map ( socket . assigns . csv_data , fn row ->
297
+ [ { _ , timestamp } ] = :ets . lookup ( @ user_cache_table , row [ "email" ] )
298
+ Map . put ( row , "timestamp" , timestamp )
299
+ end )
290
300
291
301
csv_columns =
292
302
csv_data
293
303
|> Enum . flat_map ( & Map . keys / 1 )
294
304
|> Enum . uniq ( )
295
305
296
306
socket
297
- |> assign ( :repo_cache , updated_cache )
298
307
|> assign ( :csv_data , csv_data )
299
308
|> assign ( :csv_columns , csv_columns )
300
309
end
@@ -304,66 +313,34 @@ defmodule AlgoraWeb.Admin.CampaignLive do
304
313
socket . assigns . csv_data
305
314
|> Enum . map ( & repo_key / 1 )
306
315
|> Enum . reject ( & is_nil / 1 )
307
- |> Enum . reject ( & Map . has_key? ( socket . assigns . repo_cache , & 1 ) )
316
+ |> Enum . reject ( fn key -> :ets . lookup ( @ repo_cache_table , key ) != [ ] end )
308
317
|> Enum . uniq ( )
309
318
310
- new_cache =
311
- Map . new ( new_keys , fn key ->
312
- filter =
313
- case key do
314
- { owner , name } ->
315
- token = Admin . token ( )
316
-
317
- with { :ok , repository } <- Workspace . ensure_repository ( token , owner , name ) ,
318
- { :ok , _tech_stack } <- Workspace . ensure_repo_tech_stack ( token , repository ) do
319
- dynamic ( [ r , _u ] , r . id == ^ repository . id )
320
- else
321
- _ -> false
322
- end
323
-
324
- or g_handle ->
325
- dynamic ( [ r , u ] , u . handle == ^ org_handle )
326
- end
327
-
328
- repo =
329
- Repo . one (
330
- from r in Repository ,
331
- join: u in assoc ( r , :user ) ,
332
- where: ^ filter ,
333
- order_by: [ desc: fragment ( "(?->>'stargazers_count')::integer" , r . provider_meta ) ] ,
334
- select: % {
335
- repo_owner: u . provider_login ,
336
- repo_name: r . name ,
337
- tech_stack: fragment ( "COALESCE(NULLIF(?, '{}'), ?)" , u . tech_stack , r . tech_stack )
338
- } ,
339
- limit: 1
340
- )
341
-
342
- if repo && repo . tech_stack != [ ] do
343
- matches = Settings . get_tech_matches ( List . first ( repo . tech_stack ) )
344
- { key , { repo , matches } }
345
- else
346
- { key , nil }
347
- end
348
- end )
349
-
350
- updated_cache = Map . merge ( socket . assigns . repo_cache , new_cache )
319
+ Enum . each ( new_keys , fn key ->
320
+ cache_value = fetch_repo_data ( key )
321
+ :ets . insert ( @ repo_cache_table , { key , cache_value } )
322
+ end )
351
323
352
324
csv_data =
353
- Enum . map ( socket . assigns . csv_data , fn
354
- row ->
355
- case Map . get ( updated_cache , repo_key ( row ) ) do
356
- { repo , matches } ->
357
- Map . merge ( row , % {
358
- "repo_owner" => repo . repo_owner ,
359
- "repo_name" => repo . repo_name ,
360
- "tech_stack" => repo . tech_stack ,
361
- "matches" => Enum . map ( matches , & & 1 . user . handle )
362
- } )
363
-
364
- _ ->
365
- row
366
- end
325
+ Enum . map ( socket . assigns . csv_data , fn row ->
326
+ case repo_key ( row ) do
327
+ nil ->
328
+ row
329
+
330
+ key ->
331
+ case :ets . lookup ( @ repo_cache_table , key ) do
332
+ [ { _ , { repo , matches } } ] ->
333
+ Map . merge ( row , % {
334
+ "repo_owner" => repo . repo_owner ,
335
+ "repo_name" => repo . repo_name ,
336
+ "tech_stack" => repo . tech_stack ,
337
+ "matches" => Enum . map ( matches , & & 1 . user . handle )
338
+ } )
339
+
340
+ _ ->
341
+ row
342
+ end
343
+ end
367
344
end )
368
345
369
346
csv_columns =
@@ -372,11 +349,47 @@ defmodule AlgoraWeb.Admin.CampaignLive do
372
349
|> Enum . uniq ( )
373
350
374
351
socket
375
- |> assign ( :repo_cache , updated_cache )
376
352
|> assign ( :csv_data , csv_data )
377
353
|> assign ( :csv_columns , csv_columns )
378
354
end
379
355
356
+ defp fetch_repo_data ( key ) do
357
+ filter =
358
+ case key do
359
+ { owner , name } ->
360
+ token = Admin . token ( )
361
+
362
+ with { :ok , repository } <- Workspace . ensure_repository ( token , owner , name ) ,
363
+ { :ok , _tech_stack } <- Workspace . ensure_repo_tech_stack ( token , repository ) do
364
+ dynamic ( [ r , _u ] , r . id == ^ repository . id )
365
+ else
366
+ _ -> false
367
+ end
368
+
369
+ or g_handle ->
370
+ dynamic ( [ r , u ] , u . handle == ^ org_handle )
371
+ end
372
+
373
+ repo =
374
+ Repo . one (
375
+ from r in Repository ,
376
+ join: u in assoc ( r , :user ) ,
377
+ where: ^ filter ,
378
+ order_by: [ desc: fragment ( "(?->>'stargazers_count')::integer" , r . provider_meta ) ] ,
379
+ select: % {
380
+ repo_owner: u . provider_login ,
381
+ repo_name: r . name ,
382
+ tech_stack: fragment ( "COALESCE(NULLIF(?, '{}'), ?)" , u . tech_stack , r . tech_stack )
383
+ } ,
384
+ limit: 1
385
+ )
386
+
387
+ if repo && repo . tech_stack != [ ] do
388
+ matches = Settings . get_tech_matches ( List . first ( repo . tech_stack ) )
389
+ { repo , matches }
390
+ end
391
+ end
392
+
380
393
defp assign_csv_data ( socket , data ) do
381
394
csv_data =
382
395
case String . trim ( data ) do
0 commit comments