Makes some changes in data model and enhances time entry service (with new method in repository)
This commit is contained in:
@@ -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))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,5 +75,4 @@ public class UserService {
|
||||
}
|
||||
return Mono.just(member.toGetUserDto());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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(),
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user