mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #400 from halkyon/sqlquery_enhancements
API CHANGE Deprecated internal access to SQLQuery properties
This commit is contained in:
commit
07bd8e5541
@ -137,9 +137,9 @@ class PaginatedList extends SS_ListDecorator {
|
||||
* @param SQLQuery $query
|
||||
*/
|
||||
public function setPaginationFromQuery(SQLQuery $query) {
|
||||
if ($query->limit) {
|
||||
$this->setPageLength($query->limit['limit']);
|
||||
$this->setPageStart($query->limit['start']);
|
||||
if ($limit = $query->getLimit()) {
|
||||
$this->setPageLength($limit['limit']);
|
||||
$this->setPageStart($limit['start']);
|
||||
$this->setTotalItems($query->unlimitedRowCount());
|
||||
}
|
||||
}
|
||||
|
@ -182,6 +182,27 @@ The abstract `RelationList` class and its implementations `ManyManyList` and `Ha
|
||||
are replacing the `ComponentSet` API, which is only relevant if you have instanciated these manually.
|
||||
Relations are retrieved through the same way (e.g. `$myMember->Groups()`).
|
||||
|
||||
### `SQLQuery` changes ###
|
||||
|
||||
`SQLQuery` has been changed so direct access to internal properties `$from`, `$select`, `$orderby` is
|
||||
now deprecated.
|
||||
|
||||
Instead, there are now methods you can call which allow you to get and set SQL clauses instead.
|
||||
|
||||
* `$from` getter is `getFrom()` and setters `setFrom()` and `addFrom()`
|
||||
* `$select` getter is `getSelect()` and setters `setSelect()` and `addSelect()`
|
||||
* `$where` getter is `getWhere()` and setter `setWhere()` and `addWhere()`
|
||||
* `$orderby` getter is `getOrderBy()` and setter `setOrderBy()` and `addOrderBy()`
|
||||
* `$groupby` getter is `getGroupBy()` and setter `getGroupBy()` and `addGroupBy()`
|
||||
* `$having` getter is `getHaving()` and setter `setHaving()` and `addHaving()`
|
||||
* `$limit` getter is `getLimit()` and setter `setLimit()`
|
||||
* `$distinct` getter is `getDistinct()` and setter `setDistinct()`
|
||||
* `$delete` getter is `getDelete()` and setter `setDelete()`
|
||||
* `$connective` getter is `getConnective()` and settter `setConnective()`
|
||||
|
||||
* `innerJoin()` has been renamed to `addInnerJoin()`
|
||||
* `leftJoin()` has been renamed to `addLeftJoin()`
|
||||
|
||||
### InnoDB driver for existing and new tables on MySQL (instead of MyISAM) [innodb]###
|
||||
|
||||
SilverStripe has traditionally created all MySQL tables with the MyISAM storage driver,
|
||||
|
@ -1216,9 +1216,9 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
// obviously, that means getting requireTable() to configure cascading deletes ;-)
|
||||
$srcQuery = DataList::create($this->class, $this->model)->where("ID = $this->ID")->dataQuery()->query();
|
||||
foreach($srcQuery->queriedTables() as $table) {
|
||||
$query = new SQLQuery("*", array('"'.$table.'"'));
|
||||
$query->where("\"ID\" = $this->ID");
|
||||
$query->delete = true;
|
||||
$query = new SQLQuery("*", array('"' . $table . '"'));
|
||||
$query->setWhere("\"ID\" = $this->ID");
|
||||
$query->setDelete(true);
|
||||
$query->execute();
|
||||
}
|
||||
// Remove this item out of any caches
|
||||
|
@ -58,7 +58,7 @@ class DataQuery {
|
||||
* Return the {@link DataObject} class that is being queried.
|
||||
*/
|
||||
function dataClass() {
|
||||
return $this->dataClass;
|
||||
return $this->dataClass;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,14 +75,21 @@ class DataQuery {
|
||||
*/
|
||||
function removeFilterOn($fieldExpression) {
|
||||
$matched = false;
|
||||
foreach($this->query->where as $i=>$item) {
|
||||
if(strpos($item, $fieldExpression) !== false) {
|
||||
unset($this->query->where[$i]);
|
||||
|
||||
$where = $this->query->getWhere();
|
||||
foreach($where as $i => $clause) {
|
||||
if(strpos($clause, $fieldExpression) !== false) {
|
||||
unset($where[$i]);
|
||||
$matched = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$matched) throw new InvalidArgumentException("Couldn't find $fieldExpression in the query filter.");
|
||||
// set the entire where clause back, but clear the original one first
|
||||
if($matched) {
|
||||
$this->query->setWhere($where);
|
||||
} else {
|
||||
throw new InvalidArgumentException("Couldn't find $fieldExpression in the query filter.");
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -108,13 +115,13 @@ class DataQuery {
|
||||
|
||||
// Build our intial query
|
||||
$this->query = new SQLQuery(array());
|
||||
$this->query->distinct = true;
|
||||
$this->query->setDistinct(true);
|
||||
|
||||
if($sort = singleton($this->dataClass)->stat('default_sort')) {
|
||||
$this->sort($sort);
|
||||
}
|
||||
|
||||
$this->query->from("\"$baseClass\"");
|
||||
$this->query->setFrom("\"$baseClass\"");
|
||||
|
||||
singleton($this->dataClass)->extend('augmentDataQueryCreation', $this->query, $this);
|
||||
}
|
||||
@ -140,7 +147,7 @@ class DataQuery {
|
||||
if($queriedColumns) {
|
||||
$tableClasses = ClassInfo::dataClassesFor($this->dataClass);
|
||||
|
||||
foreach ($query->where as $where) {
|
||||
foreach ($query->getWhere() as $where) {
|
||||
// Check for just the column, in the form '"Column" = ?' and the form '"Table"."Column"' = ?
|
||||
if (preg_match('/^"([^"]+)"/', $where, $matches) ||
|
||||
preg_match('/^"([^"]+)"\."[^"]+"/', $where, $matches)) {
|
||||
@ -179,7 +186,7 @@ class DataQuery {
|
||||
}
|
||||
|
||||
if ($joinTable) {
|
||||
$query->leftJoin($tableClass, "\"$tableClass\".\"ID\" = \"$baseClass\".\"ID\"") ;
|
||||
$query->addLeftJoin($tableClass, "\"$tableClass\".\"ID\" = \"$baseClass\".\"ID\"") ;
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,7 +215,7 @@ class DataQuery {
|
||||
// Get the ClassName values to filter to
|
||||
$classNames = ClassInfo::subclassesFor($this->dataClass);
|
||||
if(!$classNames) user_error("DataList::create() Can't find data sub-classes for '$callerClass'");
|
||||
$query->where[] = "\"$baseClass\".\"ClassName\" IN ('" . implode("','", $classNames) . "')";
|
||||
$query->addWhere("\"$baseClass\".\"ClassName\" IN ('" . implode("','", $classNames) . "')");
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,9 +240,7 @@ class DataQuery {
|
||||
$tableClasses = ClassInfo::dataClassesFor($this->dataClass);
|
||||
$baseClass = array_shift($tableClasses);
|
||||
|
||||
if($query->orderby) {
|
||||
$orderby = $query->getOrderBy();
|
||||
|
||||
if($orderby = $query->getOrderBy()) {
|
||||
foreach($orderby as $k => $dir) {
|
||||
// don't touch functions in the ORDER BY or function calls
|
||||
// selected as fields
|
||||
@ -270,23 +275,24 @@ class DataQuery {
|
||||
$qualCol = "\"$parts[0]\"";
|
||||
}
|
||||
|
||||
// To-do: Remove this if block once SQLQuery::$select has been refactored to store itemisedSelect()
|
||||
// To-do: Remove this if block once SQLQuery::$select has been refactored to store getSelect()
|
||||
// format internally; then this check can be part of selectField()
|
||||
if(!isset($query->select[$col]) && !in_array($qualCol, $query->select)) {
|
||||
$selects = $query->getSelect();
|
||||
if(!isset($selects[$col]) && !in_array($qualCol, $selects)) {
|
||||
$query->selectField($qualCol);
|
||||
}
|
||||
} else {
|
||||
$qualCol = '"' . implode('"."', $parts) . '"';
|
||||
|
||||
// To-do: Remove this if block once SQLQuery::$select has been refactored to store itemisedSelect()
|
||||
// To-do: Remove this if block once SQLQuery::$select has been refactored to store getSelect()
|
||||
// format internally; then this check can be part of selectField()
|
||||
if(!in_array($qualCol, $query->select)) {
|
||||
if(!in_array($qualCol, $query->getSelect())) {
|
||||
$query->selectField($qualCol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$query->orderby = $orderby;
|
||||
$query->setOrderBy($orderby);
|
||||
}
|
||||
}
|
||||
|
||||
@ -390,7 +396,7 @@ class DataQuery {
|
||||
function having($having) {
|
||||
if($having) {
|
||||
$clone = $this;
|
||||
$clone->query->having[] = $having;
|
||||
$clone->query->addHaving($having);
|
||||
return $clone;
|
||||
} else {
|
||||
return $this;
|
||||
@ -403,7 +409,7 @@ class DataQuery {
|
||||
function where($filter) {
|
||||
if($filter) {
|
||||
$clone = $this;
|
||||
$clone->query->where($filter);
|
||||
$clone->query->addWhere($filter);
|
||||
return $clone;
|
||||
} else {
|
||||
return $this;
|
||||
@ -436,7 +442,11 @@ class DataQuery {
|
||||
*/
|
||||
function sort($sort = null, $direction = null, $clear = true) {
|
||||
$clone = $this;
|
||||
$clone->query->orderby($sort, $direction, $clear);
|
||||
if($clear) {
|
||||
$clone->query->setOrderBy($sort, $direction);
|
||||
} else {
|
||||
$clone->query->addOrderBy($sort, $direction);
|
||||
}
|
||||
|
||||
return $clone;
|
||||
}
|
||||
@ -458,7 +468,7 @@ class DataQuery {
|
||||
*/
|
||||
function limit($limit, $offset = 0) {
|
||||
$clone = $this;
|
||||
$clone->query->limit($limit, $offset);
|
||||
$clone->query->setLimit($limit, $offset);
|
||||
return $clone;
|
||||
}
|
||||
|
||||
@ -470,9 +480,13 @@ class DataQuery {
|
||||
Deprecation::notice('3.0', 'Use innerJoin() or leftJoin() instead.');
|
||||
if($join) {
|
||||
$clone = $this;
|
||||
$clone->query->from[] = $join;
|
||||
$clone->query->addFrom($join);
|
||||
// TODO: This needs to be resolved for all databases
|
||||
if(DB::getConn() instanceof MySQLDatabase) $clone->query->groupby[] = reset($clone->query->from) . ".\"ID\"";
|
||||
|
||||
if(DB::getConn() instanceof MySQLDatabase) {
|
||||
$from = $clone->query->getFrom();
|
||||
$clone->query->setGroupBy(reset($from) . ".\"ID\"");
|
||||
}
|
||||
return $clone;
|
||||
} else {
|
||||
return $this;
|
||||
@ -487,7 +501,7 @@ class DataQuery {
|
||||
public function innerJoin($table, $onClause, $alias = null) {
|
||||
if($table) {
|
||||
$clone = $this;
|
||||
$clone->query->innerJoin($table, $onClause, $alias);
|
||||
$clone->query->addInnerJoin($table, $onClause, $alias);
|
||||
return $clone;
|
||||
} else {
|
||||
return $this;
|
||||
@ -502,7 +516,7 @@ class DataQuery {
|
||||
public function leftJoin($table, $onClause, $alias = null) {
|
||||
if($table) {
|
||||
$clone = $this;
|
||||
$clone->query->leftJoin($table, $onClause, $alias);
|
||||
$clone->query->addLeftJoin($table, $onClause, $alias);
|
||||
return $clone;
|
||||
} else {
|
||||
return $this;
|
||||
@ -530,7 +544,7 @@ class DataQuery {
|
||||
if ($component = $model->has_one($rel)) {
|
||||
if(!$this->query->isJoinedTo($component)) {
|
||||
$foreignKey = $model->getReverseAssociation($component);
|
||||
$this->query->leftJoin($component, "\"$component\".\"ID\" = \"{$modelClass}\".\"{$foreignKey}ID\"");
|
||||
$this->query->addLeftJoin($component, "\"$component\".\"ID\" = \"{$modelClass}\".\"{$foreignKey}ID\"");
|
||||
|
||||
/**
|
||||
* add join clause to the component's ancestry classes so that the search filter could search on its
|
||||
@ -541,7 +555,7 @@ class DataQuery {
|
||||
$ancestry = array_reverse($ancestry);
|
||||
foreach($ancestry as $ancestor){
|
||||
if($ancestor != $component){
|
||||
$this->query->innerJoin($ancestor, "\"$component\".\"ID\" = \"$ancestor\".\"ID\"");
|
||||
$this->query->addInnerJoin($ancestor, "\"$component\".\"ID\" = \"$ancestor\".\"ID\"");
|
||||
$component=$ancestor;
|
||||
}
|
||||
}
|
||||
@ -553,7 +567,7 @@ class DataQuery {
|
||||
if(!$this->query->isJoinedTo($component)) {
|
||||
$ancestry = $model->getClassAncestry();
|
||||
$foreignKey = $model->getRemoteJoinField($rel);
|
||||
$this->query->leftJoin($component, "\"$component\".\"{$foreignKey}\" = \"{$ancestry[0]}\".\"ID\"");
|
||||
$this->query->addLeftJoin($component, "\"$component\".\"{$foreignKey}\" = \"{$ancestry[0]}\".\"ID\"");
|
||||
/**
|
||||
* add join clause to the component's ancestry classes so that the search filter could search on its
|
||||
* ancestor fields.
|
||||
@ -563,7 +577,7 @@ class DataQuery {
|
||||
$ancestry = array_reverse($ancestry);
|
||||
foreach($ancestry as $ancestor){
|
||||
if($ancestor != $component){
|
||||
$this->query->innerJoin($ancestor, "\"$component\".\"ID\" = \"$ancestor\".\"ID\"");
|
||||
$this->query->addInnerJoin($ancestor, "\"$component\".\"ID\" = \"$ancestor\".\"ID\"");
|
||||
$component=$ancestor;
|
||||
}
|
||||
}
|
||||
@ -575,10 +589,10 @@ class DataQuery {
|
||||
list($parentClass, $componentClass, $parentField, $componentField, $relationTable) = $component;
|
||||
$parentBaseClass = ClassInfo::baseDataClass($parentClass);
|
||||
$componentBaseClass = ClassInfo::baseDataClass($componentClass);
|
||||
$this->query->innerJoin($relationTable, "\"$relationTable\".\"$parentField\" = \"$parentBaseClass\".\"ID\"");
|
||||
$this->query->leftJoin($componentBaseClass, "\"$relationTable\".\"$componentField\" = \"$componentBaseClass\".\"ID\"");
|
||||
$this->query->addInnerJoin($relationTable, "\"$relationTable\".\"$parentField\" = \"$parentBaseClass\".\"ID\"");
|
||||
$this->query->addLeftJoin($componentBaseClass, "\"$relationTable\".\"$componentField\" = \"$componentBaseClass\".\"ID\"");
|
||||
if(ClassInfo::hasTable($componentClass)) {
|
||||
$this->query->leftJoin($componentClass, "\"$relationTable\".\"$componentField\" = \"$componentClass\".\"ID\"");
|
||||
$this->query->addLeftJoin($componentClass, "\"$relationTable\".\"$componentField\" = \"$componentClass\".\"ID\"");
|
||||
}
|
||||
$modelClass = $componentClass;
|
||||
|
||||
@ -597,7 +611,7 @@ class DataQuery {
|
||||
public function subtract(DataQuery $subtractQuery, $field='ID') {
|
||||
$subSelect= $subtractQuery->getFinalisedQuery();
|
||||
$fieldExpression = $this->expressionForField($field, $subSelect);
|
||||
$subSelect->clearSelect();
|
||||
$subSelect->setSelect(array());
|
||||
$subSelect->selectField($fieldExpression, $field);
|
||||
$this->where($this->expressionForField($field, $this).' NOT IN ('.$subSelect->sql().')');
|
||||
|
||||
@ -611,7 +625,7 @@ class DataQuery {
|
||||
$fieldExpressions = array_map(create_function('$item',
|
||||
"return '\"$table\".\"' . \$item . '\"';"), $fields);
|
||||
|
||||
$this->query->select($fieldExpressions);
|
||||
$this->query->setSelect($fieldExpressions);
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -621,9 +635,9 @@ class DataQuery {
|
||||
*/
|
||||
public function column($field = 'ID') {
|
||||
$query = $this->getFinalisedQuery(array($field));
|
||||
$originalSelect = $query->itemisedSelect();
|
||||
$originalSelect = $query->getSelect();
|
||||
$fieldExpression = $this->expressionForField($field, $query);
|
||||
$query->clearSelect();
|
||||
$query->setSelect(array());
|
||||
$query->selectField($fieldExpression, $field);
|
||||
$this->ensureSelectContainsOrderbyColumns($query, $originalSelect);
|
||||
|
||||
@ -637,17 +651,8 @@ class DataQuery {
|
||||
return "\"$baseClass\".\"ID\"";
|
||||
|
||||
} else {
|
||||
return $query->expressionForField($field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the selected fields to start over
|
||||
*/
|
||||
public function clearSelect() {
|
||||
$this->query->clearSelect();
|
||||
|
||||
return $this;
|
||||
return $query->expressionForField($field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -721,42 +721,119 @@ abstract class SS_Database {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a SQLQuery object into a SQL statement
|
||||
* Returns the SELECT clauses ready for inserting into a query.
|
||||
* @param array $select Select columns
|
||||
* @param boolean $distinct Distinct select?
|
||||
* @return string
|
||||
*/
|
||||
public function sqlQueryToString(SQLQuery $sqlQuery) {
|
||||
$distinct = $sqlQuery->distinct ? "DISTINCT " : "";
|
||||
public function sqlSelectToString($select, $distinct = false) {
|
||||
$clauses = array();
|
||||
|
||||
if($sqlQuery->delete) {
|
||||
$text = "DELETE ";
|
||||
} else {
|
||||
$text = "SELECT $distinct" . $sqlQuery->prepareSelect();
|
||||
foreach($select as $alias => $field) {
|
||||
// Don't include redundant aliases.
|
||||
if($alias === $field || preg_match('/"' . preg_quote($alias) . '"$/', $field)) $clauses[] = $field;
|
||||
else $clauses[] = "$field AS \"$alias\"";
|
||||
}
|
||||
|
||||
if($sqlQuery->from) $text .= " FROM " . implode(" ", $sqlQuery->from);
|
||||
if($sqlQuery->where) $text .= " WHERE (" . $sqlQuery->prepareWhere(). ")";
|
||||
if($sqlQuery->groupby) $text .= " GROUP BY " . $sqlQuery->prepareGroupBy();
|
||||
if($sqlQuery->having) $text .= " HAVING ( " .$sqlQuery->prepareHaving() . " )";
|
||||
if($sqlQuery->orderby) $text .= " ORDER BY " . $sqlQuery->prepareOrderBy();
|
||||
$text = 'SELECT ';
|
||||
if($distinct) $text .= 'DISTINCT ';
|
||||
return $text .= implode(', ', $clauses);
|
||||
}
|
||||
|
||||
if($sqlQuery->limit) {
|
||||
$limit = $sqlQuery->limit;
|
||||
// Pass limit as array or SQL string value
|
||||
if(is_array($limit)) {
|
||||
if(!array_key_exists('limit',$limit)) throw new InvalidArgumentException('SQLQuery::limit(): Wrong format for $limit: ' . var_export($limit, true));
|
||||
/**
|
||||
* Return the FROM clause ready for inserting into a query.
|
||||
* @return string
|
||||
*/
|
||||
public function sqlFromToString($from) {
|
||||
return ' FROM ' . implode(' ', $from);
|
||||
}
|
||||
|
||||
if(isset($limit['start']) && is_numeric($limit['start']) && isset($limit['limit']) && is_numeric($limit['limit'])) {
|
||||
$combinedLimit = $limit['start'] ? "$limit[limit] OFFSET $limit[start]" : "$limit[limit]";
|
||||
} elseif(isset($limit['limit']) && is_numeric($limit['limit'])) {
|
||||
$combinedLimit = (int)$limit['limit'];
|
||||
} else {
|
||||
$combinedLimit = false;
|
||||
}
|
||||
if(!empty($combinedLimit)) $text .= " LIMIT " . $combinedLimit;
|
||||
/**
|
||||
* Returns the WHERE clauses ready for inserting into a query.
|
||||
* @return string
|
||||
*/
|
||||
public function sqlWhereToString($where, $connective) {
|
||||
return ' WHERE (' . implode(") {$connective} (" , $where) . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ORDER BY clauses ready for inserting into a query.
|
||||
* @return string
|
||||
*/
|
||||
public function sqlOrderByToString($orderby) {
|
||||
$statements = array();
|
||||
|
||||
foreach($orderby as $clause => $dir) {
|
||||
$statements[] = trim($clause . ' ' . $dir);
|
||||
}
|
||||
|
||||
return ' ORDER BY ' . implode(', ', $statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the GROUP BY clauses ready for inserting into a query.
|
||||
* @return string
|
||||
*/
|
||||
public function sqlGroupByToString($groupby) {
|
||||
return ' GROUP BY ' . implode(', ', $groupby);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HAVING clauses ready for inserting into a query.
|
||||
* @return string
|
||||
*/
|
||||
public function sqlHavingToString($having) {
|
||||
return ' HAVING ( ' . implode(' ) AND ( ', $having);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the LIMIT clause ready for inserting into a query.
|
||||
* @return string
|
||||
*/
|
||||
public function sqlLimitToString($limit) {
|
||||
$clause = '';
|
||||
|
||||
// Pass limit as array or SQL string value
|
||||
if(is_array($limit)) {
|
||||
if(!array_key_exists('limit', $limit)) throw new InvalidArgumentException('Database::sqlLimitToString(): Wrong format for $limit: ' . var_export($limit, true));
|
||||
|
||||
if(isset($limit['start']) && is_numeric($limit['start']) && isset($limit['limit']) && is_numeric($limit['limit'])) {
|
||||
$combinedLimit = $limit['start'] ? "$limit[limit] OFFSET $limit[start]" : "$limit[limit]";
|
||||
} elseif(isset($limit['limit']) && is_numeric($limit['limit'])) {
|
||||
$combinedLimit = (int) $limit['limit'];
|
||||
} else {
|
||||
$text .= " LIMIT " . $sqlQuery->limit;
|
||||
$combinedLimit = false;
|
||||
}
|
||||
if(!empty($combinedLimit)) $clause .= ' LIMIT ' . $combinedLimit;
|
||||
} else {
|
||||
$clause .= ' LIMIT ' . $limit;
|
||||
}
|
||||
|
||||
return $clause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a SQLQuery object into a SQL statement
|
||||
* @param $query SQLQuery
|
||||
*/
|
||||
public function sqlQueryToString(SQLQuery $query) {
|
||||
if($query->getDelete()) {
|
||||
$text = 'DELETE ';
|
||||
} else {
|
||||
$text = $this->sqlSelectToString($query->getSelect(), $query->getDistinct());
|
||||
}
|
||||
|
||||
if($query->getFrom()) $text .= $this->sqlFromToString($query->getFrom());
|
||||
if($query->getWhere()) $text .= $this->sqlWhereToString($query->getWhere(), $query->getConnective());
|
||||
|
||||
// these clauses only make sense in SELECT queries, not DELETE
|
||||
if(!$query->getDelete()) {
|
||||
if($query->getGroupBy()) $text .= $this->sqlGroupByToString($query->getGroupBy());
|
||||
if($query->getHaving()) $text .= $this->sqlHavingToString($query->getHaving()) . ' )';
|
||||
if($query->getOrderBy()) $text .= $this->sqlOrderByToString($query->getOrderBy());
|
||||
if($query->getLimit()) $text .= $this->sqlLimitToString($query->getLimit());
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
|
@ -115,15 +115,15 @@ class ManyManyList extends RelationList {
|
||||
if(!is_numeric($itemID)) throw new InvalidArgumentException("ManyManyList::removeById() expecting an ID");
|
||||
|
||||
$query = new SQLQuery("*", array("\"$this->joinTable\""));
|
||||
$query->delete = true;
|
||||
$query->setDelete(true);
|
||||
|
||||
if($filter = $this->foreignIDFilter()) {
|
||||
$query->where($filter);
|
||||
$query->setWhere($filter);
|
||||
} else {
|
||||
user_error("Can't call ManyManyList::remove() until a foreign ID is set", E_USER_WARNING);
|
||||
}
|
||||
|
||||
$query->where("\"$this->localKey\" = {$itemID}");
|
||||
$query->addWhere("\"$this->localKey\" = {$itemID}");
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
@ -132,10 +132,9 @@ class ManyManyList extends RelationList {
|
||||
*/
|
||||
function removeAll() {
|
||||
$query = $this->dataQuery()->query();
|
||||
$query->delete = true;
|
||||
$query->select(array('*'));
|
||||
$query->from = array("\"$this->joinTable\"");
|
||||
$query->orderby = null;
|
||||
$query->setDelete(true);
|
||||
$query->setSelect(array('*'));
|
||||
$query->setFrom("\"$this->joinTable\"");
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
|
@ -855,9 +855,9 @@ class MySQLDatabase extends SS_Database {
|
||||
$query = $list->dataQuery()->query();
|
||||
|
||||
// There's no need to do all that joining
|
||||
$query->from = array(str_replace(array('"','`'),'',$baseClasses[$class]) => $baseClasses[$class]);
|
||||
$query->select($select[$class]);
|
||||
$query->orderby = null;
|
||||
$query->setFrom(array(str_replace(array('"','`'), '', $baseClasses[$class]) => $baseClasses[$class]));
|
||||
$query->setSelect($select[$class]);
|
||||
$query->setOrderBy(array());
|
||||
|
||||
$querySQLs[] = $query->sql();
|
||||
$totalCount += $query->unlimitedRowCount();
|
||||
|
@ -17,21 +17,21 @@ class SQLQuery {
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $select = array();
|
||||
protected $select = array();
|
||||
|
||||
/**
|
||||
* An array of join clauses. The first one is just the table name.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $from = array();
|
||||
protected $from = array();
|
||||
|
||||
/**
|
||||
* An array of filters.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $where = array();
|
||||
protected $where = array();
|
||||
|
||||
/**
|
||||
* An array of order by clauses, functions. Stores as an associative
|
||||
@ -39,54 +39,62 @@ class SQLQuery {
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $orderby = array();
|
||||
protected $orderby = array();
|
||||
|
||||
/**
|
||||
* An array of fields to group by.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $groupby = array();
|
||||
protected $groupby = array();
|
||||
|
||||
/**
|
||||
* An array of having clauses.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $having = array();
|
||||
protected $having = array();
|
||||
|
||||
/**
|
||||
* A limit clause.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $limit;
|
||||
protected $limit;
|
||||
|
||||
/**
|
||||
* If this is true DISTINCT will be added to the SQL.
|
||||
* @var boolean
|
||||
*/
|
||||
public $distinct = false;
|
||||
protected $distinct = false;
|
||||
|
||||
/**
|
||||
* If this is true, this statement will delete rather than select.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $delete = false;
|
||||
protected $delete = false;
|
||||
|
||||
/**
|
||||
* The logical connective used to join WHERE clauses. Defaults to AND.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $connective = 'AND';
|
||||
protected $connective = 'AND';
|
||||
|
||||
/**
|
||||
* Keep an internal register of find/replace pairs to execute when it's time to actually get the
|
||||
* query SQL.
|
||||
* @var array
|
||||
*/
|
||||
private $replacementsOld = array(), $replacementsNew = array();
|
||||
protected $replacementsOld = array();
|
||||
|
||||
/**
|
||||
* Keep an internal register of find/replace pairs to execute when it's time to actually get the
|
||||
* query SQL.
|
||||
* @var array
|
||||
*/
|
||||
protected $replacementsNew = array();
|
||||
|
||||
/**
|
||||
* Construct a new SQLQuery.
|
||||
@ -103,26 +111,46 @@ class SQLQuery {
|
||||
* by this stage.
|
||||
*/
|
||||
function __construct($select = "*", $from = array(), $where = "", $orderby = "", $groupby = "", $having = "", $limit = "") {
|
||||
$this->select($select);
|
||||
$this->setSelect($select);
|
||||
// @todo
|
||||
$this->from = is_array($from) ? $from : array(str_replace(array('"','`'),'',$from) => $from);
|
||||
$this->where($where);
|
||||
$this->orderby($orderby);
|
||||
$this->groupby($groupby);
|
||||
$this->having($having);
|
||||
$this->limit($limit);
|
||||
$this->setWhere($where);
|
||||
$this->setOrderBy($orderby);
|
||||
$this->setGroupBy($groupby);
|
||||
$this->setHaving($having);
|
||||
$this->setLimit($limit);
|
||||
}
|
||||
|
||||
function __get($field) {
|
||||
if(strtolower($field) == 'select') Deprecation::notice('3.0', 'Please use getSlect() instead');
|
||||
if(strtolower($field) == 'from') Deprecation::notice('3.0', 'Please use getFrom() instead');
|
||||
if(strtolower($field) == 'groupby') Deprecation::notice('3.0', 'Please use getGroupBy() instead');
|
||||
if(strtolower($field) == 'orderby') Deprecation::notice('3.0', 'Please use getOrderBy() instead');
|
||||
if(strtolower($field) == 'having') Deprecation::notice('3.0', 'Please use getHaving() instead');
|
||||
if(strtolower($field) == 'limit') Deprecation::notice('3.0', 'Please use getLimit() instead');
|
||||
if(strtolower($field) == 'delete') Deprecation::notice('3.0', 'Please use getDelete() instead');
|
||||
if(strtolower($field) == 'connective') Deprecation::notice('3.0', 'Please use getConnective() instead');
|
||||
if(strtolower($field) == 'distinct') Deprecation::notice('3.0', 'Please use getDistinct() instead');
|
||||
|
||||
return $this->$field;
|
||||
}
|
||||
|
||||
function __set($field, $value) {
|
||||
if(strtolower($field) == 'select') Deprecation::notice('3.0', 'Please use setSelect() or addSelect() instead');
|
||||
if(strtolower($field) == 'from') Deprecation::notice('3.0', 'Please use setFrom() or addFrom() instead');
|
||||
if(strtolower($field) == 'groupby') Deprecation::notice('3.0', 'Please use setGroupBy() or addGroupBy() instead');
|
||||
if(strtolower($field) == 'orderby') Deprecation::notice('3.0', 'Please use setOrderBy() or addOrderBy() instead');
|
||||
if(strtolower($field) == 'having') Deprecation::notice('3.0', 'Please use setHaving() or addHaving() instead');
|
||||
if(strtolower($field) == 'limit') Deprecation::notice('3.0', 'Please use setLimit() instead');
|
||||
if(strtolower($field) == 'delete') Deprecation::notice('3.0', 'Please use setDelete() instead');
|
||||
if(strtolower($field) == 'connective') Deprecation::notice('3.0', 'Please use setConnective() instead');
|
||||
if(strtolower($field) == 'distinct') Deprecation::notice('3.0', 'Please use setDistinct() instead');
|
||||
|
||||
return $this->$field = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the selected fields to start over
|
||||
*/
|
||||
function clearSelect() {
|
||||
$this->select = array();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the list of columns to be selected by the query.
|
||||
* Set the list of columns to be selected by the query.
|
||||
*
|
||||
* <code>
|
||||
* // pass fields to select as single parameter array
|
||||
@ -132,35 +160,42 @@ class SQLQuery {
|
||||
* $query->select("Col1", "Col2")->from("MyTable");
|
||||
* </code>
|
||||
*
|
||||
* @param mixed $fields
|
||||
* @param string|array $fields
|
||||
* @param boolean $clear Clear existing select fields?
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function select($fields) {
|
||||
public function setSelect($fields) {
|
||||
$this->select = array();
|
||||
if (func_num_args() > 1) {
|
||||
$fields = func_get_args();
|
||||
} else if(!is_array($fields)) {
|
||||
$fields = array($fields);
|
||||
}
|
||||
|
||||
$this->select = array();
|
||||
$this->selectMore($fields);
|
||||
|
||||
return $this;
|
||||
return $this->addSelect($fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add addition columns to the select clause
|
||||
* Add to the list of columns to be selected by the query.
|
||||
*
|
||||
* @param array|string
|
||||
* <code>
|
||||
* // pass fields to select as single parameter array
|
||||
* $query->select(array("Col1","Col2"))->from("MyTable");
|
||||
*
|
||||
* // pass fields to select as multiple parameters
|
||||
* $query->select("Col1", "Col2")->from("MyTable");
|
||||
* </code>
|
||||
*
|
||||
* @param string|array $fields
|
||||
* @param boolean $clear Clear existing select fields?
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function selectMore($fields) {
|
||||
public function addSelect($fields) {
|
||||
if (func_num_args() > 1) {
|
||||
$fields = func_get_args();
|
||||
} else if(!is_array($fields)) {
|
||||
$fields = array($fields);
|
||||
}
|
||||
|
||||
$this->select = array();
|
||||
foreach($fields as $idx => $field) {
|
||||
if(preg_match('/^(.*) +AS +"?([^"]*)"?/i', $field, $matches)) {
|
||||
Deprecation::notice("3.0", "Use selectField() to specify column aliases");
|
||||
@ -169,6 +204,13 @@ class SQLQuery {
|
||||
$this->selectField($field, is_numeric($idx) ? null : $idx);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function select($fields) {
|
||||
Deprecation::notice('3.0', 'Please use setSelect() or addSelect() instead!');
|
||||
$this->setSelect($fields);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -194,68 +236,107 @@ class SQLQuery {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the target table to select from.
|
||||
* Set table for the SELECT clause.
|
||||
*
|
||||
* <code>
|
||||
* $query->from("MyTable"); // SELECT * FROM MyTable
|
||||
* </code>
|
||||
*
|
||||
* @param string $table
|
||||
* @return SQLQuery This instance
|
||||
* @param string|array $from
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function from($table) {
|
||||
$this->from[str_replace(array('"','`'),'',$table)] = $table;
|
||||
public function setFrom($from) {
|
||||
$this->from = array();
|
||||
return $this->addFrom($from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a table to the SELECT clause.
|
||||
*
|
||||
* <code>
|
||||
* $query->from("MyTable"); // SELECT * FROM MyTable
|
||||
* </code>
|
||||
*
|
||||
* @param string|array $from
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function addFrom($from) {
|
||||
if(is_array($from)) {
|
||||
$this->from = array_merge($this->from, $from);
|
||||
} elseif(!empty($from)) {
|
||||
$this->from[str_replace(array('"','`'), '', $from)] = $from;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function from($from) {
|
||||
Deprecation::notice('3.0', 'Please use setFrom() or addFrom() instead!');
|
||||
return $this->setFrom($from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a LEFT JOIN criteria to the FROM clause.
|
||||
*
|
||||
* @param String $table Table name (unquoted)
|
||||
* @param String $onPredicate The "ON" SQL fragment in a "LEFT JOIN ... AS ... ON ..." statement.
|
||||
* @param string $table Table name (unquoted)
|
||||
* @param string $onPredicate The "ON" SQL fragment in a "LEFT JOIN ... AS ... ON ..." statement.
|
||||
* Needs to be valid (quoted) SQL.
|
||||
* @param String $tableAlias Optional alias which makes it easier to identify and replace joins later on
|
||||
* @return SQLQuery This instance
|
||||
* @param string $tableAlias Optional alias which makes it easier to identify and replace joins later on
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function leftJoin($table, $onPredicate, $tableAlias=null) {
|
||||
if( !$tableAlias ) {
|
||||
$tableAlias = $table;
|
||||
}
|
||||
public function addLeftJoin($table, $onPredicate, $tableAlias = null) {
|
||||
if(!$tableAlias) $tableAlias = $table;
|
||||
$this->from[$tableAlias] = array('type' => 'LEFT', 'table' => $table, 'filter' => array($onPredicate));
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function leftjoin($table, $onPredicate, $tableAlias = null) {
|
||||
Deprecation::notice('3.0', 'Please use addLeftJoin() instead!');
|
||||
$this->addLeftJoin($table, $onPredicate, $tableAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an INNER JOIN criteria to the FROM clause.
|
||||
*
|
||||
* @param String $table Table name (unquoted)
|
||||
* @param String $onPredicate The "ON" SQL fragment in a "LEFT JOIN ... AS ... ON ..." statement.
|
||||
* @param string $table Table name (unquoted)
|
||||
* @param string $onPredicate The "ON" SQL fragment in an "INNER JOIN ... AS ... ON ..." statement.
|
||||
* Needs to be valid (quoted) SQL.
|
||||
* @param String $tableAlias Optional alias which makes it easier to identify and replace joins later on
|
||||
* @return SQLQuery This instance
|
||||
* @param string $tableAlias Optional alias which makes it easier to identify and replace joins later on
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function innerJoin($table, $onPredicate, $tableAlias=null) {
|
||||
if( !$tableAlias ) {
|
||||
$tableAlias = $table;
|
||||
}
|
||||
public function addInnerJoin($table, $onPredicate, $tableAlias = null) {
|
||||
if(!$tableAlias) $tableAlias = $table;
|
||||
$this->from[$tableAlias] = array('type' => 'INNER', 'table' => $table, 'filter' => array($onPredicate));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an additional filter (part of the ON clause) on a join
|
||||
*/
|
||||
public function addFilterToJoin($tableAlias, $filter) {
|
||||
$this->from[$tableAlias]['filter'][] = $filter;
|
||||
public function innerjoin($table, $onPredicate, $tableAlias = null) {
|
||||
Deprecation::notice('3.0', 'Please use addInnerJoin() instead!');
|
||||
return $this->addInnerJoin($table, $onPredicate, $tableAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the existing filter (ON clause) on a join
|
||||
* Add an additional filter (part of the ON clause) on a join.
|
||||
*
|
||||
* @param string $table Table to join on from the original join
|
||||
* @param string $filter The "ON" SQL fragment
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function setJoinFilter($tableAlias, $filter) {
|
||||
if(is_string($this->from[$tableAlias])) {Debug::message($tableAlias); Debug::dump($this->from);}
|
||||
$this->from[$tableAlias]['filter'] = array($filter);
|
||||
public function addFilterToJoin($table, $filter) {
|
||||
$this->from[$table]['filter'][] = $filter;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter (part of the ON clause) on a join.
|
||||
*
|
||||
* @param string $table Table to join on from the original join
|
||||
* @param string $filter The "ON" SQL fragment
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function setJoinFilter($table, $filter) {
|
||||
$this->from[$table]['filter'] = array($filter);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -285,6 +366,62 @@ class SQLQuery {
|
||||
return $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set distinct property.
|
||||
* @param boolean $value
|
||||
*/
|
||||
public function setDistinct($value) {
|
||||
$this->distinct = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distinct property.
|
||||
* @return boolean
|
||||
*/
|
||||
public function getDistinct() {
|
||||
return $this->distinct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the delete property.
|
||||
* @param boolean $value
|
||||
*/
|
||||
public function setDelete($value) {
|
||||
$this->delete = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the delete property.
|
||||
* @return boolean
|
||||
*/
|
||||
public function getDelete() {
|
||||
return $this->delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connective property.
|
||||
* @param boolean $value
|
||||
*/
|
||||
public function setConnective($value) {
|
||||
$this->connective = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the connective property.
|
||||
* @return string
|
||||
*/
|
||||
public function getConnective() {
|
||||
return $this->connective;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get limit clause
|
||||
* @return string
|
||||
*/
|
||||
public function getLimit() {
|
||||
return $this->limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass LIMIT clause either as SQL snippet or in array format.
|
||||
* Internally, limit will always be stored as a map containing the keys 'start' and 'limit'
|
||||
@ -292,7 +429,7 @@ class SQLQuery {
|
||||
* @param string|array $limit
|
||||
* @return SQLQuery This instance
|
||||
*/
|
||||
public function limit($limit, $offset = 0) {
|
||||
public function setLimit($limit, $offset = 0) {
|
||||
if($limit && is_numeric($limit)) {
|
||||
$this->limit = array(
|
||||
'start' => $offset,
|
||||
@ -313,8 +450,13 @@ class SQLQuery {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function limit($limit, $offset = 0) {
|
||||
Deprecation::notice('3.0', 'Please use setLimit() instead!');
|
||||
return $this->setLimit($limit, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass ORDER BY clause either as SQL snippet or in array format.
|
||||
* Set ORDER BY clause either as SQL snippet or in array format.
|
||||
*
|
||||
* @example $sql->orderby("Column");
|
||||
* @example $sql->orderby("Column DESC");
|
||||
@ -322,15 +464,31 @@ class SQLQuery {
|
||||
* @example $sql->orderby("Column", "DESC");
|
||||
* @example $sql->orderby(array("Column" => "ASC", "ColumnTwo" => "DESC"));
|
||||
*
|
||||
* @param string|array $orderby
|
||||
* @param string $dir
|
||||
* @param bool $clear remove existing order by clauses
|
||||
* @param string|array $orderby Clauses to add
|
||||
* @param string $dir Sort direction, ASC or DESC
|
||||
*
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function orderby($clauses = null, $direction = null, $clear = true) {
|
||||
if($clear) $this->orderby = array();
|
||||
public function setOrderBy($clauses = null, $direction = null) {
|
||||
$this->orderby = array();
|
||||
return $this->addOrderBy($clauses, $direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ORDER BY clause either as SQL snippet or in array format.
|
||||
*
|
||||
* @example $sql->orderby("Column");
|
||||
* @example $sql->orderby("Column DESC");
|
||||
* @example $sql->orderby("Column DESC, ColumnTwo ASC");
|
||||
* @example $sql->orderby("Column", "DESC");
|
||||
* @example $sql->orderby(array("Column" => "ASC", "ColumnTwo" => "DESC"));
|
||||
*
|
||||
* @param string|array $orderby Clauses to add
|
||||
* @param string $dir Sort direction, ASC or DESC
|
||||
*
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function addOrderBy($clauses = null, $direction = null) {
|
||||
if(!$clauses) {
|
||||
return $this;
|
||||
}
|
||||
@ -338,8 +496,7 @@ class SQLQuery {
|
||||
if(is_string($clauses)) {
|
||||
if(strpos($clauses, "(") !== false) {
|
||||
$sort = preg_split("/,(?![^()]*+\\))/", $clauses);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$sort = explode(",", $clauses);
|
||||
}
|
||||
|
||||
@ -356,15 +513,13 @@ class SQLQuery {
|
||||
if(!is_numeric($key)) {
|
||||
$column = trim($key);
|
||||
$columnDir = strtoupper(trim($value));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
list($column, $columnDir) = $this->getDirectionFromString($value);
|
||||
}
|
||||
|
||||
$this->orderby[$column] = $columnDir;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
user_error('SQLQuery::orderby() incorrect format for $orderby', E_USER_WARNING);
|
||||
}
|
||||
|
||||
@ -385,7 +540,7 @@ class SQLQuery {
|
||||
$column = "_SortColumn{$i}";
|
||||
|
||||
$this->selectField($clause, $column);
|
||||
$this->orderby('"' . $column . '"', $dir, false);
|
||||
$this->addOrderBy('"' . $column . '"', $dir);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
@ -394,6 +549,11 @@ class SQLQuery {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function orderby($clauses = null, $direction = null) {
|
||||
Deprecation::notice('3.0', 'Please use setOrderBy() instead!');
|
||||
return $this->setOrderBy($clauses, $direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the direction part of a single-column order by clause.
|
||||
*
|
||||
@ -415,26 +575,24 @@ class SQLQuery {
|
||||
* statements which are stored as strings. Without clauses and directions,
|
||||
* convert the orderby clause to something readable.
|
||||
*
|
||||
* @todo When $orderby is a private variable and all orderby statements
|
||||
* set through
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOrderBy() {
|
||||
$orderby = $this->orderby;
|
||||
if(!$orderby) $orderby = array();
|
||||
|
||||
if(!is_array($orderby)) {
|
||||
// spilt by any commas not within brackets
|
||||
$orderby = preg_split("/,(?![^()]*+\\))/", $orderby);
|
||||
$orderby = preg_split('/,(?![^()]*+\\))/', $orderby);
|
||||
}
|
||||
|
||||
foreach($orderby as $k => $v) {
|
||||
if(strpos($v, " ") !== false) {
|
||||
if(strpos($v, ' ') !== false) {
|
||||
unset($orderby[$k]);
|
||||
|
||||
$rule = explode(" ", trim($v));
|
||||
$rule = explode(' ', trim($v));
|
||||
$clause = $rule[0];
|
||||
$dir = (isset($rule[1])) ? $rule[1] : "ASC";
|
||||
$dir = (isset($rule[1])) ? $rule[1] : 'ASC';
|
||||
|
||||
$orderby[$clause] = $dir;
|
||||
}
|
||||
@ -451,25 +609,34 @@ class SQLQuery {
|
||||
*/
|
||||
public function reverseOrderBy() {
|
||||
$order = $this->getOrderBy();
|
||||
|
||||
$this->orderby = array();
|
||||
|
||||
foreach($order as $clause => $dir) {
|
||||
$dir = (strtoupper($dir) == "DESC") ? "ASC" : "DESC";
|
||||
|
||||
$this->orderby($clause, $dir, false);
|
||||
$dir = (strtoupper($dir) == 'DESC') ? 'ASC' : 'DESC';
|
||||
$this->addOrderBy($clause, $dir);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a GROUP BY clause.
|
||||
*
|
||||
* @param string|array $groupby
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function setGroupBy($groupby) {
|
||||
$this->groupby = array();
|
||||
return $this->addGroupBy($groupby);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a GROUP BY clause.
|
||||
*
|
||||
* @param string|array $groupby
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function groupby($groupby) {
|
||||
public function addGroupBy($groupby) {
|
||||
if(is_array($groupby)) {
|
||||
$this->groupby = array_merge($this->groupby, $groupby);
|
||||
} elseif(!empty($groupby)) {
|
||||
@ -479,13 +646,29 @@ class SQLQuery {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function groupby($where) {
|
||||
Deprecation::notice('3.0', 'Please use setGroupBy() or addHaving() instead!');
|
||||
return $this->setGroupBy($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a HAVING clause.
|
||||
* Set a HAVING clause.
|
||||
*
|
||||
* @param string|array $having
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function having($having) {
|
||||
public function setHaving($having) {
|
||||
$this->having = array();
|
||||
return $this->addHaving($having);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a HAVING clause
|
||||
*
|
||||
* @param string|array $having
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function addHaving($having) {
|
||||
if(is_array($having)) {
|
||||
$this->having = array_merge($this->having, $having);
|
||||
} elseif(!empty($having)) {
|
||||
@ -495,50 +678,76 @@ class SQLQuery {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function having($having) {
|
||||
Deprecation::notice('3.0', 'Please use setHaving() or addHaving() instead!');
|
||||
return $this->setHaving($having);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a predicate filter to the where clause.
|
||||
* Set a WHERE clause.
|
||||
*
|
||||
* Accepts a variable length of arguments, which represent
|
||||
* different ways of formatting a predicate in a where clause:
|
||||
* There are two different ways of doing this:
|
||||
*
|
||||
* <code>
|
||||
* // the entire predicate as a single string
|
||||
* $query->where("Column = 'Value'");
|
||||
*
|
||||
* // an exact match predicate with a key value pair
|
||||
* $query->where("Column", "Value");
|
||||
*
|
||||
* // a predicate with user defined operator
|
||||
* $query->where("Column", "!=", "Value");
|
||||
* // multiple predicates as an array
|
||||
* $query->where(array("Column = 'Value'", "Column != 'Value'"));
|
||||
* </code>
|
||||
*
|
||||
* @param string|array $where Predicate(s) to set
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function where() {
|
||||
public function setWhere($where) {
|
||||
$this->where = array();
|
||||
|
||||
$args = func_get_args();
|
||||
if (func_num_args() == 3) {
|
||||
$filter = "{$args[0]} {$args[1]} '{$args[2]}'";
|
||||
} elseif (func_num_args() == 2) {
|
||||
$filter = "{$args[0]} = '{$args[1]}'";
|
||||
} else {
|
||||
$filter = $args[0];
|
||||
if(isset($args[1])) {
|
||||
Deprecation::notice('3.0', 'Multiple arguments to where is deprecated. Pleas use where("Column = Something") syntax instead');
|
||||
}
|
||||
|
||||
if(is_array($filter)) {
|
||||
$this->where = array_merge($this->where,$filter);
|
||||
} elseif(!empty($filter)) {
|
||||
$this->where[] = $filter;
|
||||
return $this->addWhere($where);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a WHERE predicate.
|
||||
*
|
||||
* There are two different ways of doing this:
|
||||
*
|
||||
* <code>
|
||||
* // the entire predicate as a single string
|
||||
* $query->where("Column = 'Value'");
|
||||
*
|
||||
* // multiple predicates as an array
|
||||
* $query->where(array("Column = 'Value'", "Column != 'Value'"));
|
||||
* </code>
|
||||
*
|
||||
* @param string|array $where Predicate(s) to set
|
||||
* @return SQLQuery
|
||||
*/
|
||||
public function addWhere($where) {
|
||||
if(is_array($where)) {
|
||||
$this->where = array_merge($this->where, $where);
|
||||
} elseif(!empty($where)) {
|
||||
$this->where[] = $where;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function where($where) {
|
||||
Deprecation::notice('3.0', 'Please use setWhere() or addWhere() instead!');
|
||||
return $this->setWhere($where);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function whereAny($filters) {
|
||||
if(is_string($filters)) $filters = func_get_args();
|
||||
$clause = implode(" OR ", $filters);
|
||||
return $this->where($clause);
|
||||
return $this->setWhere($clause);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -580,70 +789,47 @@ class SQLQuery {
|
||||
return $this->prepareWhere();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of FROM clauses used internally.
|
||||
* @return array
|
||||
*/
|
||||
public function getFrom() {
|
||||
return $this->from;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of HAVING clauses used internally.
|
||||
* @return array
|
||||
*/
|
||||
public function getHaving() {
|
||||
return $this->having;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of GROUP BY clauses used internally.
|
||||
* @return array
|
||||
*/
|
||||
public function getGroupBy() {
|
||||
return $this->groupby;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of WHERE clauses used internally.
|
||||
* @return array
|
||||
*/
|
||||
public function getWhere() {
|
||||
return $this->where;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an itemised select list as a map, where keys are the aliases, and values are the column sources.
|
||||
* Aliases will always be provided (if the alias is implicit, the alias value will be inferred), and won't be quoted.
|
||||
* E.g., 'Title' => '"SiteTree"."Title"'.
|
||||
*/
|
||||
public function itemisedSelect() {
|
||||
public function getSelect() {
|
||||
return $this->select;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the WHERE clauses ready for inserting into a query.
|
||||
* @return string
|
||||
*/
|
||||
public function prepareSelect() {
|
||||
$clauses = array();
|
||||
foreach($this->select as $alias => $field) {
|
||||
// Don't include redundant aliases.
|
||||
if($alias === $field || preg_match('/"' . preg_quote($alias) . '"$/', $field)) $clauses[] = $field;
|
||||
else $clauses[] = "$field AS \"$alias\"";
|
||||
}
|
||||
return implode(", ", $clauses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the WHERE clauses ready for inserting into a query.
|
||||
* @return string
|
||||
*/
|
||||
public function prepareWhere() {
|
||||
return ($this->where) ? implode(") {$this->connective} (" , $this->where) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ORDER BY clauses ready for inserting into a query.
|
||||
* @return string
|
||||
*/
|
||||
public function prepareOrderBy() {
|
||||
$statments = array();
|
||||
|
||||
if($order = $this->getOrderBy()) {
|
||||
foreach($order as $clause => $dir) {
|
||||
$statements[] = trim($clause . ' '. $dir);
|
||||
}
|
||||
}
|
||||
|
||||
return implode(", ", $statements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the GROUP BY clauses ready for inserting into a query.
|
||||
* @return string
|
||||
*/
|
||||
public function prepareGroupBy() {
|
||||
return implode(", ", $this->groupby);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HAVING clauses ready for inserting into a query.
|
||||
* @return string
|
||||
*/
|
||||
public function prepareHaving() {
|
||||
return implode(" ) AND ( ", $sqlQuery->having);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for this query.
|
||||
*
|
||||
@ -842,7 +1028,7 @@ class SQLQuery {
|
||||
function firstRow() {
|
||||
$query = clone $this;
|
||||
$offset = $this->limit ? $this->limit['start'] : 0;
|
||||
$query->limit(1, $offset);
|
||||
$query->setLimit(1, $offset);
|
||||
return $query;
|
||||
}
|
||||
|
||||
@ -852,7 +1038,7 @@ class SQLQuery {
|
||||
function lastRow() {
|
||||
$query = clone $this;
|
||||
$offset = $this->limit ? $this->limit['start'] : 0;
|
||||
$query->limit(1, $this->count() + $offset - 1);
|
||||
$query->setLimit(1, $this->count() + $offset - 1);
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ class Versioned extends DataExtension {
|
||||
// Reading a specific data from the archive
|
||||
case 'archive':
|
||||
$date = $dataQuery->getQueryParam('Versioned.date');
|
||||
foreach($query->from as $table => $dummy) {
|
||||
foreach($query->getFrom() as $table => $dummy) {
|
||||
$query->renameTable($table, $table . '_versions');
|
||||
$query->replaceText("\"$table\".\"ID\"", "\"$table\".\"RecordID\"");
|
||||
|
||||
@ -154,7 +154,7 @@ class Versioned extends DataExtension {
|
||||
$query->selectField(sprintf('"%s_versions"."%s"', $baseTable, 'RecordID'), "ID");
|
||||
|
||||
if($table != $baseTable) {
|
||||
$query->from[$table] .= " AND \"{$table}_versions\".\"Version\" = \"{$baseTable}_versions\".\"Version\"";
|
||||
$query->from(array($table => " AND \"{$table}_versions\".\"Version\" = \"{$baseTable}_versions\".\"Version\""));
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,7 +169,7 @@ class Versioned extends DataExtension {
|
||||
case 'stage':
|
||||
$stage = $dataQuery->getQueryParam('Versioned.stage');
|
||||
if($stage && ($stage != $this->defaultStage)) {
|
||||
foreach($query->from as $table => $dummy) {
|
||||
foreach($query->getFrom() as $table => $dummy) {
|
||||
// Only rewrite table names that are actually part of the subclass tree
|
||||
// This helps prevent rewriting of other tables that get joined in, in
|
||||
// particular, many_many tables
|
||||
@ -186,7 +186,7 @@ class Versioned extends DataExtension {
|
||||
// Return all version instances
|
||||
case 'all_versions':
|
||||
case 'latest_versions':
|
||||
foreach($query->from as $alias => $join) {
|
||||
foreach($query->getFrom() as $alias => $join) {
|
||||
if($alias != $baseTable) {
|
||||
$query->setJoinFilter($alias, "\"$alias\".\"RecordID\" = \"{$baseTable}_versions\".\"RecordID\" AND \"$alias\".\"Version\" = \"{$baseTable}_versions\".\"Version\"");
|
||||
}
|
||||
@ -204,7 +204,7 @@ class Versioned extends DataExtension {
|
||||
// This provides "show all, including deleted" functonality
|
||||
if($dataQuery->getQueryParam('Versioned.mode') == 'latest_versions') {
|
||||
$archiveTable = self::requireArchiveTempTable($baseTable);
|
||||
$query->innerJoin($archiveTable, "\"$archiveTable\".\"ID\" = \"{$baseTable}_versions\".\"RecordID\" AND \"$archiveTable\".\"Version\" = \"{$baseTable}_versions\".\"Version\"");
|
||||
$query->addInnerJoin($archiveTable, "\"$archiveTable\".\"ID\" = \"{$baseTable}_versions\".\"RecordID\" AND \"$archiveTable\".\"Version\" = \"{$baseTable}_versions\".\"Version\"");
|
||||
}
|
||||
|
||||
break;
|
||||
@ -711,11 +711,11 @@ class Versioned extends DataExtension {
|
||||
|
||||
$query = $list->dataQuery()->query();
|
||||
|
||||
foreach($query->from as $table => $tableJoin) {
|
||||
foreach($query->getFrom() as $table => $tableJoin) {
|
||||
if(is_string($tableJoin) && $tableJoin[0] == '"') {
|
||||
$baseTable = str_replace('"','',$tableJoin);
|
||||
} elseif(is_string($tableJoin) && substr($tableJoin,0,5) != 'INNER') {
|
||||
$query->from[$table] = "LEFT JOIN \"$table\" ON \"$table\".\"RecordID\" = \"{$baseTable}_versions\".\"RecordID\" AND \"$table\".\"Version\" = \"{$baseTable}_versions\".\"Version\"";
|
||||
$query->setFrom(array($table => "LEFT JOIN \"$table\" ON \"$table\".\"RecordID\" = \"{$baseTable}_versions\".\"RecordID\" AND \"$table\".\"Version\" = \"{$baseTable}_versions\".\"Version\""));
|
||||
}
|
||||
$query->renameTable($table, $table . '_versions');
|
||||
}
|
||||
@ -725,8 +725,8 @@ class Versioned extends DataExtension {
|
||||
$query->selectField(sprintf('"%s_versions"."%s"', $baseTable, $name), $name);
|
||||
}
|
||||
|
||||
$query->where[] = "\"{$baseTable}_versions\".\"RecordID\" = '{$this->owner->ID}'";
|
||||
$query->orderby = ($sort) ? $sort : "\"{$baseTable}_versions\".\"LastEdited\" DESC, \"{$baseTable}_versions\".\"Version\" DESC";
|
||||
$query->addWhere("\"{$baseTable}_versions\".\"RecordID\" = '{$this->owner->ID}'");
|
||||
$query->setOrderBy(($sort) ? $sort : "\"{$baseTable}_versions\".\"LastEdited\" DESC, \"{$baseTable}_versions\".\"Version\" DESC");
|
||||
|
||||
$records = $query->execute();
|
||||
$versions = new ArrayList();
|
||||
|
@ -91,9 +91,9 @@ class DbDatetimeTest extends FunctionalTest {
|
||||
$this->matchesRoughly($result, date('Y-m-d H:i:s', strtotime('+1 Day', $this->getDbNow())), 'tomorrow');
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->select(array("test" => $this->adapter->datetimeIntervalClause('"Created"', '-15 Minutes')))
|
||||
->from('"DbDateTimeTest_Team"')
|
||||
->limit(1);
|
||||
$query->setSelect(array("test" => $this->adapter->datetimeIntervalClause('"Created"', '-15 Minutes')))
|
||||
->setFrom('"DbDateTimeTest_Team"')
|
||||
->setLimit(1);
|
||||
$result = $query->execute()->value();
|
||||
$this->matchesRoughly($result, date('Y-m-d H:i:s', strtotime(Dataobject::get_one('DbDateTimeTest_Team')->Created) - 900), '15 Minutes before creating fixture');
|
||||
|
||||
@ -116,9 +116,9 @@ class DbDatetimeTest extends FunctionalTest {
|
||||
$this->matchesRoughly($result, -45 * 60, 'now - 45 minutes ahead');
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->select(array("test" => $this->adapter->datetimeDifferenceClause('"LastEdited"', '"Created"')))
|
||||
->from('"DbDateTimeTest_Team"')
|
||||
->limit(1);
|
||||
$query->setSelect(array("test" => $this->adapter->datetimeDifferenceClause('"LastEdited"', '"Created"')))
|
||||
->setFrom('"DbDateTimeTest_Team"')
|
||||
->setLimit(1);
|
||||
|
||||
$result = $query->execute()->value();
|
||||
$lastedited = Dataobject::get_one('DbDateTimeTest_Team')->LastEdited;
|
||||
|
@ -34,10 +34,12 @@ class PaginatedListTest extends SapphireTest {
|
||||
|
||||
public function testSetPaginationFromQuery() {
|
||||
$query = $this->getMock('SQLQuery');
|
||||
$query->limit = array('limit' => 15, 'start' => 30);
|
||||
$query->expects($this->once())
|
||||
->method('getLimit')
|
||||
->will($this->returnValue(array('limit' => 15, 'start' => 30)));
|
||||
$query->expects($this->once())
|
||||
->method('unlimitedRowCount')
|
||||
->will($this->returnValue(100));
|
||||
->will($this->returnValue(100));
|
||||
|
||||
$list = new PaginatedList(new ArrayList());
|
||||
$list->setPaginationFromQuery($query);
|
||||
|
@ -15,25 +15,25 @@ class SQLQueryTest extends SapphireTest {
|
||||
|
||||
function testSelectFromBasicTable() {
|
||||
$query = new SQLQuery();
|
||||
$query->from[] = "MyTable";
|
||||
$query->setFrom('MyTable');
|
||||
$this->assertEquals("SELECT * FROM MyTable", $query->sql());
|
||||
$query->from[] = "MyJoin";
|
||||
$query->addFrom('MyJoin');
|
||||
$this->assertEquals("SELECT * FROM MyTable MyJoin", $query->sql());
|
||||
}
|
||||
|
||||
function testSelectFromUserSpecifiedFields() {
|
||||
$query = new SQLQuery();
|
||||
$query->select(array("Name", "Title", "Description"));
|
||||
$query->from[] = "MyTable";
|
||||
$query->setSelect(array("Name", "Title", "Description"));
|
||||
$query->setFrom("MyTable");
|
||||
$this->assertEquals("SELECT Name, Title, Description FROM MyTable", $query->sql());
|
||||
}
|
||||
|
||||
function testSelectWithWhereClauseFilter() {
|
||||
$query = new SQLQuery();
|
||||
$query->select(array("Name","Meta"));
|
||||
$query->from[] = "MyTable";
|
||||
$query->where[] = "Name = 'Name'";
|
||||
$query->where[] = "Meta = 'Test'";
|
||||
$query->setSelect(array("Name","Meta"));
|
||||
$query->setFrom("MyTable");
|
||||
$query->setWhere("Name = 'Name'");
|
||||
$query->addWhere("Meta = 'Test'");
|
||||
$this->assertEquals("SELECT Name, Meta FROM MyTable WHERE (Name = 'Name') AND (Meta = 'Test')", $query->sql());
|
||||
}
|
||||
|
||||
@ -46,132 +46,115 @@ class SQLQueryTest extends SapphireTest {
|
||||
|
||||
function testSelectWithChainedMethods() {
|
||||
$query = new SQLQuery();
|
||||
$query->select("Name","Meta")->from("MyTable")->where("Name", "Name")->where("Meta", "Test");
|
||||
$query->setSelect("Name","Meta")->setFrom("MyTable")->setWhere("Name = 'Name'")->addWhere("Meta = 'Test'");
|
||||
$this->assertEquals("SELECT Name, Meta FROM MyTable WHERE (Name = 'Name') AND (Meta = 'Test')", $query->sql());
|
||||
}
|
||||
|
||||
function testCanSortBy() {
|
||||
$query = new SQLQuery();
|
||||
$query->select("Name","Meta")->from("MyTable")->where("Name", "Name")->where("Meta", "Test");
|
||||
$query->setSelect("Name","Meta")->setFrom("MyTable")->setWhere("Name = 'Name'")->addWhere("Meta = 'Test'");
|
||||
$this->assertTrue($query->canSortBy('Name ASC'));
|
||||
$this->assertTrue($query->canSortBy('Name'));
|
||||
}
|
||||
|
||||
function testSelectWithChainedFilterParameters() {
|
||||
$query = new SQLQuery();
|
||||
$query->select(array("Name","Meta"))->from("MyTable");
|
||||
$query->where("Name = 'Name'")->where("Meta","Test")->where("Beta", "!=", "Gamma");
|
||||
$query->setSelect(array("Name","Meta"))->setFrom("MyTable");
|
||||
$query->setWhere("Name = 'Name'")->addWhere("Meta = 'Test'")->addWhere("Beta != 'Gamma'");
|
||||
$this->assertEquals("SELECT Name, Meta FROM MyTable WHERE (Name = 'Name') AND (Meta = 'Test') AND (Beta != 'Gamma')", $query->sql());
|
||||
}
|
||||
|
||||
function testSelectWithPredicateFilters() {
|
||||
/* this is no longer part of this
|
||||
$query = new SQLQuery();
|
||||
$query->select(array("Name"))->from("SQLQueryTest_DO");
|
||||
|
||||
$match = new ExactMatchFilter("Name", "Value");
|
||||
$match->setModel('SQLQueryTest_DO');
|
||||
$match->apply($query);
|
||||
|
||||
$match = new PartialMatchFilter("Meta", "Value");
|
||||
$match->setModel('SQLQueryTest_DO');
|
||||
$match->apply($query);
|
||||
|
||||
$this->assertEquals("SELECT Name FROM SQLQueryTest_DO WHERE (\"SQLQueryTest_DO\".\"Name\" = 'Value') AND (\"SQLQueryTest_DO\".\"Meta\" LIKE '%Value%')", $query->sql());
|
||||
*/
|
||||
}
|
||||
|
||||
function testSelectWithLimitClause() {
|
||||
// These are MySQL specific :-S
|
||||
if(DB::getConn() instanceof MySQLDatabase) {
|
||||
// numeric limit
|
||||
$query = new SQLQuery();
|
||||
$query->from[] = "MyTable";
|
||||
$query->limit(99);
|
||||
$this->assertEquals("SELECT * FROM MyTable LIMIT 99", $query->sql());
|
||||
|
||||
// array limit with start (MySQL specific)
|
||||
$query = new SQLQuery();
|
||||
$query->from[] = "MyTable";
|
||||
$query->limit(99, 97);
|
||||
$this->assertEquals("SELECT * FROM MyTable LIMIT 99 OFFSET 97", $query->sql());
|
||||
if(!(DB::getConn() instanceof MySQLDatabase || DB::getConn() instanceof SQLite3Database || DB::getConn() instanceof PostgreSQLDatabase)) {
|
||||
$this->markTestIncomplete();
|
||||
}
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->setFrom("MyTable");
|
||||
$query->setLimit(99);
|
||||
$this->assertEquals("SELECT * FROM MyTable LIMIT 99", $query->sql());
|
||||
|
||||
// array limit with start (MySQL specific)
|
||||
$query = new SQLQuery();
|
||||
$query->setFrom("MyTable");
|
||||
$query->setLimit(99, 97);
|
||||
$this->assertEquals("SELECT * FROM MyTable LIMIT 99 OFFSET 97", $query->sql());
|
||||
}
|
||||
|
||||
function testSelectWithOrderbyClause() {
|
||||
$query = new SQLQuery();
|
||||
$query->from[] = "MyTable";
|
||||
$query->orderby('MyName');
|
||||
$query->setFrom("MyTable");
|
||||
$query->setOrderBy('MyName');
|
||||
$this->assertEquals('SELECT * FROM MyTable ORDER BY MyName ASC', $query->sql());
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->from[] = "MyTable";
|
||||
$query->orderby('MyName desc');
|
||||
$query->setFrom("MyTable");
|
||||
$query->setOrderBy('MyName desc');
|
||||
$this->assertEquals('SELECT * FROM MyTable ORDER BY MyName DESC', $query->sql());
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->from[] = "MyTable";
|
||||
$query->orderby('MyName ASC, Color DESC');
|
||||
$query->setFrom("MyTable");
|
||||
$query->setOrderBy('MyName ASC, Color DESC');
|
||||
$this->assertEquals('SELECT * FROM MyTable ORDER BY MyName ASC, Color DESC', $query->sql());
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->from[] = "MyTable";
|
||||
$query->orderby('MyName ASC, Color');
|
||||
$query->setFrom("MyTable");
|
||||
$query->setOrderBy('MyName ASC, Color');
|
||||
$this->assertEquals('SELECT * FROM MyTable ORDER BY MyName ASC, Color ASC', $query->sql());
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->from[] = "MyTable";
|
||||
$query->orderby(array('MyName' => 'desc'));
|
||||
$query->setFrom("MyTable");
|
||||
$query->setOrderBy(array('MyName' => 'desc'));
|
||||
$this->assertEquals('SELECT * FROM MyTable ORDER BY MyName DESC', $query->sql());
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->from[] = "MyTable";
|
||||
$query->orderby(array('MyName' => 'desc', 'Color'));
|
||||
$query->setFrom("MyTable");
|
||||
$query->setOrderBy(array('MyName' => 'desc', 'Color'));
|
||||
$this->assertEquals('SELECT * FROM MyTable ORDER BY MyName DESC, Color ASC', $query->sql());
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->from[] = "MyTable";
|
||||
$query->orderby('implode("MyName","Color")');
|
||||
$query->setFrom("MyTable");
|
||||
$query->setOrderBy('implode("MyName","Color")');
|
||||
$this->assertEquals('SELECT *, implode("MyName","Color") AS "_SortColumn0" FROM MyTable ORDER BY "_SortColumn0" ASC', $query->sql());
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->from[] = "MyTable";
|
||||
$query->orderby('implode("MyName","Color") DESC');
|
||||
$query->setFrom("MyTable");
|
||||
$query->setOrderBy('implode("MyName","Color") DESC');
|
||||
$this->assertEquals('SELECT *, implode("MyName","Color") AS "_SortColumn0" FROM MyTable ORDER BY "_SortColumn0" DESC', $query->sql());
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->from[] = "MyTable";
|
||||
$query->orderby('RAND()');
|
||||
$query->setFrom("MyTable");
|
||||
$query->setOrderBy('RAND()');
|
||||
|
||||
$this->assertEquals('SELECT *, RAND() AS "_SortColumn0" FROM MyTable ORDER BY "_SortColumn0" ASC', $query->sql());
|
||||
}
|
||||
|
||||
public function testReverseOrderBy() {
|
||||
$query = new SQLQuery();
|
||||
$query->from('MyTable');
|
||||
$query->setFrom('MyTable');
|
||||
|
||||
// default is ASC
|
||||
$query->orderby("Name");
|
||||
$query->setOrderBy("Name");
|
||||
$query->reverseOrderBy();
|
||||
|
||||
$this->assertEquals('SELECT * FROM MyTable ORDER BY Name DESC',$query->sql());
|
||||
|
||||
$query->orderby("Name DESC");
|
||||
$query->setOrderBy("Name DESC");
|
||||
$query->reverseOrderBy();
|
||||
|
||||
$this->assertEquals('SELECT * FROM MyTable ORDER BY Name ASC',$query->sql());
|
||||
|
||||
$query->orderby(array("Name" => "ASC"));
|
||||
$query->setOrderBy(array("Name" => "ASC"));
|
||||
$query->reverseOrderBy();
|
||||
|
||||
$this->assertEquals('SELECT * FROM MyTable ORDER BY Name DESC',$query->sql());
|
||||
|
||||
$query->orderby(array("Name" => 'DESC', 'Color' => 'asc'));
|
||||
$query->setOrderBy(array("Name" => 'DESC', 'Color' => 'asc'));
|
||||
$query->reverseOrderBy();
|
||||
|
||||
$this->assertEquals('SELECT * FROM MyTable ORDER BY Name ASC, Color DESC',$query->sql());
|
||||
|
||||
$query->orderby('implode("MyName","Color") DESC');
|
||||
$query->setOrderBy('implode("MyName","Color") DESC');
|
||||
$query->reverseOrderBy();
|
||||
|
||||
$this->assertEquals('SELECT *, implode("MyName","Color") AS "_SortColumn0" FROM MyTable ORDER BY "_SortColumn0" ASC',$query->sql());
|
||||
@ -179,50 +162,42 @@ class SQLQueryTest extends SapphireTest {
|
||||
|
||||
function testFiltersOnID() {
|
||||
$query = new SQLQuery();
|
||||
$query->where[] = "ID = 5";
|
||||
$query->setWhere("ID = 5");
|
||||
$this->assertTrue(
|
||||
$query->filtersOnID(),
|
||||
"filtersOnID() is true with simple unquoted column name"
|
||||
);
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->where[] = "ID=5";
|
||||
$query->setWhere("ID=5");
|
||||
$this->assertTrue(
|
||||
$query->filtersOnID(),
|
||||
"filtersOnID() is true with simple unquoted column name and no spaces in equals sign"
|
||||
);
|
||||
/*
|
||||
$query = new SQLQuery();
|
||||
$query->where[] = "Foo='Bar' AND ID=5";
|
||||
$this->assertTrue(
|
||||
$query->filtersOnID(),
|
||||
"filtersOnID() is true with combined SQL statements"
|
||||
);
|
||||
*/
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->where[] = "Identifier = 5";
|
||||
$query->setWhere("Identifier = 5");
|
||||
$this->assertFalse(
|
||||
$query->filtersOnID(),
|
||||
"filtersOnID() is false with custom column name (starting with 'id')"
|
||||
);
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->where[] = "ParentID = 5";
|
||||
$query->setWhere("ParentID = 5");
|
||||
$this->assertFalse(
|
||||
$query->filtersOnID(),
|
||||
"filtersOnID() is false with column name ending in 'ID'"
|
||||
);
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->where[] = "MyTable.ID = 5";
|
||||
$query->setWhere("MyTable.ID = 5");
|
||||
$this->assertTrue(
|
||||
$query->filtersOnID(),
|
||||
"filtersOnID() is true with table and column name"
|
||||
);
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->where[] = "MyTable.ID= 5";
|
||||
$query->setWhere("MyTable.ID = 5");
|
||||
$this->assertTrue(
|
||||
$query->filtersOnID(),
|
||||
"filtersOnID() is true with table and quoted column name "
|
||||
@ -231,28 +206,28 @@ class SQLQueryTest extends SapphireTest {
|
||||
|
||||
function testFiltersOnFK() {
|
||||
$query = new SQLQuery();
|
||||
$query->where[] = "ID = 5";
|
||||
$query->setWhere("ID = 5");
|
||||
$this->assertFalse(
|
||||
$query->filtersOnFK(),
|
||||
"filtersOnFK() is true with simple unquoted column name"
|
||||
);
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->where[] = "Identifier = 5";
|
||||
$query->setWhere("Identifier = 5");
|
||||
$this->assertFalse(
|
||||
$query->filtersOnFK(),
|
||||
"filtersOnFK() is false with custom column name (starting with 'id')"
|
||||
);
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->where[] = "MyTable.ParentID = 5";
|
||||
$query->setWhere("MyTable.ParentID = 5");
|
||||
$this->assertTrue(
|
||||
$query->filtersOnFK(),
|
||||
"filtersOnFK() is true with table and column name"
|
||||
);
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->where[] = "MyTable.`ParentID`= 5";
|
||||
$query->setWhere("MyTable.`ParentID`= 5");
|
||||
$this->assertTrue(
|
||||
$query->filtersOnFK(),
|
||||
"filtersOnFK() is true with table and quoted column name "
|
||||
@ -261,36 +236,36 @@ class SQLQueryTest extends SapphireTest {
|
||||
|
||||
public function testInnerJoin() {
|
||||
$query = new SQLQuery();
|
||||
$query->from( 'MyTable' );
|
||||
$query->innerJoin( 'MyOtherTable', 'MyOtherTable.ID = 2' );
|
||||
$query->leftJoin( 'MyLastTable', 'MyOtherTable.ID = MyLastTable.ID' );
|
||||
$query->setFrom('MyTable');
|
||||
$query->addInnerJoin('MyOtherTable', 'MyOtherTable.ID = 2');
|
||||
$query->addLeftJoin('MyLastTable', 'MyOtherTable.ID = MyLastTable.ID');
|
||||
|
||||
$this->assertEquals( 'SELECT * FROM MyTable '.
|
||||
$this->assertEquals('SELECT * FROM MyTable '.
|
||||
'INNER JOIN "MyOtherTable" ON MyOtherTable.ID = 2 '.
|
||||
'LEFT JOIN "MyLastTable" ON MyOtherTable.ID = MyLastTable.ID',
|
||||
$query->sql()
|
||||
);
|
||||
|
||||
$query = new SQLQuery();
|
||||
$query->from( 'MyTable' );
|
||||
$query->innerJoin( 'MyOtherTable', 'MyOtherTable.ID = 2', 'table1' );
|
||||
$query->leftJoin( 'MyLastTable', 'MyOtherTable.ID = MyLastTable.ID', 'table2' );
|
||||
$query->setFrom('MyTable');
|
||||
$query->addInnerJoin('MyOtherTable', 'MyOtherTable.ID = 2', 'table1');
|
||||
$query->addLeftJoin('MyLastTable', 'MyOtherTable.ID = MyLastTable.ID', 'table2');
|
||||
|
||||
$this->assertEquals( 'SELECT * FROM MyTable '.
|
||||
$this->assertEquals('SELECT * FROM MyTable '.
|
||||
'INNER JOIN "MyOtherTable" AS "table1" ON MyOtherTable.ID = 2 '.
|
||||
'LEFT JOIN "MyLastTable" AS "table2" ON MyOtherTable.ID = MyLastTable.ID',
|
||||
$query->sql()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testWhereAny() {
|
||||
$query = new SQLQuery();
|
||||
$query->from( 'MyTable' );
|
||||
$query->setFrom('MyTable');
|
||||
|
||||
$query->whereAny(array("Monkey = 'Chimp'", "Color = 'Brown'"));
|
||||
$this->assertEquals("SELECT * FROM MyTable WHERE (Monkey = 'Chimp' OR Color = 'Brown')",$query->sql());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SQLQueryTest_DO extends DataObject implements TestOnly {
|
||||
|
Loading…
Reference in New Issue
Block a user