@@ -9,6 +9,7 @@ defmodule Asciinema.Recordings do
99
1010 alias Asciinema.Recordings . {
1111 Asciicast ,
12+ AsciicastStats ,
1213 Markers ,
1314 Paths ,
1415 Text
@@ -24,21 +25,21 @@ defmodule Asciinema.Recordings do
2425 def get_asciicast ( id ) do
2526 Asciicast
2627 |> Repo . get ( id )
27- |> Repo . preload ( :user )
28+ |> Repo . preload ( [ :user , :stats ] )
2829 end
2930
3031 def get_public_asciicast ( id ) do
3132 Asciicast
3233 |> Repo . get_by ( id: id , visibility: :public )
33- |> Repo . preload ( :user )
34+ |> Repo . preload ( [ :user , :stats ] )
3435 end
3536
3637 def fetch_asciicast ( id ) , do: OK . required ( get_asciicast ( id ) , :not_found )
3738
3839 def find_asciicast_by_secret_token ( token ) do
3940 from ( a in Asciicast , where: a . secret_token == ^ token )
4041 |> Repo . one ( )
41- |> Repo . preload ( :user )
42+ |> Repo . preload ( [ :user , :stats ] )
4243 end
4344
4445 def lookup_asciicast ( id , allow_non_public_id \\ false ) when is_binary ( id ) do
@@ -65,8 +66,12 @@ defmodule Asciinema.Recordings do
6566 def query ( filters \\ [ ] , order \\ nil )
6667
6768 def query ( filters , order ) do
69+ filters = List . wrap ( filters )
70+ needs_stats_join = order == :popularity or Enum . member? ( filters , :popular )
71+
6872 from ( Asciicast )
6973 |> where ( [ a ] , is_nil ( a . archived_at ) )
74+ |> maybe_join_stats ( needs_stats_join )
7075 |> apply_filters ( filters )
7176 |> sort ( order )
7277 end
@@ -100,7 +105,11 @@ defmodule Asciinema.Recordings do
100105 where ( q , [ a ] , a . featured == true and a . visibility == :public )
101106
102107 :popular ->
103- where ( q , [ a ] , a . popularity_score > 0.0 and a . visibility == :public )
108+ where (
109+ q ,
110+ [ a , stats: s ] ,
111+ a . visibility == :public and s . popularity_score > 0.0
112+ )
104113
105114 :public ->
106115 where ( q , [ a ] , a . visibility == :public )
@@ -118,13 +127,22 @@ defmodule Asciinema.Recordings do
118127 order_by ( q , desc: :id )
119128
120129 :popularity ->
121- order_by ( q , desc: :popularity_score , desc: :id )
130+ order_by ( q , [ a , stats: s ] ,
131+ desc: s . popularity_score ,
132+ desc: s . asciicast_id
133+ )
122134
123135 :random ->
124136 order_by ( q , fragment ( "RANDOM()" ) )
125137 end
126138 end
127139
140+ defp maybe_join_stats ( q , true ) do
141+ join ( q , :inner , [ a ] , s in assoc ( a , :stats ) , as: :stats )
142+ end
143+
144+ defp maybe_join_stats ( q , false ) , do: q
145+
128146 def search ( % Ecto.Query { } = query , q ) do
129147 query
130148 |> from ( )
@@ -558,22 +576,26 @@ defmodule Asciinema.Recordings do
558576
559577 Repo . transact (
560578 fn ->
561- # Update asciicasts with daily views in the window.
579+ # Update stats for asciicasts with daily views in the window.
562580 { count , _ } =
563- from ( a in Asciicast ,
581+ from ( s in AsciicastStats ,
582+ join: a in Asciicast ,
583+ on: a . id == s . asciicast_id ,
564584 join: ds in subquery ( decay_scores ) ,
565- on: ds . asciicast_id == a . id ,
585+ on: ds . asciicast_id == s . asciicast_id ,
566586 where: is_nil ( a . archived_at ) ,
567587 update: [ set: [ popularity_score: ds . decay_score , popularity_dirty: false ] ]
568588 )
569589 |> Repo . update_all ( [ ] )
570590
571- # Reset scores for non-archived asciicasts without views in the window.
591+ # Reset scores for non-archived stats without views in the window.
572592 Repo . update_all (
573- from ( a in Asciicast ,
593+ from ( s in AsciicastStats ,
594+ join: a in Asciicast ,
595+ on: a . id == s . asciicast_id ,
574596 where:
575- a . popularity_score > 0.0 and is_nil ( a . archived_at ) and
576- a . id not in subquery ( ids_with_views )
597+ is_nil ( a . archived_at ) and s . asciicast_id not in subquery ( ids_with_views ) and
598+ ( s . popularity_score > 0.0 or s . popularity_dirty == true )
577599 ) ,
578600 set: [ popularity_score: 0.0 , popularity_dirty: false ]
579601 )
@@ -586,21 +608,23 @@ defmodule Asciinema.Recordings do
586608
587609 :dirty ->
588610 dirty_ids =
589- from ( a in Asciicast ,
590- where: a . popularity_dirty == true and is_nil ( a . archived_at ) ,
591- select: a . id
611+ from ( s in AsciicastStats ,
612+ join: a in Asciicast ,
613+ on: a . id == s . asciicast_id ,
614+ where: s . popularity_dirty == true and is_nil ( a . archived_at ) ,
615+ select: s . asciicast_id
592616 )
593617
594618 decay_scores = from ( dv in decay_scores , where: dv . asciicast_id in subquery ( dirty_ids ) )
595619
596620 Repo . transact (
597621 fn ->
598- # Update dirty asciicasts that have daily views in the window.
622+ # Update dirty stats for asciicasts that have daily views in the window.
599623 { count , _ } =
600- from ( a in Asciicast ,
624+ from ( s in AsciicastStats ,
601625 join: ds in subquery ( decay_scores ) ,
602- on: ds . asciicast_id == a . id ,
603- where: a . id in subquery ( dirty_ids ) ,
626+ on: ds . asciicast_id == s . asciicast_id ,
627+ where: s . asciicast_id in subquery ( dirty_ids ) ,
604628 update: [
605629 set: [
606630 popularity_score: ds . decay_score ,
@@ -610,9 +634,9 @@ defmodule Asciinema.Recordings do
610634 )
611635 |> Repo . update_all ( [ ] )
612636
613- # Clear remaining dirty asciicasts with no daily views.
637+ # Clear remaining dirty stats with no daily views.
614638 Repo . update_all (
615- from ( a in Asciicast , where: a . id in subquery ( dirty_ids ) ) ,
639+ from ( s in AsciicastStats , where: s . asciicast_id in subquery ( dirty_ids ) ) ,
616640 set: [ popularity_score: 0.0 , popularity_dirty: false ]
617641 )
618642
@@ -626,8 +650,19 @@ defmodule Asciinema.Recordings do
626650
627651 def register_view ( asciicast , date \\ Date . utc_today ( ) ) do
628652 Repo . transact ( fn ->
629- from ( a in Asciicast , where: a . id == ^ asciicast . id )
630- |> Repo . update_all ( inc: [ views_count: 1 ] , set: [ popularity_dirty: true ] )
653+ Repo . insert_all (
654+ AsciicastStats ,
655+ [
656+ % {
657+ asciicast_id: asciicast . id ,
658+ popularity_score: 0.0 ,
659+ total_views: 1 ,
660+ popularity_dirty: true
661+ }
662+ ] ,
663+ on_conflict: [ inc: [ total_views: 1 ] , set: [ popularity_dirty: true ] ] ,
664+ conflict_target: [ :asciicast_id ]
665+ )
631666
632667 Repo . insert_all (
633668 "asciicast_daily_views" ,
0 commit comments