Skip to content

Commit 6b1c435

Browse files
feat(leave_tracking): leave count query
1 parent 6cd566b commit 6b1c435

4 files changed

Lines changed: 31 additions & 26 deletions

File tree

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
-- Leave table for tracking leaves
22
CREATE TABLE Leave (
33
leave_id SERIAL PRIMARY KEY,
4-
discord_id VARCHAR(255) REFERENCES Member(discord_id) ON DELETE CASCADE,
5-
from_date DATE DEFAULT CURRENT_DATE,
6-
duration INT DEFAULT 1,
4+
discord_id VARCHAR(255) NOT NULL REFERENCES Member(discord_id) ON DELETE CASCADE,
5+
from_date DATE DEFAULT CURRENT_DATE NOT NULL,
6+
duration INT DEFAULT 1 NOT NULL,
77
reason TEXT NOT NULL,
8-
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
9-
approved_by VARCHAR(255) REFERENCES Member(discord_id),
8+
applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
9+
approved_by VARCHAR(255) REFERENCES Member(discord_id) ON DELETE SET NULL,
1010
CHECK (approved_by IS NULL OR approved_by <> discord_id),
11+
CHECK (duration > 0),
1112
UNIQUE (from_date, discord_id)
1213
);

src/graphql/mutations/attendance_mutations.rs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use std::sync::Arc;
22

33
use async_graphql::{Context, Object, Result};
4-
use chrono::{NaiveDate, NaiveDateTime};
4+
use chrono::NaiveDate;
55
use chrono_tz::Asia::Kolkata;
66
use hmac::{Hmac, Mac};
77
use sha2::Sha256;
88
use sqlx::PgPool;
99

1010
use crate::auth::guards::AdminOrBotGuard;
11-
use crate::models::attendance::{AttendanceRecord, MarkAttendanceInput, MarkLeaveOutput};
11+
use crate::models::attendance::{AttendanceRecord, LeaveRecord, MarkAttendanceInput};
1212

1313
type HmacSha256 = Hmac<Sha256>;
1414

@@ -69,24 +69,22 @@ impl AttendanceMutations {
6969
ctx: &Context<'_>,
7070
discord_id: String,
7171
reason: String,
72-
applied_at: NaiveDateTime,
7372
from_date: NaiveDate,
7473
duration: i32,
75-
) -> Result<MarkLeaveOutput> {
74+
) -> Result<LeaveRecord> {
7675
let pool = ctx
7776
.data::<Arc<PgPool>>()
7877
.expect("Pool not found in context");
7978

80-
let leave: MarkLeaveOutput = sqlx::query_as::<_, MarkLeaveOutput>(
79+
let leave: LeaveRecord = sqlx::query_as::<_, LeaveRecord>(
8180
"INSERT INTO Leave
82-
(discord_id, reason, applied_at, from_date, duration)
83-
VALUES ($1, $2, $3, $4, $5)
81+
(discord_id, reason, from_date, duration)
82+
VALUES ($1, $2, $3, $4)
8483
RETURNING *
8584
",
8685
)
8786
.bind(discord_id)
8887
.bind(reason)
89-
.bind(applied_at)
9088
.bind(from_date)
9189
.bind(duration)
9290
.fetch_one(pool.as_ref())
@@ -100,23 +98,28 @@ impl AttendanceMutations {
10098
&self,
10199
ctx: &Context<'_>,
102100
discord_id: String,
101+
from_date: NaiveDate,
103102
approved_by: String,
104-
) -> Result<MarkLeaveOutput> {
103+
) -> Result<LeaveRecord> {
105104
let pool = ctx
106105
.data::<Arc<PgPool>>()
107106
.expect("Pool not found in context");
108107

109-
let leave: MarkLeaveOutput = sqlx::query_as::<_, MarkLeaveOutput>(
108+
let leave: LeaveRecord = sqlx::query_as::<_, LeaveRecord>(
110109
"UPDATE Leave
111110
SET approved_by = $1
112-
WHERE discord_id = $2
111+
WHERE discord_id = $2 AND
112+
from_date=$3 AND
113+
approved_by IS NULL
113114
RETURNING *
114115
",
115116
)
116117
.bind(approved_by)
117118
.bind(discord_id)
118-
.fetch_one(pool.as_ref())
119-
.await?;
119+
.bind(from_date)
120+
.fetch_optional(pool.as_ref())
121+
.await?
122+
.ok_or_else(|| async_graphql::Error::new("no pending leave found to approve"))?;
120123

121124
Ok(leave)
122125
}

src/graphql/queries/member_queries.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ impl MemberQueries {
9191
}
9292
}
9393

94-
// Fetch the details of the currently logged in member
94+
/// Fetch the details of the currently logged in member
9595
#[graphql(guard = "AuthGuard")]
9696
async fn me(&self, ctx: &Context<'_>) -> Result<Member> {
9797
let auth = ctx.data::<AuthContext>()?;
@@ -434,11 +434,16 @@ impl Member {
434434
start_date: NaiveDate,
435435
end_date: NaiveDate,
436436
) -> Result<i64> {
437-
let pool = ctx.data::<Arc<PgPool>>().expect("Pool must be in context.");
437+
let pool = ctx.data::<Arc<PgPool>>()?;
438438

439439
if end_date < start_date {
440440
return Err("end_date must be >= start_date".into());
441441
}
442+
let discord_id = self
443+
.discord_id
444+
.as_ref()
445+
.expect("Leave count needs discord_id");
446+
442447
let total: Option<i64> = sqlx::query_scalar(
443448
r#"
444449
SELECT SUM(
@@ -454,11 +459,7 @@ impl Member {
454459
)
455460
.bind(start_date)
456461
.bind(end_date)
457-
.bind(
458-
self.discord_id
459-
.as_ref()
460-
.expect("Leave count needs discord_id"),
461-
)
462+
.bind(discord_id)
462463
.fetch_one(pool.as_ref())
463464
.await?;
464465
Ok(total.unwrap_or(0))

src/models/attendance.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub struct MarkAttendanceInput {
2323
}
2424

2525
#[derive(SimpleObject, FromRow)]
26-
pub struct MarkLeaveOutput {
26+
pub struct LeaveRecord {
2727
pub discord_id: String,
2828
pub from_date: NaiveDate,
2929
pub applied_at: NaiveDateTime,

0 commit comments

Comments
 (0)