a mini social media app for small communities
1module database 2 3import entity { User, Notification, Like, LikeCache, Post } 4import util 5 6// new_user creates a new user and returns their struct after creation. 7pub fn (app &DatabaseAccess) new_user(user User) ?User { 8 sql app.db { 9 insert user into User 10 } or { 11 eprintln('failed to insert user ${user}') 12 return none 13 } 14 15 println('reg: ${user.username}') 16 17 return app.get_user_by_name(user.username) 18} 19 20// set_username sets the given user's username, returns true if this succeeded 21// and false otherwise. 22pub fn (app &DatabaseAccess) set_username(user_id int, new_username string) bool { 23 sql app.db { 24 update User set username = new_username where id == user_id 25 } or { 26 eprintln('failed to update username for ${user_id}') 27 return false 28 } 29 return true 30} 31 32// set_password sets the given user's password, returns true if this succeeded 33// and false otherwise. 34pub fn (app &DatabaseAccess) set_password(user_id int, hashed_new_password string) bool { 35 sql app.db { 36 update User set password = hashed_new_password where id == user_id 37 } or { 38 eprintln('failed to update password for ${user_id}') 39 return false 40 } 41 return true 42} 43 44// set_nickname sets the given user's nickname, returns true if this succeeded 45// and false otherwise. 46pub fn (app &DatabaseAccess) set_nickname(user_id int, new_nickname ?string) bool { 47 sql app.db { 48 update User set nickname = new_nickname where id == user_id 49 } or { 50 eprintln('failed to update nickname for ${user_id}') 51 return false 52 } 53 return true 54} 55 56// set_muted sets the given user's muted status, returns true if this succeeded 57// and false otherwise. 58pub fn (app &DatabaseAccess) set_muted(user_id int, muted bool) bool { 59 sql app.db { 60 update User set muted = muted where id == user_id 61 } or { 62 eprintln('failed to update muted status for ${user_id}') 63 return false 64 } 65 return true 66} 67 68// set_theme sets the given user's theme url, returns true if this succeeded and 69// false otherwise. 70pub fn (app &DatabaseAccess) set_theme(user_id int, theme ?string) bool { 71 sql app.db { 72 update User set theme = theme where id == user_id 73 } or { 74 eprintln('failed to update theme url for ${user_id}') 75 return false 76 } 77 return true 78} 79 80// set_pronouns sets the given user's pronouns, returns true if this succeeded 81// and false otherwise. 82pub fn (app &DatabaseAccess) set_pronouns(user_id int, pronouns string) bool { 83 sql app.db { 84 update User set pronouns = pronouns where id == user_id 85 } or { 86 eprintln('failed to update pronouns for ${user_id}') 87 return false 88 } 89 return true 90} 91 92// set_bio sets the given user's bio, returns true if this succeeded and false 93// otherwise. 94pub fn (app &DatabaseAccess) set_bio(user_id int, bio string) bool { 95 sql app.db { 96 update User set bio = bio where id == user_id 97 } or { 98 eprintln('failed to update bio for ${user_id}') 99 return false 100 } 101 return true 102} 103 104// get_user_by_name gets a user by their username, returns none if the user was 105// not found. 106pub fn (app &DatabaseAccess) get_user_by_name(username string) ?User { 107 users := sql app.db { 108 select from User where username == username 109 } or { [] } 110 if users.len != 1 { 111 return none 112 } 113 return users[0] 114} 115 116// get_user_by_id gets a user by their id, returns none if the user was not 117// found. 118pub fn (app &DatabaseAccess) get_user_by_id(id int) ?User { 119 users := sql app.db { 120 select from User where id == id 121 } or { [] } 122 if users.len != 1 { 123 return none 124 } 125 return users[0] 126} 127 128// get_users returns all users. 129pub fn (app &DatabaseAccess) get_users() []User { 130 users := sql app.db { 131 select from User 132 } or { [] } 133 return users 134} 135 136// does_user_like_post returns true if a user likes the given post. 137pub fn (app &DatabaseAccess) does_user_like_post(user_id int, post_id int) bool { 138 likes := app.db.exec_param2('SELECT id, is_like FROM "Like" WHERE user_id = $1 AND post_id = $2', user_id.str(), post_id.str()) or { [] } 139 if likes.len > 1 { 140 // something is very wrong lol 141 eprintln('does_user_like_post: a user somehow got two or more likes on the same post (user: ${user_id}, post: ${post_id})') 142 } else if likes.len == 0 { 143 return false 144 } 145 return util.or_throw(likes.first().vals[1]).bool() 146} 147 148// does_user_dislike_post returns true if a user dislikes the given post. 149pub fn (app &DatabaseAccess) does_user_dislike_post(user_id int, post_id int) bool { 150 likes := app.db.exec_param2('SELECT id, is_like FROM "Like" WHERE user_id = $1 AND post_id = $2', user_id.str(), post_id.str()) or { [] } 151 if likes.len > 1 { 152 // something is very wrong lol 153 eprintln('does_user_dislike_post: a user somehow got two or more likes on the same post (user: ${user_id}, post: ${post_id})') 154 } else if likes.len == 0 { 155 return false 156 } 157 return !util.or_throw(likes.first().vals[1]).bool() 158} 159 160// does_user_like_or_dislike_post returns true if a user likes *or* dislikes the 161// given post. 162pub fn (app &DatabaseAccess) does_user_like_or_dislike_post(user_id int, post_id int) bool { 163 likes := app.db.exec_param2('SELECT id FROM "Like" WHERE user_id = $1 AND post_id = $2', user_id.str(), post_id.str()) or { [] } 164 if likes.len > 1 { 165 // something is very wrong lol 166 eprintln('does_user_like_or_dislike_post: a user somehow got two or more likes on the same post (user: ${user_id}, post: ${post_id})') 167 } 168 return likes.len == 1 169} 170 171// delete_user deletes the given user and their data, returns true if this 172// succeeded and false otherwise. 173pub fn (app &DatabaseAccess) delete_user(user_id int) bool { 174 sql app.db { 175 delete from User where id == user_id 176 delete from Like where user_id == user_id 177 delete from Notification where user_id == user_id 178 } or { 179 return false 180 } 181 182 // delete posts and their likes 183 posts_from_this_user := app.db.exec_param('SELECT id FROM "Post" WHERE author_id = $1', user_id.str()) or { [] } 184 185 for post in posts_from_this_user { 186 id := util.or_throw(post.vals[0]).int() 187 sql app.db { 188 delete from Like where post_id == id 189 delete from LikeCache where post_id == id 190 } or { 191 eprintln('failed to delete like cache for post during user deletion: ${id}') 192 } 193 } 194 195 sql app.db { 196 delete from Post where author_id == user_id 197 } or { 198 eprintln('failed to delete posts by deleting user: ${user_id}') 199 } 200 201 return true 202} 203 204// search_for_users searches for posts matching the given query. 205// todo: query options/filters, such as created-after:<date>, created-before:<date>, etc 206pub fn (app &DatabaseAccess) search_for_users(query string, limit int, offset int) []User { 207 queried_users := app.db.exec_param_many('SELECT * FROM search_for_users($1, $2, $3)', [query, limit.str(), offset.str()]) or { 208 eprintln('search_for_users error in app.db.error: ${err}') 209 [] 210 } 211 users := queried_users.map(|it| User.from_row(it)) 212 return users 213}