a mini social media app for small communities

fix search page a bit and add user search code

Changed files
+80 -9
src
database
entity
templates
+1 -1
src/database/post.v
··· 160 160 return results 161 161 } 162 162 163 - // search_for_post searches for posts matching the given query. 163 + // search_for_posts searches for posts matching the given query. 164 164 // todo: query options/filters, such as user:beep, !excluded-text, etc 165 165 pub fn (app &DatabaseAccess) search_for_posts(query string, limit int, offset int) []PostSearchResult { 166 166 sql_query := "\
+21
src/database/user.v
··· 206 206 207 207 return true 208 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 212 + pub 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 + }
+1 -1
src/entity/post.v
··· 18 18 posted_at time.Time = time.now() 19 19 } 20 20 21 - // Post.from_row creates a post from the given database row. 21 + // Post.from_row creates a post object from the given database row. 22 22 // see src/database/post.v#search_for_posts for usage. 23 23 @[inline] 24 24 pub fn Post.from_row(row pg.Row) Post {
+27
src/entity/user.v
··· 1 1 module entity 2 2 3 + import db.pg 3 4 import time 5 + import util 4 6 5 7 pub struct User { 6 8 pub mut: ··· 37 39 .replace(user.password, '*'.repeat(16)) 38 40 .replace(user.password_salt, '*'.repeat(16)) 39 41 } 42 + 43 + // User.from_row creates a user object from the given database row. 44 + // see src/database/user.v#search_for_users for usage. 45 + @[inline] 46 + pub fn User.from_row(row pg.Row) User { 47 + // this throws a cgen error when put in User{} 48 + //todo: report this 49 + created_at := time.parse(util.or_throw[string](row.vals[10])) or { panic(err) } 50 + 51 + return User{ 52 + id: util.or_throw[string](row.vals[0]).int() 53 + username: util.or_throw[string](row.vals[1]) 54 + nickname: if row.vals[2] == none { ?string(none) } else { 55 + util.or_throw[string](row.vals[3]) 56 + } 57 + password: 'haha lol, nope' 58 + password_salt: 'haha lol, nope' 59 + muted: util.map_or_throw[string, bool](row.vals[5], |it| it.bool()) 60 + admin: util.map_or_throw[string, bool](row.vals[6], |it| it.bool()) 61 + theme: util.or_throw[string](row.vals[7]) 62 + bio: util.or_throw[string](row.vals[8]) 63 + pronouns: util.or_throw[string](row.vals[9]) 64 + created_at: created_at 65 + } 66 + }
+30 -7
src/templates/search.html
··· 29 29 query.value = params.get('q') 30 30 } 31 31 32 + let limit = params.get('limit') 33 + if (!limit) { 34 + limit = 10 35 + } 36 + 32 37 let offset = params.get('offset') 33 - if (!offset) { 38 + if (!limit) { 34 39 offset = 0 35 40 } 36 41 ··· 38 43 results.innerHTML = '' // yeet the children! 39 44 pages.innerHTML = '' // yeet more children! 40 45 41 - const search_results = await search(query.value, 10, Number(offset.value)) 46 + console.log('search: ', query.value, limit, offset) 47 + 48 + const search_results = await search(query.value, limit, offset) 42 49 if (search_results.length >= 0) { 43 50 for (result of search_results) { 44 51 // same as components/post_mini.html except js ··· 66 73 67 74 // set up pagination 68 75 if (offset > 0) { 69 - const back_link = document.createElement('a') 76 + // creates a separator 77 + function sep() { 78 + const span = document.createElement('span') 79 + span.innerText = ' - ' 80 + pages.appendChild(span) 81 + } 82 + 83 + const first_link = document.createElement('a') 70 84 // we escape the $ here because otherwise V will try to perform replacements at compile-time. 71 85 //todo: report this, this behaviour should be changed or at least looked into further. 72 - back_link.href = '/search?q=' + query.value + '&limit=10&offset=' + Math.min(0, offset.value - 10) 73 - back_link.innerText = '<-' 86 + first_link.href = '/search?q=' + query.value + '&limit=' + limit + '&offset=0' 87 + first_link.innerText = '0' 88 + pages.appendChild(first_link) 89 + 90 + sep() 91 + 92 + const back_link = document.createElement('a') 93 + back_link.href = '/search?q=' + query.value + '&limit=' + limit + '&offset=' + Math.min(0, offset - 10) 94 + back_link.innerText = '<' 74 95 pages.appendChild(back_link) 96 + 97 + sep() 75 98 76 99 const next_link = document.createElement('a') 77 - next_link.href = '/search?q=' + query.value + '&limit=10&offset=' + (offset.value + 10) 78 - next_link.innerText = '->' 100 + next_link.href = '/search?q=' + query.value + '&limit=' + limit + '&offset=' + (offset + 10) 101 + next_link.innerText = '>' 79 102 pages.appendChild(next_link) 80 103 } 81 104 } else {