package com.novarto.sanedbc.core.interpreter;

import com.novarto.sanedbc.core.ops.DbOps;
import fj.control.db.DB;
import fj.function.Try0;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * A set of utilities to aid in implementing {@link DB} interpreters.
 */
public final class InterpreterUtils
{
    private InterpreterUtils()
    {
        throw new UnsupportedOperationException();
    }

    private static final Logger LOGGER = LoggerFactory.getLogger(DbOps.class);

    /**
     * Returns an operation that will try to rollback the given operation upon failure.
     *
     * - Upon any instance of {@link Throwable} caught, a connection rollback will be issued
     * - The original throwable instance will be preserved without being wrapped
     * - If the connection auto-commit was mutated as part of this transformation, connection setAutoCommit
     *  will be finally issued to the connection.
     */
    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;
                    try
                    {
                        c.rollback();
                        throw e;
                    }
                    catch (SQLException rollbackFailed)
                    {
                        rollbackFailed.addSuppressed(e);
                        th = rollbackFailed;
                        throw rollbackFailed;
                    }


                }
                finally
                {
                    try
                    {
                        if (wasAutocommit)
                        {
                            c.setAutoCommit(true);
                        }
                    }
                    catch (SQLException e)
                    {
                        if (th != null)
                        {
                            th.addSuppressed(e);
                        }
                        else
                        {
                            throw e;
                        }
                    }
                }

            }
        };
    }

    /**
     * Lifts a DataSource to Try0<Connection, SQLException> (i.e. converts it to Try0<Connection, SQLException>)
     */
    public static Try0<Connection, SQLException> lift(DataSource ds)
    {
        return ds::getConnection;
    }
}

@@ -1661,58 +1661,8 @@
  e;%0A
-                    try%0A                    %7B%0A    
     
@@ -1703,36 +1703,32 @@
                 
-    
 throw e;%0A       
@@ -1724,279 +1724,8 @@
  e;%0A
-                    %7D%0A                    catch (SQLException rollbackFailed)%0A                    %7B%0A                        rollbackFailed.addSuppressed(e);%0A                        th = rollbackFailed;%0A                        throw rollbackFailed;%0A                    %7D%0A%0A
 %0A   

Revert "prefer throwing the rollback failed exception if there is one"