Makes some changes in data model and enhances time entry service (with new method in repository)

This commit is contained in:
szsa
2022-03-29 11:17:24 +02:00
parent b093715845
commit dc9eb0f0bb
11 changed files with 56 additions and 48 deletions

View File

@@ -3,8 +3,8 @@ package net.szymonsawicki.reactivetimesheetapp.application.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.szymonsawicki.reactivetimesheetapp.application.service.exception.TimeEntryServiceException;
import net.szymonsawicki.reactivetimesheetapp.application.service.exception.UserServiceException;
import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.TimeEntry;
import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.TimeEntryUtils;
import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.dto.CreateTimeEntryDto;
import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.dto.GetTimeEntryDto;
import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.repository.TimeEntryRepository;
@@ -22,28 +22,34 @@ public class TimeEntryService {
public Mono<GetTimeEntryDto> addTimeEntry(Mono<CreateTimeEntryDto> createTimeEntryDtoMono) {
return createTimeEntryDtoMono
.then(checkEntry(createTimeEntryDtoMono))
.flatMap(createTimeEntryDto -> {
// check if user from time entry exists in db
userRepository
.findById(createTimeEntryDto.user().id())
.switchIfEmpty(Mono.error(new TimeEntryServiceException("cannot find user")));
// call of the private method, which checks in db if there is a conflict with existing entries
checkTime(createTimeEntryDto);
return timeEntryRepository.save(createTimeEntryDto.toTimeEntry())
.map(TimeEntry::toGetTimeEntryDto);
});
}
private void checkTime(CreateTimeEntryDto timeEntryToCheck) {
timeEntryRepository.findAllByUserAndDate(timeEntryToCheck.user().toUser(), timeEntryToCheck.date())
.filter(timeEntry ->
TimeEntryUtils.toTimeFrom.apply(timeEntry).isAfter(timeEntryToCheck.timeTo()) ||
TimeEntryUtils.toTimeTo.apply(timeEntry).isBefore(timeEntryToCheck.timeFrom()))
.switchIfEmpty(Mono.error(new TimeEntryServiceException("entry time conflict")));
private Mono<CreateTimeEntryDto> checkEntry(Mono<CreateTimeEntryDto> timeEntryToCheck) {
return timeEntryToCheck.flatMap(t ->
// at first check if the user exists
userRepository
.findById(t.user().id())
.hasElement()
.flatMap(isUserPresent -> Boolean.TRUE.equals(isUserPresent)
?
Mono.just(timeEntryToCheck)
:
Mono.error(new UserServiceException("user not exists")))
// then collision check of the time entry
.flatMap(entry -> timeEntryRepository.timeCheck(t.timeFrom(), t.timeTo())
.flatMap(result -> result
?
Mono.error(new TimeEntryServiceException("time entry collision"))
:
Mono.just(t))));
}
}

View File

@@ -75,5 +75,4 @@ public class UserService {
}
return Mono.just(member.toGetUserDto());
}
}

View File

