Skip to content

Commit

Permalink
added support for insert select
Browse files Browse the repository at this point in the history
  • Loading branch information
mrjgreen committed Nov 2, 2014
1 parent cc820f1 commit fca2d19
Show file tree
Hide file tree
Showing 7 changed files with 304 additions and 35 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,16 @@ $connection->table('users')->insertUpdate(
//insertOnDuplicateKeyUpdate() is an alias of insertUpdate
```

####Insert Select
$connection->table('users')->insertSelect(function($select){
$select->from('admin')
->select('name', 'email')
->where('status', '=', 1);

}, array('name','email'));

`insertIgnoreSelect` and `replaceSelect` methods are supported for the MySQL grammar driver.

###Update
```PHP
$data = array(
Expand Down
63 changes: 63 additions & 0 deletions src/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,69 @@ protected function doInsert(array $values, $type)
return $this->connection->query($sql, $this->buildBulkInsertBindings($values));
}


/**
* @param $select \Closure|static
* @param array $columns
* @return bool|\PDOStatement
* @throws \Exception
*/
protected function doInsertSelect($select, array $columns, $type)
{
if($select instanceof Closure)
{
$callback = $select;

$select = $this->newQuery();

call_user_func($callback, $select);
}

if(!$select instanceof Builder)
{
throw new \Exception("Argument 1 must be a closure or an instance of Database\\Query\\Builder");
}

$sql = $this->grammar->{'compile' . ucfirst($type) . 'Select'}($this, $columns, $select, $type);

$bindings = $select->getBindings();

return $this->connection->query($sql, $bindings);
}

/**
* @param $select \Closure|static
* @param array $columns
* @return bool|\PDOStatement
* @throws \Exception
*/
public function insertSelect($select, array $columns)
{
return $this->doInsertSelect($select, $columns, 'insert');
}

/**
* @param $select \Closure|static
* @param array $columns
* @return bool|\PDOStatement
* @throws \Exception
*/
public function insertIgnoreSelect($select, array $columns)
{
return $this->doInsertSelect($select, $columns, 'insertIgnore');
}

/**
* @param $select \Closure|static
* @param array $columns
* @return bool|\PDOStatement
* @throws \Exception
*/
public function replaceSelect($select, array $columns)
{
return $this->doInsertSelect($select, $columns, 'replace');
}

/**
* Insert a new record into the database, with an update if it exists
*
Expand Down
98 changes: 77 additions & 21 deletions src/Query/Grammars/Grammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -731,22 +731,6 @@ protected function compileUnion(array $union)
return $joiner . $union['query']->toSql();
}

/**
* Compile an insert statement into SQL.
*
* @param \Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileInsertOnDuplicateKeyUpdate(Builder $query, array $values, array $updateValues)
{
$insert = $this->compileInsert($query, $values);

$update = $this->getUpdateColumns($updateValues);

return "$insert on duplicate key update $update";
}

/**
* Compile an insert statement into SQL.
*
Expand Down Expand Up @@ -779,6 +763,56 @@ protected function doCompileInsert(Builder $query, array $values, $type)
return "$type into $table ($columns) values $parameters";
}

/**
* @param Builder $insert
* @param array $columns
* @param Builder $query
* @return string
*/
public function doCompileInsertSelect(Builder $insert, array $columns, Builder $query, $type)
{
$table = $this->wrapTable($insert->from);

$columns = $this->columnize($columns);

$select = $this->compileSelect($query);

return "$type into $table ($columns) $select";
}

/**
* @param Builder $insert
* @param array $columns
* @param Builder $query
* @return string
*/
public function compileInsertSelect(Builder $insert, array $columns, Builder $query)
{
return $this->doCompileInsertSelect($insert, $columns, $query, 'insert');
}

/**
* @param Builder $insert
* @param array $columns
* @param Builder $query
* @return string
*/
public function compileInsertIgnoreSelect(Builder $insert, array $columns, Builder $query)
{
$this->throwUnsupportedGrammarException("Insert ignore");
}

/**
* @param Builder $insert
* @param array $columns
* @param Builder $query
* @return string
*/
public function compileReplaceSelect(Builder $insert, array $columns, Builder $query)
{
$this->throwUnsupportedGrammarException("Replace");
}

/**
* Compile an insert statement into SQL.
*
Expand All @@ -800,19 +834,32 @@ public function compileInsert(Builder $query, array $values)
*/
public function compileInsertIgnore(Builder $query, array $values)
{
return $this->doCompileInsert($query, $values, 'insert ignore');
$this->throwUnsupportedGrammarException("Insert ignore");
}

/**
* Compile an insert statement into SQL.
*
* @param \Database\Query\Builder $query
* @param array $values
* @return string
* @param Builder $query
* @param array $values
* @param array $updateValues
* @throws UnsupportedGrammarException
*/
public function compileInsertOnDuplicateKeyUpdate(Builder $query, array $values, array $updateValues)
{
$this->throwUnsupportedGrammarException("Insert on duplicate key update");
}

/**
* Compile a replace statement into SQL.
*
* @param Builder $query
* @param array $values
* @throws UnsupportedGrammarException
*/
public function compileReplace(Builder $query, array $values)
{
return $this->doCompileInsert($query, $values, 'replace');
$this->throwUnsupportedGrammarException("Replace");
}

/**
Expand Down Expand Up @@ -942,4 +989,13 @@ protected function removeLeadingBoolean($value)
return preg_replace('/and |or /', '', $value, 1);
}

/**
* @param $grammarDescription
* @throws UnsupportedGrammarException
*/
private function throwUnsupportedGrammarException($grammarDescription)
{
throw new UnsupportedGrammarException("$grammarDescription is not supported by the " . get_called_class() . " grammar driver");
}

}
63 changes: 63 additions & 0 deletions src/Query/Grammars/MySqlGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,69 @@ protected function compileLock(Builder $query, $value)
return $value ? 'for update' : 'lock in share mode';
}

