US02: Make it possible for the user to assign a race to a horse

This commit is contained in:
Ivaylo Ivanov 2020-03-18 20:39:02 +01:00
parent 01268263de
commit 98d555327e
10 changed files with 88 additions and 23 deletions

View File

@ -1,5 +1,7 @@
package at.ac.tuwien.sepm.assignment.individual.endpoint.dto; package at.ac.tuwien.sepm.assignment.individual.endpoint.dto;
import at.ac.tuwien.sepm.assignment.individual.enums.ERace;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Objects; import java.util.Objects;
import java.sql.Date; import java.sql.Date;
@ -10,25 +12,28 @@ public class HorseDto extends BaseDto {
private String name; private String name;
private String description; private String description;
private short score; private short score;
private ERace race;
private Date birthday; private Date birthday;
private Long owner; private Long owner;
public HorseDto() {} public HorseDto() {}
public HorseDto(String name, String description, short score, Date birthday, Long owner) { public HorseDto(String name, String description, short score, Date birthday, ERace race, Long owner) {
this.name = name; this.name = name;
this.description = description; this.description = description;
this.score = score; this.score = score;
this.birthday = birthday; this.birthday = birthday;
this.race = race;
this.owner = owner; this.owner = owner;
} }
public HorseDto(Long id, String name, String description, short score, Date birthday, LocalDateTime created, LocalDateTime updated, Long owner) { public HorseDto(Long id, String name, String description, short score, Date birthday, ERace race, LocalDateTime created, LocalDateTime updated, Long owner) {
super(id, created, updated); super(id, created, updated);
this.name = name; this.name = name;
this.description = description; this.description = description;
this.score = score; this.score = score;
this.birthday = birthday; this.birthday = birthday;
this.race = race;
this.owner = owner; this.owner = owner;
} }
@ -64,6 +69,14 @@ public class HorseDto extends BaseDto {
this.birthday = birthday; this.birthday = birthday;
} }
public ERace getRace() {
return race;
}
public void setRace(ERace race) {
this.race = race;
}
public Long getOwner() { public Long getOwner() {
return owner; return owner;
} }
@ -77,8 +90,13 @@ public class HorseDto extends BaseDto {
if (this == o) return true; if (this == o) return true;
if (!(o instanceof HorseDto)) return false; if (!(o instanceof HorseDto)) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
HorseDto horseDto = (HorseDto) o; HorseDto h = (HorseDto) o;
return Objects.equals(name, horseDto.name); return Objects.equals(name, h.name) &&
Objects.equals(description, h.description) &&
Objects.equals(score, h.score) &&
Objects.equals(birthday, h.birthday) &&
Objects.equals(race, h.race) &&
Objects.equals(owner, h.owner);
} }
@Override @Override
@ -94,6 +112,7 @@ public class HorseDto extends BaseDto {
", description='" + description + '\'' + ", description='" + description + '\'' +
", score='" + score + '\'' + ", score='" + score + '\'' +
", birthday='" + df.format(birthday) + '\'' + ", birthday='" + df.format(birthday) + '\'' +
", race='" + race + '\'' +
", owner_id='" + owner + '\''; ", owner_id='" + owner + '\'';
} }

View File

@ -8,10 +8,10 @@ import org.springframework.stereotype.Component;
@Component @Component
public class HorseMapper { public class HorseMapper {
public HorseDto entityToDto(Horse horse) { public HorseDto entityToDto(Horse horse) {
return new HorseDto(horse.getId(), horse.getName(), horse.getDescription(), horse.getScore(), horse.getBirthday(), horse.getCreatedAt(), horse.getUpdatedAt(), horse.getOwner()); return new HorseDto(horse.getId(), horse.getName(), horse.getDescription(), horse.getScore(), horse.getBirthday(), horse.getRace(), horse.getCreatedAt(), horse.getUpdatedAt(), horse.getOwner());
} }
public Horse dtoToEntity(HorseDto horse) { public Horse dtoToEntity(HorseDto horse) {
return new Horse(horse.getId(), horse.getName(), horse.getDescription(), horse.getScore(), horse.getBirthday(), horse.getOwner()); return new Horse(horse.getId(), horse.getName(), horse.getDescription(), horse.getScore(), horse.getBirthday(), horse.getRace(), horse.getOwner());
} }
} }

