diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/AccountStatsApplication.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/AccountStatsApplication.java new file mode 100644 index 0000000000..f5a99f0ad8 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/AccountStatsApplication.java @@ -0,0 +1,11 @@ +package com.baeldung.countrows; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class AccountStatsApplication { + public static void main(String[] args) { + SpringApplication.run(AccountStatsApplication.class, args); + } +} \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/entity/Account.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/entity/Account.java new file mode 100644 index 0000000000..d422c30a0e --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/entity/Account.java @@ -0,0 +1,68 @@ +package com.baeldung.countrows.entity; + +import javax.persistence.*; + +import java.security.PrivateKey; +import java.sql.Timestamp; +import java.time.Instant; +import java.util.Date; + +@Entity +@Table(name = "ACCOUNTS") +public class Account { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "accounts_seq") + @SequenceGenerator(name = "accounts_seq", sequenceName = "accounts_seq", allocationSize = 1) + @Column(name = "user_id") + private int userId; + private String username; + private String password; + private String email; + private Timestamp createdOn; + private Timestamp lastLogin; + + @OneToOne + @JoinColumn(name = "permissions_id") + private Permission permission; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setEmail(String email) { + this.email = email; + } + + public Timestamp getCreatedOn() { + return createdOn; + } + + public void setCreatedOn(Timestamp createdOn) { + this.createdOn = createdOn; + } + + public void setLastLogin(Timestamp lastLogin) { + this.lastLogin = lastLogin; + } + + public Permission getPermission() { + return permission; + } + + public void setPermission(Permission permission) { + this.permission = permission; + } + + @Override + public String toString() { + return "Account{" + "userId=" + userId + ", username='" + username + '\'' + ", password='" + password + '\'' + ", email='" + email + '\'' + ", createdOn=" + createdOn + ", lastLogin=" + lastLogin + ", permission=" + permission + '}'; + } +} \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/entity/Permission.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/entity/Permission.java new file mode 100644 index 0000000000..9acedf0558 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/entity/Permission.java @@ -0,0 +1,24 @@ +package com.baeldung.countrows.entity; + +import javax.persistence.*; + +@Entity +@Table(name = "PERMISSIONS") +public class Permission { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "permissions_id_sq") + @SequenceGenerator(name = "permissions_id_sq", sequenceName = "permissions_id_sq", allocationSize = 1) + private int id; + + private String type; + + public void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + return "Permission{" + "id=" + id + ", type='" + type + '\'' + '}'; + } +} diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/repository/AccountRepository.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/repository/AccountRepository.java new file mode 100644 index 0000000000..422962ce45 --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/repository/AccountRepository.java @@ -0,0 +1,23 @@ +package com.baeldung.countrows.repository; + +import com.baeldung.countrows.entity.Account; +import com.baeldung.countrows.entity.Permission; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.sql.Timestamp; +import java.util.Date; +import java.util.List; + +@Repository +public interface AccountRepository extends JpaRepository { + + long countByUsername(String username); + + long countByPermission(Permission permission); + + long countByPermissionAndCreatedOnGreaterThan(Permission permission, Timestamp ts); +} diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/repository/PermissionRepository.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/repository/PermissionRepository.java new file mode 100644 index 0000000000..5e598b52ef --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/repository/PermissionRepository.java @@ -0,0 +1,12 @@ +package com.baeldung.countrows.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.baeldung.countrows.entity.Permission; + +@Repository +public interface PermissionRepository extends JpaRepository { + Permission findByType(String type); +} + diff --git a/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/service/AccountStatsLogic.java b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/service/AccountStatsLogic.java new file mode 100644 index 0000000000..e4e716b4ce --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/main/java/com/baeldung/countrows/service/AccountStatsLogic.java @@ -0,0 +1,116 @@ +package com.baeldung.countrows.service; + +import java.sql.Timestamp; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.Query; +import javax.persistence.criteria.*; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.baeldung.countrows.entity.Account; +import com.baeldung.countrows.entity.Permission; +import com.baeldung.countrows.repository.AccountRepository; +import com.baeldung.countrows.repository.PermissionRepository; + +@Service +public class AccountStatsLogic { + @Autowired + private AccountRepository accountRepository; + + @PersistenceContext + private EntityManager entityManager; + + @Autowired + private PermissionRepository permissionRepository; + + public long getAccountCount() { + return accountRepository.count(); + } + + public long getAccountCountByUsername(String username) { + return accountRepository.countByUsername(username); + } + + public long getAccountCountByPermission(Permission permission) { + return accountRepository.countByPermission(permission); + } + + public long getAccountCountByPermissionAndCreatedOn(Permission permission, Date date) throws ParseException { + return accountRepository.countByPermissionAndCreatedOnGreaterThan(permission, new Timestamp(date.getTime())); + } + + public long getAccountsUsingCQ() throws ParseException { + // creating criteria builder and query + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = builder.createQuery(Long.class); + Root accountRoot = criteriaQuery.from(Account.class); + + // select query + criteriaQuery.select(builder.count(accountRoot)); + + // execute and get the result + return entityManager.createQuery(criteriaQuery) + .getSingleResult(); + } + + public long getAccountsByPermissionUsingCQ(Permission permission) throws ParseException { + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = builder.createQuery(Long.class); + Root accountRoot = criteriaQuery.from(Account.class); + + List predicateList = new ArrayList<>(); // list of predicates that will go in where clause + predicateList.add(builder.equal(accountRoot.get("permission"), permission)); + + criteriaQuery.select(builder.count(accountRoot)) + .where(builder.and(predicateList.toArray(new Predicate[0]))); + + return entityManager.createQuery(criteriaQuery) + .getSingleResult(); + } + + public long getAccountsByPermissionAndCreateOnUsingCQ(Permission permission, Date date) throws ParseException { + // creating criteria builder and query + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); // create builder + CriteriaQuery criteriaQuery = builder.createQuery(Long.class);// query instance + Root accountRoot = criteriaQuery.from(Account.class); // root instance + + // list of predicates that will go in where clause + List predicateList = new ArrayList<>(); + predicateList.add(builder.equal(accountRoot.get("permission"), permission)); + predicateList.add(builder.greaterThan(accountRoot.get("createdOn"), new Timestamp(date.getTime()))); + + // select query + criteriaQuery.select(builder.count(accountRoot)) + .where(builder.and(predicateList.toArray(new Predicate[0]))); + + // execute and get the result + return entityManager.createQuery(criteriaQuery) + .getSingleResult(); + } + + public long getAccountsUsingJPQL() throws ParseException { + Query query = entityManager.createQuery("SELECT COUNT(*) FROM Account a"); + return (long) query.getSingleResult(); + } + + public long getAccountsByPermissionUsingJPQL(Permission permission) throws ParseException { + Query query = entityManager.createQuery("SELECT COUNT(*) FROM Account a WHERE a.permission = ?1"); + query.setParameter(1, permission); + return (long) query.getSingleResult(); + } + + public long getAccountsByPermissionAndCreatedOnUsingJPQL(Permission permission, Date date) throws ParseException { + Query query = entityManager.createQuery("SELECT COUNT(*) FROM Account a WHERE a.permission = ?1 and a.createdOn > ?2"); + query.setParameter(1, permission); + query.setParameter(2, new Timestamp(date.getTime())); + return (long) query.getSingleResult(); + } +} \ No newline at end of file diff --git a/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/countrows/accountstatslogic/AccountStatsUnitTest.java b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/countrows/accountstatslogic/AccountStatsUnitTest.java new file mode 100644 index 0000000000..af825601aa --- /dev/null +++ b/persistence-modules/spring-boot-persistence-3/src/test/java/com/baeldung/boot/countrows/accountstatslogic/AccountStatsUnitTest.java @@ -0,0 +1,141 @@ +package com.baeldung.boot.countrows.accountstatslogic; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import java.sql.Timestamp; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.util.Date; +import java.util.UUID; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import com.baeldung.countrows.AccountStatsApplication; +import com.baeldung.countrows.entity.Account; +import com.baeldung.countrows.entity.Permission; +import com.baeldung.countrows.repository.AccountRepository; +import com.baeldung.countrows.repository.PermissionRepository; +import com.baeldung.countrows.service.AccountStatsLogic; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest(classes = AccountStatsApplication.class) +class AccountStatsUnitTest { + + @Autowired + private PermissionRepository permissionRepository; + + @Autowired + private AccountRepository accountRepository; + + @Autowired + private AccountStatsLogic accountStatsLogic; + + @AfterEach + public void afterEach() { + accountRepository.deleteAll(); + permissionRepository.deleteAll(); + } + + @Test + public void givenAccountInTable_whenPerformCount_returnsAppropriateCount() { + savePermissions(); + saveAccount(); + assertThat(accountStatsLogic.getAccountCount()).isEqualTo(1); + } + + @Test + public void givenAccountInTable_whenPerformCountByUsernameOrPermission_returnsAppropriateCount() { + savePermissions(); + Account account = saveAccount(); + assertThat(accountStatsLogic.getAccountCountByUsername(account.getUsername())).isEqualTo(1); + assertThat(accountStatsLogic.getAccountCountByPermission(account.getPermission())).isEqualTo(1); + } + + @Test + public void givenAccountInTable_whenPerformCountByPermissionAndCreatedOn_returnsAppropriateCount() throws ParseException { + savePermissions(); + Account account = saveAccount(); + long count = accountStatsLogic.getAccountCountByPermissionAndCreatedOn(account.getPermission(), account.getCreatedOn()); + assertThat(count).isEqualTo(1); + } + + @Test + public void givenAccountInTable_whenPerformCountUsingCQ_returnsAppropriateCount() throws ParseException { + savePermissions(); + saveAccount(); + long count = accountStatsLogic.getAccountsUsingCQ(); + assertThat(count).isEqualTo(1); + } + + @Test + public void givenAccountInTable_whenPerformCountByPermissionUsingCQ_returnsAppropriateCount() throws ParseException { + savePermissions(); + Account account = saveAccount(); + long count = accountStatsLogic.getAccountsByPermissionUsingCQ(account.getPermission()); + assertThat(count).isEqualTo(1); + } + + @Test + public void givenAccountInTable_whenPerformCountByPermissionAndCreatedOnUsingCQ_returnsAppropriateCount() throws ParseException { + savePermissions(); + Account account = saveAccount(); + long count = accountStatsLogic.getAccountsByPermissionAndCreateOnUsingCQ(account.getPermission(), account.getCreatedOn()); + assertThat(count).isEqualTo(1); + } + + @Test + public void givenAccountInTable_whenPerformCountUsingJPQL_returnsAppropriateCount() throws ParseException { + savePermissions(); + saveAccount(); + long count = accountStatsLogic.getAccountsUsingJPQL(); + assertThat(count).isEqualTo(1); + } + + @Test + public void givenAccountInTable_whenPerformCountByPermissionUsingJPQL_returnsAppropriateCount() throws ParseException { + savePermissions(); + Account account = saveAccount(); + long count = accountStatsLogic.getAccountsByPermissionUsingJPQL(account.getPermission()); + assertThat(count).isEqualTo(1); + } + + @Test + public void givenAccountInTable_whenPerformCountByPermissionAndCreatedOnUsingJPQL_returnsAppropriateCount() throws ParseException { + savePermissions(); + Account account = saveAccount(); + long count = accountStatsLogic.getAccountsByPermissionAndCreatedOnUsingJPQL(account.getPermission(), account.getCreatedOn()); + assertThat(count).isEqualTo(1); + } + + private Account saveAccount() { + return accountRepository.save(getAccount()); + } + + private void savePermissions() { + Permission editor = new Permission(); + editor.setType("editor"); + permissionRepository.save(editor); + + Permission admin = new Permission(); + admin.setType("admin"); + permissionRepository.save(admin); + } + + private Account getAccount() { + Permission permission = permissionRepository.findByType("admin"); + Account account = new Account(); + String seed = UUID.randomUUID() + .toString(); + account.setUsername("username_" + seed); + account.setEmail("username_" + seed + "@gmail.com"); + account.setPermission(permission); + account.setPassword("password_q1234"); + account.setCreatedOn(Timestamp.from(Instant.now())); + account.setLastLogin(Timestamp.from(Instant.now())); + return account; + } +}