// Path: sane-dbc-core/src/main/java/com/novarto/sanedbc/core/interpreter/InterpreterUtils.java
// public static Try0<Connection, SQLException> lift(DataSource ds)
// {
//     return ds::getConnection;
// }
// 
// Path: sane-dbc-core/src/main/java/com/novarto/sanedbc/core/interpreter/InterpreterUtils.java
// public static <A> DB<A> transactional(DB<A> op)
// {
// 
//     return new DB<A>()
//     {
//         @Override public A run(Connection c) throws SQLException
//         {
//             final boolean wasAutocommit = c.getAutoCommit();
//             Throwable th = null;
//             if (wasAutocommit)
//             {
//                 c.setAutoCommit(false);
//             }
// 
//             try
//             {
//                 A result = op.run(c);
//                 c.commit();
//                 return result;
//             }
//             catch (Throwable e)
//             {
//                 th = e;
//                 c.rollback();
//                 throw e;
// 
//             }
//             finally
//             {
//                 try
//                 {
//                     if (wasAutocommit)
//                     {
//                         c.setAutoCommit(true);
//                     }
//                 }
//                 catch (SQLException e)
//                 {
//                     if (th != null)
//                     {
//                         th.addSuppressed(e);
//                     }
//                     else
//                     {
//                         throw e;
//                     }
//                 }
//             }
// 
//         }
//     };
// }


import com.novarto.lang.SneakyThrow;
import fj.control.db.DB;
import fj.function.Try0;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import static com.novarto.sanedbc.core.interpreter.InterpreterUtils.lift;
import static com.novarto.sanedbc.core.interpreter.InterpreterUtils.transactional;
package com.novarto.sanedbc.core.interpreter;





/**
 * A standard {@link DB} interpreter that utilizes a data source to spawn connections,
 * and submits {@link DB} instances for execution in an ExecutorService. The result is lifted to a CompletableFuture.
 * The CompletableFuture returned will fail iff the underlying DB throws.
 *
 * Spawning of a connection happens inside an executor service thread, the submitted DB operation is executed in the same thread,
 * and then the connection is closed. Therefore, a connection obtained from the pool is accessed by only a single thread
 * before being returned to the pool.
 *
 */
public class AsyncDbInterpreter
{

    private final Try0<Connection, SQLException> ds;
    private final ExecutorService executor;


    public AsyncDbInterpreter(Try0<Connection, SQLException> ds, ExecutorService ex)
    {
        this.ds = ds;
        this.executor = ex;
    }

    public AsyncDbInterpreter(DataSource ds, ExecutorService ex)
    {
        this(lift(ds), ex);
    }


    /**
     * Submits this operation for execution in the executor service. The operation is executed with connection autoCommit = true,
     * i.e. non-transactionally.
     */
    public <A> CompletableFuture<A> submit(DB<A> op)
    {
        return withConnection(op, true);
    }

    /**
     * Submits this operation for execution in the executor service. The operation is executed as a transaction.
     */
    public <A> CompletableFuture<A> transact(DB<A> op)
    {
// Path: sane-dbc-core/src/main/java/com/novarto/sanedbc/core/interpreter/InterpreterUtils.java
// public static Try0<Connection, SQLException> lift(DataSource ds)
// {
//     return ds::getConnection;
// }
// 
// Path: sane-dbc-core/src/main/java/com/novarto/sanedbc/core/interpreter/InterpreterUtils.java
// public static <A> DB<A> transactional(DB<A> op)
// {
// 
//     return new DB<A>()
//     {
//         @Override public A run(Connection c) throws SQLException
//         {
//             final boolean wasAutocommit = c.getAutoCommit();
//             Throwable th = null;
//             if (wasAutocommit)
//             {
//                 c.setAutoCommit(false);
//             }
// 
//             try
//             {
//                 A result = op.run(c);
//                 c.commit();
//                 return result;
//             }
//             catch (Throwable e)
//             {
//                 th = e;
//                 c.rollback();
//                 throw e;
// 
//             }
//             finally
//             {
//                 try
//                 {
//                     if (wasAutocommit)
//                     {
//                         c.setAutoCommit(true);
//                     }
//                 }
//                 catch (SQLException e)
//                 {
//                     if (th != null)
//                     {
//                         th.addSuppressed(e);
//                     }
//                     else
//                     {
//                         throw e;
//                     }
//                 }
//             }
// 
//         }
//     };
// }


// Path: sane-dbc-core/src/main/java/com/novarto/sanedbc/core/interpreter/AsyncDbInterpreter.java
import com.novarto.lang.SneakyThrow;
import fj.control.db.DB;
import fj.function.Try0;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import static com.novarto.sanedbc.core.interpreter.InterpreterUtils.lift;
import static com.novarto.sanedbc.core.interpreter.InterpreterUtils.transactional;

package com.novarto.sanedbc.core.interpreter;





/**
 * A standard {@link DB} interpreter that utilizes a data source to spawn connections,
 * and submits {@link DB} instances for execution in an ExecutorService. The result is lifted to a CompletableFuture.
 * The CompletableFuture returned will fail iff the underlying DB throws.
 *
 * Spawning of a connection happens inside an executor service thread, the submitted DB operation is executed in the same thread,
 * and then the connection is closed. Therefore, a connection obtained from the pool is accessed by only a single thread
 * before being returned to the pool.
 *
 */
public class AsyncDbInterpreter
{

    private final Try0<Connection, SQLException> ds;
    private final ExecutorService executor;


    public AsyncDbInterpreter(Try0<Connection, SQLException> ds, ExecutorService ex)
    {
        this.ds = ds;
        this.executor = ex;
    }

    public AsyncDbInterpreter(DataSource ds, ExecutorService ex)
    {
        this(lift(ds), ex);
    }


    /**
     * Submits this operation for execution in the executor service. The operation is executed with connection autoCommit = true,
     * i.e. non-transactionally.
     */
    public <A> CompletableFuture<A> submit(DB<A> op)
    {
        return withConnection(op, true);
    }

    /**
     * Submits this operation for execution in the executor service. The operation is executed as a transaction.
     */
    public <A> CompletableFuture<A> transact(DB<A> op)
    {
        return withConnection(transactional(op), false);