View File

@ -5,39 +5,44 @@ import java.text.SimpleDateFormat;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.sql.Date; import java.sql.Date;
import java.util.Objects; import java.util.Objects;
import at.ac.tuwien.sepm.assignment.individual.enums.ERace;
public class Horse extends BaseEntity { public class Horse extends BaseEntity {
private String name; private String name;
private String description; private String description;
private short score; private short score;
private ERace race;
private Date birthday; private Date birthday;
private Long owner; private Long owner;
public Horse() {} public Horse() {}
public Horse(String name, String description, short score, Date birthday, Long owner) { public Horse(String name, String description, short score, Date birthday, ERace race,Long owner) {
this.name = name; this.name = name;
this.description = description; this.description = description;
this.score = score; this.score = score;
this.birthday = birthday; this.birthday = birthday;
this.race = race;
this.owner = owner; this.owner = owner;
} }
public Horse(Long id, String name, String description, short score, Date birthday, Long owner) { public Horse(Long id, String name, String description, short score, Date birthday, ERace race, Long owner) {
super(id); super(id);
this.name = name; this.name = name;
this.description = description; this.description = description;
this.score = score; this.score = score;
this.birthday = birthday; this.birthday = birthday;
this.race = race;
this.owner = owner; this.owner = owner;
} }
public Horse(Long id, String name, String description, short score, Date birthday, Long owner, LocalDateTime created, LocalDateTime updated) { public Horse(Long id, String name, String description, short score, Date birthday, ERace race, Long owner, LocalDateTime created, LocalDateTime updated) {
super(id, created, updated); super(id, created, updated);
this.name = name; this.name = name;
this.description = description; this.description = description;
this.score = score; this.score = score;
this.birthday = birthday; this.birthday = birthday;
this.race = race;
this.owner = owner; this.owner = owner;
} }
@ -73,6 +78,14 @@ public class Horse extends BaseEntity {
this.birthday = birthday; this.birthday = birthday;
} }
public ERace getRace() {
return race;
}
public void setRace(ERace race) {
this.race = race;
}
public Long getOwner() { public Long getOwner() {
return owner; return owner;
} }
@ -86,8 +99,13 @@ public class Horse extends BaseEntity {
if (this == o) return true; if (this == o) return true;
if (!(o instanceof Horse)) return false; if (!(o instanceof Horse)) return false;
if (!super.equals(o)) return false; if (!super.equals(o)) return false;
Horse Horse = (Horse) o; Horse h = (Horse) o;
return Objects.equals(name, Horse.name); return Objects.equals(name, h.name) &&
Objects.equals(description, h.description) &&
Objects.equals(score, h.score) &&
Objects.equals(birthday, h.birthday) &&
Objects.equals(race, h.race) &&
Objects.equals(owner, h.owner);
} }
@Override @Override
@ -103,6 +121,7 @@ public class Horse extends BaseEntity {
"description='" + description + '\'' + "description='" + description + '\'' +
", score='" + score + '\'' + ", score='" + score + '\'' +
", birthday='" + df.format(birthday) + '\'' + ", birthday='" + df.format(birthday) + '\'' +
", race='" + race + '\'' +
", owner='" + owner + '\''; ", owner='" + owner + '\'';
} }

View File

