Commit 8c209a7a authored by Taylor Otwell's avatar Taylor Otwell

Just cleaning up some code.

Signed-off-by: 's avatarTaylor Otwell <taylorotwell@gmail.com>
parent 762f2402
...@@ -237,7 +237,7 @@ class Query { ...@@ -237,7 +237,7 @@ class Query {
*/ */
public function where($column, $operator = null, $value = null, $connector = 'AND') public function where($column, $operator = null, $value = null, $connector = 'AND')
{ {
// If a CLosure is passed into the method, it means a nested where // If a Closure is passed into the method, it means a nested where
// clause is being initiated, so we will take a different course // clause is being initiated, so we will take a different course
// of action than when the statement is just a simple where. // of action than when the statement is just a simple where.
if ($column instanceof Closure) if ($column instanceof Closure)
...@@ -397,16 +397,16 @@ class Query { ...@@ -397,16 +397,16 @@ class Query {
{ {
$type = 'where_nested'; $type = 'where_nested';
// To handle a nested where statement, we will actually instantiate a // To handle a nested where statement, we will actually instantiate a new
// new Query instance and run the callback over that instance, which // Query instance and run the callback over that instance, which will
// will allow the developer to have a fresh query. // allow the developer to have a fresh query instance
$query = new Query($this->connection, $this->grammar, $this->from); $query = new Query($this->connection, $this->grammar, $this->from);
call_user_func($callback, $query); call_user_func($callback, $query);
// Once the callback has been run on the query, we will store the // Once the callback has been run on the query, we will store the nested
// nested query instance on the where clause array so that it's // query instance on the where clause array so that it's passed to the
// passed to the query's query grammar instance. // query's query grammar instance when building.
$this->wheres[] = compact('type', 'query', 'connector'); $this->wheres[] = compact('type', 'query', 'connector');
$this->bindings = array_merge($this->bindings, $query->bindings); $this->bindings = array_merge($this->bindings, $query->bindings);
...@@ -429,32 +429,31 @@ class Query { ...@@ -429,32 +429,31 @@ class Query {
$segments = preg_split('/(_and_|_or_)/i', $finder, -1, $flags); $segments = preg_split('/(_and_|_or_)/i', $finder, -1, $flags);
// The connector variable will determine which connector will be // The connector variable will determine which connector will be used
// used for the condition. We'll change it as we come across new // for the condition. We'll change it as we come across new boolean
// connectors in the dynamic method string. // connectors in the dynamic method string.
// //
// The index variable helps us get the correct parameter value // The index variable helps us get the correct parameter value for
// for the where condition. We increment it each time we add // the where condition. We increment it each time we add another
// a condition to the query's where. // condition to the query's where clause.
$connector = 'AND'; $connector = 'AND';
$index = 0; $index = 0;
foreach ($segments as $segment) foreach ($segments as $segment)
{ {
// If the segment is not a boolean connector, we can assume it // If the segment is not a boolean connector, we can assume it it is
// it is a column name, and we'll add it to the query as a new // a column name, and we'll add it to the query as a new constraint
// where clause. // of the query's where clause and keep iterating the segments.
//
// Otherwise, we'll store the connector so that we know how to
// connection the next where clause we find to the query, as
// all connectors should precede a new where clause.
if ($segment != '_and_' and $segment != '_or_') if ($segment != '_and_' and $segment != '_or_')
{ {
$this->where($segment, '=', $parameters[$index], $connector); $this->where($segment, '=', $parameters[$index], $connector);
$index++; $index++;
} }
// Otherwise, we will store the connector so we know how the next
// where clause we find in the query should be connected to the
// previous one and will add it when we find the next one.
else else
{ {
$connector = trim(strtoupper($segment), '_'); $connector = trim(strtoupper($segment), '_');
...@@ -777,9 +776,9 @@ class Query { ...@@ -777,9 +776,9 @@ class Query {
{ {
$wrapped = $this->grammar->wrap($column); $wrapped = $this->grammar->wrap($column);
// To make the adjustment to the column, we'll wrap the expression in // To make the adjustment to the column, we'll wrap the expression in an
// an Expression instance, which forces the adjustment to be injected // Expression instance, which forces the adjustment to be injected into
// into the query as a string instead of bound. // the query as a string instead of bound.
$value = Database::raw($wrapped.$operator.$amount); $value = Database::raw($wrapped.$operator.$amount);
return $this->update(array($column => $value)); return $this->update(array($column => $value));
...@@ -793,10 +792,9 @@ class Query { ...@@ -793,10 +792,9 @@ class Query {
*/ */
public function update($values) public function update($values)
{ {
// For update statements, we need to merge the bindings such that // For update statements, we need to merge the bindings such that the update
// the update values occur before the where bindings in the array // values occur before the where bindings in the array since the sets will
// since the set statements will precede any of the where clauses // precede any of the where clauses in the SQL syntax that is generated.
// in the SQL syntax that is generated.
$bindings = array_merge(array_values($values), $this->bindings); $bindings = array_merge(array_values($values), $this->bindings);
$sql = $this->grammar->update($this, $values); $sql = $this->grammar->update($this, $values);
...@@ -814,9 +812,9 @@ class Query { ...@@ -814,9 +812,9 @@ class Query {
*/ */
public function delete($id = null) public function delete($id = null)
{ {
// If an ID is given to the method, we'll set the where clause // If an ID is given to the method, we'll set the where clause to
// to match on the value of the ID. This allows the developer // match on the value of the ID. This allows the developer to
// to quickly delete a row by its primary key value. // quickly delete a row by its primary key value.
if ( ! is_null($id)) if ( ! is_null($id))
{ {
$this->where('id', '=', $id); $this->where('id', '=', $id);
...@@ -839,6 +837,9 @@ class Query { ...@@ -839,6 +837,9 @@ class Query {
return $this->dynamic_where($method, $parameters, $this); return $this->dynamic_where($method, $parameters, $this);
} }
// All of the aggregate methods are handled by a single method, so we'll
// catch them all here and then pass them off to the agregate method
// instead of creating methods for each one of them.
if (in_array($method, array('count', 'min', 'max', 'avg', 'sum'))) if (in_array($method, array('count', 'min', 'max', 'avg', 'sum')))
{ {
if (count($parameters) == 0) $parameters[0] = '*'; if (count($parameters) == 0) $parameters[0] = '*';
......
...@@ -37,10 +37,6 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -37,10 +37,6 @@ class Grammar extends \Laravel\Database\Grammar {
// Each portion of the statement is compiled by a function corresponding // Each portion of the statement is compiled by a function corresponding
// to an item in the components array. This lets us to keep the creation // to an item in the components array. This lets us to keep the creation
// of the query very granular and very flexible. // of the query very granular and very flexible.
//
// Note that each component also connects to a public property on the
// query instance, allowing us to pass the correct data into each
// of the compiler functions.
foreach ($this->components as $component) foreach ($this->components as $component)
{ {
if ( ! is_null($query->$component)) if ( ! is_null($query->$component))
...@@ -91,7 +87,13 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -91,7 +87,13 @@ class Grammar extends \Laravel\Database\Grammar {
{ {
$column = $this->columnize($query->aggregate['columns']); $column = $this->columnize($query->aggregate['columns']);
if ($query->distinct and $column !== '*') $column = 'DISTINCT '.$column; // If the "distinct" flag is set and we're not aggregating everything
// we'll set the distinct clause on the query, since this is used
// to count all of the distinct values in a column, etc.
if ($query->distinct and $column !== '*')
{
$column = 'DISTINCT '.$column;
}
return 'SELECT '.$query->aggregate['aggregator'].'('.$column.') AS '.$this->wrap('aggregate'); return 'SELECT '.$query->aggregate['aggregator'].'('.$column.') AS '.$this->wrap('aggregate');
} }
...@@ -118,19 +120,15 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -118,19 +120,15 @@ class Grammar extends \Laravel\Database\Grammar {
// We need to iterate through each JOIN clause that is attached to the // We need to iterate through each JOIN clause that is attached to the
// query an translate it into SQL. The table and the columns will be // query an translate it into SQL. The table and the columns will be
// wrapped in identifiers to avoid naming collisions. // wrapped in identifiers to avoid naming collisions.
//
// Once all of the JOINs have been compiled, we can concatenate them
// together using a single space, which should give us the complete
// set of joins in valid SQL that can appended to the query.
foreach ($query->joins as $join) foreach ($query->joins as $join)
{ {
$table = $this->wrap_table($join->table); $table = $this->wrap_table($join->table);
$clauses = array(); $clauses = array();
// Each JOIN statement may have multiple clauses, so we will // Each JOIN statement may have multiple clauses, so we will iterate
// iterate through each clause creating the conditions then // through each clause creating the conditions then we'll join all
// we will concatenate them all together. // of the together at the end to build the clause.
foreach ($join->clauses as $clause) foreach ($join->clauses as $clause)
{ {
extract($clause); extract($clause);
...@@ -142,10 +140,9 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -142,10 +140,9 @@ class Grammar extends \Laravel\Database\Grammar {
$clauses[] = "{$connector} {$column1} {$operator} {$column2}"; $clauses[] = "{$connector} {$column1} {$operator} {$column2}";
} }
// The first clause will have a connector on the front, // The first clause will have a connector on the front, but it is
// but it is not needed on the first condition, so we // not needed on the first condition, so we will strip it off of
// will strip it off of the condition before adding // the condition before adding it to the arrya of joins.
// it to the array of joins.
$search = array('AND ', 'OR '); $search = array('AND ', 'OR ');
$clauses[0] = str_replace($search, '', $clauses[0]); $clauses[0] = str_replace($search, '', $clauses[0]);
...@@ -155,9 +152,9 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -155,9 +152,9 @@ class Grammar extends \Laravel\Database\Grammar {
$sql[] = "{$join->type} JOIN {$table} ON {$clauses}"; $sql[] = "{$join->type} JOIN {$table} ON {$clauses}";
} }
// Finally, we should have an array of JOIN clauses // Finally, we should have an array of JOIN clauses that we can
// that we can implode together and return as the // implode together and return as the complete SQL for the
// complete SQL for the JOIN of the query. // join clause of the query under construction.
return implode(' ', $sql); return implode(' ', $sql);
} }
...@@ -173,11 +170,7 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -173,11 +170,7 @@ class Grammar extends \Laravel\Database\Grammar {
// Each WHERE clause array has a "type" that is assigned by the query // Each WHERE clause array has a "type" that is assigned by the query
// builder, and each type has its own compiler function. We will call // builder, and each type has its own compiler function. We will call
// the appropriate compiler for each where clause in the query. // the appropriate compiler for each where clause.
//
// Keeping each particular where clause in its own "compiler" allows
// us to keep the query generation process very granular, making it
// easier to customize derived grammars for other databases.
foreach ($query->wheres as $where) foreach ($query->wheres as $where)
{ {
$sql[] = $where['connector'].' '.$this->{$where['type']}($where); $sql[] = $where['connector'].' '.$this->{$where['type']}($where);
...@@ -187,7 +180,7 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -187,7 +180,7 @@ class Grammar extends \Laravel\Database\Grammar {
{ {
// We attach the boolean connector to every where segment just // We attach the boolean connector to every where segment just
// for convenience. Once we have built the entire clause we'll // for convenience. Once we have built the entire clause we'll
// remove the first instance of a connector from the clause. // remove the first instance of a connector.
return 'WHERE '.preg_replace('/AND |OR /', '', implode(' ', $sql), 1); return 'WHERE '.preg_replace('/AND |OR /', '', implode(' ', $sql), 1);
} }
} }
...@@ -296,9 +289,7 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -296,9 +289,7 @@ class Grammar extends \Laravel\Database\Grammar {
{ {
foreach ($query->orderings as $ordering) foreach ($query->orderings as $ordering)
{ {
$direction = strtoupper($ordering['direction']); $sql[] = $this->wrap($ordering['column']).' '.strtoupper($ordering['direction']);
$sql[] = $this->wrap($ordering['column']).' '.$direction;
} }
return 'ORDER BY '.implode(', ', $sql); return 'ORDER BY '.implode(', ', $sql);
...@@ -341,12 +332,12 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -341,12 +332,12 @@ class Grammar extends \Laravel\Database\Grammar {
// Force every insert to be treated like a batch insert. This simply makes // Force every insert to be treated like a batch insert. This simply makes
// creating the SQL syntax a little easier on us since we can always treat // creating the SQL syntax a little easier on us since we can always treat
// the values as if it is an array containing multiple inserts. // the values as if it contains multiple inserts.
if ( ! is_array(reset($values))) $values = array($values); if ( ! is_array(reset($values))) $values = array($values);
// Since we only care about the column names, we can pass any of the insert // Since we only care about the column names, we can pass any of the insert
// arrays into the "columnize" method. The columns should be the same for // arrays into the "columnize" method. The columns should be the same for
// every insert to the table so we can just use the first record. // every record inserted into the table.
$columns = $this->columnize(array_keys(reset($values))); $columns = $this->columnize(array_keys(reset($values)));
// Build the list of parameter place-holders of values bound to the query. // Build the list of parameter place-holders of values bound to the query.
...@@ -370,10 +361,9 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -370,10 +361,9 @@ class Grammar extends \Laravel\Database\Grammar {
{ {
$table = $this->wrap_table($query->from); $table = $this->wrap_table($query->from);
// Each column in the UPDATE statement needs to be wrapped in keyword // Each column in the UPDATE statement needs to be wrapped in the keyword
// identifiers, and a place-holder needs to be created for each value // identifiers, and a place-holder needs to be created for each value in
// in the array of bindings. Of course, if the value of the binding // the array of bindings, so we'll build the sets first.
// is an expression, the expression string will be injected.
foreach ($values as $column => $value) foreach ($values as $column => $value)
{ {
$columns[] = $this->wrap($column).' = '.$this->parameter($value); $columns[] = $this->wrap($column).' = '.$this->parameter($value);
...@@ -381,10 +371,9 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -381,10 +371,9 @@ class Grammar extends \Laravel\Database\Grammar {
$columns = implode(', ', $columns); $columns = implode(', ', $columns);
// UPDATE statements may be constrained by a WHERE clause, so we'll // UPDATE statements may be constrained by a WHERE clause, so we'll run
// run the entire where compilation process for those contraints. // the entire where compilation process for those contraints. This is
// This is easily achieved by passing the query to the "wheres" // easily achieved by passing it to the "wheres" method.
// method which will call all of the where compilers.
return trim("UPDATE {$table} SET {$columns} ".$this->wheres($query)); return trim("UPDATE {$table} SET {$columns} ".$this->wheres($query));
} }
...@@ -398,9 +387,6 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -398,9 +387,6 @@ class Grammar extends \Laravel\Database\Grammar {
{ {
$table = $this->wrap_table($query->from); $table = $this->wrap_table($query->from);
// Like the UPDATE statement, the DELETE statement is constrained
// by WHERE clauses, so we'll need to run the "wheres" method to
// make the WHERE clauses for the query.
return trim("DELETE FROM {$table} ".$this->wheres($query)); return trim("DELETE FROM {$table} ".$this->wheres($query));
} }
...@@ -413,17 +399,16 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -413,17 +399,16 @@ class Grammar extends \Laravel\Database\Grammar {
*/ */
public function shortcut($sql, $bindings) public function shortcut($sql, $bindings)
{ {
// Laravel provides an easy short-cut notation for writing raw // Laravel provides an easy short-cut notation for writing raw WHERE IN
// WHERE IN statements. If (...) is in the query, it will be // statements. If (...) is in the query, it will be replaced with the
// replaced with the correct number of parameters based on // correct number of parameters based on the bindings.
// the bindings for the query.
if (strpos($sql, '(...)') !== false) if (strpos($sql, '(...)') !== false)
{ {
for ($i = 0; $i < count($bindings); $i++) for ($i = 0; $i < count($bindings); $i++)
{ {
// If the binding is an array, we can just assume it's // If the binding is an array, we can just assume it's used to
// used to fill a "where in" condition, so we'll just // fill a "where in" condition, so we will just replace the
// replace the next place-holder in the query. // next place-holder in the query with the constraint.
if (is_array($bindings[$i])) if (is_array($bindings[$i]))
{ {
$parameters = $this->parameterize($bindings[$i]); $parameters = $this->parameterize($bindings[$i]);
......
...@@ -23,8 +23,7 @@ class SQLServer extends Grammar { ...@@ -23,8 +23,7 @@ class SQLServer extends Grammar {
// SQL Server does not currently implement an "OFFSET" type keyword, so we // SQL Server does not currently implement an "OFFSET" type keyword, so we
// actually have to generate the ANSI standard SQL for doing offset like // actually have to generate the ANSI standard SQL for doing offset like
// functionality. In the next version of SQL Server, an OFFSET like // functionality. OFFSET is in SQL Server 2012, however.
// keyword is included for convenience.
if ($query->offset > 0) if ($query->offset > 0)
{ {
return $this->ansi_offset($query, $sql); return $this->ansi_offset($query, $sql);
...@@ -32,7 +31,7 @@ class SQLServer extends Grammar { ...@@ -32,7 +31,7 @@ class SQLServer extends Grammar {
// Once all of the clauses have been compiled, we can join them all as // Once all of the clauses have been compiled, we can join them all as
// one statement. Any segments that are null or an empty string will // one statement. Any segments that are null or an empty string will
// be removed from the array of clauses before they are imploded. // be removed from the array before imploding.
return $this->concatenate($sql); return $this->concatenate($sql);
} }
...@@ -48,13 +47,9 @@ class SQLServer extends Grammar { ...@@ -48,13 +47,9 @@ class SQLServer extends Grammar {
$select = ($query->distinct) ? 'SELECT DISTINCT ' : 'SELECT '; $select = ($query->distinct) ? 'SELECT DISTINCT ' : 'SELECT ';
// Instead of using a "LIMIT" keyword, SQL Server uses the "TOP" // Instead of using a "LIMIT" keyword, SQL Server uses the TOP keyword
// keyword within the SELECT statement. So, if we have a limit, // within the SELECT statement. So, if we have a limit, we will add
// we will add it here. // it to the query here if there is not an OFFSET present.
//
// We will not add the TOP clause if there is an offset however,
// since we will have to handle offsets using the ANSI syntax
// and will need to remove the TOP clause in that situation.
if ($query->limit > 0 and $query->offset <= 0) if ($query->limit > 0 and $query->offset <= 0)
{ {
$select .= 'TOP '.$query->limit.' '; $select .= 'TOP '.$query->limit.' ';
...@@ -72,18 +67,17 @@ class SQLServer extends Grammar { ...@@ -72,18 +67,17 @@ class SQLServer extends Grammar {
*/ */
protected function ansi_offset(Query $query, $components) protected function ansi_offset(Query $query, $components)
{ {
// An ORDER BY clause is required to make this offset query // An ORDER BY clause is required to make this offset query work, so if
// work, so if one doesn't exist, we'll just create a dummy // one doesn't exist, we'll just create a dummy clause to trick the
// clause to satisfy the database. // database and pacify it so it doesn't complain about the query.
if ( ! isset($components['orderings'])) if ( ! isset($components['orderings']))
{ {
$components['orderings'] = 'ORDER BY (SELECT 0)'; $components['orderings'] = 'ORDER BY (SELECT 0)';
} }
// We need to add the row number to the query results so we // We need to add the row number to the query so we can compare it to
// can compare it against the offset and limit values given // the offset and limit values given for the statement. So we'll add
// for the statement. To do that we'll add an expression to // an expression to the select for the row number.
// the select statement for the row number.
$orderings = $components['orderings']; $orderings = $components['orderings'];
$components['selects'] .= ", ROW_NUMBER() OVER ({$orderings}) AS RowNum"; $components['selects'] .= ", ROW_NUMBER() OVER ({$orderings}) AS RowNum";
...@@ -92,10 +86,9 @@ class SQLServer extends Grammar { ...@@ -92,10 +86,9 @@ class SQLServer extends Grammar {
$start = $query->offset + 1; $start = $query->offset + 1;
// Next we need to calculate the constraint that should be // Next we need to calculate the constraint that should be placed on
// placed on the row number to get the correct offset and // the row number to get the correct offset and limit on the query.
// limit on the query. If a limit has not been set, we'll // If there is not limit, we'll just handle the offset.
// only add a constraint to handle offset.
if ($query->limit > 0) if ($query->limit > 0)
{ {
$finish = $query->offset + $query->limit; $finish = $query->offset + $query->limit;
...@@ -107,10 +100,9 @@ class SQLServer extends Grammar { ...@@ -107,10 +100,9 @@ class SQLServer extends Grammar {
$constraint = ">= {$start}"; $constraint = ">= {$start}";
} }
// Now, we're finally ready to build the final SQL query. // We're finally ready to build the final SQL query so we'll create
// We'll create a common table expression with the query // a common table expression with the query and select all of the
// and then select all of the results from it where the // results with row numbers between the limit and offset.
// row number is between oru given limit and offset.
$sql = $this->concatenate($components); $sql = $this->concatenate($components);
return "SELECT * FROM ($sql) AS TempTable WHERE RowNum {$constraint}"; return "SELECT * FROM ($sql) AS TempTable WHERE RowNum {$constraint}";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment