⭐ Moe-Counter Compatible Website Hit Counter Written in Gleam mayu.due.moe
hit-counter svg moe
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(database): Optimise queries

Fuwn 07ed2a89 397f7ea9

+33 -55
+33 -55
src/database.gleam
··· 1 1 import birl 2 2 import gleam/dynamic 3 - import gleam/io 3 + import gleam/option 4 4 import gleam/string 5 5 import sqlight 6 + import wisp 6 7 7 8 pub type Counter { 8 9 Counter(name: String, num: Int, created_at: String, updated_at: String) 9 10 } 10 11 11 - fn check_error(result, message) { 12 - case result { 13 - Ok(_) -> Nil 14 - Error(_) -> { 15 - io.print(message) 16 - 17 - Nil 18 - } 19 - } 20 - } 21 - 22 12 pub fn setup(connection) { 23 - check_error( 13 + let _ = 24 14 sqlight.exec( 25 15 "pragma foreign_keys = off; 26 16 ··· 30 20 num int not null default (0) 31 21 ) strict;", 32 22 connection, 33 - ), 34 - "Failed to create table tb_count", 35 - ) 23 + ) 36 24 37 25 let add_column = fn(name) { 38 26 let _ = ··· 50 38 Nil 51 39 } 52 40 53 - pub fn add_counter(connection, name) { 54 - sqlight.query( 55 - "insert into tb_count (name) values (?);", 56 - with: [sqlight.text(name)], 57 - on: connection, 58 - expecting: dynamic.optional(dynamic.int), 59 - ) 60 - } 61 - 62 41 fn sqlite_now() { 63 42 birl.to_iso8601(birl.utc_now()) 64 43 |> string.slice(0, 19) ··· 67 46 68 47 pub fn get_counter(connection, name) { 69 48 case name { 70 - "demo" -> Ok(Counter("demo", 0_123_456_789, "", "")) 49 + "demo" -> Ok(Counter("demo", 1_234_567_890, "", "")) 71 50 _ -> { 72 - check_error( 73 - sqlight.query( 74 - "insert or ignore into tb_count (name, created_at) values (?, ?);", 75 - with: [sqlight.text(name), sqlight.text(sqlite_now())], 76 - on: connection, 77 - expecting: dynamic.optional(dynamic.int), 78 - ), 79 - "Failed to insert or ignore into tb_count", 80 - ) 81 - check_error( 82 - sqlight.query( 83 - "update tb_count set num = num + 1, updated_at = ? where name = ?;", 84 - with: [sqlight.text(sqlite_now()), sqlight.text(name)], 85 - on: connection, 86 - expecting: dynamic.int, 87 - ), 88 - "Failed to update tb_count", 89 - ) 90 - 91 51 case 92 52 sqlight.query( 93 - "select name, num, created_at, updated_at from tb_count where name = ?;", 94 - with: [sqlight.text(name)], 53 + "INSERT INTO tb_count (name, created_at, updated_at, num) 54 + VALUES (?1, ?2, ?2, 1) 55 + ON CONFLICT(name) DO UPDATE SET 56 + num = tb_count.num + 1, 57 + updated_at = excluded.updated_at 58 + RETURNING name, num, created_at, updated_at;", 59 + with: [sqlight.text(name), sqlight.text(sqlite_now())], 95 60 on: connection, 96 61 expecting: dynamic.tuple4( 97 62 dynamic.string, 98 63 dynamic.int, 99 - dynamic.string, 100 - dynamic.string, 64 + dynamic.optional(dynamic.string), 65 + dynamic.optional(dynamic.string), 101 66 ), 102 67 ) 103 68 { 104 - Ok([first_element]) -> { 69 + Ok([row]) -> 105 70 Ok(Counter( 106 - first_element.0, 107 - first_element.1, 108 - first_element.2, 109 - first_element.3, 71 + row.0, 72 + row.1, 73 + option.unwrap(row.2, ""), 74 + option.unwrap(row.3, ""), 110 75 )) 76 + Ok([]) -> { 77 + wisp.log_error("Database query returned no rows unexpectedly.") 78 + 79 + Error("Unreachable entity") 111 80 } 112 - _ -> Error("Unreachable entity") 81 + Ok([_, _, ..]) -> { 82 + wisp.log_error("Database query returned multiple rows unexpectedly.") 83 + 84 + Error("Unreachable entity") 85 + } 86 + Error(_) -> { 87 + wisp.log_error("Database query failed.") 88 + 89 + Error("Database operation failed") 90 + } 113 91 } 114 92 } 115 93 }