v0.2.0 Switch to mongoDB

This commit is contained in:
Murtadha 2024-12-13 17:52:33 -05:00
parent 3d2a1cdf68
commit e22d2b6fca
9 changed files with 62 additions and 292 deletions

29
pom.xml
View file

@ -27,7 +27,7 @@
<url/> <url/>
</scm> </scm>
<properties> <properties>
<java.version>17</java.version> <java.version>21</java.version>
</properties> </properties>
<dependencies> <dependencies>
@ -67,35 +67,10 @@
<version>3.5.6-Final</version> <version>3.5.6-Final</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>3.3.4</version>
</dependency> -->
<!-- https://mvnrepository.com/artifact/com.github.gwenn/sqlite-dialect -->
<dependency>
<groupId>com.github.gwenn</groupId>
<artifactId>sqlite-dialect</artifactId>
<version>0.1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.45.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId> <artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>3.3.4</version>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>

View file

@ -1,18 +1,16 @@
package io.titan.portfolio.controller; package io.titan.portfolio.controller;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.ExceptionHandler; // import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping; // import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; // import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; // import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping; // import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody; // import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; // import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; // import org.springframework.web.bind.annotation.RestController;
import io.titan.portfolio.model.Education; import io.titan.portfolio.model.Education;
import io.titan.portfolio.service.EducationService; import io.titan.portfolio.service.EducationService;
@ -29,74 +27,35 @@ public class EducationController {
} }
@GetMapping @GetMapping
public ResponseEntity<List<Education>> getAllEducation() { List<Education> getAllEducation(){
List<Education> educations = educationService.getAllEducation(); return educationService.getAllEducation();
return ResponseEntity.ok(educations);
} }
@GetMapping("/{id}") @GetMapping("/{id}")
public ResponseEntity<Education> getEducationById(@PathVariable Long id) { ResponseEntity<Education> getEducationById(@PathVariable String id) {
return educationService.getEducationById(id) return educationService.getEducationById(id)
.map(ResponseEntity::ok) .map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build()); .orElse(ResponseEntity.notFound().build());
} }
@PostMapping @PostMapping
public ResponseEntity<Education> createEducation(@RequestBody Education education) { ResponseEntity<Void> createEducation(@RequestBody Education education) {
try { educationService.createEducation(education);
Education createdEducation = educationService.createEducation(education); return ResponseEntity.status(HttpStatus.CREATED).build();
return ResponseEntity.status(HttpStatus.CREATED).body(createdEducation);
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(null);
}
} }
@PutMapping("/{id}") @PutMapping("/{id}")
public ResponseEntity<Education> updateEducation(@PathVariable Long id, @RequestBody Education education) { ResponseEntity<Education> updateEducation(@PathVariable String id, @RequestBody Education education) {
if (!id.equals(education.id())) { if (!id.equals(education.id())) {
return ResponseEntity.badRequest().build(); return ResponseEntity.badRequest().build();
} }
try { educationService.updateEducation(education);
Education updatedEducation = educationService.updateEducation(education); return ResponseEntity.ok(education);
return ResponseEntity.ok(updatedEducation);
} catch (EmptyResultDataAccessException e) {
return ResponseEntity.notFound().build();
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(null);
}
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public ResponseEntity<Void> deleteEducation(@PathVariable Long id) { ResponseEntity<Void> deleteEducation(@PathVariable String id) {
try { boolean deleted = educationService.deleteEducation(id);
educationService.deleteEducation(id); return deleted ? ResponseEntity.ok().build() : ResponseEntity.notFound().build();
return ResponseEntity.noContent().build();
} catch (EmptyResultDataAccessException e) {
return ResponseEntity.notFound().build();
}
}
@ExceptionHandler(EmptyResultDataAccessException.class)
public ResponseEntity<String> handleNotFound(EmptyResultDataAccessException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage());
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<String> handleBadRequest(IllegalArgumentException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}
@ExceptionHandler(DataAccessException.class)
public ResponseEntity<String> handleDataAccessException(DataAccessException e) {
// Log the exception
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An unexpected error occurred");
}
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleGeneralException(Exception e) {
// Log the exception
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An unexpected error occurred");
} }
} }

View file

