Skip to content

Implemented database seeding as per #61 #107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}
RUST_ENV=development
ROOT_SECRET=insecuresecret123 # Used to verify origin of attendance mutations
ROOT_PORT=3000

# Seed toggle
SEEDING_ENABLED=false
20 changes: 20 additions & 0 deletions src/database_seeder/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use sqlx::PgPool;
use std::fs;
use std::path::Path;

pub async fn seed_database(pool: &PgPool) {
let sql_path = Path::new("src/database_seeder/seed.sql");
let seed_sql = fs::read_to_string(sql_path).expect("Failed to read seed.sql file");

let statements: Vec<&str> = seed_sql
.split(';')
.filter(|stmt| !stmt.trim().is_empty())
.collect();

for statement in statements {
sqlx::query(statement)
.execute(pool)
.await
.expect("Failed to execute seed statement");
}
}
125 changes: 125 additions & 0 deletions src/database_seeder/seed.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
-- Member
INSERT INTO member (
roll_no, name, email, sex, year, hostel, mac_address, discord_id, group_id
)
SELECT
'R' || LPAD(i::TEXT, 4, '0'),
CASE
WHEN i % 5 = 0 THEN 'John Doe ' || i
WHEN i % 5 = 1 THEN 'Jane Smith ' || i
WHEN i % 5 = 2 THEN 'Alex Johnson ' || i
WHEN i % 5 = 3 THEN 'Emily Davis ' || i
ELSE 'Chris Brown ' || i
END,
CASE
WHEN i % 5 = 0 THEN 'john.doe' || i || '@example.com'
WHEN i % 5 = 1 THEN 'jane.smith' || i || '@example.com'
WHEN i % 5 = 2 THEN 'alex.johnson' || i || '@example.com'
WHEN i % 5 = 3 THEN 'emily.davis' || i || '@example.com'
ELSE 'chris.brown' || i || '@example.com'
END,
CASE
WHEN i % 2 = 0 THEN 'M'::sex_type
ELSE 'F'::sex_type
END,
(i % 4) + 1,
'Hostel ' || ((i % 5) + 1),
'00:14:22:01:' || LPAD(TO_HEX(i), 2, '0') || ':' || LPAD(TO_HEX(i + 60), 2, '0'),
'discord_user_' || i,
(i % 8) + 1
FROM generate_series(1, 60) AS i
ON CONFLICT (roll_no) DO NOTHING;


-- Attendance
INSERT INTO Attendance (
member_id, date, is_present, time_in, time_out
)
SELECT
m.member_id,
CURRENT_DATE - ((i * 3) % 30),
rnd.is_present,
CASE WHEN rnd.is_present THEN rnd.time_in ELSE NULL END,
CASE WHEN rnd.is_present THEN rnd.time_out ELSE NULL END
FROM generate_series(1, 600) AS i
JOIN (
SELECT generate_series(1, 60) AS idx, member_id
FROM member
) AS m ON (i % 60) + 1 = m.idx
JOIN (
SELECT
TRUE AS is_present,
'08:30'::TIME + (INTERVAL '1 minute' * (random() * 60)) AS time_in,
'17:00'::TIME + (INTERVAL '1 minute' * (random() * 60)) AS time_out
UNION ALL
SELECT FALSE, NULL, NULL
) AS rnd ON TRUE
WHERE (random() < 0.75)
ON CONFLICT (member_id, date) DO NOTHING;


-- AttendanceSummary
INSERT INTO AttendanceSummary (
member_id, year, month, days_attended
)
SELECT
m.member_id,
2025,
(i % 12) + 1,
FLOOR(random() * 26 + 3)::INT
FROM generate_series(1, 400) AS i
JOIN (
SELECT generate_series(1, 60) AS idx, member_id
FROM member
) AS m ON (i % 60) + 1 = m.idx
ON CONFLICT (member_id, year, month) DO NOTHING;


-- StatusUpdateStreak
INSERT INTO StatusUpdateStreak (
member_id, current_streak, max_streak
)
SELECT
member_id,
FLOOR(random() * 10 + 1)::INT,
FLOOR(random() * 30 + 10)::INT
FROM member
ON CONFLICT (member_id) DO NOTHING;


-- Project
INSERT INTO Project (
member_id, title
)
SELECT
(i % 60) + 1,
CASE
WHEN i % 3 = 0 THEN 'Machine Learning Project ' || i
WHEN i % 3 = 1 THEN 'Web Development Project ' || i
ELSE 'Data Analysis Project ' || i
END
FROM generate_series(1, 200) AS i
WHERE NOT EXISTS (
SELECT 1 FROM Project
WHERE member_id = (i % 60) + 1 AND title = CASE
WHEN i % 3 = 0 THEN 'Machine Learning Project ' || i
WHEN i % 3 = 1 THEN 'Web Development Project ' || i
ELSE 'Data Analysis Project ' || i
END
);


-- StatusUpdateHistory
INSERT INTO StatusUpdateHistory (
member_id, date, is_updated
)
SELECT
m.member_id,
CURRENT_DATE - ((i * 2) % 30),
i % 2 = 0
FROM generate_series(1, 500) AS i
JOIN (
SELECT generate_series(1, 60) AS idx, member_id
FROM member
) AS m ON (i % 60) + 1 = m.idx
ON CONFLICT (member_id, date) DO NOTHING;
11 changes: 11 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ use tracing::info;
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};

use daily_task::run_daily_task_at_midnight;
use database_seeder::seed_database;
use graphql::{Mutation, Query};
use routes::setup_router;

pub mod daily_task;
pub mod database_seeder;
pub mod graphql;
pub mod models;
pub mod routes;
Expand All @@ -23,6 +25,7 @@ struct Config {
secret_key: String,
database_url: String,
port: String,
seeding_enabled: bool,
}

impl Config {
Expand All @@ -33,6 +36,9 @@ impl Config {
secret_key: std::env::var("ROOT_SECRET").expect("ROOT_SECRET must be set."),
database_url: std::env::var("DATABASE_URL").expect("DATABASE_URL must be set."),
port: std::env::var("ROOT_PORT").expect("ROOT_PORT must be set."),
seeding_enabled: std::env::var("SEEDING_ENABLED")
.map(|v| v.to_lowercase() == "true")
.unwrap_or(false),
}
}
}
Expand All @@ -45,6 +51,11 @@ async fn main() {
let pool = setup_database(&config.database_url).await;
let schema = build_graphql_schema(pool.clone(), config.secret_key);

if config.seeding_enabled {
info!("Seeding database...");
seed_database(&pool).await;
}

tokio::task::spawn(async {
run_daily_task_at_midnight(pool).await;
});
Expand Down
Loading