@@ -9,8 +9,7 @@ import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.type.Category;
import net.szymonsawicki.reactivetimesheetapp.domain.user.User;
import net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.entity.TimeEntryEntity;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
@AllArgsConstructor
@NoArgsConstructor
@@ -19,9 +18,8 @@ import java.time.LocalTime;
public class TimeEntry {
String id;
LocalDate date;
LocalTime timeFrom;
LocalTime timeTo;
LocalDateTime timeFrom;
LocalDateTime timeTo;
User user;
Category category;
String description;
@@ -29,7 +27,6 @@ public class TimeEntry {
public TimeEntryEntity toEntity() {
return TimeEntryEntity.builder()
.id(id)
.date(date)
.timeFrom(timeFrom)
.timeTo(timeTo)
.user(user.toEntity())
@@ -41,7 +38,6 @@ public class TimeEntry {
public GetTimeEntryDto toGetTimeEntryDto() {
return new GetTimeEntryDto(
id,
date,
timeFrom,
timeTo,
user.toGetUserDto(),

View File

@@ -1,11 +1,11 @@
package net.szymonsawicki.reactivetimesheetapp.domain.time_entry;
import java.time.LocalTime;
import java.time.LocalDateTime;
import java.util.function.Function;
public interface TimeEntryUtils {
Function<TimeEntry, LocalTime> toTimeFrom = timeEntry -> timeEntry.timeFrom;
Function<TimeEntry, LocalTime> toTimeTo = timeEntry -> timeEntry.timeTo;
Function<TimeEntry, LocalDateTime> toTimeFrom = timeEntry -> timeEntry.timeFrom;
Function<TimeEntry, LocalDateTime> toTimeTo = timeEntry -> timeEntry.timeTo;
}

View File

@@ -4,13 +4,11 @@ import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.TimeEntry;
import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.type.Category;
import net.szymonsawicki.reactivetimesheetapp.domain.user.dto.GetUserDto;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
public record CreateTimeEntryDto(LocalDate date, LocalTime timeFrom, LocalTime timeTo, GetUserDto user, Category category, String description) {
public record CreateTimeEntryDto(LocalDateTime timeFrom, LocalDateTime timeTo, GetUserDto user, Category category, String description) {
public TimeEntry toTimeEntry() {
return TimeEntry.builder()
.date(date)
.timeFrom(timeFrom)
.timeTo(timeTo)
.user(user.toUser())

View File

@@ -2,17 +2,12 @@ package net.szymonsawicki.reactivetimesheetapp.domain.time_entry.dto;
import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.TimeEntry;
import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.type.Category;
import net.szymonsawicki.reactivetimesheetapp.domain.user.User;
import net.szymonsawicki.reactivetimesheetapp.domain.user.dto.GetUserDto;
import java.time.LocalDate;
import java.time.LocalTime;
public record GetTimeEntryDto(String id, LocalDate date, LocalTime timeFrom, LocalTime timeTo, GetUserDto user, Category category, String description) {
public record GetTimeEntryDto(String id, java.time.LocalDateTime timeFrom, java.time.LocalDateTime timeTo, GetUserDto user, Category category, String description) {
TimeEntry toTimeEntry() {
return TimeEntry.builder()
.id(id)
.date(date)
.timeFrom(timeFrom)
.timeTo(timeTo)
.user(user.toUser())

View File

@@ -4,10 +4,15 @@ import net.szymonsawicki.reactivetimesheetapp.domain.configs.CrudRepository;
import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.TimeEntry;
import net.szymonsawicki.reactivetimesheetapp.domain.user.User;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDate;
import java.time.LocalDateTime;
public interface TimeEntryRepository extends CrudRepository<TimeEntry, String> {
Flux<TimeEntry> findAllByUserAndDate(User user, LocalDate date);
Flux<TimeEntry> findAllByUser(User user);
Mono<Boolean> timeCheck(LocalDateTime dateFrom, LocalDateTime dateTo);
}

View File

@@ -2,12 +2,19 @@ package net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.dao;
import net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.entity.TimeEntryEntity;
import net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.entity.UserEntity;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDate;
import java.time.LocalDateTime;
public interface TimeEntryDao extends ReactiveMongoRepository<TimeEntryEntity, String> {
Flux<TimeEntryEntity> findAllByUserAndDate(UserEntity user, LocalDate date);
Flux<TimeEntryEntity> findAllByUser(UserEntity user);
@Query(value = "{'timeFrom':{ $gte: ?1},'timeTo':{ $lte: ?0}}")
Mono<Boolean> timeCheck(LocalDateTime timeFrom, LocalDateTime timeTo);
}

View File

@@ -6,12 +6,10 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.TimeEntry;
import net.szymonsawicki.reactivetimesheetapp.domain.time_entry.type.Category;
import net.szymonsawicki.reactivetimesheetapp.domain.user.User;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
@Document(collection = "time_entries")
@Builder
@@ -23,9 +21,8 @@ public class TimeEntryEntity {
@Id
String id;
LocalDate date;
LocalTime timeFrom;
LocalTime timeTo;
LocalDateTime timeFrom;
LocalDateTime timeTo;
UserEntity user;
Category category;
String description;
@@ -33,7 +30,6 @@ public class TimeEntryEntity {
public TimeEntry toTimeEntry() {
return TimeEntry.builder()
.id(id)
.date(date)
.timeFrom(timeFrom)
.timeTo(timeTo)
.user(user.toUser())

View File

@@ -11,6 +11,7 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Repository
@@ -56,7 +57,7 @@ public class TimeEntryRepositoryImpl implements TimeEntryRepository {
@Override
public Flux<TimeEntry> findAllByUserAndDate(User user, LocalDate date) {
return timeEntryDao.findAllByUserAndDate(user.toEntity(),date)
return timeEntryDao.findAllByUserAndDate(user.toEntity(), date)
.flatMap(timeEntryEntity -> Mono.just(timeEntryEntity.toTimeEntry()));
}
@@ -65,4 +66,9 @@ public class TimeEntryRepositoryImpl implements TimeEntryRepository {
return timeEntryDao.findAllByUser(user.toEntity())
.flatMap(timeEntryEntity -> Mono.just(timeEntryEntity.toTimeEntry()));
}
@Override
public Mono<Boolean> timeCheck(LocalDateTime dateFrom, LocalDateTime dateTo) {
return timeEntryDao.timeCheck(dateFrom, dateTo);
}
}

View File

@@ -34,7 +34,7 @@ public class Routing {
.andRoute(GET("/{username}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::findByUsername)
.andRoute(POST("/").and(accept(MediaType.APPLICATION_JSON)), userHandlers::createUser)
.andRoute(DELETE("/{id}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::deleteUser))
.andNest(path("/time_entries"),
.andNest(path("/time-entries"),
RouterFunctions.route(POST("/").and(accept(MediaType.APPLICATION_JSON)), timeEntryHandlers::addTimeEntry));
}
}