package com.vladmihalcea.book.hpjp.jdbc.caching;

import com.vladmihalcea.book.hpjp.util.AbstractOracleIntegrationTest;
import com.vladmihalcea.book.hpjp.util.ReflectionUtils;
import com.vladmihalcea.book.hpjp.util.providers.entity.BlogEntityProvider;
import org.junit.Ignore;
import org.junit.Test;

import java.sql.PreparedStatement;
import java.sql.SQLException;

import static org.junit.Assert.fail;

/**
 * OracleImplicitStatementCacheTest - Test Oracle implicit Statement cache
 *
 * @author Vlad Mihalcea
 */
public class OracleExplicitStatementCacheTest extends AbstractOracleIntegrationTest {

    public static final String INSERT_POST = "insert into post (title, version, id) values (?, ?, ?)";

    public static final String INSERT_POST_COMMENT = "insert into post_comment (post_id, review, version, id) values (?, ?, ?, ?)";

    public static final String SELECT_POST_REVIEWS =
            "select p.title, pc.review " +
                    "from post p left join post_comment pc on p.id = pc.post_id " +
                    "where EXISTS ( " +
                    "   select 1 from post_comment where version = ? and id > p.id " +
                    ")";

    public static final String SELECT_POST_REVIEWS_KEY = "post_reviews";

    private BlogEntityProvider entityProvider = new BlogEntityProvider();

    @Override
    protected Class<?>[] entities() {
        return entityProvider.entities();
    }

    @Override
    public void init() {
        super.init();
        doInJDBC(connection -> {
            try (
                    PreparedStatement postStatement = connection.prepareStatement(INSERT_POST);
                    PreparedStatement postCommentStatement = connection.prepareStatement(INSERT_POST_COMMENT);
            ) {
                int postCount = getPostCount();
                int postCommentCount = getPostCommentCount();

                int index;

                for (int i = 0; i < postCount; i++) {
                    index = 0;
                    postStatement.setString(++index, String.format("Post no. %1$d", i));
                    postStatement.setInt(++index, 0);
                    postStatement.setLong(++index, i);
                    postStatement.executeUpdate();
                }

                for (int i = 0; i < postCount; i++) {
                    for (int j = 0; j < postCommentCount; j++) {
                        index = 0;
                        postCommentStatement.setLong(++index, i);
                        postCommentStatement.setString(++index, String.format("Post comment %1$d", j));
                        postCommentStatement.setInt(++index, (int) (Math.random() * 1000));
                        postCommentStatement.setLong(++index, (postCommentCount * i) + j);
                        postCommentStatement.executeUpdate();
                    }
                }
            } catch (SQLException e) {
                fail(e.getMessage());
            }
        });
    }

    @Test
    @Ignore
    public void testStatementCaching() {
        doInJDBC(connection -> {
            for (int i = 0; i < 5; i++) {
                ReflectionUtils.invokeSetter(connection,"explicitCachingEnabled", true);
                ReflectionUtils.invokeSetter(connection,"statementCacheSize", 1);
                PreparedStatement statement = ReflectionUtils.invokeMethod(connection, ReflectionUtils.getMethod(connection, "getStatementWithKey", String.class), SELECT_POST_REVIEWS_KEY);
                if (statement == null)
                    statement = connection.prepareStatement(SELECT_POST_REVIEWS);
                try {
                    statement.setInt(1, 10);
                    statement.execute();
                } finally {
                    ReflectionUtils.invokeMethod(statement, ReflectionUtils.getMethod(statement, "closeWithKey", String.class), SELECT_POST_REVIEWS_KEY);
                }
            }
        });
    }

    protected int getPostCount() {
        return 1000;
    }

    protected int getPostCommentCount() {
        return 5;
    }

    @Override
    protected boolean proxyDataSource() {
        return false;
    }
}

@@ -156,99 +156,124 @@
 til.
-ReflectionUtils;%0Aimport com.vladmihalcea.book.hpjp.util.providers.entity.BlogEntityProvider
+providers.entity.BlogEntityProvider;%0Aimport oracle.jdbc.OracleConnection;%0Aimport oracle.jdbc.OraclePreparedStatement
 ;%0Aim
@@ -3145,38 +3145,98 @@
     
-ReflectionUtils.invokeSetter(c
+OracleConnection oracleConnection = (OracleConnection) connection;%0A                oracleC
 onne
@@ -3244,11 +3244,13 @@
 tion
-,%22e
+.setE
 xpli
@@ -3266,19 +3266,17 @@
 gEnabled
-%22, 
+(
 true);%0A 
@@ -3294,38 +3294,15 @@
     
-ReflectionUtils.invokeSetter(c
+oracleC
 onne
@@ -3310,11 +3310,13 @@
 tion
-,%22s
+.setS
 tate
@@ -3328,19 +3328,17 @@
 acheSize
-%22, 
+(
 1);%0A    
@@ -3383,125 +3383,45 @@
 t = 
-ReflectionUtils.invokeMethod(connection, ReflectionUtils.getMethod(connection, %22getStatementWithKey%22, String.class), 
+oracleConnection.getStatementWithKey(
 SELE
@@ -3723,74 +3723,35 @@
     
-ReflectionUtils.invokeMethod(statement, ReflectionUtils.getMethod(
+((OraclePreparedStatement) 
 stat
@@ -3759,11 +3759,10 @@
 ment
-, %22
+).
 clos
@@ -3773,26 +3773,9 @@
 hKey
-%22, String.class), 
+(
 SELE

Use Oracle-specific API