Skip to content

Commit

Permalink
refactor: organize excel trait impl into smaller files
Browse files Browse the repository at this point in the history
  • Loading branch information
albugowy15 committed Feb 25, 2024
1 parent d229371 commit 821bf6a
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 198 deletions.
11 changes: 4 additions & 7 deletions src/commands/compare.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
use std::{collections::HashMap, path::PathBuf, sync::Arc};

use anyhow::{Error, Result};
use sqlx::MySqlPool;

use crate::{
db::{
self,
Expand All @@ -16,6 +11,8 @@ use crate::{
file::OutWriter,
},
};
use sqlx::MySqlPool;
use std::{collections::HashMap, path::PathBuf, sync::Arc};

fn compare_class(db_class: &ClassFromSchedule, excel_class: &ClassFromSchedule) -> bool {
let db_class_lec = &db_class.lecturer_code;
Expand All @@ -40,13 +37,13 @@ fn compare_class(db_class: &ClassFromSchedule, excel_class: &ClassFromSchedule)
}

type SpawnGetSchedule =
tokio::task::JoinHandle<Result<HashMap<(String, String), ClassFromSchedule>, Error>>;
tokio::task::JoinHandle<Result<HashMap<(String, String), ClassFromSchedule>, sqlx::Error>>;
fn spawn_get_schedule(pool: &Arc<MySqlPool>) -> SpawnGetSchedule {
let cloned_pool = pool.clone();
tokio::task::spawn(async move { ClassRepository::new(&cloned_pool).get_schedule().await })
}

type SpawnPrepareData = tokio::task::JoinHandle<Result<LecturerSubjectSessionMap, Error>>;
type SpawnPrepareData = tokio::task::JoinHandle<Result<LecturerSubjectSessionMap, sqlx::Error>>;
fn spawn_prepare_data(pool: &Arc<MySqlPool>) -> SpawnPrepareData {
let cloned_pool = pool.clone();
tokio::task::spawn(async move { prepare_data(&cloned_pool).await })
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use crate::{db::repository::class::Class, DAYS, DAY_OFFSET};
use calamine::DataType;

use super::{AsIdParser, Excel, Parser, Retrieve, ScheduleParser, SessionParser};
use super::{AsIdParser, Excel, Parser, Retrieve};

impl AsIdParser for Excel {
fn get_subject_id_with_code(&self, val: &str) -> Option<(String, String)> {
Expand All @@ -18,7 +15,7 @@ impl AsIdParser for Excel {
let unk_id = self
.lecturer_subjects_session_map
.lecturers
.get(&String::from("UNK"))?
.get("UNK")?
.to_string();
let lecturers_id: Vec<String> = lecturers
.into_iter()
Expand All @@ -34,66 +31,18 @@ impl AsIdParser for Excel {
}
}

impl SessionParser<i8> for Excel {
fn get_session(&self, row_idx: u32) -> Option<i8> {
let session_str = self.retrieve_session(row_idx)?;
let session_name = Excel::parse_session(&session_str)?;
self.lecturer_subjects_session_map
.sessions
.get(&session_name)
.cloned()
}
}

impl ScheduleParser<Class> for Excel {
fn get_schedule(&self) -> Vec<Class> {
let mut list_class: Vec<Class> = Vec::with_capacity(self.range.get_size().1);

for (row_idx, row) in self.range.rows().enumerate() {
for (col_idx, c) in row.iter().enumerate() {
let val = match c.get_string() {
Some(val) => val,
None => continue,
};
let (subject_id, class_code) = match self.get_subject_id_with_code(val) {
Some(val) => val,
None => continue,
};
let lecturers_id = match self.get_lecturer_id(row_idx as u32, col_idx as u32) {
Some(val) => val,
None => continue,
};
let day = DAYS[row_idx / DAY_OFFSET];
let session_id = match self.get_session(row_idx as u32) {
Some(val) => val,
None => continue,
};
let data = Class {
matkul_id: subject_id,
lecturers_id,
day: day.to_string(),
code: class_code,
session_id,
};
list_class.push(data);
}
}
list_class
}
}

#[cfg(test)]
mod tests {
use std::collections::HashMap;

use calamine::Range;

use crate::db::repository::LecturerSubjectSessionMap;

use super::*;
use std::collections::HashMap;

#[test]
fn test_get_subject_with_code() {
fn test_get_subject_id_with_code() {
// Create a parser
let mut subject_to_id = HashMap::new();
subject_to_id.insert(
Expand Down
72 changes: 72 additions & 0 deletions src/utils/excel/as_string_parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use super::{AsStringParser, Excel, Parser, Retrieve};

impl AsStringParser for Excel {
fn get_subject_with_code(&self, val: &str) -> Option<(String, String)> {
let (subject_name, code) = Self::parse_subject_with_code(val)?;
self.lecturer_subjects_session_map
.subjects
.get(&subject_name.to_lowercase())
.map(|_| (subject_name, code))
}

fn get_lecturer(&self, row: u32, col: u32) -> Option<Vec<String>> {
let lecturers_str = self.retrieve_class_detail(row, col)?;
let lecturers = Excel::parse_lecturer(&lecturers_str)?;
let lecturers_code: Vec<String> = lecturers
.into_iter()
.flat_map(|lecture_code| {
let code = match self
.lecturer_subjects_session_map
.lecturers
.contains_key(lecture_code.trim())
{
true => lecture_code.trim().to_string(),
false => "UNK".to_string(),
};
vec![code.to_string()]
})
.collect();

match lecturers_code.is_empty() {
true => None,
false => Some(lecturers_code),
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::db::repository::LecturerSubjectSessionMap;
use calamine::Range;
use std::collections::HashMap;

#[test]
fn test_get_subject_with_code() {
// Create a parser
let mut subject_to_id = HashMap::new();
subject_to_id.insert(
"jaringan komputer".to_string(),
"c6hhfe7737483833".to_string(),
);

let excel = Excel {
lecturer_subjects_session_map: LecturerSubjectSessionMap {
subjects: subject_to_id,
lecturers: HashMap::new(),
sessions: HashMap::new(),
},
range: Range::new((0, 0), (100, 100)),
};

// Test the get_subject_with_code method
let result = excel.get_subject_with_code("Jaringan Komputer - C");
assert_eq!(
result,
Some(("Jaringan Komputer".to_string(), "C".to_string()))
);

let result = excel.get_subject_with_code("Physics - P101");
assert_eq!(result, None);
}
}
50 changes: 50 additions & 0 deletions src/utils/excel/find_class.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use calamine::DataType;

use crate::{db::repository::class::ClassFindSchedule, DAYS};

use super::{Excel, FindClassSchedule, Parser, Retrieve};

impl FindClassSchedule for Excel {
fn find_schedule_from_class(&self, subject_name: &str) -> Vec<ClassFindSchedule> {
let mut schedules: Vec<ClassFindSchedule> = Vec::with_capacity(self.range.get_size().1);
for (row_idx, row) in self.range.rows().enumerate() {
for (col_idx, c) in row.iter().enumerate() {
let val = match c.get_string() {
Some(val) => val,
None => continue,
};
if !val.contains(subject_name) {
continue;
}

let lecturers_str = match self.retrieve_class_detail(row_idx as u32, col_idx as u32)
{
Some(lecs) => lecs,
None => continue,
};
let lecturers = match Excel::parse_lecturer(&lecturers_str) {
Some(lecs) => lecs,
None => continue,
};
let day = DAYS[row_idx / 14];

let session_str = match self.retrieve_session(row_idx as u32) {
Some(session) => session,
None => continue,
};
let session_name = match Excel::parse_session(&session_str) {
Some(session) => session,
None => continue,
};
let data = ClassFindSchedule {
class: val.to_string(),
lecturers_code: lecturers,
day: day.to_string(),
session_start: session_name,
};
schedules.push(data);
}
}
schedules
}
}
65 changes: 10 additions & 55 deletions src/utils/excel/mod.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
pub mod parser;
pub mod retrieve;
mod as_id_parser;
mod as_string_parser;
pub mod find_class;
mod parser;
mod retrieve;
pub mod schedule_parser;
pub mod schedule_parser_with_id;
mod session_parser;

use std::path::PathBuf;

use anyhow::{Context, Result};
use calamine::{open_workbook, Data, DataType, Range, Reader, Xlsx};
use anyhow::Context;
use calamine::{open_workbook, Data, Range, Reader, Xlsx};

use crate::{
db::repository::{class::ClassFindSchedule, LecturerSubjectSessionMap},
DAYS,
};
use crate::db::repository::{class::ClassFindSchedule, LecturerSubjectSessionMap};

pub struct Excel {
range: Range<Data>,
lecturer_subjects_session_map: LecturerSubjectSessionMap,
}

impl Excel {
pub fn new(file_path: &PathBuf, sheet_name: &str) -> Result<Self> {
pub fn new(file_path: &PathBuf, sheet_name: &str) -> anyhow::Result<Self> {
let mut excel: Xlsx<_> =
open_workbook(file_path).with_context(|| "Cannot open excel file")?;
let range = excel.worksheet_range(sheet_name)?;
Expand Down Expand Up @@ -70,48 +70,3 @@ pub trait ScheduleParser<T> {
pub trait FindClassSchedule {
fn find_schedule_from_class(&self, subject_name: &str) -> Vec<ClassFindSchedule>;
}

impl FindClassSchedule for Excel {
fn find_schedule_from_class(&self, subject_name: &str) -> Vec<ClassFindSchedule> {
let mut schedules: Vec<ClassFindSchedule> = Vec::with_capacity(self.range.get_size().1);
for (row_idx, row) in self.range.rows().enumerate() {
for (col_idx, c) in row.iter().enumerate() {
let val = match c.get_string() {
Some(val) => val,
None => continue,
};
if !val.contains(subject_name) {
continue;
}

let lecturers_str = match self.retrieve_class_detail(row_idx as u32, col_idx as u32)
{
Some(lecs) => lecs,
None => continue,
};
let lecturers = match Excel::parse_lecturer(&lecturers_str) {
Some(lecs) => lecs,
None => continue,
};
let day = DAYS[row_idx / 14];

let session_str = match self.retrieve_session(row_idx as u32) {
Some(session) => session,
None => continue,
};
let session_name = match Excel::parse_session(&session_str) {
Some(session) => session,
None => continue,
};
let data = ClassFindSchedule {
class: val.to_string(),
lecturers_code: lecturers,
day: day.to_string(),
session_start: session_name,
};
schedules.push(data);
}
}
schedules
}
}
Loading

0 comments on commit 821bf6a

Please sign in to comment.