From e4efbd5e4a05ee1545c1328cdbbb7a1132866b8a Mon Sep 17 00:00:00 2001 From: anthonyrys Date: Fri, 4 Oct 2024 17:49:43 -0400 Subject: [PATCH 01/11] Add Course - Add Course Controller - Add Course Entity - Add Course Key - Add Course Repository --- .gitignore | 5 ++- pom.xml | 4 +++ .../controller/CourseController.java | 31 ++++++++++++++++ .../com/carpi/carpibackend/entity/Course.java | 35 +++++++++++++++++++ .../carpi/carpibackend/keys/CourseKey.java | 17 +++++++++ .../repository/CourseRepository.java | 10 ++++++ src/main/resources/.env.properties.example | 3 ++ src/main/resources/application.properties | 6 ++++ 8 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/carpi/carpibackend/controller/CourseController.java create mode 100644 src/main/java/com/carpi/carpibackend/entity/Course.java create mode 100644 src/main/java/com/carpi/carpibackend/keys/CourseKey.java create mode 100644 src/main/java/com/carpi/carpibackend/repository/CourseRepository.java create mode 100644 src/main/resources/.env.properties.example diff --git a/.gitignore b/.gitignore index 5eac309..54f2b0f 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,7 @@ build/ !**/src/test/**/build/ ### VS Code ### -.vscode/ \ No newline at end of file +.vscode/ + +### Enviroment ### +env.properties diff --git a/pom.xml b/pom.xml index 14ce122..72aa981 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,10 @@ mysql-connector-j runtime + + org.springframework.boot + spring-boot-starter-data-jpa + org.projectlombok lombok diff --git a/src/main/java/com/carpi/carpibackend/controller/CourseController.java b/src/main/java/com/carpi/carpibackend/controller/CourseController.java new file mode 100644 index 0000000..dca6f1d --- /dev/null +++ b/src/main/java/com/carpi/carpibackend/controller/CourseController.java @@ -0,0 +1,31 @@ +package com.carpi.carpibackend.controller; + +import org.springframework.beans.factory.annotation.Autowired; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import com.carpi.carpibackend.entity.Course; +import com.carpi.carpibackend.repository.CourseRepository; + +@CrossOrigin +@RestController +@RequestMapping("/api/v1/course") +public class CourseController { + + private final CourseRepository courseRepository; + + @Autowired + public CourseController(CourseRepository courseRepository) { + this.courseRepository = courseRepository; + } + + @ResponseBody + @GetMapping + public ResponseEntity> getAll() { + return ResponseEntity.ok(courseRepository.findAll()); + } + +} diff --git a/src/main/java/com/carpi/carpibackend/entity/Course.java b/src/main/java/com/carpi/carpibackend/entity/Course.java new file mode 100644 index 0000000..1310e1c --- /dev/null +++ b/src/main/java/com/carpi/carpibackend/entity/Course.java @@ -0,0 +1,35 @@ +package com.carpi.carpibackend.entity; + +import com.carpi.carpibackend.keys.CourseKey; + +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter + +@Entity +@Table(name = "courses") +public class Course { + + @EmbeddedId + private CourseKey pkCourses; + + @Column(name = "dept", nullable = false) + private String department; + + @Column(name = "code_num", nullable = false) + private int code; + + @Column(name = "title", nullable = false) + private String title; + + @Column(name = "desc_text", nullable = false) + private String description; + +} diff --git a/src/main/java/com/carpi/carpibackend/keys/CourseKey.java b/src/main/java/com/carpi/carpibackend/keys/CourseKey.java new file mode 100644 index 0000000..bc65dfa --- /dev/null +++ b/src/main/java/com/carpi/carpibackend/keys/CourseKey.java @@ -0,0 +1,17 @@ +package com.carpi.carpibackend.keys; + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; + +import java.io.Serializable; + +@Embeddable +public class CourseKey implements Serializable { + + @Column(name = "dept", insertable = false, updatable = false, nullable = false) + private String department; + + @Column(name = "code_num", insertable = false, updatable = false, nullable = false) + private int code; + +} diff --git a/src/main/java/com/carpi/carpibackend/repository/CourseRepository.java b/src/main/java/com/carpi/carpibackend/repository/CourseRepository.java new file mode 100644 index 0000000..8edc1ee --- /dev/null +++ b/src/main/java/com/carpi/carpibackend/repository/CourseRepository.java @@ -0,0 +1,10 @@ +package com.carpi.carpibackend.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.carpi.carpibackend.keys.CourseKey; +import com.carpi.carpibackend.entity.Course; + +public interface CourseRepository extends JpaRepository { + +} diff --git a/src/main/resources/.env.properties.example b/src/main/resources/.env.properties.example new file mode 100644 index 0000000..b721dd4 --- /dev/null +++ b/src/main/resources/.env.properties.example @@ -0,0 +1,3 @@ +DB_URL= +DB_USERNAME= +DB_PASSWORD= diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index ddfa32a..8d87d89 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,7 @@ spring.application.name=carpi-backend + +spring.config.import=file:src/main/resources/env.properties + +spring.datasource.url=${DB_URL} +spring.datasource.username=${DB_USERNAME} +spring.datasource.password=${DB_PASSWORD} From 4954ba55ad367a125574a54597a6ab283026e726 Mon Sep 17 00:00:00 2001 From: anthonyrys Date: Tue, 8 Oct 2024 17:32:40 -0400 Subject: [PATCH 02/11] Add Department --- .../controller/CourseController.java | 9 ++---- .../carpi/carpibackend/entity/Department.java | 32 +++++++++++++++++++ .../carpi/carpibackend/keys/CourseKey.java | 6 ++++ .../carpibackend/keys/DepartmentKey.java | 20 ++++++++++++ .../repository/DepartmentRepository.java | 10 ++++++ 5 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/carpi/carpibackend/entity/Department.java create mode 100644 src/main/java/com/carpi/carpibackend/keys/DepartmentKey.java create mode 100644 src/main/java/com/carpi/carpibackend/repository/DepartmentRepository.java diff --git a/src/main/java/com/carpi/carpibackend/controller/CourseController.java b/src/main/java/com/carpi/carpibackend/controller/CourseController.java index dca6f1d..350c05a 100644 --- a/src/main/java/com/carpi/carpibackend/controller/CourseController.java +++ b/src/main/java/com/carpi/carpibackend/controller/CourseController.java @@ -1,9 +1,8 @@ package com.carpi.carpibackend.controller; -import org.springframework.beans.factory.annotation.Autowired; - import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.springframework.beans.factory.annotation.Autowired; import java.util.List; @@ -15,12 +14,8 @@ @RequestMapping("/api/v1/course") public class CourseController { - private final CourseRepository courseRepository; - @Autowired - public CourseController(CourseRepository courseRepository) { - this.courseRepository = courseRepository; - } + private CourseRepository courseRepository; @ResponseBody @GetMapping diff --git a/src/main/java/com/carpi/carpibackend/entity/Department.java b/src/main/java/com/carpi/carpibackend/entity/Department.java new file mode 100644 index 0000000..4785b6e --- /dev/null +++ b/src/main/java/com/carpi/carpibackend/entity/Department.java @@ -0,0 +1,32 @@ +package com.carpi.carpibackend.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; + +import lombok.Getter; +import lombok.Setter; + +import com.carpi.carpibackend.keys.DepartmentKey; + +@Getter +@Setter + +@Entity +@Table(name = "departments") +public class Department { + + @EmbeddedId + private DepartmentKey pkDepartments; + + @Column(name = "dept_code", nullable = false) + private String departmentCode; + + @Column(name = "dept_name", nullable = false) + private String departmentName; + + @Column(name = "school_name", nullable = false) + private String schoolName; + +} diff --git a/src/main/java/com/carpi/carpibackend/keys/CourseKey.java b/src/main/java/com/carpi/carpibackend/keys/CourseKey.java index bc65dfa..c13f09e 100644 --- a/src/main/java/com/carpi/carpibackend/keys/CourseKey.java +++ b/src/main/java/com/carpi/carpibackend/keys/CourseKey.java @@ -3,8 +3,14 @@ import jakarta.persistence.Column; import jakarta.persistence.Embeddable; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; + import java.io.Serializable; +@NoArgsConstructor +@AllArgsConstructor + @Embeddable public class CourseKey implements Serializable { diff --git a/src/main/java/com/carpi/carpibackend/keys/DepartmentKey.java b/src/main/java/com/carpi/carpibackend/keys/DepartmentKey.java new file mode 100644 index 0000000..9d22f8c --- /dev/null +++ b/src/main/java/com/carpi/carpibackend/keys/DepartmentKey.java @@ -0,0 +1,20 @@ +package com.carpi.carpibackend.keys; + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@NoArgsConstructor +@AllArgsConstructor + +@Embeddable +public class DepartmentKey implements Serializable { + + @Column(name = "dept_code", insertable = false, updatable = false, nullable = false) + private String departmentCode; + +} diff --git a/src/main/java/com/carpi/carpibackend/repository/DepartmentRepository.java b/src/main/java/com/carpi/carpibackend/repository/DepartmentRepository.java new file mode 100644 index 0000000..3be10df --- /dev/null +++ b/src/main/java/com/carpi/carpibackend/repository/DepartmentRepository.java @@ -0,0 +1,10 @@ +package com.carpi.carpibackend.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.carpi.carpibackend.entity.Department; +import com.carpi.carpibackend.keys.DepartmentKey; + +public interface DepartmentRepository extends JpaRepository { + +} From 8c711e5501cb0c0090a22903595520ca7ea13130 Mon Sep 17 00:00:00 2001 From: anthonyrys Date: Fri, 18 Oct 2024 17:12:50 -0400 Subject: [PATCH 03/11] Remove Department --- .../com/carpi/carpibackend/entity/Course.java | 7 +++- .../carpi/carpibackend/entity/Department.java | 32 ------------------- .../carpibackend/keys/DepartmentKey.java | 20 ------------ .../repository/DepartmentRepository.java | 10 ------ 4 files changed, 6 insertions(+), 63 deletions(-) delete mode 100644 src/main/java/com/carpi/carpibackend/entity/Department.java delete mode 100644 src/main/java/com/carpi/carpibackend/keys/DepartmentKey.java delete mode 100644 src/main/java/com/carpi/carpibackend/repository/DepartmentRepository.java diff --git a/src/main/java/com/carpi/carpibackend/entity/Course.java b/src/main/java/com/carpi/carpibackend/entity/Course.java index 1310e1c..5e70efc 100644 --- a/src/main/java/com/carpi/carpibackend/entity/Course.java +++ b/src/main/java/com/carpi/carpibackend/entity/Course.java @@ -14,7 +14,7 @@ @Setter @Entity -@Table(name = "courses") +@Table(name = "course") public class Course { @EmbeddedId @@ -32,4 +32,9 @@ public class Course { @Column(name = "desc_text", nullable = false) private String description; + @Column(name = "credit_min", nullable = false) + private short creditMin; + + @Column(name = "credit_max", nullable = false) + private short creditMax; } diff --git a/src/main/java/com/carpi/carpibackend/entity/Department.java b/src/main/java/com/carpi/carpibackend/entity/Department.java deleted file mode 100644 index 4785b6e..0000000 --- a/src/main/java/com/carpi/carpibackend/entity/Department.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.carpi.carpibackend.entity; - -import jakarta.persistence.Column; -import jakarta.persistence.EmbeddedId; -import jakarta.persistence.Entity; -import jakarta.persistence.Table; - -import lombok.Getter; -import lombok.Setter; - -import com.carpi.carpibackend.keys.DepartmentKey; - -@Getter -@Setter - -@Entity -@Table(name = "departments") -public class Department { - - @EmbeddedId - private DepartmentKey pkDepartments; - - @Column(name = "dept_code", nullable = false) - private String departmentCode; - - @Column(name = "dept_name", nullable = false) - private String departmentName; - - @Column(name = "school_name", nullable = false) - private String schoolName; - -} diff --git a/src/main/java/com/carpi/carpibackend/keys/DepartmentKey.java b/src/main/java/com/carpi/carpibackend/keys/DepartmentKey.java deleted file mode 100644 index 9d22f8c..0000000 --- a/src/main/java/com/carpi/carpibackend/keys/DepartmentKey.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.carpi.carpibackend.keys; - -import jakarta.persistence.Column; -import jakarta.persistence.Embeddable; - -import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; - -import java.io.Serializable; - -@NoArgsConstructor -@AllArgsConstructor - -@Embeddable -public class DepartmentKey implements Serializable { - - @Column(name = "dept_code", insertable = false, updatable = false, nullable = false) - private String departmentCode; - -} diff --git a/src/main/java/com/carpi/carpibackend/repository/DepartmentRepository.java b/src/main/java/com/carpi/carpibackend/repository/DepartmentRepository.java deleted file mode 100644 index 3be10df..0000000 --- a/src/main/java/com/carpi/carpibackend/repository/DepartmentRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.carpi.carpibackend.repository; - -import org.springframework.data.jpa.repository.JpaRepository; - -import com.carpi.carpibackend.entity.Department; -import com.carpi.carpibackend.keys.DepartmentKey; - -public interface DepartmentRepository extends JpaRepository { - -} From 688d69f2b423981379bfeb7c66f271831ce0421a Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+SameriteRL@users.noreply.github.com> Date: Wed, 23 Oct 2024 23:46:41 -0400 Subject: [PATCH 04/11] Port course search from CARPI Bot We now have a working endpoint that takes in a single search term parameter, and returns a list of raw CourseSearchResult entities. Not the final product by the way; CourseSearchResult contains some extraneous fields (pkCourses, codeMatch, titleExactMatch, etc.) that the client doesn't need. I want to make some mapper class that'll be able to map the relevant fields from a CourseSearchResult to a Course entity or a proper DTO. Afterwards, I don't think anything really needs to be done to the search algorithm. --- pom.xml | 8 +-- .../com/carpi/carpibackend/Application.java | 1 - .../controller/CourseController.java | 25 ++++++-- .../com/carpi/carpibackend/entity/Course.java | 1 - .../entity/CourseSearchResult.java | 55 ++++++++++++++++ .../carpi/carpibackend/keys/CourseKey.java | 8 +-- .../repository/CourseRepository.java | 4 +- .../CourseSearchResultRepository.java | 62 +++++++++++++++++++ .../service/CourseSearchService.java | 58 +++++++++++++++++ src/main/resources/application.properties | 1 + 10 files changed, 206 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/carpi/carpibackend/entity/CourseSearchResult.java create mode 100644 src/main/java/com/carpi/carpibackend/repository/CourseSearchResultRepository.java create mode 100644 src/main/java/com/carpi/carpibackend/service/CourseSearchService.java diff --git a/pom.xml b/pom.xml index 72aa981..7cb7e13 100644 --- a/pom.xml +++ b/pom.xml @@ -34,11 +34,11 @@ org.springframework.boot spring-boot-starter-web - + - com.mysql - mysql-connector-j - runtime + mysql + mysql-connector-java + 8.0.33 org.springframework.boot diff --git a/src/main/java/com/carpi/carpibackend/Application.java b/src/main/java/com/carpi/carpibackend/Application.java index 21f18c2..3fa06d1 100644 --- a/src/main/java/com/carpi/carpibackend/Application.java +++ b/src/main/java/com/carpi/carpibackend/Application.java @@ -9,5 +9,4 @@ public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } - } diff --git a/src/main/java/com/carpi/carpibackend/controller/CourseController.java b/src/main/java/com/carpi/carpibackend/controller/CourseController.java index 350c05a..3a0a742 100644 --- a/src/main/java/com/carpi/carpibackend/controller/CourseController.java +++ b/src/main/java/com/carpi/carpibackend/controller/CourseController.java @@ -1,13 +1,20 @@ package com.carpi.carpibackend.controller; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.beans.factory.annotation.Autowired; - import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + import com.carpi.carpibackend.entity.Course; +import com.carpi.carpibackend.entity.CourseSearchResult; import com.carpi.carpibackend.repository.CourseRepository; +import com.carpi.carpibackend.service.CourseSearchService; @CrossOrigin @RestController @@ -17,10 +24,18 @@ public class CourseController { @Autowired private CourseRepository courseRepository; + @Autowired + private CourseSearchService courseSearchService; + @ResponseBody - @GetMapping + @GetMapping("getAll") public ResponseEntity> getAll() { return ResponseEntity.ok(courseRepository.findAll()); } + @ResponseBody + @GetMapping("search/{searchTerm}") + public ResponseEntity> searchCourse(@PathVariable String searchTerm) { + return ResponseEntity.ok(courseSearchService.searchCourse(searchTerm)); + } } diff --git a/src/main/java/com/carpi/carpibackend/entity/Course.java b/src/main/java/com/carpi/carpibackend/entity/Course.java index 5e70efc..f662b97 100644 --- a/src/main/java/com/carpi/carpibackend/entity/Course.java +++ b/src/main/java/com/carpi/carpibackend/entity/Course.java @@ -6,7 +6,6 @@ import jakarta.persistence.EmbeddedId; import jakarta.persistence.Entity; import jakarta.persistence.Table; - import lombok.Getter; import lombok.Setter; diff --git a/src/main/java/com/carpi/carpibackend/entity/CourseSearchResult.java b/src/main/java/com/carpi/carpibackend/entity/CourseSearchResult.java new file mode 100644 index 0000000..3581f2f --- /dev/null +++ b/src/main/java/com/carpi/carpibackend/entity/CourseSearchResult.java @@ -0,0 +1,55 @@ +package com.carpi.carpibackend.entity; + +import com.carpi.carpibackend.keys.CourseKey; + +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter + +@Entity +public class CourseSearchResult { + + @EmbeddedId + private CourseKey pkCourses; + + @Column(name = "dept", nullable = false) + private String department; + + @Column(name = "code_num", nullable = false) + private int code; + + @Column(name = "title", nullable = false) + private String title; + + @Column(name = "desc_text", nullable = false) + private String description; + + @Column(name = "credit_min", nullable = false) + private short creditMin; + + @Column(name = "credit_max", nullable = false) + private short creditMax; + + @Column(name = "code_match", nullable = false) + private boolean codeMatch; + + @Column(name = "title_exact_match", nullable = false) + private boolean titleExactMatch; + + @Column(name = "title_start_match", nullable = false) + private boolean titleStartMatch; + + @Column(name = "title_match", nullable = false) + private boolean titleMatch; + + @Column(name = "title_acronym", nullable = false) + private boolean titleAcronym; + + @Column(name = "title_abbrev", nullable = false) + private boolean titleAbbrev; +} diff --git a/src/main/java/com/carpi/carpibackend/keys/CourseKey.java b/src/main/java/com/carpi/carpibackend/keys/CourseKey.java index c13f09e..1a08fa8 100644 --- a/src/main/java/com/carpi/carpibackend/keys/CourseKey.java +++ b/src/main/java/com/carpi/carpibackend/keys/CourseKey.java @@ -1,12 +1,11 @@ package com.carpi.carpibackend.keys; +import java.io.Serializable; + import jakarta.persistence.Column; import jakarta.persistence.Embeddable; - -import lombok.NoArgsConstructor; import lombok.AllArgsConstructor; - -import java.io.Serializable; +import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @@ -19,5 +18,4 @@ public class CourseKey implements Serializable { @Column(name = "code_num", insertable = false, updatable = false, nullable = false) private int code; - } diff --git a/src/main/java/com/carpi/carpibackend/repository/CourseRepository.java b/src/main/java/com/carpi/carpibackend/repository/CourseRepository.java index 8edc1ee..fd63c14 100644 --- a/src/main/java/com/carpi/carpibackend/repository/CourseRepository.java +++ b/src/main/java/com/carpi/carpibackend/repository/CourseRepository.java @@ -1,10 +1,12 @@ package com.carpi.carpibackend.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; -import com.carpi.carpibackend.keys.CourseKey; import com.carpi.carpibackend.entity.Course; +import com.carpi.carpibackend.keys.CourseKey; +@Repository public interface CourseRepository extends JpaRepository { } diff --git a/src/main/java/com/carpi/carpibackend/repository/CourseSearchResultRepository.java b/src/main/java/com/carpi/carpibackend/repository/CourseSearchResultRepository.java new file mode 100644 index 0000000..4db579e --- /dev/null +++ b/src/main/java/com/carpi/carpibackend/repository/CourseSearchResultRepository.java @@ -0,0 +1,62 @@ +package com.carpi.carpibackend.repository; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import com.carpi.carpibackend.entity.CourseSearchResult; +import com.carpi.carpibackend.keys.CourseKey; + +@Repository +public interface CourseSearchResultRepository extends JpaRepository { + + @Query( + value = """ + SELECT + course.dept AS dept, + course.code_num AS code_num, + course.title AS title, + course.desc_text AS desc_text, + course.credit_min AS credit_min, + course.credit_max AS credit_max, + REGEXP_LIKE(CONCAT(course.dept, ' ', course.code_num), ?1, 'i') AS code_match, + REGEXP_LIKE(course.title, ?2, 'i') AS title_exact_match, + REGEXP_LIKE(course.title, ?3, 'i') AS title_start_match, + REGEXP_LIKE(course.title, ?4, 'i') AS title_match, + REGEXP_LIKE(course.title, ?5, 'i') AS title_acronym, + REGEXP_LIKE(course.title, ?6, 'i') AS title_abbrev + FROM + course + GROUP BY + 1, 2 + HAVING + code_match > 0 + OR title_exact_match > 0 + OR title_start_match > 0 + OR title_match > 0 + OR title_acronym > 0 + OR title_abbrev > 0 + ORDER BY + code_match DESC, + title_exact_match DESC, + title_start_match DESC, + title_match DESC, + title_acronym DESC, + title_abbrev DESC, + code_num ASC, + dept ASC + ; + """, + nativeQuery = true + ) + public List searchCourse( + String regexCode, + String regexFull, + String regexStart, + String regexAny, + String regexAcronym, + String regexAbbrev + ); +} diff --git a/src/main/java/com/carpi/carpibackend/service/CourseSearchService.java b/src/main/java/com/carpi/carpibackend/service/CourseSearchService.java new file mode 100644 index 0000000..5c0d56a --- /dev/null +++ b/src/main/java/com/carpi/carpibackend/service/CourseSearchService.java @@ -0,0 +1,58 @@ +package com.carpi.carpibackend.service; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.carpi.carpibackend.entity.CourseSearchResult; +import com.carpi.carpibackend.repository.CourseSearchResultRepository; + +@Service +public class CourseSearchService { + + @Autowired + private CourseSearchResultRepository courseSearchResultRepository; + + /** + * + * @param searchTerm + * @return + */ + public List searchCourse(String searchTerm) { + final String regStartOrSpace = "(^|.* )"; + String regexCode = "^" + searchTerm + "$", + regexFull = "^" + searchTerm + "$", + regexStart = "^" + searchTerm, + regexAny = searchTerm, + regexAcronym = regStartOrSpace; + for (int i = 0; i < searchTerm.length(); ++i) { + char ch = searchTerm.charAt(i); + if (ch != ' ') { + regexAcronym += ch + ".* "; + } + } + regexAcronym = regexAcronym.substring(0, regexAcronym.length() - 3); + String regexAbbrev = ""; + String[] tokens = searchTerm.split(" "); + if (tokens.length > 1) { + regexAbbrev += regStartOrSpace; + for (int i = 0; i < tokens.length; ++i) { + regexAbbrev += tokens[i] + ".* "; + } + regexAbbrev = regexAbbrev.substring(0, regexAbbrev.length() - 3); + } + else { + regexAbbrev = "a^"; + } + return courseSearchResultRepository.searchCourse( + regexCode, + regexFull, + regexStart, + regexAny, + regexAcronym, + regexAbbrev + ); + } + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8d87d89..7d00cae 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,3 +5,4 @@ spring.config.import=file:src/main/resources/env.properties spring.datasource.url=${DB_URL} spring.datasource.username=${DB_USERNAME} spring.datasource.password=${DB_PASSWORD} +# spring.jpa.hibernate.ddl-auto=update From 2521925a8e78acf384bafe2e21f60ec3edb3af0d Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+SameriteRL@users.noreply.github.com> Date: Thu, 24 Oct 2024 15:22:13 -0400 Subject: [PATCH 05/11] Revert MySQL driver dependency I changed this dependency in the last commit from com.mysql to mysql, but after a bit of research I realize that the one from before is the correct one to use (developed officially by MySQL). This change has been reverted. --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 7cb7e13..4e277bf 100644 --- a/pom.xml +++ b/pom.xml @@ -34,11 +34,11 @@ org.springframework.boot spring-boot-starter-web - + - mysql - mysql-connector-java - 8.0.33 + com.mysql + mysql-connector-j + 9.1.0 org.springframework.boot From 0a55e4aac70ce20a5dea079df9ba4562455e0e50 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+SameriteRL@users.noreply.github.com> Date: Thu, 24 Oct 2024 15:23:30 -0400 Subject: [PATCH 06/11] Add Course DTO Implemented the course DTO and used the ModelMapper library to map from CourseSearchResult entities to CourseDto DTOs, in the controller. Added an ApplicationConfig.java for general configuration and beans. --- pom.xml | 6 +++++ .../carpi/carpibackend/ApplicationConfig.java | 14 ++++++++++++ .../controller/CourseController.java | 14 ++++++++++-- .../com/carpi/carpibackend/dto/CourseDto.java | 22 +++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/carpi/carpibackend/ApplicationConfig.java create mode 100644 src/main/java/com/carpi/carpibackend/dto/CourseDto.java diff --git a/pom.xml b/pom.xml index 4e277bf..80015cb 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,12 @@ lombok true + + + org.modelmapper + modelmapper + 3.2.1 + org.springframework.boot spring-boot-starter-test diff --git a/src/main/java/com/carpi/carpibackend/ApplicationConfig.java b/src/main/java/com/carpi/carpibackend/ApplicationConfig.java new file mode 100644 index 0000000..fa7e0cf --- /dev/null +++ b/src/main/java/com/carpi/carpibackend/ApplicationConfig.java @@ -0,0 +1,14 @@ +package com.carpi.carpibackend; + +import org.modelmapper.ModelMapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ApplicationConfig { + + @Bean + public ModelMapper modelMapper() { + return new ModelMapper(); + } +} diff --git a/src/main/java/com/carpi/carpibackend/controller/CourseController.java b/src/main/java/com/carpi/carpibackend/controller/CourseController.java index 3a0a742..3d9d433 100644 --- a/src/main/java/com/carpi/carpibackend/controller/CourseController.java +++ b/src/main/java/com/carpi/carpibackend/controller/CourseController.java @@ -1,7 +1,9 @@ package com.carpi.carpibackend.controller; import java.util.List; +import java.util.stream.Collectors; +import org.modelmapper.ModelMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; @@ -11,6 +13,7 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; +import com.carpi.carpibackend.dto.CourseDto; import com.carpi.carpibackend.entity.Course; import com.carpi.carpibackend.entity.CourseSearchResult; import com.carpi.carpibackend.repository.CourseRepository; @@ -27,6 +30,9 @@ public class CourseController { @Autowired private CourseSearchService courseSearchService; + @Autowired + private ModelMapper modelMapper; + @ResponseBody @GetMapping("getAll") public ResponseEntity> getAll() { @@ -35,7 +41,11 @@ public ResponseEntity> getAll() { @ResponseBody @GetMapping("search/{searchTerm}") - public ResponseEntity> searchCourse(@PathVariable String searchTerm) { - return ResponseEntity.ok(courseSearchService.searchCourse(searchTerm)); + public ResponseEntity> searchCourse(@PathVariable String searchTerm) { + List searchResults = courseSearchService.searchCourse(searchTerm); + List courseDtos = searchResults.stream().map( + result -> modelMapper.map(result, CourseDto.class) + ).collect(Collectors.toList()); + return ResponseEntity.ok(courseDtos); } } diff --git a/src/main/java/com/carpi/carpibackend/dto/CourseDto.java b/src/main/java/com/carpi/carpibackend/dto/CourseDto.java new file mode 100644 index 0000000..0c7b9dd --- /dev/null +++ b/src/main/java/com/carpi/carpibackend/dto/CourseDto.java @@ -0,0 +1,22 @@ +package com.carpi.carpibackend.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter + +public class CourseDto { + + private String department; + + private int code; + + private String title; + + private String description; + + private short creditMin; + + private short creditMax; +} From 47f3ecacf6b631801ecdc50c8d936d47ce43bd85 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+SameriteRL@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:21:13 -0400 Subject: [PATCH 07/11] Implement equals() and hashCode() for CourseKey --- .../carpi/carpibackend/keys/CourseKey.java | 19 +++++++++++++++++++ src/main/resources/application.properties | 1 - 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/carpi/carpibackend/keys/CourseKey.java b/src/main/java/com/carpi/carpibackend/keys/CourseKey.java index 1a08fa8..18704b8 100644 --- a/src/main/java/com/carpi/carpibackend/keys/CourseKey.java +++ b/src/main/java/com/carpi/carpibackend/keys/CourseKey.java @@ -18,4 +18,23 @@ public class CourseKey implements Serializable { @Column(name = "code_num", insertable = false, updatable = false, nullable = false) private int code; + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof CourseKey) { + CourseKey other = (CourseKey) obj; + return department.equals(other.department) && code == other.code; + } + return false; + } + + @Override + public int hashCode() { + int result = department.hashCode(); + result = 31 * result + Integer.hashCode(code); + return result; + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 7d00cae..8d87d89 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,4 +5,3 @@ spring.config.import=file:src/main/resources/env.properties spring.datasource.url=${DB_URL} spring.datasource.username=${DB_USERNAME} spring.datasource.password=${DB_PASSWORD} -# spring.jpa.hibernate.ddl-auto=update From e1377155491147fd867d3aa96efd382f7b341329 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+SameriteRL@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:41:59 -0400 Subject: [PATCH 08/11] Add department & semester filter to course search The course DTO now includes information about the semesters it's been offered in, and a list of it's special attributes (HASS Inquiry, etc.). Issues that need to be worked on: Attributes haven't been added to the database at this point in time, so the attribute filter has been commented out. Only a single department filter, attribute filter, and semester filter can be applied. There is currently no support for multiple department filters, etc. Co-Authored-By: Jack Zgombic <69125339+jzgom067@users.noreply.github.com> --- .../carpi/carpibackend/ApplicationConfig.java | 23 +++++++- .../controller/CourseController.java | 32 ++++++----- .../com/carpi/carpibackend/dto/CourseDto.java | 4 ++ .../entity/CourseSearchResult.java | 6 +++ .../CourseSearchResultRepository.java | 43 +++++++++++---- .../service/CourseSearchService.java | 53 ++++++++++++++----- 6 files changed, 120 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/carpi/carpibackend/ApplicationConfig.java b/src/main/java/com/carpi/carpibackend/ApplicationConfig.java index fa7e0cf..0d2198e 100644 --- a/src/main/java/com/carpi/carpibackend/ApplicationConfig.java +++ b/src/main/java/com/carpi/carpibackend/ApplicationConfig.java @@ -1,14 +1,35 @@ package com.carpi.carpibackend; +import org.modelmapper.Converter; import org.modelmapper.ModelMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import com.carpi.carpibackend.dto.CourseDto; +import com.carpi.carpibackend.entity.CourseSearchResult; + @Configuration public class ApplicationConfig { + + private static final String[] EMPTY_LIST = new String[0]; @Bean public ModelMapper modelMapper() { - return new ModelMapper(); + ModelMapper modelMapper = new ModelMapper(); + Converter split = + ctx -> ctx.getSource() == null ? EMPTY_LIST : ctx.getSource().split(","); + modelMapper.typeMap(CourseSearchResult.class, CourseDto.class).addMappings( + mapper -> { + mapper.using(split).map( + CourseSearchResult::getSemesterList, + CourseDto::setSemesterList + ); + mapper.using(split).map( + CourseSearchResult::getAttributeList, + CourseDto::setAttributeList + ); + } + ); + return modelMapper; } } diff --git a/src/main/java/com/carpi/carpibackend/controller/CourseController.java b/src/main/java/com/carpi/carpibackend/controller/CourseController.java index 3d9d433..e873bc7 100644 --- a/src/main/java/com/carpi/carpibackend/controller/CourseController.java +++ b/src/main/java/com/carpi/carpibackend/controller/CourseController.java @@ -8,15 +8,12 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.carpi.carpibackend.dto.CourseDto; -import com.carpi.carpibackend.entity.Course; import com.carpi.carpibackend.entity.CourseSearchResult; -import com.carpi.carpibackend.repository.CourseRepository; import com.carpi.carpibackend.service.CourseSearchService; @CrossOrigin @@ -24,28 +21,29 @@ @RequestMapping("/api/v1/course") public class CourseController { - @Autowired - private CourseRepository courseRepository; - @Autowired private CourseSearchService courseSearchService; @Autowired private ModelMapper modelMapper; - @ResponseBody - @GetMapping("getAll") - public ResponseEntity> getAll() { - return ResponseEntity.ok(courseRepository.findAll()); + @GetMapping("/all") + public ResponseEntity> getAll() { + return searchCourses(null, null, null, null); } - @ResponseBody - @GetMapping("search/{searchTerm}") - public ResponseEntity> searchCourse(@PathVariable String searchTerm) { - List searchResults = courseSearchService.searchCourse(searchTerm); + @GetMapping("/search") + public ResponseEntity> searchCourses( + @RequestParam(required = false) String prompt, + @RequestParam(required = false) String deptFilter, + @RequestParam(required = false) String attrFilter, + @RequestParam(required = false) String semFilter + ) { + List searchResults = + courseSearchService.searchCourses(prompt, deptFilter, attrFilter, semFilter); List courseDtos = searchResults.stream().map( - result -> modelMapper.map(result, CourseDto.class) - ).collect(Collectors.toList()); + result -> modelMapper.map(result, CourseDto.class) + ).collect(Collectors.toList()); return ResponseEntity.ok(courseDtos); } } diff --git a/src/main/java/com/carpi/carpibackend/dto/CourseDto.java b/src/main/java/com/carpi/carpibackend/dto/CourseDto.java index 0c7b9dd..db391e7 100644 --- a/src/main/java/com/carpi/carpibackend/dto/CourseDto.java +++ b/src/main/java/com/carpi/carpibackend/dto/CourseDto.java @@ -19,4 +19,8 @@ public class CourseDto { private short creditMin; private short creditMax; + + private String[] semesterList; + + private String[] attributeList; } diff --git a/src/main/java/com/carpi/carpibackend/entity/CourseSearchResult.java b/src/main/java/com/carpi/carpibackend/entity/CourseSearchResult.java index 3581f2f..41c33be 100644 --- a/src/main/java/com/carpi/carpibackend/entity/CourseSearchResult.java +++ b/src/main/java/com/carpi/carpibackend/entity/CourseSearchResult.java @@ -35,6 +35,12 @@ public class CourseSearchResult { @Column(name = "credit_max", nullable = false) private short creditMax; + @Column(name = "sem_list", nullable = false) + private String semesterList; + + @Column(name = "attr_list", nullable = true) + private String attributeList; + @Column(name = "code_match", nullable = false) private boolean codeMatch; diff --git a/src/main/java/com/carpi/carpibackend/repository/CourseSearchResultRepository.java b/src/main/java/com/carpi/carpibackend/repository/CourseSearchResultRepository.java index 4db579e..922207b 100644 --- a/src/main/java/com/carpi/carpibackend/repository/CourseSearchResultRepository.java +++ b/src/main/java/com/carpi/carpibackend/repository/CourseSearchResultRepository.java @@ -11,7 +11,7 @@ @Repository public interface CourseSearchResultRepository extends JpaRepository { - + @Query( value = """ SELECT @@ -21,6 +21,8 @@ public interface CourseSearchResultRepository extends JpaRepository 0 - OR title_exact_match > 0 - OR title_start_match > 0 - OR title_match > 0 - OR title_acronym > 0 - OR title_abbrev > 0 + ( + code_match > 0 + OR title_exact_match > 0 + OR title_start_match > 0 + OR title_match > 0 + OR title_acronym > 0 + OR title_abbrev > 0 + ) + AND sem_list LIKE CONCAT('%', IF(?8 IS NOT NULL, ?8, sem_list), '%') ORDER BY code_match DESC, title_exact_match DESC, @@ -51,12 +71,15 @@ public interface CourseSearchResultRepository extends JpaRepository searchCourse( + public List searchCourses( String regexCode, String regexFull, String regexStart, String regexAny, String regexAcronym, - String regexAbbrev + String regexAbbrev, + String deptFilter, + // String attrFilter, + String semsFilter ); } diff --git a/src/main/java/com/carpi/carpibackend/service/CourseSearchService.java b/src/main/java/com/carpi/carpibackend/service/CourseSearchService.java index 5c0d56a..f69ceee 100644 --- a/src/main/java/com/carpi/carpibackend/service/CourseSearchService.java +++ b/src/main/java/com/carpi/carpibackend/service/CourseSearchService.java @@ -15,26 +15,50 @@ public class CourseSearchService { private CourseSearchResultRepository courseSearchResultRepository; /** - * - * @param searchTerm - * @return + * @author Jack Zgombic + * @author Raymond Chen + * @param searchPrompt Prompt used to search for relevant courses. May be null. + * @param deptFilter Department filter (e.g. "CSCI", "MATH"). May be null. + * @param attrFilter Attribute filter (e.g. "HASS Inquiry"). May be null. + * @param semsFilter Semester filter (e.g. "Fall", "Spring"). May be null. + * @return A list containing the most relevant courses according to the given + * search prompt and filters, or a list of all courses if all arguments + * are null. */ - public List searchCourse(String searchTerm) { + public List searchCourses( + String searchPrompt, + String deptFilter, + String attrFilter, + String semsFilter + ) { + if (searchPrompt == null) { + return courseSearchResultRepository.searchCourses( + ".*", + ".*", + ".*", + ".*", + ".*", + ".*", + deptFilter, + // attrFilter, + semsFilter + ); + } final String regStartOrSpace = "(^|.* )"; - String regexCode = "^" + searchTerm + "$", - regexFull = "^" + searchTerm + "$", - regexStart = "^" + searchTerm, - regexAny = searchTerm, + String regexCode = "^" + searchPrompt + "$", + regexFull = "^" + searchPrompt + "$", + regexStart = "^" + searchPrompt, + regexAny = searchPrompt, regexAcronym = regStartOrSpace; - for (int i = 0; i < searchTerm.length(); ++i) { - char ch = searchTerm.charAt(i); + for (int i = 0; i < searchPrompt.length(); ++i) { + char ch = searchPrompt.charAt(i); if (ch != ' ') { regexAcronym += ch + ".* "; } } regexAcronym = regexAcronym.substring(0, regexAcronym.length() - 3); String regexAbbrev = ""; - String[] tokens = searchTerm.split(" "); + String[] tokens = searchPrompt.split(" "); if (tokens.length > 1) { regexAbbrev += regStartOrSpace; for (int i = 0; i < tokens.length; ++i) { @@ -45,13 +69,16 @@ public List searchCourse(String searchTerm) { else { regexAbbrev = "a^"; } - return courseSearchResultRepository.searchCourse( + return courseSearchResultRepository.searchCourses( regexCode, regexFull, regexStart, regexAny, regexAcronym, - regexAbbrev + regexAbbrev, + deptFilter, + // attrFilter, + semsFilter ); } From 786ae23adc5fa3a474a7f6bd71e39c6e0a856679 Mon Sep 17 00:00:00 2001 From: Raymond Chen <42894676+SameriteRL@users.noreply.github.com> Date: Fri, 8 Nov 2024 16:46:24 -0500 Subject: [PATCH 09/11] Add support for multiple filters of same type Added in attribute filtering, and query parameters now allow for a sequence of filters of the same type. For example, you can now filter by both "CSCI" and "ITWS" and get courses that are from either department. You can also filter by "Communication Intensive" and "HASS Inquiry" attributes and get courses that have both of them. --- .../controller/CourseController.java | 19 +++-- .../CourseSearchResultRepository.java | 25 +++--- .../service/CourseSearchService.java | 83 ++++++++++++------- 3 files changed, 77 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/carpi/carpibackend/controller/CourseController.java b/src/main/java/com/carpi/carpibackend/controller/CourseController.java index e873bc7..ed541ec 100644 --- a/src/main/java/com/carpi/carpibackend/controller/CourseController.java +++ b/src/main/java/com/carpi/carpibackend/controller/CourseController.java @@ -1,5 +1,6 @@ package com.carpi.carpibackend.controller; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -8,8 +9,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.carpi.carpibackend.dto.CourseDto; @@ -34,13 +35,17 @@ public ResponseEntity> getAll() { @GetMapping("/search") public ResponseEntity> searchCourses( - @RequestParam(required = false) String prompt, - @RequestParam(required = false) String deptFilter, - @RequestParam(required = false) String attrFilter, - @RequestParam(required = false) String semFilter + @RequestParam(required = false) String searchPrompt, + @RequestParam(required = false) String[] deptFilters, + @RequestParam(required = false) String[] attrFilters, + @RequestParam(required = false) String[] semFilters ) { - List searchResults = - courseSearchService.searchCourses(prompt, deptFilter, attrFilter, semFilter); + List searchResults = courseSearchService.searchCourses( + searchPrompt, + deptFilters, + attrFilters, + semFilters + ); List courseDtos = searchResults.stream().map( result -> modelMapper.map(result, CourseDto.class) ).collect(Collectors.toList()); diff --git a/src/main/java/com/carpi/carpibackend/repository/CourseSearchResultRepository.java b/src/main/java/com/carpi/carpibackend/repository/CourseSearchResultRepository.java index 922207b..b37bd30 100644 --- a/src/main/java/com/carpi/carpibackend/repository/CourseSearchResultRepository.java +++ b/src/main/java/com/carpi/carpibackend/repository/CourseSearchResultRepository.java @@ -22,7 +22,7 @@ public interface CourseSearchResultRepository extends JpaRepository 0 GROUP BY dept, code_num, @@ -57,7 +57,8 @@ LEFT JOIN course_attribute USING(dept, code_num) OR title_acronym > 0 OR title_abbrev > 0 ) - AND sem_list LIKE CONCAT('%', IF(?8 IS NOT NULL, ?8, sem_list), '%') + AND REGEXP_LIKE(IFNULL(attr_list, ''), ?8, 'i') > 0 + AND REGEXP_LIKE(sem_list, ?9, 'i') > 0 ORDER BY code_match DESC, title_exact_match DESC, @@ -72,14 +73,14 @@ AND sem_list LIKE CONCAT('%', IF(?8 IS NOT NULL, ?8, sem_list), '%') nativeQuery = true ) public List searchCourses( - String regexCode, - String regexFull, - String regexStart, - String regexAny, - String regexAcronym, - String regexAbbrev, - String deptFilter, - // String attrFilter, - String semsFilter + String searchCodeRegex, + String searchFullRegex, + String searchStartRegex, + String searchAnyRegex, + String searchAcronymRegex, + String searchAbbrevRegex, + String deptFilterRegex, + String attrFilterRegex, + String semFilterRegex ); } diff --git a/src/main/java/com/carpi/carpibackend/service/CourseSearchService.java b/src/main/java/com/carpi/carpibackend/service/CourseSearchService.java index f69ceee..b29d772 100644 --- a/src/main/java/com/carpi/carpibackend/service/CourseSearchService.java +++ b/src/main/java/com/carpi/carpibackend/service/CourseSearchService.java @@ -1,5 +1,6 @@ package com.carpi.carpibackend.service; +import java.util.Arrays; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; @@ -18,19 +19,40 @@ public class CourseSearchService { * @author Jack Zgombic * @author Raymond Chen * @param searchPrompt Prompt used to search for relevant courses. May be null. - * @param deptFilter Department filter (e.g. "CSCI", "MATH"). May be null. - * @param attrFilter Attribute filter (e.g. "HASS Inquiry"). May be null. - * @param semsFilter Semester filter (e.g. "Fall", "Spring"). May be null. + * @param deptFilters Department filters (e.g. "CSCI", "MATH"). May be null. + * @param attrFilters Attribute filters (e.g. "HASS Inquiry"). May be null. + * @param semFilters Semester filters (e.g. "Fall", "Spring"). May be null. * @return A list containing the most relevant courses according to the given * search prompt and filters, or a list of all courses if all arguments * are null. */ public List searchCourses( String searchPrompt, - String deptFilter, - String attrFilter, - String semsFilter + String[] deptFilters, + String[] attrFilters, + String[] semFilters ) { + String[] deptFiltersCopy = null, + attrFiltersCopy = null, + semFiltersCopy = null; + String deptFilterRegex = ".*", + attrFilterRegex = ".*", + semFilterRegex = ".*"; + if (deptFilters != null && deptFilters.length > 0) { + deptFiltersCopy = Arrays.copyOf(deptFilters, deptFilters.length); + Arrays.sort(deptFiltersCopy); + deptFilterRegex = String.join("|", deptFiltersCopy); + } + if (attrFilters != null && attrFilters.length > 0) { + attrFiltersCopy = Arrays.copyOf(attrFilters, attrFilters.length); + Arrays.sort(attrFiltersCopy); + attrFilterRegex = String.join(".*", attrFiltersCopy); + } + if (semFilters != null && semFilters.length > 0) { + semFiltersCopy = Arrays.copyOf(semFilters, semFilters.length); + Arrays.sort(semFiltersCopy); + semFilterRegex = String.join(".*", semFiltersCopy); + } if (searchPrompt == null) { return courseSearchResultRepository.searchCourses( ".*", @@ -39,47 +61,46 @@ public List searchCourses( ".*", ".*", ".*", - deptFilter, - // attrFilter, - semsFilter + deptFilterRegex, + attrFilterRegex, + semFilterRegex ); } final String regStartOrSpace = "(^|.* )"; - String regexCode = "^" + searchPrompt + "$", - regexFull = "^" + searchPrompt + "$", - regexStart = "^" + searchPrompt, - regexAny = searchPrompt, - regexAcronym = regStartOrSpace; + String searchCodeRegex = "^" + searchPrompt + "$", + searchFullRegex = "^" + searchPrompt + "$", + searchStartRegex = "^" + searchPrompt, + searchAnyRegex = searchPrompt, + searchAcronymRegex = regStartOrSpace; for (int i = 0; i < searchPrompt.length(); ++i) { char ch = searchPrompt.charAt(i); if (ch != ' ') { - regexAcronym += ch + ".* "; + searchAcronymRegex += ch + ".* "; } } - regexAcronym = regexAcronym.substring(0, regexAcronym.length() - 3); - String regexAbbrev = ""; + searchAcronymRegex = searchAcronymRegex.substring(0, searchAcronymRegex.length() - 3); + String searchAbbrevRegex = ""; String[] tokens = searchPrompt.split(" "); if (tokens.length > 1) { - regexAbbrev += regStartOrSpace; + searchAbbrevRegex += regStartOrSpace; for (int i = 0; i < tokens.length; ++i) { - regexAbbrev += tokens[i] + ".* "; + searchAbbrevRegex += tokens[i] + ".* "; } - regexAbbrev = regexAbbrev.substring(0, regexAbbrev.length() - 3); + searchAbbrevRegex = searchAbbrevRegex.substring(0, searchAbbrevRegex.length() - 3); } else { - regexAbbrev = "a^"; + searchAbbrevRegex = "a^"; } return courseSearchResultRepository.searchCourses( - regexCode, - regexFull, - regexStart, - regexAny, - regexAcronym, - regexAbbrev, - deptFilter, - // attrFilter, - semsFilter + searchCodeRegex, + searchFullRegex, + searchStartRegex, + searchAnyRegex, + searchAcronymRegex, + searchAbbrevRegex, + deptFilterRegex, + attrFilterRegex, + semFilterRegex ); } - } From e59619e0095e8cc799146a3c6db07abedff92001 Mon Sep 17 00:00:00 2001 From: anthonyrys Date: Tue, 12 Nov 2024 16:28:13 -0500 Subject: [PATCH 10/11] Update tests workflow --- .github/workflows/tests.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ec40f34..c38cb1f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,6 +14,12 @@ jobs: distribution: 'temurin' java-version: '17' + - name: Setup env.properties + run: | + echo "DB_URL=${{ secrets.DB_URL }}" >> src/main/resources/env.properties + echo "DB_USERNAME=${{ secrets.DB_USERNAME }}" >> src/main/resources/env.properties + echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> src/main/resources/env.properties + - name: Cache Maven packages uses: actions/cache@v4 with: From 7796cbb8d12bed31c4c6f1f0abcd15a869e85016 Mon Sep 17 00:00:00 2001 From: anthonyrys <99291131+anthonyrys@users.noreply.github.com> Date: Fri, 15 Nov 2024 16:30:22 -0500 Subject: [PATCH 11/11] Rename .env.properties.example to env.properties.example --- .../resources/{.env.properties.example => env.properties.example} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/resources/{.env.properties.example => env.properties.example} (100%) diff --git a/src/main/resources/.env.properties.example b/src/main/resources/env.properties.example similarity index 100% rename from src/main/resources/.env.properties.example rename to src/main/resources/env.properties.example