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}