// Path: sane-dbc-core/src/main/java/com/novarto/sanedbc/core/interpreter/SyncDbInterpreter.java
// public class SyncDbInterpreter
// {
//     private final Try0<Connection, SQLException> ds;
// 
//     /**
//      * Construct an interpreter, given a piece of code which knows how to spawn connections, e.g. a Data Source, Connection Pool,
//      * Driver Manager, etc.
//      * @param ds - the data source, which can spawn connections
//      */
//     public SyncDbInterpreter(Try0<Connection, SQLException> ds)
//     {
//         this.ds = ds;
//     }
// 
//     /**
//      * Attempt to run this operation and return its result
//      * @param doOp the operation to run
//      * @param <A> the result type of the operation
//      * @return the successful result
//      * @throws RuntimeException if an {@link SQLException} is encountered
//      */
//     public <A> A submit(DB<A> doOp)
//     {
//         try (Connection c = ds.f())
//         {
//             return doOp.run(c);
//         }
//         catch (SQLException e)
//         {
//             throw new RuntimeException(e);
//         }
// 
//     }
// 
//     /**
//      * Attempt to run this operation and return its result. The operation is run transactionally - i.e. if any error is
//      * encountered, the operation is rolled back.
//      * @param doOp the operation to run
//      * @param <A> the result type of the operation
//      * @return the successful result
//      * @throws RuntimeException if an {@link SQLException} is encountered
//      */
//     public <A> A transact(DB<A> doOp)
//     {
// 
//         return submit(transactional(doOp));
// 
//     }
// }
// 
// Path: sane-dbc-core/src/main/java/com/novarto/sanedbc/core/ops/DbOps.java
// public static <A> DB<Option<A>> unique(DB<? extends Iterable<A>> op)
// {
//     return op.map(xs ->
//     {
//         Iterator<A> it = xs.iterator();
//         if (!it.hasNext())
//         {
//             return none();
//         }
// 
//         A result = it.next();
// 
//         if (it.hasNext())
//         {
//             throw new RuntimeException("unique with more than one element");
//         }
//         return some(result);
//     });
// }


import com.novarto.sanedbc.core.interpreter.SyncDbInterpreter;
import com.novarto.sanedbc.core.ops.*;
import fj.Unit;
import fj.control.db.DB;
import fj.data.List;
import fj.data.Option;
import org.junit.Test;
import java.sql.DriverManager;
import static com.novarto.sanedbc.core.ops.DbOps.unique;
import static fj.data.List.nil;
import static java.util.Arrays.asList;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
                    "INSERT INTO STUFF(DESCRIPTION) VALUES(?)",
                    //given the current element of the iterable, return a binder which sets the parameters for that element
                    // if you extracted the binder from the previous operations in a field named SET_DESCRIPTION, code becomes
                    // description -> SET_DESCRIPTION
                    description -> ps -> ps.setString(1, description),
                    //the iterables to insert
                    descriptions
            );
        }

        /*
            Count all entries in the table, where the description is LIKE the passed parameter
         */
        public static DB<Long> count(String like)
        {
            String searchQuery = like.trim();

            //an aggregate op expects the resultset to have one element, and that element to be cast to long
            //useful for numeric aggregate operations
            return new AggregateOp("SELECT COUNT(*) FROM STUFF WHERE LOWER(DESCRIPTION) LIKE LOWER(?)",
                    ps -> ps.setString(1, searchQuery + "%")
            );
        }


    }

    @Test
    public void testIt()
    {
// Path: sane-dbc-core/src/main/java/com/novarto/sanedbc/core/interpreter/SyncDbInterpreter.java
// public class SyncDbInterpreter
// {
//     private final Try0<Connection, SQLException> ds;
// 
//     /**
//      * Construct an interpreter, given a piece of code which knows how to spawn connections, e.g. a Data Source, Connection Pool,
//      * Driver Manager, etc.
//      * @param ds - the data source, which can spawn connections
//      */
//     public SyncDbInterpreter(Try0<Connection, SQLException> ds)
//     {
//         this.ds = ds;
//     }
// 
//     /**
//      * Attempt to run this operation and return its result
//      * @param doOp the operation to run
//      * @param <A> the result type of the operation
//      * @return the successful result
//      * @throws RuntimeException if an {@link SQLException} is encountered
//      */
//     public <A> A submit(DB<A> doOp)
//     {
//         try (Connection c = ds.f())
//         {
//             return doOp.run(c);
//         }
//         catch (SQLException e)
//         {
//             throw new RuntimeException(e);
//         }
// 
//     }
// 
//     /**
//      * Attempt to run this operation and return its result. The operation is run transactionally - i.e. if any error is
//      * encountered, the operation is rolled back.
//      * @param doOp the operation to run
//      * @param <A> the result type of the operation
//      * @return the successful result
//      * @throws RuntimeException if an {@link SQLException} is encountered
//      */
//     public <A> A transact(DB<A> doOp)
//     {
// 
//         return submit(transactional(doOp));
// 
//     }
// }
// 
// Path: sane-dbc-core/src/main/java/com/novarto/sanedbc/core/ops/DbOps.java
// public static <A> DB<Option<A>> unique(DB<? extends Iterable<A>> op)
// {
//     return op.map(xs ->
//     {
//         Iterator<A> it = xs.iterator();
//         if (!it.hasNext())
//         {
//             return none();
//         }
// 
//         A result = it.next();
// 
//         if (it.hasNext())
//         {
//             throw new RuntimeException("unique with more than one element");
//         }
//         return some(result);
//     });
// }


// Path: sane-dbc-examples/src/test/java/com/novarto/sanedbc/examples/BasicUsage.java
import com.novarto.sanedbc.core.interpreter.SyncDbInterpreter;
import com.novarto.sanedbc.core.ops.*;
import fj.Unit;
import fj.control.db.DB;
import fj.data.List;
import fj.data.Option;
import org.junit.Test;
import java.sql.DriverManager;
import static com.novarto.sanedbc.core.ops.DbOps.unique;
import static fj.data.List.nil;
import static java.util.Arrays.asList;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

                    "INSERT INTO STUFF(DESCRIPTION) VALUES(?)",
                    //given the current element of the iterable, return a binder which sets the parameters for that element
                    // if you extracted the binder from the previous operations in a field named SET_DESCRIPTION, code becomes
                    // description -> SET_DESCRIPTION
                    description -> ps -> ps.setString(1, description),
                    //the iterables to insert
                    descriptions
            );
        }

        /*
            Count all entries in the table, where the description is LIKE the passed parameter
         */
        public static DB<Long> count(String like)
        {
            String searchQuery = like.trim();

            //an aggregate op expects the resultset to have one element, and that element to be cast to long
            //useful for numeric aggregate operations
            return new AggregateOp("SELECT COUNT(*) FROM STUFF WHERE LOWER(DESCRIPTION) LIKE LOWER(?)",
                    ps -> ps.setString(1, searchQuery + "%")
            );
        }


    }

    @Test
    public void testIt()
    {
        SyncDbInterpreter dbi = new SyncDbInterpreter(