/**
* Compile an insert statement into SQL.
*
* @param \Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileInsertIgnore(Builder $query, array $values)
{
return $this->doCompileInsert($query, $values, 'insert ignore');
}

/**
* Compile an insert statement into SQL.
*
* @param \Database\Query\Builder $query
* @param array $values
* @param array $updateValues
* @return string
*/
public function compileInsertOnDuplicateKeyUpdate(Builder $query, array $values, array $updateValues)
{
$insert = $this->compileInsert($query, $values);

$update = $this->getUpdateColumns($updateValues);

return "$insert on duplicate key update $update";
}

/**
* Compile a replace statement into SQL.
*
* @param \Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileReplace(Builder $query, array $values)
{
return $this->doCompileInsert($query, $values, 'replace');
}

/**
* @param Builder $insert
* @param array $columns
* @param Builder $query
* @return string
*/
public function compileInsertIgnoreSelect(Builder $insert, array $columns, Builder $query)
{
return $this->doCompileInsertSelect($insert, $columns, $query, 'insert ignore');
}

/**
* @param Builder $insert
* @param array $columns
* @param Builder $query
* @return string
*/
public function compileReplaceSelect(Builder $insert, array $columns, Builder $query)
{
return $this->doCompileInsertSelect($insert, $columns, $query, 'replace');
}

/**
* Compile an update statement into SQL.
*
Expand Down
18 changes: 15 additions & 3 deletions src/Query/Grammars/SQLiteGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class SQLiteGrammar extends Grammar
* @param array $values
* @return string
*/
public function compileInsert(Builder $query, array $values)
public function doCompileInsert(Builder $query, array $values, $type)
{
// Essentially we will force every insert to be treated as a batch insert which
// simply makes creating the SQL easier for us since we can utilize the same
Expand All @@ -38,7 +38,7 @@ public function compileInsert(Builder $query, array $values)
// grammar insert builder because no special syntax is needed for the single
// row inserts in SQLite. However, if there are multiples, we'll continue.
if (count($values) == 1) {
return parent::compileInsert($query, reset($values));
return parent::doCompileInsert($query, reset($values), $type);
}

$names = $this->columnize(array_keys(reset($values)));
Expand All @@ -54,7 +54,19 @@ public function compileInsert(Builder $query, array $values)

$columns = array_fill(0, count($values), implode(', ', $columns));

return "insert into $table ($names) select " . implode(' union select ', $columns);
return "$type into $table ($names) select " . implode(' union select ', $columns);
}

/**
* Compile an insert statement into SQL.
*
* @param \Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileInsertIgnore(Builder $query, array $values)
{
return $this->doCompileInsert($query, $values, 'insert or ignore');
}

/**
Expand Down
6 changes: 6 additions & 0 deletions src/Query/Grammars/UnsupportedGrammarException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php namespace Database\Query\Grammars;

class UnsupportedGrammarException extends \Exception
{

}

0 comments on commit fca2d19

Please sign in to comment.