@ -1,14 +1,19 @@
package io.titan.portfolio.model; package io.titan.portfolio.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.List; import java.util.List;
@Document(collection = "education")
public record Education( public record Education(
Long id, @Id String id,
String title, String title,
String organization, String organization,
String logo, String logo,
String location, String location,
String duration, Integer fromDate,
Integer toDate,
String description, String description,
List<String> achievements, List<String> achievements,
List<String> skills, List<String> skills,
@ -17,13 +22,13 @@ public record Education(
String techStackTitle String techStackTitle
) { ) {
public Education() { public Education() {
this(null, null, null, null, null, null, null, null, null, null, null, null); this(null, null, null, null, null, null, null, null, null, null, null, null, null);
} }
public Education(String title, String organization, String logo, String location, String duration, public Education(String title, String organization, String logo, String location, Integer fromDate, Integer toDate,
String description, List<String> achievements, List<String> skills, String description, List<String> achievements, List<String> skills,
List<String> techStack, String skillsTitle, String techStackTitle) { List<String> techStack, String skillsTitle, String techStackTitle) {
this(null, title, organization, logo, location, duration, description, this(null, title, organization, logo, location, fromDate, toDate, description,
achievements, skills, techStack, skillsTitle, techStackTitle); achievements, skills, techStack, skillsTitle, techStackTitle);
} }
} }

View file

@ -1,119 +1,22 @@
package io.titan.portfolio.repository; package io.titan.portfolio.repository;
import io.titan.portfolio.model.Education; import io.titan.portfolio.model.Education;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import java.sql.PreparedStatement; import org.springframework.data.mongodb.repository.MongoRepository;
import java.sql.Statement; import org.springframework.stereotype.Repository;
import java.util.Arrays; // import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List; // import org.springframework.jdbc.core.RowMapper;
import java.util.Optional; // import org.springframework.jdbc.support.GeneratedKeyHolder;
// import org.springframework.jdbc.support.KeyHolder;
// import org.springframework.stereotype.Repository;
// import java.sql.PreparedStatement;
// import java.sql.Statement;
// import java.util.Arrays;
// import java.util.List;
// import java.util.Optional;
@Repository @Repository
public class EducationRepository { public interface EducationRepository extends MongoRepository<Education, String>{
private final JdbcTemplate jdbcTemplate;
public EducationRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
private static final RowMapper<Education> EDUCATION_ROW_MAPPER = (rs, rowNum) -> new Education(
rs.getLong("id"),
rs.getString("title"),
rs.getString("organization"),
rs.getString("logo"),
rs.getString("location"),
rs.getString("duration"),
rs.getString("description"),
Arrays.asList(rs.getString("achievements").split(",")),
Arrays.asList(rs.getString("skills").split(",")),
Arrays.asList(rs.getString("tech_stack").split(",")),
rs.getString("skills_title"),
rs.getString("tech_stack_title")
);
public List<Education> findAll() {
String sql = "SELECT * FROM Education";
return jdbcTemplate.query(sql, EDUCATION_ROW_MAPPER);
}
public Optional<Education> findById(Long id) {
String sql = "SELECT * FROM Education WHERE id = ?";
List<Education> results = jdbcTemplate.query(sql, EDUCATION_ROW_MAPPER, id);
return results.isEmpty() ? Optional.empty() : Optional.of(results.get(0));
}
public Education save(Education education) {
String sql = "INSERT INTO Education (title, organization, logo, location, duration, description, " +
"achievements, skills, tech_stack, skills_title, tech_stack_title) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
ps.setString(1, education.title());
ps.setString(2, education.organization());
ps.setString(3, education.logo());
ps.setString(4, education.location());
ps.setString(5, education.duration());
ps.setString(6, education.description());
ps.setString(7, String.join(",", education.achievements()));
ps.setString(8, String.join(",", education.skills()));
ps.setString(9, String.join(",", education.techStack()));
ps.setString(10, education.skillsTitle());
ps.setString(11, education.techStackTitle());
return ps;
}, keyHolder);
Long generatedId = keyHolder.getKey().longValue();
return new Education(
generatedId,
education.title(),
education.organization(),
education.logo(),
education.location(),
education.duration(),
education.description(),
education.achievements(),
education.skills(),
education.techStack(),
education.skillsTitle(),
education.techStackTitle()
);
}
public void update(Education education) {
String sql = "UPDATE Education SET title = ?, organization = ?, logo = ?, location = ?, " +
"duration = ?, description = ?, achievements = ?, skills = ?, tech_stack = ?, " +
"skills_title = ?, tech_stack_title = ? WHERE id = ?";
jdbcTemplate.update(sql,
education.title(),
education.organization(),
education.logo(),
education.location(),
education.duration(),
education.description(),
String.join(",", education.achievements()),
String.join(",", education.skills()),
String.join(",", education.techStack()),
education.skillsTitle(),
education.techStackTitle(),
education.id()
);
}
public boolean existsById(Long id) {
String sql = "SELECT COUNT(*) FROM Education WHERE id = ?";
Integer count = jdbcTemplate.queryForObject(sql, Integer.class, id);
return count != null && count > 0;
}
public void deleteById(Long id) {
String sql = "DELETE FROM Education WHERE id = ?";
jdbcTemplate.update(sql, id);
}
} }

