<?php
/**
* 数据库类
* 
* @version 2.0.0
*/

class db extends pdoHelper
{
    /**当前 sqler*/
    protected $currentSqler = null;
    /**
     * 构造
     *
     * @param string $key 配置项中的 net.db.<key>
     */
	public function __construct($cfg='main')
    {
        if(is_string($cfg)){
            parent::__construct($cfg,\mvc::$cfg['database'][$cfg]);
        }else{
            $key = $cfg['hostname'].':'.$cfg['hostport'].'@'.$cfg['database'].'-'.md4(serialize($cfg));
            parent::__construct($key,$cfg);
        }
    }

    /**
     * 绑定原生SQL
     * 
     * @param string $sql
     * @return self
     */
    public function sql(string $sql): self
    {
        $this->query($sql);
        return $this;
    }

    /**
     * 绑定查询构建器 sqler
     * 
     * - 绑定查询Helper并执行查询语句,准备好 statement 供 all,row,one 使用。
     * @param sqler $helper
     * @return self
     */
    public function select(sqler $helper): self
    {
        $this->currentSqler = $helper;
        $this->query($helper->getSelectSQL());
        return $this;
    }       

    /**
     * 取查询结果所有行
     *
     * @param [type] $type 默认\PDO::FETCH_ASSOC, 可选:\PDO::FETCH_NUM,\PDO::FETCH_BOTH
     * @return array
     */
    public function all($type=\PDO::FETCH_ASSOC):array
    {
        if (!is_null($this->currentSqler->mapFetchKeyValue)) {
            $rows = parent::all($type);
            $data = [];
            if (!empty($rows)) {
                list($keyField, $valueField, $func) = $this->currentSqler->mapFetchKeyValue;
                $data = map($rows, $keyField, $valueField, $func);
            }
            return $data;
        }else if (!is_null($this->currentSqler->columnField)) {
            $rows = parent::all($type);
            $data = [];
            if (!empty($rows)) {
                $field = $this->currentSqler->columnField;
                foreach($rows as $i=>$row){
                    $data[$i] = $row[$field];
                }
            }
            return $data;
        }else{
            return parent::all($type);
        }
    }

    public function has(sqler $helper):bool
    {
        $this->currentSqler = $helper;
        return !empty( $this->query($helper->getHasSQL())->one() );
    }  

    public function count(sqler $helper):int
    {
        $this->currentSqler = $helper;
        return $this->query($helper->getCountSQL())->one();
    }  


    /**
     * 构建多条件插入语句
     *
     * @param int $chunkQty array_chunk 按多少条数来分割
     * @return array 多批插入SQL
     */
    public function insert(sqler $helper, int $chunkQty = 100):int
    {
        $this->currentSqler = $helper;
        if($helper->hasLots()){
            return $this->insertLots($helper, $chunkQty);  //批量
        }else{
            return $this->exec($helper->getInsertSQL());
        }
    }   

    /**
     * 构建插入语句 - 批量
     *
     * @param int $chunkQty array_chunk 按多少条数来分割
     * @return array 多批插入SQL
     */
    public function insertLots(sqler $helper, int $chunkQty = 100):int
    {
        $this->currentSqler = $helper;
        $sqlArr = $helper->getInsertLotsSQLs($chunkQty);
        $num = 0;
        if($sqlArr){
            foreach($sqlArr as $sql){
                $num += $this->exec($sql);
            }
        }
        return $num;
    }   

    /**
     * 构建完全字段替换或插入语句(原生 REPLACE INTO)
     */
    public function replaceInto(sqler $helper):int
    {
        $this->currentSqler = $helper;
        return $this->exec($helper->getReplaceIntoSQL());
    }   

    /**
     * 构建检测字段替换或插入语句, 值相同不更新，值不同则更新，没有找到则新增
     */
    public function replaceCheck(sqler $helper):int
    {
        if(!$helper->hasWhere()){
            throw new \Exception("构建SQL失败,缺失条件语句，须调用 where() 方法");
        }
        $this->currentSqler = $helper;
        if($this->has($helper)){
            return $this->exec($helper->getUpdateSQL());
        }else{
            return $this->exec($helper->getInsertSQL());
        }
    }   

    public function update(sqler $helper):int
    {
        $this->currentSqler = $helper;
        return $this->exec($helper->getUpdateSQL());
    }   

    public function delete(sqler $helper):int
    {
        $this->currentSqler = $helper;
        return $this->exec($helper->getDeleteSQL());
    }   

    public function truncate(sqler $helper):int
    {
        $this->currentSqler = $helper;
        return $this->exec($helper->getTruncateSQL());
    }   
}