diff --git a/pom.xml b/pom.xml
index e823d390..72be188b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,10 +40,9 @@
org.springframework.boot
spring-boot-starter-security
-
org.springframework.boot
- spring-boot-starter-jdbc
+ spring-boot-starter-data-jpa
org.postgresql
diff --git a/src/main/java/com/emobile/springtodo/config/AppConfig.java b/src/main/java/com/emobile/springtodo/config/AppConfig.java
index d5f1ebc2..858e0b08 100644
--- a/src/main/java/com/emobile/springtodo/config/AppConfig.java
+++ b/src/main/java/com/emobile/springtodo/config/AppConfig.java
@@ -54,7 +54,7 @@ public JdbcTemplate jdbcTemplate(DataSource dataSource) {
}
@Bean
- public PlatformTransactionManager txManager() {
+ public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
diff --git a/src/main/java/com/emobile/springtodo/mapper/TaskMapper.java b/src/main/java/com/emobile/springtodo/mapper/TaskMapper.java
index 84977410..ccc8fa9a 100644
--- a/src/main/java/com/emobile/springtodo/mapper/TaskMapper.java
+++ b/src/main/java/com/emobile/springtodo/mapper/TaskMapper.java
@@ -6,6 +6,7 @@
import com.emobile.springtodo.model.dto.task.TaskSaveRequest;
import com.emobile.springtodo.model.entity.Task;
import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.mapstruct.ReportingPolicy;
@@ -45,8 +46,7 @@ public interface TaskMapper {
* @param model {@link Task} for mapping.
* @return mapped {@link TaskResponse}.
*/
-// @Mapping(target = "createdAt", qualifiedByName = "OffsetDateTimeToString")
-// @Mapping(target = "updatedAt", qualifiedByName = "OffsetDateTimeToString")
+ @Mapping(source = "author.id", target = "authorId")
TaskResponse modelToResponse(Task model);
diff --git a/src/main/java/com/emobile/springtodo/model/entity/Task.java b/src/main/java/com/emobile/springtodo/model/entity/Task.java
index 88ad60b8..36c61fc3 100644
--- a/src/main/java/com/emobile/springtodo/model/entity/Task.java
+++ b/src/main/java/com/emobile/springtodo/model/entity/Task.java
@@ -1,5 +1,15 @@
package com.emobile.springtodo.model.entity;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
@@ -22,35 +32,54 @@
@Getter
@FieldNameConstants
@Builder
+@Entity
+@Table(name = "tasks")
public class Task implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* Long Task id.
*/
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = Fields.id)
private Long id;
/**
* Task name.
*/
+ @Column(name = Fields.name)
private String name;
/**
* Task description.
*/
+ @Column(name = Fields.description)
private String description;
/**
* Task {@link TaskStatus} status.
*/
+ @Enumerated(EnumType.STRING)
+ @Column(name = Fields.status)
private TaskStatus status;
/**
* Task creation time without timezone.
*/
+ @Column(name = "created_at")
private LocalDateTime createdAt;
/**
* Task update time without timezone.
*/
+ @Column(name = "updated_at")
private LocalDateTime updatedAt;
/**
- * The User id who owns the Task.
+ * The User who owns the Task.
*/
- private Long authorId;
+ @EqualsAndHashCode.Exclude
+ @ManyToOne
+ @JoinColumn(name = "author_id", referencedColumnName = "id")
+ private User author;
+
+ @EqualsAndHashCode.Include
+ public Long getAuthorId() {
+ return author.getId();
+ }
}
diff --git a/src/main/java/com/emobile/springtodo/model/entity/User.java b/src/main/java/com/emobile/springtodo/model/entity/User.java
index 9ab52043..e3a56866 100644
--- a/src/main/java/com/emobile/springtodo/model/entity/User.java
+++ b/src/main/java/com/emobile/springtodo/model/entity/User.java
@@ -1,6 +1,7 @@
package com.emobile.springtodo.model.entity;
import com.emobile.springtodo.model.security.RoleType;
+import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
@@ -24,32 +25,52 @@
@Getter
@FieldNameConstants
@Builder
+@Entity
+@NamedEntityGraph(
+ name = "User.withTasks",
+ attributeNodes = @NamedAttributeNode("taskList")
+)
+@Table(name = "users",
+ indexes = {
+ @Index(columnList = User.Fields.username, unique = true),
+ @Index(columnList = User.Fields.email, unique = true)
+ })
public class User implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* Long User id.
*/
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = Fields.id)
private Long id;
/**
* User name.
*/
+ @Column(name = Fields.username)
private String username;
/**
* User password.
*/
+ @Column(name = Fields.password)
private String password;
/**
* User email.
*/
+ @Column(name = Fields.email)
private String email;
/**
* User authorization role type.
*/
+ @Enumerated(EnumType.STRING)
+ @Column(name = Fields.role)
private RoleType role;
/**
* User tasks.
*/
+ @ToString.Exclude
+ @OneToMany(mappedBy = Task.Fields.author, orphanRemoval = true)
@Builder.Default
private List taskList = new ArrayList<>();
}
diff --git a/src/main/java/com/emobile/springtodo/model/util/PageInfo.java b/src/main/java/com/emobile/springtodo/model/util/PageInfo.java
index 46f65ff0..0836f048 100644
--- a/src/main/java/com/emobile/springtodo/model/util/PageInfo.java
+++ b/src/main/java/com/emobile/springtodo/model/util/PageInfo.java
@@ -33,5 +33,5 @@ public record PageInfo(
/**
* Minimum size of the number field.
*/
- private static final int MIN_NUMBER_SIZE = 1;
+ private static final int MIN_NUMBER_SIZE = 0;
}
diff --git a/src/main/java/com/emobile/springtodo/repository/CrudRepository.java b/src/main/java/com/emobile/springtodo/repository/CrudRepository.java
deleted file mode 100644
index 79cb3d45..00000000
--- a/src/main/java/com/emobile/springtodo/repository/CrudRepository.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.emobile.springtodo.repository;
-
-import com.emobile.springtodo.model.util.Page;
-import com.emobile.springtodo.model.util.PageInfo;
-
-import java.util.Optional;
-
-/**
- * Default CRUD interface repository for working with entity {@link T}.
- *
- * @param entity for work
- */
-public interface CrudRepository {
- /**
- * Find all {@link T} objects from db
- * with {@code pageNumber} and {@code pageSize} from {@code pageInfo}.
- *
- * @return {@link Page} with {@link T} list.
- */
- Page findAll(PageInfo pageinfo);
-
- /**
- * Search object {@link T} in db.
- *
- * @param id id searched {@link T} object
- * @return {@link Optional} if exist, {@link Optional#empty()} if not
- */
- Optional findById(Long id);
-
- /**
- * Save object model of type {@link T}.
- *
- * @param model object of type {@link T} to save
- * @return object of type {@link T} that was saved
- */
- T save(T model);
-
- /**
- * Update object model of type {@link T}
- * by {@code T.id} value.
- *
- * @param model object of type {@link T} to update
- * @return object of type {@link T} that was updated
- */
- T update(T model);
-
- /**
- * Delete object with {@code T.id}
- * equals {@code id} from database.
- *
- * @param id id of the object to be deleted
- * @return {@code true} if success
- */
- boolean deleteById(Long id);
-}
diff --git a/src/main/java/com/emobile/springtodo/repository/TaskRepository.java b/src/main/java/com/emobile/springtodo/repository/TaskRepository.java
deleted file mode 100644
index a1b9b6ee..00000000
--- a/src/main/java/com/emobile/springtodo/repository/TaskRepository.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.emobile.springtodo.repository;
-
-import com.emobile.springtodo.model.entity.Task;
-
-/**
- * Default interface repository for working with entity {@link Task}.
- */
-public interface TaskRepository extends CrudRepository {
- /**
- * Delete all {@link Task} objects in database.
- *
- * @return {@code true} if success
- */
- boolean deleteAll();
-
- /**
- * Delete all {@link Task} objects in database
- * for user with {@code userId}.
- *
- * @return {@code true} if success
- */
- boolean deleteAllByUserId(Long authorId);
-}
diff --git a/src/main/java/com/emobile/springtodo/repository/UserRepository.java b/src/main/java/com/emobile/springtodo/repository/UserRepository.java
deleted file mode 100644
index a6693088..00000000
--- a/src/main/java/com/emobile/springtodo/repository/UserRepository.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.emobile.springtodo.repository;
-
-import com.emobile.springtodo.model.entity.User;
-
-import java.util.Optional;
-
-/**
- * Default interface repository for working with entity {@link User}.
- */
-public interface UserRepository extends CrudRepository {
- /**
- * Find {@link User}
- * with {@code User.username} equals {@code username}.
- *
- * @param username username searched {@link User}
- * @return {@link Optional} if exist, {@link Optional#empty()} if not
- */
- Optional findByUsername(String username);
-
- /**
- * Check duplicate {@code username}.
- * For save {@link User}.
- *
- * @param username username searched {@link User}
- * @return {@code true} if exist, {@code false} if not
- */
- boolean existsByUsername(String username);
-
- /**
- * Check duplicate {@code username}.
- * For update {@link User}.
- *
- * @param username username searched {@link User}
- * @return {@code true} if exist, {@code false} if not
- */
- boolean existsByUsernameAndIdNot(String username, Long currentUserId);
-
- /**
- * Check duplicate {@code email}.
- * For save {@link User}.
- *
- * @param email username searched {@link User}
- * @return {@code true} if exist, {@code false} if not
- */
- boolean existsByEmail(String email);
-
- /**
- * Check duplicate {@code email}.
- * For update {@link User}.
- *
- * @param email username searched {@link User}
- * @return {@code true} if exist, {@code false} if not
- */
- boolean existsByEmailAndIdNot(String email, Long currentUserId);
-}
diff --git a/src/main/java/com/emobile/springtodo/repository/impl/TaskRepositoryImpl.java b/src/main/java/com/emobile/springtodo/repository/impl/TaskRepositoryImpl.java
deleted file mode 100644
index d4821f6e..00000000
--- a/src/main/java/com/emobile/springtodo/repository/impl/TaskRepositoryImpl.java
+++ /dev/null
@@ -1,205 +0,0 @@
-package com.emobile.springtodo.repository.impl;
-
-import com.emobile.springtodo.aop.LazyLogger;
-import com.emobile.springtodo.exception.NullResultSetException;
-import com.emobile.springtodo.model.entity.Task;
-import com.emobile.springtodo.model.entity.TaskStatus;
-import com.emobile.springtodo.model.util.Page;
-import com.emobile.springtodo.model.util.PageInfo;
-import com.emobile.springtodo.repository.TaskRepository;
-import lombok.RequiredArgsConstructor;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.core.RowMapper;
-import org.springframework.stereotype.Repository;
-
-import java.util.Optional;
-
-import static com.emobile.springtodo.util.JdbcUtil.optionalExtractor;
-
-/**
- * Repository for working with entity {@link Task}.
- */
-@RequiredArgsConstructor
-@Repository
-public class TaskRepositoryImpl implements TaskRepository {
- /**
- * For work with db.
- */
- private final JdbcTemplate jdbcTemplate;
-
- /**
- * Find all {@link Task} objects from db
- * with {@code pageNumber} and {@code pageSize} from {@code pageInfo}.
- * LIMIT - {@code pageSize}.
- * OFFSET - ({@code pageNumber} -1) * {@code pageSize}.
- *
- * @return {@link Page} with {@link Task} list.
- * @see #getMapper()
- */
- @Override
- @LazyLogger
- public Page findAll(PageInfo pageInfo) {
- final String sql = """
- SELECT * FROM tasks
- LIMIT ? OFFSET ?
- """;
- int beginInd = (pageInfo.pageNumber() - 1) * pageInfo.pageSize();
- return new Page<>(
- jdbcTemplate.query(sql,
- getMapper(),
- pageInfo.pageSize(),
- beginInd
- )
- );
- }
-
- /**
- * Search object {@link Task} in db.
- *
- * @param id id searched {@link Task} object
- * @return {@link Optional} if exist, {@link Optional#empty()} if not
- * @see #getMapper()
- */
- @Override
- @LazyLogger
- public Optional findById(Long id) {
- final String sql = """
- SELECT *
- FROM tasks
- WHERE id=?
- """;
- return jdbcTemplate.query(
- sql,
- optionalExtractor(getMapper()),
- id
- );
- }
-
- /**
- * Save object model of type {@link Task}.
- *
- * @param model object of type {@link Task} to save
- * @return object of type {@link Task} that was saved
- * @throws NullResultSetException if returning value from db is null
- */
- @Override
- @LazyLogger
- public Task save(Task model) {
- final String sql = """
- INSERT INTO tasks(name, description, status,
- created_at, updated_at, author_id)
- VALUES (?,?,?,?,?,?)
- RETURNING *
- """;
- return jdbcTemplate.query(sql,
- optionalExtractor(getMapper()),
- model.getName(),
- model.getDescription(),
- model.getStatus().name(),
- model.getCreatedAt(),
- model.getUpdatedAt(),
- model.getAuthorId()
- ).orElseThrow(NullResultSetException.create(
- "taskRepository save() query exception"
- ));
- }
-
- /**
- * Update object model of type {@link Task}
- * by {@code T.id} value.
- *
- * @param model object of type {@link Task} to update
- * @return object of type {@link Task} that was updated
- * @throws NullResultSetException if returning value from db is null
- */
- @Override
- @LazyLogger
- public Task update(Task model) {
- final String sql = """
- UPDATE tasks
- SET name=?, description=?, status=?, updated_at=?, author_id =?
- WHERE id=?
- RETURNING *
- """;
- return jdbcTemplate.query(sql,
- optionalExtractor(getMapper()),
- model.getName(),
- model.getDescription(),
- model.getStatus().name(),
- model.getUpdatedAt(),
- model.getAuthorId(),
- model.getId()
- ).orElseThrow(NullResultSetException.create(
- "taskRepository update() query exception"
- ));
- }
-
- /**
- * Delete object with {@code Task.id}
- * equals {@code id} from database.
- *
- * @param id id of the object to be deleted
- * @return {@code true} if success
- */
- @Override
- @LazyLogger
- public boolean deleteById(Long id) {
- final String sql = """
- DELETE
- FROM tasks
- WHERE id=?
- """;
- int result = jdbcTemplate.update(sql, id);
- return result != 0;
- }
-
- /**
- * Delete all {@link Task} objects in database.
- *
- * @return {@code true} if success
- */
- @Override
- @LazyLogger
- public boolean deleteAll() {
- final String sql = "TRUNCATE tasks";
- int result = jdbcTemplate.update(sql);
- return result != 0;
- }
-
- /**
- * Delete all {@link Task} objects in database
- * for user with {@code userId}.
- *
- * @return {@code true} if success
- */
- @Override
- @LazyLogger
- public boolean deleteAllByUserId(Long userId) {
- final String sql = """
- DELETE
- FROM tasks
- WHERE author_id=?
- """;
- int result = jdbcTemplate.update(sql, userId);
- return result != 0;
- }
-
- /**
- * {@link Task} {@link RowMapper}.
- *
- * @return mapper for {@link Task} entity
- */
- private RowMapper getMapper() {
- return (rs, rn) -> Task.builder()
- .id(rs.getLong(Task.Fields.id))
- .name(rs.getString(Task.Fields.name))
- .description(rs.getString(Task.Fields.description))
- .status(TaskStatus.valueOf(rs.getString(Task.Fields.status)))
- .createdAt(rs.getTimestamp("created_at")
- .toLocalDateTime())
- .updatedAt(rs.getTimestamp("updated_at")
- .toLocalDateTime())
- .authorId(rs.getLong("author_id"))
- .build();
- }
-}
diff --git a/src/main/java/com/emobile/springtodo/repository/impl/UserRepositoryImpl.java b/src/main/java/com/emobile/springtodo/repository/impl/UserRepositoryImpl.java
deleted file mode 100644
index 1b8aad8d..00000000
--- a/src/main/java/com/emobile/springtodo/repository/impl/UserRepositoryImpl.java
+++ /dev/null
@@ -1,366 +0,0 @@
-package com.emobile.springtodo.repository.impl;
-
-import com.emobile.springtodo.aop.LazyLogger;
-import com.emobile.springtodo.exception.NullResultSetException;
-import com.emobile.springtodo.model.entity.Task;
-import com.emobile.springtodo.model.entity.TaskStatus;
-import com.emobile.springtodo.model.entity.User;
-import com.emobile.springtodo.model.security.RoleType;
-import com.emobile.springtodo.model.util.Page;
-import com.emobile.springtodo.model.util.PageInfo;
-import com.emobile.springtodo.repository.UserRepository;
-import lombok.RequiredArgsConstructor;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.core.RowMapper;
-import org.springframework.stereotype.Repository;
-
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-import static com.emobile.springtodo.util.JdbcUtil.optionalExtractor;
-
-/**
- * Repository for working with entity {@link User}.
- */
-@RequiredArgsConstructor
-@Repository
-public class UserRepositoryImpl implements UserRepository {
- /**
- * For work with db.
- */
- private final JdbcTemplate jdbcTemplate;
-
- /**
- * Find all {@link User} objects from db
- * with {@code pageNumber} and {@code pageSize} from {@code pageInfo}.
- * LIMIT - {@code pageSize}.
- * OFFSET - ({@code pageNumber} -1) * {@code pageSize}.
- *
- * @return {@link Page} with {@link User} list.
- * @see #getUserMapper()
- */
- @Override
- @LazyLogger
- public Page findAll(PageInfo pageInfo) {
- final String sql = """
- SELECT * FROM users
- LIMIT ? OFFSET ?
- """;
- int beginInd = (pageInfo.pageNumber() - 1) * pageInfo.pageSize();
- return new Page<>(
- jdbcTemplate.query(
- sql,
- getUserMapper(),
- pageInfo.pageSize(),
- beginInd
- )
- );
- }
-
- /**
- * Search object {@link User} in db.
- *
- * @param id id searched {@link User} object
- * @return {@link Optional} if exist, {@link Optional#empty()} if not
- * @see #getUserTaskMapper()
- */
- @Override
- @LazyLogger
- public Optional findById(Long id) {
- final String sql = """
- SELECT u.*, t.*
- FROM users u
- LEFT JOIN tasks t on u.id = t.author_id
- WHERE u.id= ?
- """;
- return jdbcTemplate.query(
- sql,
- optionalExtractor(getUserTaskMapper()),
- id
- );
- }
-
- /**
- * Find {@link User}
- * with {@code User.username} equals {@code username}.
- *
- * @param username username searched {@link User}
- * @return {@link Optional} if exist, {@link Optional#empty()} if not
- */
- @Override
- @LazyLogger
- public Optional findByUsername(String username) {
- final String sql = """
- SELECT u.*, t.*
- FROM users u
- LEFT JOIN tasks t on u.id = t.author_id
- WHERE u.username= ?
- """;
- return jdbcTemplate.query(
- sql,
- optionalExtractor(getUserTaskMapper()),
- username
- );
- }
-
- /**
- * Save object model of type {@link User}.
- *
- * @param model object of type {@link User} to save
- * @return object of type {@link User} that was saved
- * @throws NullResultSetException if returning value from db is null
- */
- @Override
- @LazyLogger
- public User save(User model) {
- final String sql = """
- INSERT INTO users(username, password, email, role)
- VALUES (?,?,?,?)
- RETURNING *
- """;
- return jdbcTemplate.query(sql,
- optionalExtractor(getUserMapper()),
- model.getUsername(),
- model.getPassword(),
- model.getEmail(),
- model.getRole().name())
- .orElseThrow(NullResultSetException.create(
- "userRepository save() query exception"
- ));
- }
-
- /**
- * Update object model of type {@link User}
- * by {@code T.id} value.
- *
- * @param model object of type {@link User} to update
- * @return object of type {@link User} that was updated
- * @throws NullResultSetException if returning value from db is null
- */
- @Override
- @LazyLogger
- public User update(User model) {
- final String sql = """
- UPDATE users
- SET username=?, password=?, email=?, role=?
- WHERE id=?
- RETURNING *
- """;
- return jdbcTemplate.query(sql,
- optionalExtractor(getUserMapper()),
- model.getUsername(),
- model.getPassword(),
- model.getEmail(),
- model.getRole().name(),
- model.getId())
- .orElseThrow(NullResultSetException.create(
- "userRepository update() query exception"
- ));
- }
-
- /**
- * Delete object with {@code User.id}
- * equals {@code id} from database.
- *
- * @param id id of the object to be deleted
- * @return {@code true} if success
- */
- @Override
- @LazyLogger
- public boolean deleteById(Long id) {
- final String sql = """
- DELETE
- FROM users
- WHERE id=?
- """;
- int result = jdbcTemplate.update(sql, id);
- return result != 0;
- }
-
- /**
- * Check duplicate {@code username}.
- * For save {@link User}.
- *
- * @param username username searched {@link User}
- * @return {@code true} if exist, {@code false} if not
- * @see #getExistsMapper()
- */
- @Override
- @LazyLogger
- public boolean existsByUsername(String username) {
- final String sql = """
- SELECT EXISTS (SELECT *
- FROM users
- WHERE username = ?)
- AS result
- """;
- return jdbcTemplate.queryForObject(sql, getExistsMapper(), username);
- }
-
- /**
- * Check duplicate {@code username}.
- * For update {@link User}.
- *
- * @param username username searched {@link User}
- * @return {@code true} if exist, {@code false} if not
- * @see #getExistsMapper()
- */
- @Override
- @LazyLogger
- public boolean existsByUsernameAndIdNot(String username, Long currentUserId) {
- final String sql = """
- SELECT EXISTS (SELECT *
- FROM users
- WHERE username = ?
- AND id != ?)
- AS result
- """;
- return jdbcTemplate.queryForObject(
- sql,
- getExistsMapper(),
- username,
- currentUserId
- );
- }
-
- /**
- * Check duplicate {@code email}.
- * For save {@link User}.
- *
- * @param email username searched {@link User}
- * @return {@code true} if exist, {@code false} if not
- * @see #getExistsMapper()
- */
- @Override
- @LazyLogger
- public boolean existsByEmail(String email) {
- final String sql = """
- SELECT EXISTS (SELECT *
- FROM users
- WHERE email = ?)
- AS result
- """;
- return jdbcTemplate.queryForObject(sql, getExistsMapper(), email);
- }
-
- /**
- * Check duplicate {@code email}.
- * For update {@link User}.
- *
- * @param email username searched {@link User}
- * @return {@code true} if exist, {@code false} if not
- * @see #getExistsMapper()
- */
- @Override
- @LazyLogger
- public boolean existsByEmailAndIdNot(String email, Long currentUserId) {
- final String sql = """
- SELECT EXISTS (SELECT *
- FROM users
- WHERE email = ?
- AND id != ?)
- AS result
- """;
- return jdbcTemplate.queryForObject(
- sql,
- getExistsMapper(),
- email,
- currentUserId
- );
- }
-
- /**
- * {@link User} {@link RowMapper}.
- *
- * @return mapper for {@link User} entity
- */
- private RowMapper getUserMapper() {
- return (rs, rn) -> User.builder()
- .id(rs.getLong(User.Fields.id))
- .username(rs.getString(User.Fields.username))
- .password(rs.getString(User.Fields.password))
- .email(rs.getString(User.Fields.email))
- .role(RoleType.valueOf(rs.getString(User.Fields.role)))
- .build();
- }
-
- /**
- * Грустно и костыльно, но работает.
- *
- * {code rs.getLong("author_id")} for wasNull() check.
- *
- * @return mapper for {@link User} with filled {@code taskList} fields
- * @see #fillUserFields(ResultSet, List)
- * @see #fillTaskFields(ResultSet)
- */
- private RowMapper getUserTaskMapper() {
- return (rs, rn) -> {
- List taskList = new ArrayList<>();
- User user = fillUserFields(rs, taskList);
- rs.getLong("author_id");
- if (!rs.wasNull()) {
- do {
- Task task = fillTaskFields(rs);
- taskList.add(task);
- } while (rs.next());
- }
- return user;
- };
- }
-
- /**
- * fill {@link User} entity.
- * {@code id} columnIndex - 1.
- *
- * @param rs resultSet for map
- * @param taskList list ref
- * @return {@link User} with filled fields
- * @throws SQLException if resultSet get exception
- */
- private User fillUserFields(ResultSet rs, List taskList) throws SQLException {
- return User.builder()
- .id(rs.getLong(1))
- .username(rs.getString(User.Fields.username))
- .password(rs.getString(User.Fields.password))
- .email(rs.getString(User.Fields.email))
- .role(RoleType.valueOf(rs.getString(User.Fields.role)))
- .taskList(taskList)
- .build();
- }
-
- /**
- * fill {@link Task} entity.
- * {@code id} columnIndex - 6.
- *
- * @param rs resultSet for map
- * @return {@link Task} with filled fields
- * @throws SQLException if resultSet get exception
- */
- private Task fillTaskFields(ResultSet rs) throws SQLException {
- return Task.builder()
- .id(rs.getLong(6))
- .name(rs.getString(Task.Fields.name))
- .description(rs.getString(Task.Fields.description))
- .status(TaskStatus.valueOf(rs.getString(Task.Fields.status)))
- .createdAt(rs.getTimestamp("created_at")
- .toLocalDateTime())
- .updatedAt(rs.getTimestamp("updated_at")
- .toLocalDateTime())
- .authorId(rs.getLong("author_id"))
- .build();
- }
-
- /**
- * {@link RowMapper} for exist check.
- *
- * @return mapper for exist check
- */
- private RowMapper getExistsMapper() {
- return (resultSet, rowNum) ->
- resultSet.getString("result")
- .equals("t");
- }
-}
diff --git a/src/main/java/com/emobile/springtodo/repository/jpa/TaskRepository.java b/src/main/java/com/emobile/springtodo/repository/jpa/TaskRepository.java
new file mode 100644
index 00000000..50c7e5bf
--- /dev/null
+++ b/src/main/java/com/emobile/springtodo/repository/jpa/TaskRepository.java
@@ -0,0 +1,10 @@
+package com.emobile.springtodo.repository.jpa;
+
+import com.emobile.springtodo.model.entity.Task;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface TaskRepository extends JpaRepository {
+ void deleteAllByAuthor_Id(Long authorId);
+}
diff --git a/src/main/java/com/emobile/springtodo/repository/jpa/UserRepository.java b/src/main/java/com/emobile/springtodo/repository/jpa/UserRepository.java
new file mode 100644
index 00000000..249a1e35
--- /dev/null
+++ b/src/main/java/com/emobile/springtodo/repository/jpa/UserRepository.java
@@ -0,0 +1,24 @@
+package com.emobile.springtodo.repository.jpa;
+
+import com.emobile.springtodo.model.entity.User;
+import org.springframework.data.jpa.repository.EntityGraph;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface UserRepository extends JpaRepository {
+ @EntityGraph(value = "User.withTasks", type = EntityGraph.EntityGraphType.FETCH)
+ Optional findById(Long id);
+
+ Optional findByUsername(String username);
+
+ boolean existsByUsername(String username);
+
+ boolean existsByUsernameAndIdNot(String username, Long currentUserId);
+
+ boolean existsByEmail(String email);
+
+ boolean existsByEmailAndIdNot(String email, Long currentUserId);
+}
diff --git a/src/main/java/com/emobile/springtodo/service/impl/TaskServiceImpl.java b/src/main/java/com/emobile/springtodo/service/impl/TaskServiceImpl.java
index 71594d79..3336cde3 100644
--- a/src/main/java/com/emobile/springtodo/service/impl/TaskServiceImpl.java
+++ b/src/main/java/com/emobile/springtodo/service/impl/TaskServiceImpl.java
@@ -4,10 +4,12 @@
import com.emobile.springtodo.config.property.cache.AppCacheProperties;
import com.emobile.springtodo.exception.EntityNotFoundException;
import com.emobile.springtodo.model.entity.Task;
+import com.emobile.springtodo.model.entity.User;
import com.emobile.springtodo.model.security.AppUserDetails;
import com.emobile.springtodo.model.util.PageInfo;
-import com.emobile.springtodo.repository.TaskRepository;
+import com.emobile.springtodo.repository.jpa.TaskRepository;
import com.emobile.springtodo.service.TaskService;
+import com.emobile.springtodo.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
@@ -16,6 +18,7 @@
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
+import org.springframework.data.domain.PageRequest;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -42,6 +45,14 @@ public class TaskServiceImpl implements TaskService {
* {@link Task} Repository.
*/
private final TaskRepository taskRepository;
+ /**
+ * {@link User} Service.
+ * To fill author field.
+ *
+ * @see #enrich(Task)
+ * @see #enrich(Task, Task)
+ */
+ private final UserService userService;
/**
* Time management object.
*/
@@ -64,7 +75,9 @@ public void setSelf(TaskService self) {
@Transactional(readOnly = true)
@LazyLogger
public List findAll(PageInfo pageInfo) {
- return taskRepository.findAll(pageInfo).content();
+ return taskRepository.findAll(
+ PageRequest.of(pageInfo.pageNumber(), pageInfo.pageSize())
+ ).getContent();
}
/**
@@ -129,7 +142,7 @@ public Task save(Task model) {
@LazyLogger
public Task update(Long id, Task model) {
model = enrich(model, self.findById(id));
- return taskRepository.update(model);
+ return taskRepository.save(model);
}
/**
@@ -145,7 +158,7 @@ private Task enrich(Task model) {
.status(model.getStatus())
.createdAt(LocalDateTime.now(clock))
.updatedAt(LocalDateTime.now(clock))
- .authorId(getCurrentUserId())
+ .author(userService.findById(getCurrentUserId()))
.build();
}
@@ -180,7 +193,7 @@ private Task enrich(Task model, Task taskToUpdate) {
: model.getStatus())
.createdAt(taskToUpdate.getCreatedAt())
.updatedAt(LocalDateTime.now(clock))
- .authorId(taskToUpdate.getAuthorId())
+ .author(userService.findById(taskToUpdate.getAuthorId()))
.build();
}
@@ -236,6 +249,6 @@ public void deleteAll() {
@Transactional
@LazyLogger
public void deleteAllByUserId(Long userId) {
- taskRepository.deleteAllByUserId(userId);
+ taskRepository.deleteAllByAuthor_Id(userId);
}
}
diff --git a/src/main/java/com/emobile/springtodo/service/impl/UserServiceImpl.java b/src/main/java/com/emobile/springtodo/service/impl/UserServiceImpl.java
index 23687951..665539e6 100644
--- a/src/main/java/com/emobile/springtodo/service/impl/UserServiceImpl.java
+++ b/src/main/java/com/emobile/springtodo/service/impl/UserServiceImpl.java
@@ -4,11 +4,9 @@
import com.emobile.springtodo.config.property.cache.AppCacheProperties;
import com.emobile.springtodo.exception.AlreadyExitsException;
import com.emobile.springtodo.exception.EntityNotFoundException;
-import com.emobile.springtodo.model.entity.Task;
import com.emobile.springtodo.model.entity.User;
import com.emobile.springtodo.model.util.PageInfo;
-import com.emobile.springtodo.repository.UserRepository;
-import com.emobile.springtodo.service.TaskService;
+import com.emobile.springtodo.repository.jpa.UserRepository;
import com.emobile.springtodo.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
@@ -18,6 +16,7 @@
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
+import org.springframework.data.domain.PageRequest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -42,11 +41,6 @@ public class UserServiceImpl implements UserService {
* {@link User} Repository.
*/
private final UserRepository userRepository;
- /**
- * {@link Task} Service.
- * To delete all task deleted user.
- */
- private final TaskService taskService;
/**
* Default PasswordEncoder.
* Needed to define and update the field password in {@link User}.
@@ -73,7 +67,9 @@ public void setSelf(UserService self) {
@Transactional(readOnly = true)
@LazyLogger
public List findAll(PageInfo pageInfo) {
- return userRepository.findAll(pageInfo).content();
+ return userRepository.findAll(
+ PageRequest.of(pageInfo.pageNumber(), pageInfo.pageSize())
+ ).getContent();
}
/**
@@ -157,7 +153,7 @@ public User update(Long id, User model) {
model = enrich(model, self.findById(id));
self.checkDuplicateUsername(model.getUsername(), model.getId());
self.checkDuplicateEmail(model.getEmail(), model.getId());
- return userRepository.update(model);
+ return userRepository.save(model);
}
/**
@@ -298,13 +294,14 @@ public void checkDuplicateEmail(String email, Long currentUserId) {
@Caching(evict = {
@CacheEvict(value = AppCacheProperties.Types.USER_BY_NAME, allEntries = true),
@CacheEvict(value = AppCacheProperties.Types.USER_BY_ID, key = "#id"),
- @CacheEvict(value = AppCacheProperties.Types.USERS, allEntries = true)
+ @CacheEvict(value = AppCacheProperties.Types.USERS, allEntries = true),
+ @CacheEvict(value = AppCacheProperties.Types.TASKS, allEntries = true),
+ @CacheEvict(value = AppCacheProperties.Types.TASK_BY_ID, allEntries = true)
})
@Transactional
@LazyLogger
public void deleteById(Long id) {
self.findById(id);
- taskService.deleteAllByUserId(id);
userRepository.deleteById(id);
}
}
diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml
index c2fee0c1..fccc94e2 100644
--- a/src/main/resources/config/application.yml
+++ b/src/main/resources/config/application.yml
@@ -6,6 +6,9 @@ spring:
url: ${SERVER_URL:jdbc:postgresql://localhost:5432/spring_todo_db}
username: ${SERVER_USERNAME:postgres}
password: ${SERVER_PASS:1322}
+ jpa:
+ show-sql: true
+ open-in-view: true
data:
redis:
port: ${REDIS_PORT:6379}
diff --git a/src/test/java/com/emobile/springtodo/repository/impl/TaskRepositoryImplTest.java b/src/test/java/com/emobile/springtodo/repository/jpa/TaskRepositoryTest.java
similarity index 87%
rename from src/test/java/com/emobile/springtodo/repository/impl/TaskRepositoryImplTest.java
rename to src/test/java/com/emobile/springtodo/repository/jpa/TaskRepositoryTest.java
index cd45bfda..321da653 100644
--- a/src/test/java/com/emobile/springtodo/repository/impl/TaskRepositoryImplTest.java
+++ b/src/test/java/com/emobile/springtodo/repository/jpa/TaskRepositoryTest.java
@@ -1,18 +1,20 @@
-package com.emobile.springtodo.repository.impl;
+package com.emobile.springtodo.repository.jpa;
import com.emobile.springtodo.model.entity.Task;
import com.emobile.springtodo.model.entity.TaskStatus;
import com.emobile.springtodo.model.entity.User;
import com.emobile.springtodo.model.security.RoleType;
-import com.emobile.springtodo.model.util.Page;
-import com.emobile.springtodo.model.util.PageInfo;
+import jakarta.persistence.EntityManager;
import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.test.context.DynamicPropertyRegistry;
@@ -33,9 +35,12 @@
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Testcontainers
-@DisplayName("TaskRepositoryImplTest Tests")
-class TaskRepositoryImplTest {
- private TaskRepositoryImpl repository;
+@DisplayName("TaskRepositoryTest Tests")
+class TaskRepositoryTest {
+ @Autowired
+ private TaskRepository repository;
+ @Autowired
+ EntityManager entityManager;
@Autowired
private JdbcTemplate jdbcTemplate;
private static final LocalDateTime MILLENNIUM = LocalDateTime.of(2000, Month.JANUARY, 1, 0, 0, 0);
@@ -58,26 +63,19 @@ static void afterAll() {
postgreContainer.stop();
}
- @BeforeEach
- void setUp() {
- repository = new TaskRepositoryImpl(jdbcTemplate);
- jdbcTemplate.update("TRUNCATE tasks CASCADE");
- jdbcTemplate.update("TRUNCATE users CASCADE");
- }
-
@Test
@DisplayName("findAll test: get all user data.")
void givenPageInfoWhenGetAllThenListUser() {
- PageInfo pageInfo = new PageInfo(5, 1);
- Task test1 = new Task(2L, "name", "des",
- TaskStatus.TODO, BEFORE_MILLENNIUM, MILLENNIUM, 3L);
- Task test2 = new Task(4L, "name", "des",
- TaskStatus.TODO, BEFORE_MILLENNIUM, MILLENNIUM, 2L);
- Page expected = new Page<>(List.of(test1, test2));
+ Pageable pageInfo = PageRequest.of(0, 5);
User testAuthor = new User(3L, "user", "pass1",
"email1@co.m", RoleType.ROLE_USER, List.of());
User testAuthor2 = new User(2L, "user2", "pass1",
"email2@co.m", RoleType.ROLE_USER, List.of());
+ Task test1 = new Task(2L, "name", "des",
+ TaskStatus.TODO, BEFORE_MILLENNIUM, MILLENNIUM, testAuthor);
+ Task test2 = new Task(4L, "name", "des",
+ TaskStatus.TODO, BEFORE_MILLENNIUM, MILLENNIUM, testAuthor2);
+ PageImpl expected = new PageImpl<>(List.of(test1, test2), pageInfo, 2);
addToDb(testAuthor);
addToDb(testAuthor2);
addToDb(test1);
@@ -92,10 +90,10 @@ void givenPageInfoWhenGetAllThenListUser() {
@DisplayName("findById test: get user data by id.")
void givenExistingIdWhenGetByIdThenUser() {
Long taskId = 2L;
- Task test1 = new Task(taskId, "name", "des",
- TaskStatus.TODO, BEFORE_MILLENNIUM, MILLENNIUM, 4L);
User testAuthor = new User(4L, "user", "pass1",
"email1@co.m", RoleType.ROLE_USER, List.of());
+ Task test1 = new Task(taskId, "name", "des",
+ TaskStatus.TODO, BEFORE_MILLENNIUM, MILLENNIUM, testAuthor);
addToDb(testAuthor);
addToDb(test1);
@@ -118,16 +116,17 @@ void givenNotExistingIdWhenGetByIdThenThrow() {
@Test
@DisplayName("update test: send task data to repository.")
void givenTaskWhenUpdateThenUpdatedTask() {
- Task test1 = new Task(2L, "name", "des",
- TaskStatus.TODO, BEFORE_MILLENNIUM, BEFORE_MILLENNIUM, 3L);
- Task expected = new Task(2L, "name2", "des2",
- TaskStatus.DONE, BEFORE_MILLENNIUM, MILLENNIUM, 3L);
User testAuthor = new User(3L, "user", "pass1",
"email1@co.m", RoleType.ROLE_USER, List.of());
+ Task test1 = new Task(2L, "name", "des",
+ TaskStatus.TODO, BEFORE_MILLENNIUM, BEFORE_MILLENNIUM, testAuthor);
+ Task expected = new Task(2L, "name2", "des2",
+ TaskStatus.DONE, BEFORE_MILLENNIUM, MILLENNIUM, testAuthor);
addToDb(testAuthor);
addToDb(test1);
- repository.update(expected);
+ repository.save(expected);
+ entityManager.flush();
assertTrue(existsInDb(expected));
}
@@ -136,14 +135,16 @@ void givenTaskWhenUpdateThenUpdatedTask() {
@DisplayName("delete test: delete task data message to repository.")
void givenTaskIdWhenDeleteThenVoid() {
Long taskId = 2L;
- Task test1 = new Task(taskId, "name", "des",
- TaskStatus.TODO, BEFORE_MILLENNIUM, BEFORE_MILLENNIUM, 3L);
User testAuthor = new User(3L, "user", "pass1",
"email1@co.m", RoleType.ROLE_USER, List.of());
+ Task test1 = new Task(taskId, "name", "des",
+ TaskStatus.TODO, BEFORE_MILLENNIUM, BEFORE_MILLENNIUM, testAuthor);
addToDb(testAuthor);
addToDb(test1);
repository.deleteById(taskId);
+ entityManager.flush();
+
assertFalse(existsInDb(test1));
}
@@ -166,7 +167,7 @@ INSERT INTO tasks(id, name, description, status, created_at, updated_at, author_
jdbcTemplate.update(sql,
task.getId(), task.getName(), task.getDescription(),
task.getStatus().name(), task.getCreatedAt(),
- task.getUpdatedAt(), task.getAuthorId()
+ task.getUpdatedAt(), task.getAuthor().getId()
);
}
@@ -185,7 +186,7 @@ SELECT EXISTS (SELECT *
return jdbcTemplate.queryForObject(sql, getExistsMapper(),
task.getName(), task.getDescription(),
task.getStatus().name(), task.getCreatedAt(),
- task.getUpdatedAt(), task.getAuthorId()
+ task.getUpdatedAt(), task.getAuthor().getId()
);
}
diff --git a/src/test/java/com/emobile/springtodo/repository/impl/UserRepositoryImplTest.java b/src/test/java/com/emobile/springtodo/repository/jpa/UserRepositoryTest.java
similarity index 86%
rename from src/test/java/com/emobile/springtodo/repository/impl/UserRepositoryImplTest.java
rename to src/test/java/com/emobile/springtodo/repository/jpa/UserRepositoryTest.java
index d3a928cd..87a526b5 100644
--- a/src/test/java/com/emobile/springtodo/repository/impl/UserRepositoryImplTest.java
+++ b/src/test/java/com/emobile/springtodo/repository/jpa/UserRepositoryTest.java
@@ -1,18 +1,20 @@
-package com.emobile.springtodo.repository.impl;
+package com.emobile.springtodo.repository.jpa;
import com.emobile.springtodo.model.entity.Task;
import com.emobile.springtodo.model.entity.TaskStatus;
import com.emobile.springtodo.model.entity.User;
import com.emobile.springtodo.model.security.RoleType;
-import com.emobile.springtodo.model.util.Page;
-import com.emobile.springtodo.model.util.PageInfo;
+import jakarta.persistence.EntityManager;
import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.test.context.DynamicPropertyRegistry;
@@ -33,9 +35,12 @@
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Testcontainers
-@DisplayName("UserRepositoryImpl Tests")
-class UserRepositoryImplTest {
- private UserRepositoryImpl repository;
+@DisplayName("UserRepository Tests")
+class UserRepositoryTest {
+ @Autowired
+ private UserRepository repository;
+ @Autowired
+ EntityManager entityManager;
@Autowired
private JdbcTemplate jdbcTemplate;
private static final LocalDateTime MILLENNIUM = LocalDateTime.of(2000, Month.JANUARY, 1, 0, 0, 0);
@@ -57,21 +62,15 @@ static void afterAll() {
postgreContainer.stop();
}
- @BeforeEach
- void setUp() {
- repository = new UserRepositoryImpl(jdbcTemplate);
- jdbcTemplate.update("TRUNCATE users CASCADE");
- }
-
@Test
@DisplayName("findAll test: get all user data.")
void givenPageInfoWhenGetAllThenListUser() {
- PageInfo pageInfo = new PageInfo(5, 1);
+ Pageable pageInfo = PageRequest.of(0, 5);
User test1 = new User(2L, "test1", "pass1",
"email1@co.m", RoleType.ROLE_USER, List.of());
User test2 = new User(3L, "test2", "pass2",
"email2@co.m", RoleType.ROLE_ADMIN, List.of());
- Page expected = new Page<>(List.of(test1, test2));
+ Page expected = new PageImpl<>(List.of(test1, test2), pageInfo, 2);
addToDb(test1);
addToDb(test2);
@@ -84,9 +83,11 @@ void givenPageInfoWhenGetAllThenListUser() {
@DisplayName("findById test: get user data by id.")
void givenExistingIdWhenGetByIdThenUser() {
Long userId = 2L;
- Task testTask = new Task(2L, "name", "des",
- TaskStatus.TODO, BEFORE_MILLENNIUM, MILLENNIUM, userId);
User test1 = new User(userId, "test1", "pass1",
+ "email1@co.m", RoleType.ROLE_USER, List.of());
+ Task testTask = new Task(2L, "name", "des",
+ TaskStatus.TODO, BEFORE_MILLENNIUM, MILLENNIUM, test1);
+ User expected = new User(userId, "test1", "pass1",
"email1@co.m", RoleType.ROLE_USER, List.of(testTask));
addToDb(test1);
addToDb(testTask);
@@ -94,7 +95,7 @@ void givenExistingIdWhenGetByIdThenUser() {
Optional actual = repository.findById(userId);
assertTrue(actual.isPresent());
- assertEquals(test1, actual.get());
+ assertEquals(expected, actual.get());
}
@Test
@@ -111,9 +112,11 @@ void givenNotExistingIdWhenGetByIdThenThrow() {
@DisplayName("findByUsername test: get user data by name.")
void givenExistingNameWhenGetByIdThenUser() {
String userUsername = "user";
- Task testTask = new Task(2L, "name", "des",
- TaskStatus.TODO, BEFORE_MILLENNIUM, MILLENNIUM, 2L);
User test1 = new User(2L, userUsername, "pass1",
+ "email1@co.m", RoleType.ROLE_USER, List.of());
+ Task testTask = new Task(2L, "name", "des",
+ TaskStatus.TODO, BEFORE_MILLENNIUM, MILLENNIUM, test1);
+ User expected = new User(2L, userUsername, "pass1",
"email1@co.m", RoleType.ROLE_USER, List.of(testTask));
addToDb(test1);
addToDb(testTask);
@@ -121,7 +124,7 @@ void givenExistingNameWhenGetByIdThenUser() {
Optional actual = repository.findByUsername(userUsername);
assertTrue(actual.isPresent());
- assertEquals(test1, actual.get());
+ assertEquals(expected, actual.get());
}
@Test
@@ -141,6 +144,7 @@ void givenUserWhenSendUserToDbThenSavedUser() {
"email2@co.m", RoleType.ROLE_USER, List.of());
repository.save(userToSave);
+ entityManager.flush();
assertTrue(existsInDb(userToSave));
}
@@ -154,7 +158,8 @@ void givenUserWhenUpdateThenUpdatedUser() {
"email2@co.m", RoleType.ROLE_USER, List.of());
addToDb(test1);
- repository.update(expected);
+ repository.save(expected);
+ entityManager.flush();
assertTrue(existsInDb(expected));
}
@@ -168,6 +173,8 @@ void givenUserIdWhenDeleteThenVoid() {
addToDb(test1);
repository.deleteById(userId);
+ entityManager.flush();
+
assertFalse(existsInDb(test1));
}
diff --git a/src/test/java/com/emobile/springtodo/service/impl/TaskServiceImplTest.java b/src/test/java/com/emobile/springtodo/service/impl/TaskServiceImplTest.java
index 13eea52f..23d328b6 100644
--- a/src/test/java/com/emobile/springtodo/service/impl/TaskServiceImplTest.java
+++ b/src/test/java/com/emobile/springtodo/service/impl/TaskServiceImplTest.java
@@ -6,15 +6,17 @@
import com.emobile.springtodo.model.entity.User;
import com.emobile.springtodo.model.security.AppUserDetails;
import com.emobile.springtodo.model.security.RoleType;
-import com.emobile.springtodo.model.util.Page;
import com.emobile.springtodo.model.util.PageInfo;
-import com.emobile.springtodo.repository.TaskRepository;
+import com.emobile.springtodo.repository.jpa.TaskRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
@@ -43,6 +45,8 @@ class TaskServiceImplTest {
private TaskServiceImpl taskService;
@Mock
private TaskRepository taskRepository;
+ @Mock
+ private UserServiceImpl userService;
private static final LocalDateTime MILLENNIUM = LocalDateTime.of(2000, Month.JANUARY, 1, 0, 0, 0);
private static final LocalDateTime BEFORE_MILLENNIUM = MILLENNIUM.minusDays(5);
private final Clock clock = Clock.fixed(MILLENNIUM.toInstant(ZoneOffset.UTC), ZoneOffset.UTC);
@@ -50,33 +54,41 @@ class TaskServiceImplTest {
@BeforeEach
void setUp() {
- taskService = new TaskServiceImpl(taskRepository, clock);
+ taskService = new TaskServiceImpl(taskRepository, userService, clock);
taskService.setSelf(taskService);
}
@Test
- @DisplayName("findAll test: get all user data.")
- void givenWhenGetAllThenListUser() {
- List userList = new ArrayList<>(List.of(
+ @DisplayName("findAll test: get all task data.")
+ void givenWhenGetAllThenListTask() {
+ List taskList = new ArrayList<>(List.of(
new Task(),
new Task()
));
- PageInfo pageInfo = new PageInfo(0, 10);
+ Pageable pageInfo = PageRequest.of(0, 10);
when(taskRepository.findAll(pageInfo))
- .thenReturn(new Page<>(userList));
+ .thenReturn(new PageImpl<>(taskList));
- List actual = taskService.findAll(pageInfo);
+ List actual = taskService.findAll(new PageInfo(10, 0));
- assertEquals(userList.size(), actual.size());
+ assertEquals(taskList.size(), actual.size());
verify(taskRepository, times(1))
.findAll(pageInfo);
}
@Test
- @DisplayName("findById test: get user data by id.")
- void givenExistingIdWhenGetByIdThenUser() {
- Long userId = 1L;
+ @DisplayName("findById test: get task data by id.")
+ void givenExistingIdWhenGetByIdThenTask() {
+ Long taskId = 1L;
+ User defaultUser = new User(
+ 2L,
+ "user",
+ "pass",
+ "email",
+ RoleType.ROLE_USER,
+ Collections.emptyList()
+ );
Task defaultTask = new Task(
1L,
"name",
@@ -84,13 +96,13 @@ void givenExistingIdWhenGetByIdThenUser() {
TaskStatus.DONE,
LocalDateTime.of(2, 2, 2, 2, 2),
LocalDateTime.of(2, 2, 2, 2, 2),
- 2L
+ defaultUser
);
- when(taskRepository.findById(userId))
+ when(taskRepository.findById(taskId))
.thenReturn(Optional.of(defaultTask));
- Task actual = taskService.findById(userId);
+ Task actual = taskService.findById(taskId);
assertEquals(defaultTask, actual);
verify(taskRepository, times(1))
@@ -98,15 +110,15 @@ void givenExistingIdWhenGetByIdThenUser() {
}
@Test
- @DisplayName("findById test: try to get user data by not existing id.")
+ @DisplayName("findById test: try to get task data by not existing id.")
void givenNotExistingIdWhenGetByIdThenThrow() {
- Long userId = 1L;
+ Long taskId = 1L;
- when(taskRepository.findById(userId))
+ when(taskRepository.findById(taskId))
.thenReturn(Optional.empty());
assertThrows(EntityNotFoundException.class,
- () -> taskService.findById(userId),
+ () -> taskService.findById(taskId),
" index is incorrect."
);
verify(taskRepository, times(1))
@@ -114,8 +126,8 @@ void givenNotExistingIdWhenGetByIdThenThrow() {
}
@Test
- @DisplayName("save test: send user data to repository.")
- void givenUserWhenSendUserToDbThenSavedUser() {
+ @DisplayName("save test: send task data to repository.")
+ void givenTaskWhenSendTaskToDbThenSavedTask() {
Long userPrincipalId = 10L;
Task taskToSave = new Task(
null,
@@ -126,15 +138,6 @@ void givenUserWhenSendUserToDbThenSavedUser() {
null,
null
);
- Task expected = new Task(
- null,
- "name",
- "description",
- TaskStatus.DONE,
- MILLENNIUM,
- MILLENNIUM,
- userPrincipalId
- );
User defaultUser = new User(
userPrincipalId,
"username",
@@ -143,6 +146,15 @@ void givenUserWhenSendUserToDbThenSavedUser() {
RoleType.ROLE_USER,
Collections.emptyList()
);
+ Task expected = new Task(
+ null,
+ "name",
+ "description",
+ TaskStatus.DONE,
+ MILLENNIUM,
+ MILLENNIUM,
+ defaultUser
+ );
AppUserDetails principal = new AppUserDetails(defaultUser);
Authentication auth =
new UsernamePasswordAuthenticationToken(
@@ -154,6 +166,8 @@ void givenUserWhenSendUserToDbThenSavedUser() {
when(securityContext.getAuthentication()).thenReturn(auth);
when(taskRepository.save(expected))
.thenReturn(expected);
+ when(userService.findById(userPrincipalId))
+ .thenReturn(defaultUser);
Task actual = taskService.save(taskToSave);
@@ -163,9 +177,17 @@ void givenUserWhenSendUserToDbThenSavedUser() {
}
@Test
- @DisplayName("update test: with partially filled User data.")
- void givenPartiallyFilledUserUpdateThenUpdatedUser() {
- Long userId = 1L;
+ @DisplayName("update test: with partially filled Task data.")
+ void givenPartiallyFilledTaskUpdateThenUpdatedTask() {
+ Long taskId = 1L;
+ User defaultUser = new User(
+ 2L,
+ "user",
+ "pass",
+ "email",
+ RoleType.ROLE_USER,
+ Collections.emptyList()
+ );
Task partiallyFilledTask = new Task(
null,
"name",
@@ -173,7 +195,7 @@ void givenPartiallyFilledUserUpdateThenUpdatedUser() {
TaskStatus.TODO,
null,
null,
- 2L
+ defaultUser
);
Task taskToUpdate = new Task(
1L,
@@ -182,7 +204,7 @@ void givenPartiallyFilledUserUpdateThenUpdatedUser() {
TaskStatus.DONE,
BEFORE_MILLENNIUM,
BEFORE_MILLENNIUM,
- 2L
+ defaultUser
);
Task expected = new Task(
1L,
@@ -191,28 +213,38 @@ void givenPartiallyFilledUserUpdateThenUpdatedUser() {
TaskStatus.TODO,
BEFORE_MILLENNIUM,
MILLENNIUM,
- 2L
+ defaultUser
);
- when(taskRepository.findById(userId))
+ when(taskRepository.findById(taskId))
.thenReturn(Optional.of(taskToUpdate));
- when(taskRepository.update(expected))
+ when(taskRepository.save(expected))
.thenReturn(expected);
+ when(userService.findById(2L))
+ .thenReturn(defaultUser);
- Task actual = taskService.update(userId, partiallyFilledTask);
+ Task actual = taskService.update(taskId, partiallyFilledTask);
assertEquals(expected, actual);
verify(taskRepository, times(1))
- .update(expected);
+ .save(expected);
verify(taskRepository, times(1))
.findById(1L);
}
@Test
- @DisplayName("update test: with filled User data.")
- void givenFilledUserAndUserIdWhenUpdateThenUpdatedUser() {
- Long userId = 1L;
+ @DisplayName("update test: with filled Task data.")
+ void givenFilledTaskAndTaskIdWhenUpdateThenUpdatedTask() {
+ Long taskId = 1L;
+ User defaultUser = new User(
+ 2L,
+ "user",
+ "pass",
+ "email",
+ RoleType.ROLE_USER,
+ Collections.emptyList()
+ );
Task taskToUpdate = new Task(
1L,
"name",
@@ -220,7 +252,7 @@ void givenFilledUserAndUserIdWhenUpdateThenUpdatedUser() {
TaskStatus.DONE,
BEFORE_MILLENNIUM,
BEFORE_MILLENNIUM,
- 2L
+ defaultUser
);
Task expected = new Task(
1L,
@@ -229,28 +261,38 @@ void givenFilledUserAndUserIdWhenUpdateThenUpdatedUser() {
TaskStatus.DONE,
BEFORE_MILLENNIUM,
MILLENNIUM,
- 2L
+ defaultUser
);
- when(taskRepository.findById(userId))
+ when(taskRepository.findById(taskId))
.thenReturn(Optional.of(expected));
- when(taskRepository.update(expected))
+ when(taskRepository.save(expected))
.thenReturn(expected);
+ when(userService.findById(2L))
+ .thenReturn(defaultUser);
- Task actual = taskService.update(userId, taskToUpdate);
+ Task actual = taskService.update(taskId, taskToUpdate);
assertEquals(expected, actual);
verify(taskRepository, times(1))
- .update(expected);
+ .save(expected);
verify(taskRepository, times(1))
.findById(1L);
}
@Test
- @DisplayName("update test: try update with not existed user id.")
- void givenUserAndNotExistedUserIdWhenUpdateThenUpdatedUser() {
- Long notExistedUserId = 1L;
+ @DisplayName("update test: try update with not existed task id.")
+ void givenTaskAndNotExistedTaskIdWhenUpdateThenUpdatedTask() {
+ Long notExistedTaskId = 1L;
LocalDateTime creationTime = LocalDateTime.of(1999, Month.DECEMBER, 10, 0, 0, 0);
+ User defaultUser = new User(
+ 2L,
+ "user",
+ "pass",
+ "email",
+ RoleType.ROLE_USER,
+ Collections.emptyList()
+ );
Task taskToUpdate = new Task(
1L,
"name",
@@ -258,25 +300,25 @@ void givenUserAndNotExistedUserIdWhenUpdateThenUpdatedUser() {
TaskStatus.DONE,
creationTime,
creationTime,
- 2L
+ defaultUser
);
- when(taskRepository.findById(notExistedUserId))
+ when(taskRepository.findById(notExistedTaskId))
.thenReturn(Optional.empty());
assertThrows(EntityNotFoundException.class,
- () -> taskService.update(notExistedUserId, taskToUpdate),
- "UserId is incorrect."
+ () -> taskService.update(notExistedTaskId, taskToUpdate),
+ "TaskId is incorrect."
);
verify(taskRepository, times(0))
- .update(any());
+ .save(any());
verify(taskRepository, times(1))
.findById(any());
}
@Test
- @DisplayName("delete test: delete user data message to repository.")
- void givenExistedUserIdWhenDeleteThenVoid() {
+ @DisplayName("delete test: delete task data message to repository.")
+ void givenExistedTaskIdWhenDeleteThenVoid() {
Long existedTaskId = 1L;
when(taskRepository.findById(existedTaskId))
@@ -291,16 +333,16 @@ void givenExistedUserIdWhenDeleteThenVoid() {
@Test
@DisplayName("delete test: delete task data message to repository.")
- void givenNotExistedUserIdWhenDeleteThenVoid() {
- Long notExistedUserId = 1L;
+ void givenNotExistedTaskIdWhenDeleteThenVoid() {
+ Long notExistedTaskId = 1L;
assertThrows(EntityNotFoundException.class,
- () -> taskService.deleteById(notExistedUserId),
- "UserId is incorrect."
+ () -> taskService.deleteById(notExistedTaskId),
+ "TaskId is incorrect."
);
verify(taskRepository, times(1))
- .findById(notExistedUserId);
+ .findById(notExistedTaskId);
verify(taskRepository, times(0))
- .deleteById(notExistedUserId);
+ .deleteById(notExistedTaskId);
}
}
\ No newline at end of file
diff --git a/src/test/java/com/emobile/springtodo/service/impl/UserServiceImplTest.java b/src/test/java/com/emobile/springtodo/service/impl/UserServiceImplTest.java
index 45c0a174..a3df32f2 100644
--- a/src/test/java/com/emobile/springtodo/service/impl/UserServiceImplTest.java
+++ b/src/test/java/com/emobile/springtodo/service/impl/UserServiceImplTest.java
@@ -3,9 +3,8 @@
import com.emobile.springtodo.exception.EntityNotFoundException;
import com.emobile.springtodo.model.entity.User;
import com.emobile.springtodo.model.security.RoleType;
-import com.emobile.springtodo.model.util.Page;
import com.emobile.springtodo.model.util.PageInfo;
-import com.emobile.springtodo.repository.UserRepository;
+import com.emobile.springtodo.repository.jpa.UserRepository;
import com.emobile.springtodo.service.TaskService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
@@ -13,6 +12,9 @@
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.ArrayList;
@@ -34,14 +36,12 @@ class UserServiceImplTest {
@Mock
private UserRepository userRepository;
@Mock
- private TaskService taskService;
- @Mock
private PasswordEncoder passwordEncoder;
@BeforeEach
void setUp() {
- userService = new UserServiceImpl(userRepository, taskService, passwordEncoder);
+ userService = new UserServiceImpl(userRepository, passwordEncoder);
userService.setSelf(userService);
}
@@ -52,12 +52,12 @@ void givenWhenGetAllThenListUser() {
new User(),
new User()
));
- PageInfo pageInfo = new PageInfo(0, 10);
+ Pageable pageInfo = PageRequest.of(0, 10);
when(userRepository.findAll(pageInfo))
- .thenReturn(new Page<>(userList));
+ .thenReturn(new PageImpl<>(userList));
- List actual = userService.findAll(pageInfo);
+ List actual = userService.findAll(new PageInfo(10, 0));
assertEquals(userList.size(), actual.size());
verify(userRepository, times(1))
@@ -199,7 +199,7 @@ void givenPartiallyFilledUserUpdateThenUpdatedUser() {
when(userRepository.findById(userId))
.thenReturn(Optional.of(userToUpdate));
- when(userRepository.update(expected))
+ when(userRepository.save(expected))
.thenReturn(expected);
when(passwordEncoder.encode(defaultPass))
.thenReturn(defaultPass);
@@ -208,7 +208,7 @@ void givenPartiallyFilledUserUpdateThenUpdatedUser() {
assertEquals(expected, actual);
verify(userRepository, times(1))
- .update(expected);
+ .save(expected);
verify(userRepository, times(1))
.findById(1L);
}
@@ -229,7 +229,7 @@ void givenFilledUserAndUserIdWhenUpdateThenUpdatedUser() {
when(userRepository.findById(userId))
.thenReturn(Optional.of(userToUpdate));
- when(userRepository.update(userToUpdate))
+ when(userRepository.save(userToUpdate))
.thenReturn(userToUpdate);
when(passwordEncoder.encode(defaultPass))
.thenReturn(defaultPass);
@@ -238,7 +238,7 @@ void givenFilledUserAndUserIdWhenUpdateThenUpdatedUser() {
assertEquals(userToUpdate, actual);
verify(userRepository, times(1))
- .update(userToUpdate);
+ .save(userToUpdate);
verify(userRepository, times(1))
.findById(1L);
}
@@ -265,7 +265,7 @@ void givenUserAndNotExistedUserIdWhenUpdateThenUpdatedUser() {
"UserId is incorrect."
);
verify(userRepository, times(0))
- .update(any());
+ .save(any());
verify(userRepository, times(1))
.findById(any());
}