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