@ -1,11 +1,13 @@
package at.ac.tuwien.sepm.assignment.individual.persistence.impl; package at.ac.tuwien.sepm.assignment.individual.persistence.impl;
import at.ac.tuwien.sepm.assignment.individual.entity.Horse; import at.ac.tuwien.sepm.assignment.individual.entity.Horse;
import at.ac.tuwien.sepm.assignment.individual.enums.ERace;
import at.ac.tuwien.sepm.assignment.individual.exception.NotFoundException; import at.ac.tuwien.sepm.assignment.individual.exception.NotFoundException;
import at.ac.tuwien.sepm.assignment.individual.persistence.HorseDao; import at.ac.tuwien.sepm.assignment.individual.persistence.HorseDao;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DataRetrievalFailureException; import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@ -48,9 +50,13 @@ public class HorseJdbcDao implements HorseDao {
@Override @Override
public Horse addHorse(Horse horse) throws DataAccessException { public Horse addHorse(Horse horse) throws DataAccessException {
LOGGER.trace("Add horse {}", horse.toString()); LOGGER.trace("Add horse {}", horse.toString());
String sql = "INSERT INTO " + TABLE_NAME + "(name, description, score, birthday, owner_id, created_at, updated_at) VALUES(?, ?, ?, ?, ?, ?, ?)"; String sql = "INSERT INTO " + TABLE_NAME + "(name, description, score, birthday, race, owner_id, created_at, updated_at) VALUES(?, ?, ?, ?, ?, ?, ?, ?)";
try { try {
// Check if the constraints are violated
if(horse.getName() == null || horse.getScore() == 0 || horse.getBirthday() == null || horse.getRace() == null)
throw new DataIntegrityViolationException("Required parameters for horse missing");
LocalDateTime currentTime = LocalDateTime.now(); LocalDateTime currentTime = LocalDateTime.now();
horse.setCreatedAt(currentTime); horse.setCreatedAt(currentTime);
@ -61,18 +67,20 @@ public class HorseJdbcDao implements HorseDao {
int changes = jdbcTemplate.update(connection -> { int changes = jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); PreparedStatement ps = connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
ps.setString(1, horse.getName()); ps.setString(1, horse.getName());
ps.setString(2, horse.getDescription()); ps.setString(2, horse.getDescription());
ps.setInt(3, horse.getScore()); ps.setInt(3, horse.getScore());
ps.setDate(4, horse.getBirthday()); ps.setDate(4, horse.getBirthday());
ps.setString(5, horse.getRace().toString()); // Convert to string to be able to save in DB
if(horse.getOwner() == null || horse.getOwner() == 0) if(horse.getOwner() == null || horse.getOwner() == 0)
ps.setNull(5, Types.NULL); ps.setNull(6, Types.NULL);
else else
ps.setObject(5, horse.getOwner()); ps.setObject(6, horse.getOwner());
ps.setObject(6, horse.getCreatedAt()); ps.setObject(7, horse.getCreatedAt());
ps.setObject(7, horse.getUpdatedAt()); ps.setObject(8, horse.getUpdatedAt());
return ps; return ps;
}, keyHolder); }, keyHolder);
@ -97,7 +105,10 @@ public class HorseJdbcDao implements HorseDao {
horse.setDescription(resultSet.getString("description")); horse.setDescription(resultSet.getString("description"));
horse.setScore(resultSet.getShort("score")); horse.setScore(resultSet.getShort("score"));
horse.setBirthday(resultSet.getDate("birthday")); horse.setBirthday(resultSet.getDate("birthday"));
horse.setRace(ERace.valueOf(resultSet.getString("race"))); // Convert to Enum for usage in objects
horse.setOwner(resultSet.getLong("owner_id")); horse.setOwner(resultSet.getLong("owner_id"));
horse.setCreatedAt(resultSet.getTimestamp("created_at").toLocalDateTime());
horse.setUpdatedAt(resultSet.getTimestamp("updated_at").toLocalDateTime());
return horse; return horse;
} }
} }

View File

