// Path: src/main/java/com/pgasync/Connectible.java
// public interface Connectible extends QueryExecutor {
// 
//     CompletableFuture<Connection> getConnection();
// 
//     CompletableFuture<Void> close();
// }
// 
// Path: src/main/java/com/pgasync/Connection.java
// public interface Connection extends QueryExecutor {
// 
//     CompletableFuture<PreparedStatement> prepareStatement(String sql, Oid... parametersTypes);
// 
//     /**
//      * The typical scenario of using notifications is as follows:
//      * - {@link #subscribe(String, Consumer)}
//      * - Some calls of @onNotification callback
//      * - {@link Listening#unlisten()}
//      *
//      * @param channel Channel name to listen to.
//      * @param onNotification Callback, thar is cinvoked every time notification arrives.
//      * @return CompletableFuture instance, completed when subscription will be registered at the backend.
//      */
//     CompletableFuture<Listening> subscribe(String channel, Consumer<String> onNotification);
// 
//     CompletableFuture<Void> close();
// }
// 
// Path: src/main/java/com/pgasync/PreparedStatement.java
// public interface PreparedStatement {
// 
//     /**
//      * Fetches the whole row set and returns a {@link CompletableFuture} completed with an instance of {@link ResultSet}.
//      * This future may be completed with an error. Use this method if you are sure, that all data, returned by the query can be placed into memory.
//      *
//      * @param params Array of query parameters values.
//      * @return An instance of {@link ResultSet} with data.
//      */
//     CompletableFuture<ResultSet> query(Object... params);
// 
//     /**
//      * Fetches data rows from Postgres one by one. Use this method when you are unsure, that all data, returned by the query can be placed into memory.
//      *
//      * @param onColumns {@link Consumer} of parameters by name map. Gets called when bind/describe chain succeeded.
//      * @param processor {@link Consumer} of single data row. Performs transformation from {@link DataRow} message
//      *                                  to {@link Row} implementation instance.
//      * @param params Array of query parameters values.
//      * @return CompletableFuture that completes when the whole process ends or when an error occurs. Future's value will indicate the number of rows affected by the query.
//      */
//     CompletableFuture<Integer> fetch(BiConsumer<Map<String, PgColumn>, PgColumn[]> onColumns, Consumer<Row> processor, Object... params);
// 
//     /**
//      * Closes this {@link PreparedStatement} and possibly frees resources. In case of pool statement it may be returned to a pool for future reuse.
//      * @return CompletableFuture that is completed when the network process ends.
//      * Network process may occur if returned statement has evicted some other statement from the pool in case of pooled statement.
//      * Closing of such evicted statement is network activity, we should be aware of.
//      */
//     CompletableFuture<Void> close();
// 
// }


import com.pgasync.Connectible;
import com.pgasync.Connection;
import com.pgasync.PreparedStatement;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
package com.github.pgasync;


/**
 * @author Marat Gainullin
 */
public class PreparedStatementsCacheTest {

    private static final String SELECT_52 = "select 52";
    private static final String SELECT_32 = "select 32";

    @ClassRule
    public static DatabaseRule dbr = new DatabaseRule(DatabaseRule.createPoolBuilder(5));

    private Connectible pool;

    @Before
    public void setup() {
        pool = dbr.builder
                .maxConnections(1)
                .maxStatements(1)
                .pool();
    }

    @After
    public void shutdown() {
        pool.close().join();
    }

    @Test
    public void shouldEvictedStatementBeReallyClosed() {
        Connection conn = pool.getConnection().join();
        try {
            PreparedStatement evictor = conn.prepareStatement(SELECT_52).join();
            try {
// Path: src/main/java/com/pgasync/Connectible.java
// public interface Connectible extends QueryExecutor {
// 
//     CompletableFuture<Connection> getConnection();
// 
//     CompletableFuture<Void> close();
// }
// 
// Path: src/main/java/com/pgasync/Connection.java
// public interface Connection extends QueryExecutor {
// 
//     CompletableFuture<PreparedStatement> prepareStatement(String sql, Oid... parametersTypes);
// 
//     /**
//      * The typical scenario of using notifications is as follows:
//      * - {@link #subscribe(String, Consumer)}
//      * - Some calls of @onNotification callback
//      * - {@link Listening#unlisten()}
//      *
//      * @param channel Channel name to listen to.
//      * @param onNotification Callback, thar is cinvoked every time notification arrives.
//      * @return CompletableFuture instance, completed when subscription will be registered at the backend.
//      */
//     CompletableFuture<Listening> subscribe(String channel, Consumer<String> onNotification);
// 
//     CompletableFuture<Void> close();
// }
// 
// Path: src/main/java/com/pgasync/PreparedStatement.java
// public interface PreparedStatement {
// 
//     /**
//      * Fetches the whole row set and returns a {@link CompletableFuture} completed with an instance of {@link ResultSet}.
//      * This future may be completed with an error. Use this method if you are sure, that all data, returned by the query can be placed into memory.
//      *
//      * @param params Array of query parameters values.
//      * @return An instance of {@link ResultSet} with data.
//      */
//     CompletableFuture<ResultSet> query(Object... params);
// 
//     /**
//      * Fetches data rows from Postgres one by one. Use this method when you are unsure, that all data, returned by the query can be placed into memory.
//      *
//      * @param onColumns {@link Consumer} of parameters by name map. Gets called when bind/describe chain succeeded.
//      * @param processor {@link Consumer} of single data row. Performs transformation from {@link DataRow} message
//      *                                  to {@link Row} implementation instance.
//      * @param params Array of query parameters values.
//      * @return CompletableFuture that completes when the whole process ends or when an error occurs. Future's value will indicate the number of rows affected by the query.
//      */
//     CompletableFuture<Integer> fetch(BiConsumer<Map<String, PgColumn>, PgColumn[]> onColumns, Consumer<Row> processor, Object... params);
// 
//     /**
//      * Closes this {@link PreparedStatement} and possibly frees resources. In case of pool statement it may be returned to a pool for future reuse.
//      * @return CompletableFuture that is completed when the network process ends.
//      * Network process may occur if returned statement has evicted some other statement from the pool in case of pooled statement.
//      * Closing of such evicted statement is network activity, we should be aware of.
//      */
//     CompletableFuture<Void> close();
// 
// }


// Path: src/test/java/com/github/pgasync/PreparedStatementsCacheTest.java
import com.pgasync.Connectible;
import com.pgasync.Connection;
import com.pgasync.PreparedStatement;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;

package com.github.pgasync;


/**
 * @author Marat Gainullin
 */
public class PreparedStatementsCacheTest {

    private static final String SELECT_52 = "select 52";
    private static final String SELECT_32 = "select 32";

    @ClassRule
    public static DatabaseRule dbr = new DatabaseRule(DatabaseRule.createPoolBuilder(5));

    private Connectible pool;

    @Before
    public void setup() {
        pool = dbr.builder
                .maxConnections(1)
                .maxStatements(1)
                .pool();
    }

    @After
    public void shutdown() {
        pool.close().join();
    }

    @Test
    public void shouldEvictedStatementBeReallyClosed() {
        Connection conn = pool.getConnection().join();
        try {
            PreparedStatement evictor = conn.prepareStatement(SELECT_52).join();
            try {
                PreparedStatement evicted = conn.prepareStatement(SELECT_32).join();