package com.vladmihalcea.book.hpjp.hibernate.logging.validator;

import com.vladmihalcea.book.hpjp.hibernate.logging.validator.sql.SQLStatementCountValidator;
import com.vladmihalcea.book.hpjp.util.AbstractTest;
import org.junit.Test;

import javax.persistence.*;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

/**
 * @author Vlad Mihalcea
 */
public class SQLStatementCountValidatorTest extends AbstractTest {

    @Override
    protected Class<?>[] entities() {
        return new Class[] {
            Post.class,
            PostComment.class,
        };
    }

    @Entity(name = "Post")
    @Table(name = "post")
    public static class Post {

        @Id
        private Long id;

        private String title;

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }
    }

    @Entity(name = "PostComment")
    @Table(name = "post_comment")
    public static class PostComment {

        @Id
        private Long id;

        @ManyToOne(
            fetch = FetchType.LAZY
        )
        private Post post;

        private String review;

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public Post getPost() {
            return post;
        }

        public void setPost(Post post) {
            this.post = post;
        }

        public String getReview() {
            return review;
        }

        public void setReview(String review) {
            this.review = review;
        }
    }

    @Override
    public void init() {
        super.init();
        doInJPA(entityManager -> {
            Post post1 = new Post();
            post1.setId( 1L );
            post1.setTitle("Post one");

            entityManager.persist(post1);

            PostComment comment1 = new PostComment();
            comment1.setId(1L);
            comment1.setReview("Good");
            comment1.setPost( post1 );

            entityManager.persist(comment1);

            Post post2 = new Post();
            post2.setId( 2L );
            post2.setTitle("Post two");

            entityManager.persist(post2);

            PostComment comment2 = new PostComment();
            comment2.setId(2L);
            comment2.setReview("Excellent");
            comment2.setPost( post2 );

            entityManager.persist(comment2);
        });
    }

    @Test
    public void testNPlusOne() {
        doInJPA( entityManager -> {
            LOGGER.info( "Detect N+1" );

            SQLStatementCountValidator.reset();

            List<PostComment> comments = entityManager.createQuery(
                "select pc " +
                "from PostComment pc", PostComment.class )
            .getResultList();
            assertEquals( 2, comments.size() );

            SQLStatementCountValidator.assertSelectCount( 1 );
        } );
    }

    @Test
    public void testJoinFetch() {

        doInJPA(entityManager -> {
            LOGGER.info("Join fetch to prevent N+1");
            SQLStatementCountValidator.reset();
            List<PostComment> postComments = entityManager
                    .createQuery("select pc from PostComment pc join fetch pc.post", PostComment.class)
                    .getResultList();

            for(PostComment postComment : postComments) {
                assertNotNull(postComment.getPost());
            }

            SQLStatementCountValidator.assertSelectCount(1);
        });
    }
}

@@ -552,17 +552,16 @@
  Class%5B%5D
- 
 %7B%0A      
@@ -1976,12 +1976,10 @@
 tId(
- 
 1L
- 
 );%0A 
@@ -2216,23 +2216,21 @@
 setPost(
- 
 post1
- 
 );%0A%0A    
@@ -2336,12 +2336,10 @@
 tId(
- 
 2L
- 
 );%0A 
@@ -2581,23 +2581,21 @@
 setPost(
- 
 post2
- 
 );%0A%0A    
@@ -2713,17 +2713,16 @@
 doInJPA(
- 
 entityMa
@@ -2756,17 +2756,16 @@
 ER.info(
- 
 %22Detect 
@@ -2768,21 +2768,19 @@
 ect N+1%22
- 
 );%0A
-%0A
         
@@ -2887,16 +2887,19 @@
 teQuery(
+%22%22%22
 %0A       
@@ -2907,17 +2907,16 @@
         
-%22
 select p
@@ -2920,12 +2920,8 @@
 t pc
- %22 +
 %0A   
@@ -2933,17 +2933,16 @@
         
-%22
 from Pos
@@ -2952,16 +2952,35 @@
 mment pc
+%0A                %22%22
 %22, PostC
@@ -2991,17 +2991,16 @@
 nt.class
- 
 )%0A      
@@ -3019,24 +3019,25 @@
 sultList();%0A
+%0A
             
@@ -3049,17 +3049,16 @@
 tEquals(
- 
 2, comme
@@ -3067,17 +3067,16 @@
 s.size()
- 
 );%0A%0A    
@@ -3132,11 +3132,9 @@
 unt(
- 1 
+1
 );%0A 
@@ -3141,17 +3141,16 @@
        %7D
- 
 );%0A    %7D
@@ -3195,17 +3195,16 @@
 tch() %7B%0A
-%0A
         
@@ -3328,24 +3328,25 @@
 or.reset();%0A
+%0A
             
@@ -3391,16 +3391,32 @@
 yManager
+.createQuery(%22%22%22
 %0A       
@@ -3428,35 +3428,34 @@
     
-    .createQuery(%22select pc
+select pc %0A               
  fro
@@ -3471,16 +3471,33 @@
 ment pc 
+%0A                
 join fet
@@ -3506,16 +3506,35 @@
  pc.post
+%0A                %22%22
 %22, PostC
@@ -3543,32 +3543,24 @@
 ment.class)%0A
-        
             
@@ -3593,16 +3593,17 @@
      for
+ 
 (PostCom

Refactor code