@ -16,8 +16,8 @@ public class Validator {
} }
public void validateNewHorse(Horse horse) throws ValidationException { public void validateNewHorse(Horse horse) throws ValidationException {
if(horse.getName() == null || horse.getScore() == 0 || horse.getBirthday() == null || horse.getDescription() == null){ if(horse.getName() == null || horse.getScore() == 0 || horse.getBirthday() == null || horse.getRace() == null){
throw new ValidationException("All or some required values missing: name, description, score, birthday"); throw new ValidationException("All or some required values missing: name, score, birthday, race");
} }
if(horse.getScore() > 5 || horse.getScore() < 1) { if(horse.getScore() > 5 || horse.getScore() < 1) {
throw new ValidationException("Score value " + horse.getScore() + " not allowed. The score must be an integer between 1 and 5"); throw new ValidationException("Score value " + horse.getScore() + " not allowed. The score must be an integer between 1 and 5");

View File

@ -6,6 +6,9 @@ CREATE TABLE IF NOT EXISTS owner
updated_at DATETIME NOT NULL updated_at DATETIME NOT NULL
); );
-- Create enum for the race
CREATE TYPE IF NOT EXISTS RACE AS ENUM('ARABIAN', 'MORGAN', 'PAINT', 'APPALOOSA');
CREATE TABLE IF NOT EXISTS horse CREATE TABLE IF NOT EXISTS horse
( (
id BIGINT AUTO_INCREMENT PRIMARY KEY, id BIGINT AUTO_INCREMENT PRIMARY KEY,
@ -13,9 +16,11 @@ CREATE TABLE IF NOT EXISTS horse
description TEXT, description TEXT,
score TINYINT NOT NULL CHECK(score >= 1 AND score <= 5), score TINYINT NOT NULL CHECK(score >= 1 AND score <= 5),
birthday DATE NOT NULL, birthday DATE NOT NULL,
race RACE NOT NULL,
created_at DATETIME NOT NULL, created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL updated_at DATETIME NOT NULL
); );
-- Add nullable owner foreign key
ALTER TABLE horse ADD IF NOT EXISTS owner_id BIGINT NULL; ALTER TABLE horse ADD IF NOT EXISTS owner_id BIGINT NULL;
ALTER TABLE horse ADD CONSTRAINT IF NOT EXISTS FL_OWNER FOREIGN KEY (owner_id) REFERENCES owner(id); ALTER TABLE horse ADD CONSTRAINT IF NOT EXISTS FL_OWNER FOREIGN KEY (owner_id) REFERENCES owner(id);

View File

@ -3,6 +3,7 @@ package at.ac.tuwien.sepm.assignment.individual.integration;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import at.ac.tuwien.sepm.assignment.individual.endpoint.dto.HorseDto; import at.ac.tuwien.sepm.assignment.individual.endpoint.dto.HorseDto;
import at.ac.tuwien.sepm.assignment.individual.enums.ERace;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
@ -30,7 +31,7 @@ public class HorseEndpointTest {
@DisplayName("Adding a new horse with the correct parameters will return HTTP 201 and the new HorseDto") @DisplayName("Adding a new horse with the correct parameters will return HTTP 201 and the new HorseDto")
public void addingNewHorse_correctParameters_shouldReturnStatus201AndHorse() { public void addingNewHorse_correctParameters_shouldReturnStatus201AndHorse() {
String birthday = "2020-01-01"; String birthday = "2020-01-01";
HorseDto newHorse = new HorseDto("Zephyr", "Nice horse", (short) 4, Date.valueOf(birthday), null); HorseDto newHorse = new HorseDto("Zephyr", "Nice horse", (short) 4, Date.valueOf(birthday), ERace.APPALOOSA, null);
HttpEntity<HorseDto> request = new HttpEntity<>(newHorse); HttpEntity<HorseDto> request = new HttpEntity<>(newHorse);
ResponseEntity<HorseDto> response = REST_TEMPLATE ResponseEntity<HorseDto> response = REST_TEMPLATE

View File

@ -3,6 +3,7 @@ package at.ac.tuwien.sepm.assignment.individual.unit.persistence;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import at.ac.tuwien.sepm.assignment.individual.entity.Horse; import at.ac.tuwien.sepm.assignment.individual.entity.Horse;
import at.ac.tuwien.sepm.assignment.individual.enums.ERace;
import at.ac.tuwien.sepm.assignment.individual.persistence.HorseDao; import at.ac.tuwien.sepm.assignment.individual.persistence.HorseDao;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -20,7 +21,7 @@ public abstract class HorseDaoTestBase {
@DisplayName("Adding a new horse with the correct parameters should return the horse") @DisplayName("Adding a new horse with the correct parameters should return the horse")
public void addingNewHorse_correctParameters_shouldReturnHorse() { public void addingNewHorse_correctParameters_shouldReturnHorse() {
String birthday = "2020-01-01"; String birthday = "2020-01-01";
Horse newHorse = new Horse("Zephyr", "Nice horse", (short) 4, Date.valueOf(birthday), null); Horse newHorse = new Horse("Zephyr", "Nice horse", (short) 4, Date.valueOf(birthday), ERace.APPALOOSA, null);
Horse savedHorse = horseDao.addHorse(newHorse); Horse savedHorse = horseDao.addHorse(newHorse);
assertEquals(newHorse, savedHorse); assertEquals(newHorse, savedHorse);
} }
@ -29,7 +30,7 @@ public abstract class HorseDaoTestBase {
@DisplayName("Adding a new horse with the incorrect parameters should throw DataAccessException") @DisplayName("Adding a new horse with the incorrect parameters should throw DataAccessException")
public void addingNewHorse_incorrectParameters_shouldThrowDataAccess() { public void addingNewHorse_incorrectParameters_shouldThrowDataAccess() {
String birthday = "2020-01-01"; String birthday = "2020-01-01";
Horse newHorse = new Horse("Zephyr", "Nice horse", (short) 80, Date.valueOf(birthday), null); Horse newHorse = new Horse("Zephyr", "Nice horse", (short) 80, Date.valueOf(birthday), null, null);
assertThrows(DataAccessException.class, () -> horseDao.addHorse(newHorse)); assertThrows(DataAccessException.class, () -> horseDao.addHorse(newHorse));
} }

View File

@ -3,6 +3,7 @@ package at.ac.tuwien.sepm.assignment.individual.unit.service;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import at.ac.tuwien.sepm.assignment.individual.entity.Horse; import at.ac.tuwien.sepm.assignment.individual.entity.Horse;
import at.ac.tuwien.sepm.assignment.individual.enums.ERace;
import at.ac.tuwien.sepm.assignment.individual.service.HorseService; import at.ac.tuwien.sepm.assignment.individual.service.HorseService;
import at.ac.tuwien.sepm.assignment.individual.util.ValidationException; import at.ac.tuwien.sepm.assignment.individual.util.ValidationException;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
@ -28,7 +29,7 @@ public class HorseServiceTest {
@DisplayName("Adding a new horse with the correct parameters will return the new horse") @DisplayName("Adding a new horse with the correct parameters will return the new horse")
public void addingNewHorse_correctParameters_shouldReturnHorse() { public void addingNewHorse_correctParameters_shouldReturnHorse() {
String birthday = "2020-01-01"; String birthday = "2020-01-01";
Horse newHorse = new Horse("Zephyr", "Nice horse", (short) 4, Date.valueOf(birthday), null); Horse newHorse = new Horse("Zephyr", "Nice horse", (short) 4, Date.valueOf(birthday), ERace.APPALOOSA, null);
Horse savedHorse = horseService.addHorse(newHorse); Horse savedHorse = horseService.addHorse(newHorse);
assertEquals(newHorse, savedHorse); assertEquals(newHorse, savedHorse);
} }
@ -37,7 +38,7 @@ public class HorseServiceTest {
@DisplayName("Adding a new horse with the incorrect parameters will throw a ValidationException") @DisplayName("Adding a new horse with the incorrect parameters will throw a ValidationException")
public void addingNewHorse_incorrectParameters_shouldThrowValidation() { public void addingNewHorse_incorrectParameters_shouldThrowValidation() {
String birthday = "2020-01-01"; String birthday = "2020-01-01";
Horse newHorse = new Horse("Zephyr", "Nice horse", (short) 80, Date.valueOf(birthday), null); Horse newHorse = new Horse("Zephyr", "Nice horse", (short) 80, Date.valueOf(birthday), null, null);
assertThrows(ValidationException.class, () -> horseService.addHorse(newHorse)); assertThrows(ValidationException.class, () -> horseService.addHorse(newHorse));
} }
} }

View File

@ -5,6 +5,14 @@ export class Horse {
public description: string, public description: string,
public score: number, public score: number,
public birthday: Date, public birthday: Date,
public race: ERace,
public owner: number) { public owner: number) {
} }
} }
enum ERace {
ARABIAN,
MORGAN,
PAINT,
APPALOOSA
}