package com.atlassian.bitbucket.mesh.dbunit;

import com.atlassian.bitbucket.mesh.MeshTestWiring;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.datatype.IDataTypeFactory;
import org.dbunit.ext.h2.H2DataTypeFactory;

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

/**
 * Adapts between DbUnit's {@code IDatabaseConnection} and a standard Java {@code DataSource}. This factory only
 * supports H2 for its underlying database.
 */
public class DatabaseConnectionFactory {

    private final DataSource dataSource;
    private final IDataTypeFactory dataTypeFactory;

    public DatabaseConnectionFactory(DataSource dataSource) {
        this.dataSource = dataSource;

        dataTypeFactory = new H2DataTypeFactory();
    }

    /**
     * Constructs a new DbUnit {@code DatabaseConnection}, configures its {@code IDataTypeFactory} and returns it.
     * <p>
     * If a Spring transaction is in progress, this should automatically use the same connection. See the wiring for
     * this bean in {@link MeshTestWiring} for more on how that works.
     *
     * @return a new DbUnit connection
     * @throws DatabaseUnitException if a new {@code DatabaseConnection} cannot be constructed from the JDBC connection
     * @throws SQLException          if a JDBC connection cannot be opened
     */
    public IDatabaseConnection newConnection() throws DatabaseUnitException, SQLException {
        Connection jdbcConnection = dataSource.getConnection();

        DatabaseConnection connection = new DatabaseConnection(jdbcConnection, null);
        connection.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, dataTypeFactory);

        return connection;
    }
}