FIX optimisation de certaine requête : il faut trier après pas avant, banane !
[euphorik.git] / modules / erl / euphorik_bd.erl
index bb092fa..89c9836 100755 (executable)
@@ -29,6 +29,7 @@
    connect/0,
    connect/1,
    reset/0,
+   update/0,
    
    % users :
    nouveau_user/2,
@@ -46,6 +47,7 @@
    user_by_login_password/2,
    user_by_mess/1,
    toggle_ek_master/1,
+   css_from_user_cookie/1,
    
    % messages :
    nouveau_message/3,
@@ -55,6 +57,7 @@
    messages/2,\r
    messages/3,
    message_by_id/1,
+   message_by_id_sans_transaction/1,
    messages_by_ids/1,
    message_existe/1,
    reponses/0,
@@ -105,6 +108,7 @@ create() ->
    mnesia:start(),
    create_tables(),
    reset().
+   
 create_tables() ->
    mnesia:create_table(counter, [
       {attributes, record_info(fields, counter)},
@@ -151,7 +155,8 @@ connect(Node) ->
 
 % Efface tous les users, minichat_reponse et minichat.\r
 reset() ->\r
-   mnesia:clear_table(counter),\r
+   mnesia:clear_table(counter),
+   mnesia:clear_table(proprietes),\r
    mnesia:clear_table(user),\r
    mnesia:clear_table(reponse_minichat),\r
    mnesia:clear_table(minichat),
@@ -166,6 +171,37 @@ reset() ->
    end).
 
 
+% Met à jour la bd, compare ?VERSION_BD avec la version dans la table 'proprietes'
+% et exécute les patchs nécessaires.
+update() ->
+   mnesia:transaction(
+      fun() ->
+         case mnesia:read({proprietes, version}) of
+            [#proprietes{nom = Version}] ->
+               update(Version);
+            _ ->
+               erreur
+         end
+      end
+   ).
+   
+
+% Mise à jour de la BD.
+% attention : il est nécessaire de se trouver dans une transaction.
+update(?VERSION_BD) -> fini;
+update(Version) ->
+   patch(Version),
+   update(Version + 1).
+   
+   
+% Applique une modification de la BD pour passer d'une version à la suivante.
+% 1 -> 2
+patch(1) ->
+   ok.
+% 2 -> 3
+%patch(2) ->
+
+
 % Ajoute un nouveau user et le renvoie
 nouveau_user(Pseudo, Cookie) ->
    F = fun() ->
@@ -271,7 +307,13 @@ update_pseudo_user(UserId, Pseudo) ->
 % Attention : pas d'index sur ce champs (la date)   
 print_users(N) ->
    resultat_transaction(mnesia:transaction(fun() ->
-      C = cursor(q([E || E <- qlc:keysort(9, mnesia:table(user), [{order, descending}])])),
+      C = cursor(
+         qlc:keysort(
+            9, 
+            q([E || E <- mnesia:table(user)]),
+            [{order, descending}]
+         )
+      ),
       Users = qlc:next_answers(C, N),
       lists:foreach(
          fun(U) ->
@@ -366,7 +408,19 @@ toggle_ek_master(User_id) ->
       end
    )).
    
+
+% Renvoie une chaine représentant le cookie ou undefined si pas trouvé.
+css_from_user_cookie(Cookie) ->
+   case user_by_cookie(Cookie) of 
+      {ok, User} ->
+         User#user.css;
+      _ ->
+         undefined
+   end.
    
+
+
+
 user_by_login_password(Login, Password) ->
    resultat_transaction(mnesia:transaction(
       fun() ->
@@ -460,12 +514,15 @@ messages(N) ->
 
 
 % Renvoie N messages se trouvant sur la page P
-messages(N, P) ->  
+messages(N, P) ->
    F = fun() ->
-      C = cursor(q([
-         E#minichat{contenu = contenu_message(E)} ||
-         E <- qlc:keysort(2, mnesia:table(minichat), [{order, descending}])
-      ])),
+      C = cursor(
+         qlc:keysort(
+            2, 
+            q([E#minichat{contenu = contenu_message(E)} || E <- mnesia:table(minichat)]),
+            [{order, descending}]
+         )
+      ),
       if P > 1 -> qlc:next_answers(C, N * (P - 1));
          true -> ok
       end,
@@ -484,20 +541,26 @@ messages(Id, N, P) ->
    
 % Renvoie {ok, #minichat} (voir #minichat de euphorik_bd.hrl) à partir de son id.
 message_by_id(Id) ->
-   case resultat_transaction(mnesia:transaction(
+   resultat_transaction(mnesia:transaction(
       fun() ->
-         e(q([E#minichat{contenu = contenu_message(E)} || E <- qlc:keysort(2, mnesia:table(minichat), [{order, ascending}]), Id =:= E#minichat.id]))
+         message_by_id_sans_transaction(Id)
       end
-   )) of
-      [M] -> {ok, M};
-      _ -> erreur
+   )).
+message_by_id_sans_transaction(Id) ->
+   case mnesia:read({minichat, Id}) of
+      [] -> erreur;
+      [M] ->
+         {ok, M#minichat{contenu = contenu_message(M)}}
    end.
    
    
 % Renvoie le contenu d'un message donnée, à utiliser à l'intérieur d'une transaction.
 % TODO : Cette fonction pourrait être remplacé par un "outer-join", est-ce possible avec qlc ?
 contenu_message(E) ->
-   lists:flatten(E#minichat.contenu ++ e(q([T#troll.content || T <- mnesia:table(troll), T#troll.id =:= E#minichat.troll_id]))).
+   case mnesia:read({troll, E#minichat.troll_id}) of
+      [] -> E#minichat.contenu;
+      [T] -> E#minichat.contenu ++ T#troll.content
+   end.
   
 
 % Renvoie une liste de message (voir #minichat de euphorik_bd.hrl) à partir d'une liste d'id (Ids).
@@ -505,8 +568,11 @@ messages_by_ids(Ids) ->
    resultat_transaction(mnesia:transaction(
       fun() ->
          % TODO : optimisations ? serait-ce du O(n) ?
-         Query = q([E || E <- qlc:keysort(2, mnesia:table(minichat), [{order, ascending}]), lists:any(fun(Id) -> Id =:= E#minichat.id end, Ids)]),
-         e(Query)
+         e(qlc:keysort(
+            2,
+            q([E || E <- mnesia:table(minichat), lists:any(fun(Id) -> Id =:= E#minichat.id end, Ids)]),
+            [{order, ascending}]
+         ))
       end
    )).
    
@@ -589,15 +655,15 @@ list_ban() ->
    resultat_transaction(mnesia:transaction(
       fun() ->
          Now = now(),
-         e(q([
+         e(qlc:keysort(1, q([
             {
                IP#ip_table.ip,
                delta_date_minute(date_plus_minutes(IP#ip_table.ban, IP#ip_table.ban_duration), Now),
                e(q([{U#user.pseudo, U#user.login} || U <- mnesia:table(user), U#user.last_ip =:= IP#ip_table.ip]))
             } ||
-            IP <- qlc:keysort(2, mnesia:table(ip_table)),
+            IP <- mnesia:table(ip_table),
             if IP#ip_table.ban =:= undefined -> false; true -> date_plus_minutes(IP#ip_table.ban, IP#ip_table.ban_duration) > Now end
-         ]))
+         ])))
       end
    )).
 
@@ -688,7 +754,7 @@ can_register(IP) ->
 trolls() ->
    resultat_transaction(mnesia:transaction(
       fun() ->
-         e(q([T || T <- qlc:keysort(2, mnesia:table(troll))]))
+         e(qlc:keysort(2, q([T || T <- mnesia:table(troll)])))
       end
    )).
    
@@ -697,7 +763,7 @@ trolls() ->
 trolls(Last_id) ->
    resultat_transaction(mnesia:transaction(
       fun() ->
-         e(q([T || T <- qlc:keysort(2, mnesia:table(troll)), T#troll.id > Last_id, T#troll.date_post =:= undefined]))
+         e(qlc:keysort(2, q([T || T <- mnesia:table(troll), T#troll.id > Last_id, T#troll.date_post =:= undefined])))
       end
    )).
    
@@ -788,7 +854,7 @@ current_troll() ->
    resultat_transaction(mnesia:transaction(
       fun() ->
          % TODO : ya pas moyen de désigner le champs plutot qu'avec un nombre pour le tri ?
-         C = cursor(q([T || T <- qlc:keysort(5, mnesia:table(troll), [{order, descending}]), T#troll.date_post =/= undefined])),
+         C = cursor(qlc:keysort(5, q([T || T <- mnesia:table(troll), T#troll.date_post =/= undefined]), [{order, descending}])),
          R = case qlc:next_answers(C, 1) of
             [T] -> T;
             _ -> aucun