package com.hotent.base.datasource;

import java.util.function.Consumer;
import java.util.function.Supplier;

import javax.sql.DataSource;

import com.baomidou.mybatisplus.annotation.DbType;
import com.fasterxml.jackson.databind.JsonNode;

/**
 * 当前数据源上下文接口
 *
 * @company 广州宏天软件股份有限公司
 * @author heyifan
 * @email heyf@jee-soft.cn
 * @date 2020年4月22日
 */
public interface DatabaseContext {
	/**
	 * 通过数据源别名设置当前数据源
	 * <pre>
	 * 1.请尽量使用注解@DS("alias")来切换数据源，该注解可以用<br/>在方法或者类上，其数据源切换的作用域仅限于该方法或该类；
	 * 2.如不能使用注解时可以调用本方法切换数据源，但是需要采用<br/>try(DatabaseSwitchResult result = databaseContext.setDataSource(alias)){<br/>}<br/>这样的方式调用，因为切换的数据源最终需要清除。
	 * </pre>
	 * @param alias
	 * @return
	 */
	DatabaseSwitchResult setDataSource(String alias);
	/**
	 * 通过别名获取数据源
	 * <pre>
	 * 1.首先从当前多数据源池获取别名所对应的数据源；
	 * 2.没获取到时尝试从系统数据源管理的库表中查找对应连接池，找到后初始化数据源并加入当前数据源池。
	 * </pre>
	 * @param alias
	 * @return
	 */
	DataSource getDataSourceByAlias(String alias);
	/**
	 * 利用Java反射机制把dataSource成javax.sql.DataSource对象
	 * @param sysDataSource
	 * @return
	 */
	DataSource getDsFromSysSource(JsonNode sysDataSource);
	/**
	 * 通过别名销毁该数据源
	 * <pre>
	 * 1.如果数据源是druid连接池，则关闭该连接池；
	 * 2.在Mybatis-Plus的多数据源中移除该数据源。
	 * </pre>
	 * @param alias
	 */
	void destroyDataSourceByAlias(String alias, DataSource dataSource);
	/**
	 * 获取当前线程的数据源
	 * @return
	 */
	DataSource getDataSource();
	/**
	 * 获取当前数据源的DbType
	 * @return
	 */
	DbType getDbTypeObj();
	/**
	 * 获取当前线程数据源类型
	 * @return
	 */
	String getDbType();
	/**
	 * 获取指定别名数据源的数据库类型
	 * @param alias
	 * @return
	 */
	String getDbTypeByAlias(String alias);
	
	/**
	 * <pre>
	 * 	切换数据源 默认抛出异常,事务回滚
	 * </pre>
	 * @param <T>
	 * @param dsName
	 * @param supplier
	 * @return
	 */
	<T> T switchDS(String dsName, Supplier<T> supplier) throws Exception;
	
	/**
	 * <pre>
	 * 	切换数据源
	 *  consumer 接收异常对象 由调用者决定异常处理情况 是否抛异常 
	 *  抛出异常，事务回滚
	 *  不抛出异常，事务不回滚
	 * </pre>
	 * @param <T>
	 * @param <E>
	 * @param dsName
	 * @param supplier
	 * @param consumer 切换数据源的操作事务要和主事务一致性 需要在consumer中抛出异常，如果不抛出异常，有可能的情况是切换数据源的数据操作失败，主数据源之后的操作都成功
	 * @return
	 */
	<T> T switchDS(String dsName, Supplier<T> supplier,Consumer<Exception> consumer);
	
	
}
