<?php
/**
 * Base SQL Storage implementation for common functionality.
 *
 * $Horde: framework/RDO/RDO/Storage/sql.php,v 1.3.2.1 2005/10/18 11:01:23 jan Exp $
 *
 * @package RDO
 */
abstract class RDO_Storage_sql extends RDO_Storage {

    /**
     */
    public function exists(RDO_Mapper $mapper, $criteria)
    {
        $criteria = $this->toCriteria($criteria, $mapper);
        $criteria->setFields(array(1));
        return $this->queryOne($this->process($criteria));
    }

    /**
     */
    public function count(RDO_Mapper $mapper, $criteria)
    {
        $criteria = $this->toCriteria($criteria, $mapper);
        $criteria->setFields(array('COUNT(*)'));
        return $this->queryOne($this->process($criteria));
    }

    /**
     */
    public function findNow(RDO_Mapper $mapper, $mode, $criteria)
    {
        $criteria = $this->toCriteria($criteria, $mapper);
        $criteria->setFields(array('*'));

        if ($mode == RDO::FIND_FIRST) {
            $criteria->limit(1);
        }

        return $this->query($this->process($criteria));
    }

    /**
     */
    public function quote($field, $data = null)
    {
        if (is_null($data)) {
            return 'NULL';
        }

        switch ($field['type']) {
        case RDO_MetaData::INTEGER:
            return (int)$data;

        case RDO_MetaData::STRING:
            return $this->quoteString($data);

        default:
            throw new RDO_Exception('Unknown data type: ' . $field['type']);
        }
    }

    /**
     */
    public function process(RDO_Criteria $criteria)
    {
        $meta = $criteria->mapper->describe();

        $sql = 'SELECT ' . implode(', ', $criteria->fields) .
            ' FROM ' . $meta->container;

        foreach ($criteria->relationships as $relationship) {
            $rmeta = $relationship['mapper']->describe();
            $sql .= ' INNER JOIN ' . $relationship['container'] . ' ON ' .
                $meta->container . '.' . $meta->key . ' = ' . $relationship['container'] . '.' . $meta->key;
            foreach ($relationship['criteria'] as $key => $value) {
                $sql .= ' AND ' . $relationship['container'] . '.' . $key . ' = ' . $value;
            }
        }

        $clauses = array();
        foreach ($criteria->tests as $test) {
            $clauses[] = $test['field'] . ' ' . $test['test'] . ' ' . $this->quote($meta->getField($test['field']), $test['value']);
        }
        if ($clauses) {
            $sql .= ' WHERE ' . implode(' ' . $criteria->conjunction . ' ', $clauses);
        }

        if ($criteria->limit) {
            $sql .= ' LIMIT ' . $criteria->limit;
        }

        return $sql;
    }

}
