@@ -13,6 +13,7 @@ pub struct Email {
1313 pub user_id : i32 ,
1414 pub email : String ,
1515 pub verified : bool ,
16+ pub primary : bool ,
1617 #[ diesel( deserialize_as = String , serialize_as = String ) ]
1718 pub token : SecretString ,
1819}
@@ -24,46 +25,65 @@ pub struct NewEmail<'a> {
2425 pub email : & ' a str ,
2526 #[ builder( default = false ) ]
2627 pub verified : bool ,
28+ #[ builder( default = false ) ]
29+ pub primary : bool ,
2730}
2831
2932impl NewEmail < ' _ > {
30- pub async fn insert ( & self , conn : & mut AsyncPgConnection ) -> QueryResult < ( ) > {
33+ pub async fn insert ( & self , conn : & mut AsyncPgConnection ) -> QueryResult < Email > {
3134 diesel:: insert_into ( emails:: table)
3235 . values ( self )
33- . execute ( conn)
34- . await ?;
35-
36- Ok ( ( ) )
36+ . returning ( Email :: as_returning ( ) )
37+ . get_result ( conn)
38+ . await
3739 }
3840
39- /// Inserts the email into the database and returns the confirmation token,
40- /// or does nothing if it already exists and returns `None`.
41- pub async fn insert_if_missing (
41+ /// Inserts the email into the database and returns it, unless the user already has a
42+ /// primary email, in which case it will do nothing and return `None`.
43+ pub async fn insert_primary_if_missing (
4244 & self ,
4345 conn : & mut AsyncPgConnection ,
44- ) -> QueryResult < Option < SecretString > > {
45- diesel:: insert_into ( emails:: table)
46- . values ( self )
47- . on_conflict_do_nothing ( )
48- . returning ( emails:: token)
49- . get_result :: < String > ( conn)
50- . await
51- . map ( Into :: into)
52- . optional ( )
46+ ) -> QueryResult < Option < Email > > {
47+ // Check if the user already has a primary email
48+ let primary_count = emails:: table
49+ . filter ( emails:: user_id. eq ( self . user_id ) )
50+ . filter ( emails:: primary. eq ( true ) )
51+ . count ( )
52+ . get_result :: < i64 > ( conn)
53+ . await ?;
54+
55+ if primary_count > 0 {
56+ return Ok ( None ) ; // User already has a primary email
57+ }
58+
59+ self . insert ( conn) . await . map ( Some )
5360 }
5461
55- pub async fn insert_or_update (
62+ // Inserts an email for the user, replacing the primary email if it exists.
63+ pub async fn insert_or_update_primary (
5664 & self ,
5765 conn : & mut AsyncPgConnection ,
58- ) -> QueryResult < SecretString > {
59- diesel:: insert_into ( emails:: table)
60- . values ( self )
61- . on_conflict ( emails:: user_id)
62- . do_update ( )
63- . set ( self )
64- . returning ( emails:: token)
65- . get_result :: < String > ( conn)
66- . await
67- . map ( Into :: into)
66+ ) -> QueryResult < Email > {
67+ // Attempt to update an existing primary email
68+ let updated_email = diesel:: update (
69+ emails:: table
70+ . filter ( emails:: user_id. eq ( self . user_id ) )
71+ . filter ( emails:: primary. eq ( true ) ) ,
72+ )
73+ . set ( (
74+ emails:: email. eq ( self . email ) ,
75+ emails:: verified. eq ( self . verified ) ,
76+ ) )
77+ . returning ( Email :: as_returning ( ) )
78+ . get_result ( conn)
79+ . await
80+ . optional ( ) ?;
81+
82+ if let Some ( email) = updated_email {
83+ Ok ( email)
84+ } else {
85+ // Otherwise, insert a new email
86+ self . insert ( conn) . await
87+ }
6888 }
6989}
0 commit comments