wip: currently rewriting the project as a full stack application tangled.org/kacaii.dev/sigo
gleam
0
fork

Configure Feed

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

:sparkles: finish dashboard stats route

closes issue #8

Kacaii 10f17d70 2ea81e74

+362 -208
+19 -9
README.md
··· 8 8 9 9 ## Routes 10 10 11 - | Route | Description | Method | 12 - | --------------------------- | ---------------------------------------- | ----------- | 13 - | /api/user/signup | Register a new user account | POST (Form) | 14 - | /api/user/login | Login with your user account | POST (Form) | 15 - | /api/occurrence/new | Register new occurrence | POST (Form) | 16 - | /api/user/{id}/occurrences | Get all occurrences applied by this user | GET | 17 - | /api/user/{id}/crew_members | List fellow brigade members of this user | GET | 18 - | /api/brigade/{id}/members | List brigade members | GET | 11 + | Route | Description | Method | 12 + | --------------------------- | -------------------------------------------- | ----------- | 13 + | /api/user/signup | Register a new user account | POST (Form) | 14 + | /api/user/login | Login with your user account | POST (Form) | 15 + | /api/occurrence/new | Register new occurrence | POST (Form) | 16 + | /api/dashboard/stats | Retrieves useful information from the server | GET | 17 + | /api/user/{id}/occurrences | Get all occurrences applied by this user | GET | 18 + | /api/user/{id}/crew_members | List fellow brigade members of this user | GET | 19 + | /api/brigade/{id}/members | List brigade members | GET | 19 20 20 21 ## Entity RelationShip Diagram 21 22 ··· 79 80 TEXT description 80 81 POINT location 81 82 TEXT reference_point 82 - NUMERIC(2) loss_percentage 83 + TEXT vehicle_code 84 + UUID[] participants_id 83 85 TIMESTAMP created_at 84 86 TIMESTAMP updated_at 85 87 TIMESTAMP resolved_at 88 + } 89 + 90 + occurrence_brigade_member }o--o{ user_account : participant 91 + occurrence_brigade_member }o--o{ brigade : participates_of 92 + occurrence_brigade_member { 93 + UUID id 94 + UUID user_id 95 + UUID brigade_id 86 96 } 87 97 ``` 88 98
+3 -1
justfile
··· 38 38 [group(' postgres')] 39 39 [group(' ship')] 40 40 @rebuild_empty: 41 - @psql senac_brigade -f priv/sql/create/triggers.sql 41 + @psql senac_brigade -f priv/sql/drop.sql 42 42 @psql senac_brigade -f priv/sql/create/tables.sql 43 + @psql senac_brigade -f priv/sql/create/triggers.sql 43 44 @psql senac_brigade -f priv/sql/create/functions.sql 45 + @psql senac_brigade -f priv/sql/create/views.sql 44 46 45 47 # 󰜉 Rebuild the database with values in it 46 48 [group(' postgres')]
-22
priv/sql/create/tables.sql
··· 1 - --  DROP ------------------------------------------------------------------- 2 1 BEGIN; 3 - 4 - DROP INDEX IF EXISTS public.idx_brigade_membership_brigade_id; 5 - DROP INDEX IF EXISTS public.idx_brigade_membership_user_id; 6 - DROP INDEX IF EXISTS public.idx_occurrence_applicant_id; 7 - DROP INDEX IF EXISTS public.idx_user_registration; 8 - DROP INDEX IF EXISTS public.idx_user_id; 9 - DROP INDEX IF EXISTS public.idx_occurrence_id; 10 - DROP INDEX IF EXISTS public.idx_occurrence_brigade_member_user_id; 11 - DROP INDEX IF EXISTS public.idx_occurrence_brigade_member_occurrence_id; 12 - 13 - -- pgt-ignore-start lint/safety/banDropTable: We are resetting the Database 14 - DROP TABLE IF EXISTS public.occurrence; 15 - DROP TABLE IF EXISTS public.occurrence_category; 16 - DROP TABLE IF EXISTS public.occurrence_brigade_member; 17 - DROP TABLE IF EXISTS public.brigade_membership; 18 - DROP TABLE IF EXISTS public.brigade; 19 - DROP TABLE IF EXISTS public.user_account; 20 - DROP TABLE IF EXISTS public.user_role; 21 - -- pgt-ignore-end lint/safety/banDropTable 22 - 23 - --  CREATE ----------------------------------------------------------------- 24 2 25 3 CREATE TABLE IF NOT EXISTS public.user_role ( 26 4 id UUID PRIMARY KEY DEFAULT UUIDV7(),
-4
priv/sql/create/triggers.sql
··· 1 - DROP FUNCTION IF EXISTS public.dump_occurrence_participants; 2 - DROP TRIGGER IF EXISTS tgr_insert_member_participation ON occurrence; 3 - 4 - --  5 1 CREATE OR REPLACE FUNCTION public.dump_occurrence_participants() 6 2 RETURNS TRIGGER AS $$ 7 3 BEGIN
+21
priv/sql/create/views.sql
··· 1 + CREATE OR REPLACE VIEW vw_count_active_occurrences AS 2 + SELECT COUNT(oc.id) AS count 3 + FROM public.occurrence AS oc 4 + WHERE oc.resolved_at IS NULL; 5 + 6 + ----------------------------------------------------- 7 + CREATE OR REPLACE VIEW vw_count_recent_occurrences AS 8 + SELECT COUNT(oc.id) AS count 9 + FROM public.occurrence AS oc 10 + WHERE oc.created_at >= (NOW() - '1 day'::INTERVAL); 11 + 12 + ---------------------------------------------------- 13 + CREATE OR REPLACE VIEW vw_count_total_occurrences AS 14 + SELECT COUNT(oc.id) AS count 15 + FROM public.occurrence AS oc; 16 + 17 + ------------------------------------------------------ 18 + CREATE OR REPLACE VIEW vw_count_active_brigades AS 19 + SELECT COUNT(id) 20 + FROM public.brigade 21 + WHERE is_active = TRUE;
+27
priv/sql/drop.sql
··· 1 + -------------------------------------------------------------------------------- 2 + DROP VIEW IF EXISTS vw_count_active_occurrences; 3 + DROP VIEW IF EXISTS vw_count_recent_occurrences; 4 + DROP VIEW IF EXISTS vw_count_total_occurrences; 5 + DROP VIEW IF EXISTS vw_count_active_brigades; 6 + 7 + -------------------------------------------------------------------------------- 8 + DROP TRIGGER IF EXISTS tgr_insert_member_participation ON occurrence; 9 + DROP FUNCTION IF EXISTS public.dump_occurrence_participants; 10 + -------------------------------------------------------------------------------- 11 + 12 + DROP INDEX IF EXISTS public.idx_brigade_membership_brigade_id; 13 + DROP INDEX IF EXISTS public.idx_brigade_membership_user_id; 14 + DROP INDEX IF EXISTS public.idx_occurrence_applicant_id; 15 + DROP INDEX IF EXISTS public.idx_user_registration; 16 + DROP INDEX IF EXISTS public.idx_occurrence_brigade_member_user_id; 17 + DROP INDEX IF EXISTS public.idx_occurrence_brigade_member_occurrence_id; 18 + 19 + -- pgt-ignore-start lint/safety/banDropTable: We are resetting the Database 20 + DROP TABLE IF EXISTS public.occurrence; 21 + DROP TABLE IF EXISTS public.occurrence_category; 22 + DROP TABLE IF EXISTS public.occurrence_brigade_member; 23 + DROP TABLE IF EXISTS public.brigade_membership; 24 + DROP TABLE IF EXISTS public.brigade; 25 + DROP TABLE IF EXISTS public.user_account; 26 + DROP TABLE IF EXISTS public.user_role; 27 + -- pgt-ignore-end lint/safety/banDropTable
+5
src/app/router.gleam
··· 8 8 //// Unmatched routes return a 404 Not Found response. 9 9 10 10 import app/routes/brigade/get_brigade_members 11 + import app/routes/dashboard 11 12 import app/routes/occurrence/register_new_occurrence 12 13 import app/routes/user/get_crew_members 13 14 import app/routes/user/get_ocurrences_by_applicant ··· 25 26 //  Authorization routes 26 27 http.Post, ["api", "user", "signup"] -> signup.handle_form(request:, ctx:) 27 28 http.Post, ["api", "user", "login"] -> login.handle_form(request:, ctx:) 29 + 30 + // 󰨇 Dashboard stats 31 + http.Get, ["api", "dashboard", "stats"] -> 32 + dashboard.handle_request(request:, ctx:) 28 33 29 34 //  User data routes 30 35 http.Get, ["api", "user", id, "occurrences"] ->
-33
src/app/routes/brigade/sql.gleam
··· 9 9 import pog 10 10 import youid/uuid.{type Uuid} 11 11 12 - /// A row you get from running the `count_active_brigades` query 13 - /// defined in `./src/app/routes/brigade/sql/count_active_brigades.sql`. 14 - /// 15 - /// > 🐿️ This type definition was generated automatically using v4.4.1 of the 16 - /// > [squirrel package](https://github.com/giacomocavalieri/squirrel). 17 - /// 18 - pub type CountActiveBrigadesRow { 19 - CountActiveBrigadesRow(count: Int) 20 - } 21 - 22 - /// 󰆙 Counts the number of active brigades in the database. 23 - /// 24 - /// > 🐿️ This function was generated automatically using v4.4.1 of 25 - /// > the [squirrel package](https://github.com/giacomocavalieri/squirrel). 26 - /// 27 - pub fn count_active_brigades( 28 - db: pog.Connection, 29 - ) -> Result(pog.Returned(CountActiveBrigadesRow), pog.QueryError) { 30 - let decoder = { 31 - use count <- decode.field(0, decode.int) 32 - decode.success(CountActiveBrigadesRow(count:)) 33 - } 34 - 35 - "-- 󰆙 Counts the number of active brigades in the database. 36 - SELECT COUNT(id) 37 - FROM public.brigade 38 - WHERE is_active = TRUE; 39 - " 40 - |> pog.query 41 - |> pog.returning(decoder) 42 - |> pog.execute(db) 43 - } 44 - 45 12 /// A row you get from running the `get_brigade_members` query 46 13 /// defined in `./src/app/routes/brigade/sql/get_brigade_members.sql`. 47 14 ///
-4
src/app/routes/brigade/sql/count_active_brigades.sql
··· 1 - -- 󰆙 Counts the number of active brigades in the database. 2 - SELECT COUNT(id) 3 - FROM public.brigade 4 - WHERE is_active = TRUE;
+51 -10
src/app/routes/dashboard.gleam
··· 1 - import app/routes/occurrence.{type Occurrence} 2 - import app/routes/occurrence/count_active_occurrences 1 + import app/routes/dashboard/sql 3 2 import app/web.{type Context} 3 + import gleam/http 4 + import gleam/json 5 + import gleam/list 4 6 import gleam/result 5 7 import wisp 6 8 ··· 9 11 request request: wisp.Request, 10 12 ctx ctx: Context, 11 13 ) -> wisp.Response { 14 + use <- wisp.require_method(request, http.Get) 15 + 12 16 let query_result = { 13 - use active_occurrences <- result.try({ 14 - count_active_occurrences.handle_query(ctx:) 15 - }) 16 - todo 17 + use returned <- result.try( 18 + sql.get_dashboard_stats(ctx.conn) 19 + |> result.replace_error(DatabaseError), 20 + ) 21 + use row <- result.try( 22 + list.first(returned.rows) 23 + |> result.replace_error(DatabaseReturnedEmptyRow), 24 + ) 25 + 26 + Ok(get_dashboard_stats_row_to_json(row)) 27 + } 28 + 29 + case query_result { 30 + Ok(value) -> wisp.json_response(json.to_string(value), 200) 31 + Error(err) -> { 32 + case err { 33 + DatabaseError -> 34 + wisp.internal_server_error() 35 + |> wisp.set_body(wisp.Text( 36 + "Ocorreu um erro ao acessar o Banco de Dados", 37 + )) 38 + DatabaseReturnedEmptyRow -> 39 + wisp.internal_server_error() 40 + |> wisp.set_body(wisp.Text("O Banco de dados não retornou resultados")) 41 + } 42 + } 17 43 } 44 + } 18 45 19 - todo 46 + fn get_dashboard_stats_row_to_json( 47 + get_dashboard_stats_row: sql.GetDashboardStatsRow, 48 + ) -> json.Json { 49 + let sql.GetDashboardStatsRow( 50 + active_brigades_count:, 51 + total_occurrences_count:, 52 + active_occurrences_count:, 53 + recent_occurrences_count:, 54 + ) = get_dashboard_stats_row 55 + json.object([ 56 + #("active_brigades_count", json.int(active_brigades_count)), 57 + #("total_occurrences_count", json.int(total_occurrences_count)), 58 + #("active_occurrences_count", json.int(active_occurrences_count)), 59 + #("recent_occurrences_count", json.int(recent_occurrences_count)), 60 + ]) 20 61 } 21 62 22 - // TODO: Docs 23 - pub type DashBoard { 24 - DashBoard(active_occurrences: Int, recent_occurrence: List(Occurrence)) 63 + pub type GetDashboardStatsError { 64 + DatabaseReturnedEmptyRow 65 + DatabaseError 25 66 }
+68
src/app/routes/dashboard/sql.gleam
··· 1 + //// This module contains the code to run the sql queries defined in 2 + //// `./src/app/routes/dashboard/sql`. 3 + //// > 🐿️ This module was generated automatically using v4.4.1 of 4 + //// > the [squirrel package](https://github.com/giacomocavalieri/squirrel). 5 + //// 6 + 7 + import gleam/dynamic/decode 8 + import pog 9 + 10 + /// A row you get from running the `get_dashboard_stats` query 11 + /// defined in `./src/app/routes/dashboard/sql/get_dashboard_stats.sql`. 12 + /// 13 + /// > 🐿️ This type definition was generated automatically using v4.4.1 of the 14 + /// > [squirrel package](https://github.com/giacomocavalieri/squirrel). 15 + /// 16 + pub type GetDashboardStatsRow { 17 + GetDashboardStatsRow( 18 + active_brigades_count: Int, 19 + total_occurrences_count: Int, 20 + active_occurrences_count: Int, 21 + recent_occurrences_count: Int, 22 + ) 23 + } 24 + 25 + /// 26 + /// 27 + /// > 🐿️ This function was generated automatically using v4.4.1 of 28 + /// > the [squirrel package](https://github.com/giacomocavalieri/squirrel). 29 + /// 30 + pub fn get_dashboard_stats( 31 + db: pog.Connection, 32 + ) -> Result(pog.Returned(GetDashboardStatsRow), pog.QueryError) { 33 + let decoder = { 34 + use active_brigades_count <- decode.field(0, decode.int) 35 + use total_occurrences_count <- decode.field(1, decode.int) 36 + use active_occurrences_count <- decode.field(2, decode.int) 37 + use recent_occurrences_count <- decode.field(3, decode.int) 38 + decode.success(GetDashboardStatsRow( 39 + active_brigades_count:, 40 + total_occurrences_count:, 41 + active_occurrences_count:, 42 + recent_occurrences_count:, 43 + )) 44 + } 45 + 46 + "-- 47 + SELECT 48 + ( 49 + SELECT count 50 + FROM public.vw_count_active_brigades 51 + ) AS active_brigades_count, 52 + ( 53 + SELECT count 54 + FROM public.vw_count_total_occurrences 55 + ) AS total_occurrences_count, 56 + ( 57 + SELECT count 58 + FROM public.vw_count_active_occurrences 59 + ) AS active_occurrences_count, 60 + ( 61 + SELECT count FROM 62 + public.vw_count_recent_occurrences 63 + ) AS recent_occurrences_count; 64 + " 65 + |> pog.query 66 + |> pog.returning(decoder) 67 + |> pog.execute(db) 68 + }
+18
src/app/routes/dashboard/sql/get_dashboard_stats.sql
··· 1 + -- 2 + SELECT 3 + ( 4 + SELECT count 5 + FROM public.vw_count_active_brigades 6 + ) AS active_brigades_count, 7 + ( 8 + SELECT count 9 + FROM public.vw_count_total_occurrences 10 + ) AS total_occurrences_count, 11 + ( 12 + SELECT count 13 + FROM public.vw_count_active_occurrences 14 + ) AS active_occurrences_count, 15 + ( 16 + SELECT count FROM 17 + public.vw_count_recent_occurrences 18 + ) AS recent_occurrences_count;
-32
src/app/routes/occurrence/count_active_occurrences.gleam
··· 1 - import app/routes/occurrence/sql 2 - import app/web.{type Context} 3 - import gleam/list 4 - import gleam/result 5 - 6 - // TODO: Documentation 7 - pub fn handle_query( 8 - ctx ctx: Context, 9 - ) -> Result(Int, CountActiveOccurrencesError) { 10 - let query_result = { 11 - use returned <- result.try( 12 - sql.count_active_occurrences(ctx.conn) 13 - |> result.replace_error(DataBaseError), 14 - ) 15 - use row <- result.try( 16 - list.first(returned.rows) 17 - |> result.replace_error(DataBaseReturnedEmptyRow), 18 - ) 19 - 20 - Ok(row.count) 21 - } 22 - 23 - case query_result { 24 - Error(err) -> Error(err) 25 - Ok(count) -> Ok(count) 26 - } 27 - } 28 - 29 - pub opaque type CountActiveOccurrencesError { 30 - DataBaseReturnedEmptyRow 31 - DataBaseError 32 - }
+134 -12
src/app/routes/occurrence/sql.gleam
··· 5 5 //// 6 6 7 7 import gleam/dynamic/decode 8 + import gleam/option.{type Option} 9 + import gleam/time/timestamp.{type Timestamp} 8 10 import pog 9 11 import youid/uuid.{type Uuid} 10 12 11 - /// A row you get from running the `count_active_occurrences` query 12 - /// defined in `./src/app/routes/occurrence/sql/count_active_occurrences.sql`. 13 + /// A row you get from running the `get_occurences_by_applicant` query 14 + /// defined in `./src/app/routes/occurrence/sql/get_occurences_by_applicant.sql`. 13 15 /// 14 16 /// > 🐿️ This type definition was generated automatically using v4.4.1 of the 15 17 /// > [squirrel package](https://github.com/giacomocavalieri/squirrel). 16 18 /// 17 - pub type CountActiveOccurrencesRow { 18 - CountActiveOccurrencesRow(count: Int) 19 + pub type GetOccurencesByApplicantRow { 20 + GetOccurencesByApplicantRow( 21 + id: Uuid, 22 + description: Option(String), 23 + category: Option(String), 24 + subcategory: Option(String), 25 + created_at: Option(Timestamp), 26 + resolved_at: Option(Timestamp), 27 + location: List(Float), 28 + reference_point: Option(String), 29 + ) 19 30 } 20 31 21 - /// 󰆙 Counts the number of active occurrences 32 + ///  Retrieves all occurrences associated with a user, 33 + /// including detailed category information and resolution status. 22 34 /// 23 35 /// > 🐿️ This function was generated automatically using v4.4.1 of 24 36 /// > the [squirrel package](https://github.com/giacomocavalieri/squirrel). 25 37 /// 26 - pub fn count_active_occurrences( 38 + pub fn get_occurences_by_applicant( 27 39 db: pog.Connection, 28 - ) -> Result(pog.Returned(CountActiveOccurrencesRow), pog.QueryError) { 40 + arg_1: Uuid, 41 + ) -> Result(pog.Returned(GetOccurencesByApplicantRow), pog.QueryError) { 29 42 let decoder = { 30 - use count <- decode.field(0, decode.int) 31 - decode.success(CountActiveOccurrencesRow(count:)) 43 + use id <- decode.field(0, uuid_decoder()) 44 + use description <- decode.field(1, decode.optional(decode.string)) 45 + use category <- decode.field(2, decode.optional(decode.string)) 46 + use subcategory <- decode.field(3, decode.optional(decode.string)) 47 + use created_at <- decode.field(4, decode.optional(pog.timestamp_decoder())) 48 + use resolved_at <- decode.field(5, decode.optional(pog.timestamp_decoder())) 49 + use location <- decode.field(6, decode.list(decode.float)) 50 + use reference_point <- decode.field(7, decode.optional(decode.string)) 51 + decode.success(GetOccurencesByApplicantRow( 52 + id:, 53 + description:, 54 + category:, 55 + subcategory:, 56 + created_at:, 57 + resolved_at:, 58 + location:, 59 + reference_point:, 60 + )) 32 61 } 33 62 34 - "-- 󰆙 Counts the number of active occurrences 35 - SELECT COUNT(oc.id) 63 + "--  Retrieves all occurrences associated with a user, 64 + -- including detailed category information and resolution status. 65 + SELECT 66 + o.id, 67 + o.description, 68 + oc_cat.category_name AS category, 69 + sub_cat.category_name AS subcategory, 70 + o.created_at, 71 + o.resolved_at, 72 + o.location, 73 + o.reference_point 74 + FROM public.query_all_ocurrences_by_user_id($1) AS oc_list (id) 75 + INNER JOIN public.occurrence AS o 76 + ON oc_list.id = o.id 77 + LEFT JOIN public.occurrence_category AS oc_cat 78 + ON o.category_id = oc_cat.id 79 + LEFT JOIN public.occurrence_category AS sub_cat 80 + ON o.subcategory_id = sub_cat.id; 81 + " 82 + |> pog.query 83 + |> pog.parameter(pog.text(uuid.to_string(arg_1))) 84 + |> pog.returning(decoder) 85 + |> pog.execute(db) 86 + } 87 + 88 + /// A row you get from running the `get_recent_occurrences` query 89 + /// defined in `./src/app/routes/occurrence/sql/get_recent_occurrences.sql`. 90 + /// 91 + /// > 🐿️ This type definition was generated automatically using v4.4.1 of the 92 + /// > [squirrel package](https://github.com/giacomocavalieri/squirrel). 93 + /// 94 + pub type GetRecentOccurrencesRow { 95 + GetRecentOccurrencesRow( 96 + id: Uuid, 97 + created_at: Option(Timestamp), 98 + description: Option(String), 99 + category: Option(String), 100 + subcategory: Option(String), 101 + location: List(Float), 102 + reference_point: Option(String), 103 + ) 104 + } 105 + 106 + ///  Find all occurrences from the last 24 hours 107 + /// 108 + /// > 🐿️ This function was generated automatically using v4.4.1 of 109 + /// > the [squirrel package](https://github.com/giacomocavalieri/squirrel). 110 + /// 111 + pub fn get_recent_occurrences( 112 + db: pog.Connection, 113 + ) -> Result(pog.Returned(GetRecentOccurrencesRow), pog.QueryError) { 114 + let decoder = { 115 + use id <- decode.field(0, uuid_decoder()) 116 + use created_at <- decode.field(1, decode.optional(pog.timestamp_decoder())) 117 + use description <- decode.field(2, decode.optional(decode.string)) 118 + use category <- decode.field(3, decode.optional(decode.string)) 119 + use subcategory <- decode.field(4, decode.optional(decode.string)) 120 + use location <- decode.field(5, decode.list(decode.float)) 121 + use reference_point <- decode.field(6, decode.optional(decode.string)) 122 + decode.success(GetRecentOccurrencesRow( 123 + id:, 124 + created_at:, 125 + description:, 126 + category:, 127 + subcategory:, 128 + location:, 129 + reference_point:, 130 + )) 131 + } 132 + 133 + "--  Find all occurrences from the last 24 hours 134 + SELECT 135 + oc.id, 136 + oc.created_at, 137 + oc.description, 138 + oc_cat.category_name AS category, 139 + sub_cat.category_name AS subcategory, 140 + oc.location, 141 + oc.reference_point 36 142 FROM public.occurrence AS oc 37 - WHERE oc.resolved_at IS NULL; 143 + LEFT JOIN public.occurrence_category AS oc_cat 144 + ON oc.category_id = oc_cat.id 145 + LEFT JOIN public.occurrence_category AS sub_cat 146 + ON oc.subcategory_id = sub_cat.id 147 + WHERE oc.created_at >= (NOW() - '1 day'::INTERVAL); 38 148 " 39 149 |> pog.query 40 150 |> pog.returning(decoder) ··· 85 195 |> pog.returning(decoder) 86 196 |> pog.execute(db) 87 197 } 198 + 199 + // --- Encoding/decoding utils ------------------------------------------------- 200 + 201 + /// A decoder to decode `Uuid`s coming from a Postgres query. 202 + /// 203 + fn uuid_decoder() { 204 + use bit_array <- decode.then(decode.bit_array) 205 + case uuid.from_bit_array(bit_array) { 206 + Ok(uuid) -> decode.success(uuid) 207 + Error(_) -> decode.failure(uuid.v7(), "Uuid") 208 + } 209 + }
-4
src/app/routes/occurrence/sql/count_active_occurrences.sql
··· 1 - -- 󰆙 Counts the number of active occurrences 2 - SELECT COUNT(oc.id) 3 - FROM public.occurrence AS oc 4 - WHERE oc.resolved_at IS NULL;
+15
src/app/routes/occurrence/sql/get_recent_occurrences.sql
··· 1 + --  Find all occurrences from the last 24 hours 2 + SELECT 3 + oc.id, 4 + oc.created_at, 5 + oc.description, 6 + oc_cat.category_name AS category, 7 + sub_cat.category_name AS subcategory, 8 + oc.location, 9 + oc.reference_point 10 + FROM public.occurrence AS oc 11 + LEFT JOIN public.occurrence_category AS oc_cat 12 + ON oc.category_id = oc_cat.id 13 + LEFT JOIN public.occurrence_category AS sub_cat 14 + ON oc.subcategory_id = sub_cat.id 15 + WHERE oc.created_at >= (NOW() - '1 day'::INTERVAL);
+1 -1
src/app/routes/user/get_ocurrences_by_applicant.gleam
··· 3 3 //// It returns a list of occurrences (incidents/reports) that were submitted 4 4 //// by the specified user, including detailed information about each occurrence. 5 5 6 - import app/routes/user/sql 6 + import app/routes/occurrence/sql 7 7 import app/web 8 8 import gleam/float 9 9 import gleam/http
-76
src/app/routes/user/sql.gleam
··· 6 6 7 7 import gleam/dynamic/decode 8 8 import gleam/option.{type Option} 9 - import gleam/time/timestamp.{type Timestamp} 10 9 import pog 11 10 import youid/uuid.{type Uuid} 12 11 ··· 100 99 " 101 100 |> pog.query 102 101 |> pog.parameter(pog.text(arg_1)) 103 - |> pog.returning(decoder) 104 - |> pog.execute(db) 105 - } 106 - 107 - /// A row you get from running the `get_occurences_by_applicant` query 108 - /// defined in `./src/app/routes/user/sql/get_occurences_by_applicant.sql`. 109 - /// 110 - /// > 🐿️ This type definition was generated automatically using v4.4.1 of the 111 - /// > [squirrel package](https://github.com/giacomocavalieri/squirrel). 112 - /// 113 - pub type GetOccurencesByApplicantRow { 114 - GetOccurencesByApplicantRow( 115 - id: Uuid, 116 - description: Option(String), 117 - category: Option(String), 118 - subcategory: Option(String), 119 - created_at: Option(Timestamp), 120 - resolved_at: Option(Timestamp), 121 - location: List(Float), 122 - reference_point: Option(String), 123 - ) 124 - } 125 - 126 - ///  Retrieves all occurrences associated with a user, 127 - /// including detailed category information and resolution status. 128 - /// 129 - /// > 🐿️ This function was generated automatically using v4.4.1 of 130 - /// > the [squirrel package](https://github.com/giacomocavalieri/squirrel). 131 - /// 132 - pub fn get_occurences_by_applicant( 133 - db: pog.Connection, 134 - arg_1: Uuid, 135 - ) -> Result(pog.Returned(GetOccurencesByApplicantRow), pog.QueryError) { 136 - let decoder = { 137 - use id <- decode.field(0, uuid_decoder()) 138 - use description <- decode.field(1, decode.optional(decode.string)) 139 - use category <- decode.field(2, decode.optional(decode.string)) 140 - use subcategory <- decode.field(3, decode.optional(decode.string)) 141 - use created_at <- decode.field(4, decode.optional(pog.timestamp_decoder())) 142 - use resolved_at <- decode.field(5, decode.optional(pog.timestamp_decoder())) 143 - use location <- decode.field(6, decode.list(decode.float)) 144 - use reference_point <- decode.field(7, decode.optional(decode.string)) 145 - decode.success(GetOccurencesByApplicantRow( 146 - id:, 147 - description:, 148 - category:, 149 - subcategory:, 150 - created_at:, 151 - resolved_at:, 152 - location:, 153 - reference_point:, 154 - )) 155 - } 156 - 157 - "--  Retrieves all occurrences associated with a user, 158 - -- including detailed category information and resolution status. 159 - SELECT 160 - o.id, 161 - o.description, 162 - oc_cat.category_name AS category, 163 - sub_cat.category_name AS subcategory, 164 - o.created_at, 165 - o.resolved_at, 166 - o.location, 167 - o.reference_point 168 - FROM public.query_all_ocurrences_by_user_id($1) AS oc_list (id) 169 - INNER JOIN public.occurrence AS o 170 - ON oc_list.id = o.id 171 - LEFT JOIN public.occurrence_category AS oc_cat 172 - ON o.category_id = oc_cat.id 173 - LEFT JOIN public.occurrence_category AS sub_cat 174 - ON o.subcategory_id = sub_cat.id; 175 - " 176 - |> pog.query 177 - |> pog.parameter(pog.text(uuid.to_string(arg_1))) 178 102 |> pog.returning(decoder) 179 103 |> pog.execute(db) 180 104 }
src/app/routes/user/sql/get_occurences_by_applicant.sql src/app/routes/occurrence/sql/get_occurences_by_applicant.sql