View file

@ -2,10 +2,6 @@ package io.titan.portfolio.service;
import io.titan.portfolio.model.Education; import io.titan.portfolio.model.Education;
import io.titan.portfolio.repository.EducationRepository; import io.titan.portfolio.repository.EducationRepository;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
@ -20,75 +16,26 @@ public class EducationService{
} }
public List<Education> getAllEducation(){ public List<Education> getAllEducation(){
try {
return educationRepository.findAll(); return educationRepository.findAll();
} catch (DataAccessException e) {
// Log the error
System.err.println("Error retrieving all education records: " + e.getMessage());
throw new RuntimeException("Failed to retrieve education records", e);
}
} }
public Optional<Education> getEducationById(Long id) { public Optional<Education> getEducationById(String id){
try {
return educationRepository.findById(id); return educationRepository.findById(id);
} catch (DataAccessException e) {
// Log the error
System.err.println("Error retrieving education by id: " + e.getMessage());
throw new RuntimeException("Failed to retrieve education record", e);
}
} }
public Education createEducation(Education education) { public Education createEducation(Education education) {
try {
return educationRepository.save(education); return educationRepository.save(education);
} catch (DataIntegrityViolationException e) {
// Log the error
System.err.println("Error creating education record: " + e.getMessage());
throw new IllegalArgumentException("Invalid education data: " + e.getMessage());
} catch (DataAccessException e) {
// Log the error
System.err.println("Error creating education record: " + e.getMessage());
throw new RuntimeException("Failed to create education record", e);
}
} }
public Education updateEducation(Education education) { public void updateEducation(Education education) {
try { educationRepository.save(education);
if (!educationRepository.existsById(education.id())) {
throw new EmptyResultDataAccessException("Education record not found with id: " + education.id(), 1);
}
educationRepository.update(education);
return education;
} catch (EmptyResultDataAccessException e) {
// Log the error
System.err.println("Education record not found: " + e.getMessage());
throw e;
} catch (DataIntegrityViolationException e) {
// Log the error
System.err.println("Error updating education record: " + e.getMessage());
throw new IllegalArgumentException("Invalid education data: " + e.getMessage());
} catch (DataAccessException e) {
// Log the error
System.err.println("Error updating education record: " + e.getMessage());
throw new RuntimeException("Failed to update education record", e);
}
} }
public void deleteEducation(Long id) { public boolean deleteEducation(String id) {
try { if (educationRepository.existsById(id)) {
if (!educationRepository.existsById(id)) {
throw new EmptyResultDataAccessException("Education record not found with id: " + id, 1);
}
educationRepository.deleteById(id); educationRepository.deleteById(id);
} catch (EmptyResultDataAccessException e) { return true;
// Log the error }
System.err.println("Education record not found: " + e.getMessage()); return false;
throw e;
} catch (DataAccessException e) {
// Log the error
System.err.println("Error deleting education record: " + e.getMessage());
throw new RuntimeException("Failed to delete education record", e);
}
} }
} }

View file

@ -1,10 +1,5 @@
spring.datasource.url=jdbc:sqlite:titan.db spring.data.mongodb.uri=mongodb://portfolio_user:portfolio_P%40ssword@localhost:27017/portfolio_db
spring.datasource.driver-class-name=org.sqlite.JDBC spring.application.name=titan_backend
spring.sql.init.mode=always
spring.sql.init.schema-locations=classpath:education_schema.sql
spring.application.name=demo
spring.devtools.restart.enabled=true spring.devtools.restart.enabled=true
server.port=8282 server.port=8282

View file

@ -1,14 +0,0 @@
CREATE TABLE IF NOT EXISTS Education (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
organization TEXT NOT NULL,
logo TEXT,
location TEXT,
duration TEXT,
description TEXT,
achievements TEXT,
skills TEXT,
tech_stack TEXT,
skills_title TEXT,
tech_stack_title TEXT
);

BIN
titan.db

Binary file not shown.

View file

@ -1 +1 @@
0.1.2 0.2.0