diff --git a/include/class.orm.php b/include/class.orm.php index f39442305787ebde322fab28d889272c5bcc170b..0146b9d5bc7d14e8d4c14fe0507200696d28d8c7 100644 --- a/include/class.orm.php +++ b/include/class.orm.php @@ -519,6 +519,28 @@ class SqlInterval extends SqlFunction { } } +class SqlField extends SqlFunction { + function __construct($table, $column=false) { + $this->column = $column ?: $table; + if ($column) + $this->table = $table; + } + + function toSql($compiler, $model=false, $alias=false) { + return $compiler->quote($this->column); + } +} + +class SqlCode extends SqlFunction { + function __construct($code) { + $this->code = $code; + } + + function toSql($compiler, $model=false, $alias=false) { + return $this->code; + } +} + class Aggregate extends SqlFunction { var $func; @@ -565,6 +587,8 @@ class QuerySet implements IteratorAggregate, ArrayAccess, Serializable { var $values = array(); var $defer = array(); var $annotations = array(); + var $extra = array(); + var $distinct = array(); var $lock = false; const LOCK_EXCLUSIVE = 1; @@ -626,6 +650,19 @@ class QuerySet implements IteratorAggregate, ArrayAccess, Serializable { return $this; } + function extra(array $extra) { + foreach ($extra as $section=>$info) { + $this->extra[$section] = array_merge($this->extra[$section] ?: array(), $info); + } + return $this; + } + + function distinct() { + foreach (func_get_args() as $D) + $this->distinct[] = $D; + return $this; + } + function values() { $this->values = func_get_args(); $this->iterator = 'HashArrayIterator'; @@ -1390,10 +1427,22 @@ class SqlCompiler { return $this->params; } - function getJoins() { + function getJoins($queryset) { $sql = ''; foreach ($this->joins as $j) $sql .= $j['sql']; + // Add extra items from QuerySet + if (isset($queryset->extra['tables'])) { + foreach ($queryset->extra['tables'] as $S) { + $join = ' JOIN '; + // Left joins require an ON () clause + if ($lastparen = strrpos($S, '(')) { + if (preg_match('/\bon\b/i', substr($S, $lastparen - 4, 4))) + $join = ' LEFT' . $join; + } + $sql .= $join.$S; + } + } return $sql; } @@ -1609,6 +1658,11 @@ class MySqlCompiler extends SqlCompiler { else $having[] = $C; } + if (isset($queryset->extra['where'])) { + foreach ($queryset->extra['where'] as $S) { + $where[] = '('.$S.')'; + } + } if ($where) $where = ' WHERE '.implode(' AND ', $where); if ($having) @@ -1620,7 +1674,7 @@ class MySqlCompiler extends SqlCompiler { $model = $queryset->model; $table = $model::$meta['table']; list($where, $having) = $this->getWhereHavingClause($queryset); - $joins = $this->getJoins(); + $joins = $this->getJoins($queryset); $sql = 'SELECT COUNT(*) AS count FROM '.$this->quote($table).$joins.$where; $exec = new MysqlExecutor($sql, $this->params); $row = $exec->getArray(); @@ -1736,14 +1790,17 @@ class MySqlCompiler extends SqlCompiler { if ($fieldMap) $fieldMap[0][0][] = $A->getAlias(); } - $group_by = array(); foreach ($model::$meta['pk'] as $pk) $group_by[] = $rootAlias .'.'. $pk; - if ($group_by) - $group_by = ' GROUP BY '.implode(',', $group_by); } + if (isset($queryset->distinct)) { + foreach ($queryset->distinct as $d) + list($group_by[]) = $this->getField($d, $model); + } + $group_by = $group_by ? ' GROUP BY '.implode(',', $group_by) : ''; + + $joins = $this->getJoins($queryset); - $joins = $this->getJoins(); $sql = 'SELECT '.implode(', ', $fields).' FROM ' .$table.$joins.$where.$group_by.$having.$sort; if ($queryset->limit) @@ -1809,7 +1866,7 @@ class MySqlCompiler extends SqlCompiler { $model = $queryset->model; $table = $model::$meta['table']; list($where, $having) = $this->getWhereHavingClause($queryset); - $joins = $this->getJoins(); + $joins = $this->getJoins($queryset); $sql = 'DELETE '.$this->quote($table).'.* FROM ' .$this->quote($table).$joins.$where; return new MysqlExecutor($sql, $this->params); @@ -1823,7 +1880,7 @@ class MySqlCompiler extends SqlCompiler { $set[] = sprintf('%s = %s', $this->quote($field), $this->input($value)); $set = implode(', ', $set); list($where, $having) = $this->getWhereHavingClause($queryset); - $joins = $this->getJoins(); + $joins = $this->getJoins($queryset); $sql = 'UPDATE '.$this->quote($table).' SET '.$set.$joins.$where; return new MysqlExecutor($sql, $this->params); }