MySqlGrammar.php
TLDR
This file, MySqlGrammar.php
is a PHP file located in the Illuminate\Database\Query\Grammars
namespace. It is a part of the Demo Projects
project. This file contains the MySqlGrammar
class which extends the Grammar
class. This class defines various methods related to the MySQL database grammar.
Methods
whereNull
This method adds a "where null" clause to the query. If the column value is a JSON selector, it wraps the column and path using json_extract
. Returns the SQL syntax for the "where null" clause.
whereNotNull
This method adds a "where not null" clause to the query. If the column value is a JSON selector, it wraps the column and path using json_extract
. Returns the SQL syntax for the "where not null" clause.
whereFullText
This method compiles a "where fulltext" clause for the query. It takes an array of columns, a value, and optional search mode and expansion options. Returns the SQL syntax for the "where fulltext" clause.
compileIndexHint
This method compiles the index hints for the query. It takes a Builder
object and an IndexHint
object and returns the SQL syntax for the index hint.
compileInsertOrIgnore
This method compiles an "insert ignore" statement into SQL. It takes a Builder
object and an array of values and returns the SQL syntax for the insert statement with "ignore" keyword.
compileJsonContains
This method compiles a "JSON contains" statement into SQL. It takes a column name and a value and returns the SQL syntax for the "JSON contains" statement.
compileJsonContainsKey
This method compiles a "JSON contains key" statement into SQL. It takes a column name and returns the SQL syntax for the "JSON contains key" statement.
compileJsonLength
This method compiles a "JSON length" statement into SQL. It takes a column name, operator, and value and returns the SQL syntax for the "JSON length" statement.
compileJsonValueCast
This method compiles a "JSON value cast" statement into SQL. It takes a value and returns the SQL syntax for the "JSON value cast" statement.
compileRandom
This method compiles the random statement into SQL. It takes a seed value and returns the SQL syntax for the "random" statement.
compileLock
This method compiles the lock into SQL. It takes a Builder
object and a value and returns the SQL syntax for the lock statement.
compileInsert
This method compiles an insert statement into SQL. It takes a Builder
object and an array of values and returns the SQL syntax for the insert statement.
compileUpdateColumns
This method compiles the columns for an update statement. It takes a Builder
object and an array of values and returns the SQL syntax for the update columns.
compileUpsert
This method compiles an "upsert" statement into SQL. It takes a Builder
object, an array of values, an array of uniqueBy columns, and an array of update columns. It returns the SQL syntax for the "upsert" statement.
prepareBindingsForUpdate
This method prepares the bindings for an update statement. It takes an array of bindings and an array of values. Booleans, integers, and doubles are inserted into JSON updates as raw values.
compileDeleteWithoutJoins
This method compiles a delete query that does not use joins. It takes a Builder
object, table name, and where clause. It returns the SQL syntax for the delete statement.
wrapValue
This method wraps a single string in keyword identifiers. It returns the wrapped string.
wrapJsonSelector
This method wraps the given JSON selector. It returns the wrapped JSON selector.
wrapJsonBooleanSelector
This method wraps the given JSON selector for boolean values. It returns the wrapped JSON boolean selector.
Classes
This file does not define any additional classes.
<?php
namespace Illuminate\Database\Query\Grammars;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Str;
class MySqlGrammar extends Grammar
{
/**
* The grammar specific operators.
*
* @var string[]
*/
protected $operators = ['sounds like'];
/**
* Add a "where null" clause to the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNull(Builder $query, $where)
{
$columnValue = (string) $this->getValue($where['column']);
if ($this->isJsonSelector($columnValue)) {
[$field, $path] = $this->wrapJsonFieldAndPath($columnValue);
return '(json_extract('.$field.$path.') is null OR json_type(json_extract('.$field.$path.')) = \'NULL\')';
}
return parent::whereNull($query, $where);
}
/**
* Add a "where not null" clause to the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNotNull(Builder $query, $where)
{
$columnValue = (string) $this->getValue($where['column']);
if ($this->isJsonSelector($columnValue)) {
[$field, $path] = $this->wrapJsonFieldAndPath($columnValue);
return '(json_extract('.$field.$path.') is not null AND json_type(json_extract('.$field.$path.')) != \'NULL\')';
}
return parent::whereNotNull($query, $where);
}
/**
* Compile a "where fulltext" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
public function whereFullText(Builder $query, $where)
{
$columns = $this->columnize($where['columns']);
$value = $this->parameter($where['value']);
$mode = ($where['options']['mode'] ?? []) === 'boolean'
? ' in boolean mode'
: ' in natural language mode';
$expanded = ($where['options']['expanded'] ?? []) && ($where['options']['mode'] ?? []) !== 'boolean'
? ' with query expansion'
: '';
return "match ({$columns}) against (".$value."{$mode}{$expanded})";
}
/**
* Compile the index hints for the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param \Illuminate\Database\Query\IndexHint $indexHint
* @return string
*/
protected function compileIndexHint(Builder $query, $indexHint)
{
return match ($indexHint->type) {
'hint' => "use index ({$indexHint->index})",
'force' => "force index ({$indexHint->index})",
default => "ignore index ({$indexHint->index})",
};
}
/**
* Compile an insert ignore statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileInsertOrIgnore(Builder $query, array $values)
{
return Str::replaceFirst('insert', 'insert ignore', $this->compileInsert($query, $values));
}
/**
* Compile a "JSON contains" statement into SQL.
*
* @param string $column
* @param string $value
* @return string
*/
protected function compileJsonContains($column, $value)
{
[$field, $path] = $this->wrapJsonFieldAndPath($column);
return 'json_contains('.$field.', '.$value.$path.')';
}
/**
* Compile a "JSON contains key" statement into SQL.
*
* @param string $column
* @return string
*/
protected function compileJsonContainsKey($column)
{
[$field, $path] = $this->wrapJsonFieldAndPath($column);
return 'ifnull(json_contains_path('.$field.', \'one\''.$path.'), 0)';
}
/**
* Compile a "JSON length" statement into SQL.
*
* @param string $column
* @param string $operator
* @param string $value
* @return string
*/
protected function compileJsonLength($column, $operator, $value)
{
[$field, $path] = $this->wrapJsonFieldAndPath($column);
return 'json_length('.$field.$path.') '.$operator.' '.$value;
}
/**
* Compile a "JSON value cast" statement into SQL.
*
* @param string $value
* @return string
*/
public function compileJsonValueCast($value)
{
return 'cast('.$value.' as json)';
}
/**
* Compile the random statement into SQL.
*
* @param string|int $seed
* @return string
*/
public function compileRandom($seed)
{
return 'RAND('.$seed.')';
}
/**
* Compile the lock into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param bool|string $value
* @return string
*/
protected function compileLock(Builder $query, $value)
{
if (! is_string($value)) {
return $value ? 'for update' : 'lock in share mode';
}
return $value;
}
/**
* Compile an insert statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileInsert(Builder $query, array $values)
{
if (empty($values)) {
$values = [[]];
}
return parent::compileInsert($query, $values);
}
/**
* Compile the columns for an update statement.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @return string
*/
protected function compileUpdateColumns(Builder $query, array $values)
{
return collect($values)->map(function ($value, $key) {
if ($this->isJsonSelector($key)) {
return $this->compileJsonUpdateColumn($key, $value);
}
return $this->wrap($key).' = '.$this->parameter($value);
})->implode(', ');
}
/**
* Compile an "upsert" statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @param array $uniqueBy
* @param array $update
* @return string
*/
public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)
{
$useUpsertAlias = $query->connection->getConfig('use_upsert_alias');
$sql = $this->compileInsert($query, $values);
if ($useUpsertAlias) {
$sql .= ' as laravel_upsert_alias';
}
$sql .= ' on duplicate key update ';
$columns = collect($update)->map(function ($value, $key) use ($useUpsertAlias) {
if (! is_numeric($key)) {
return $this->wrap($key).' = '.$this->parameter($value);
}
return $useUpsertAlias
? $this->wrap($value).' = '.$this->wrap('laravel_upsert_alias').'.'.$this->wrap($value)
: $this->wrap($value).' = values('.$this->wrap($value).')';
})->implode(', ');
return $sql.$columns;
}
/**
* Prepare a JSON column being updated using the JSON_SET function.
*
* @param string $key
* @param mixed $value
* @return string
*/
protected function compileJsonUpdateColumn($key, $value)
{
if (is_bool($value)) {
$value = $value ? 'true' : 'false';
} elseif (is_array($value)) {
$value = 'cast(? as json)';
} else {
$value = $this->parameter($value);
}
[$field, $path] = $this->wrapJsonFieldAndPath($key);
return "{$field} = json_set({$field}{$path}, {$value})";
}
/**
* Compile an update statement without joins into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param string $table
* @param string $columns
* @param string $where
* @return string
*/
protected function compileUpdateWithoutJoins(Builder $query, $table, $columns, $where)
{
$sql = parent::compileUpdateWithoutJoins($query, $table, $columns, $where);
if (! empty($query->orders)) {
$sql .= ' '.$this->compileOrders($query, $query->orders);
}
if (isset($query->limit)) {
$sql .= ' '.$this->compileLimit($query, $query->limit);
}
return $sql;
}
/**
* Prepare the bindings for an update statement.
*
* Booleans, integers, and doubles are inserted into JSON updates as raw values.
*
* @param array $bindings
* @param array $values
* @return array
*/
public function prepareBindingsForUpdate(array $bindings, array $values)
{
$values = collect($values)->reject(function ($value, $column) {
return $this->isJsonSelector($column) && is_bool($value);
})->map(function ($value) {
return is_array($value) ? json_encode($value) : $value;
})->all();
return parent::prepareBindingsForUpdate($bindings, $values);
}
/**
* Compile a delete query that does not use joins.
*
* @param \Illuminate\Database\Query\Builder $query
* @param string $table
* @param string $where
* @return string
*/
protected function compileDeleteWithoutJoins(Builder $query, $table, $where)
{
$sql = parent::compileDeleteWithoutJoins($query, $table, $where);
// When using MySQL, delete statements may contain order by statements and limits
// so we will compile both of those here. Once we have finished compiling this
// we will return the completed SQL statement so it will be executed for us.
if (! empty($query->orders)) {
$sql .= ' '.$this->compileOrders($query, $query->orders);
}
if (isset($query->limit)) {
$sql .= ' '.$this->compileLimit($query, $query->limit);
}
return $sql;
}
/**
* Wrap a single string in keyword identifiers.
*
* @param string $value
* @return string
*/
protected function wrapValue($value)
{
return $value === '*' ? $value : '`'.str_replace('`', '``', $value).'`';
}
/**
* Wrap the given JSON selector.
*
* @param string $value
* @return string
*/
protected function wrapJsonSelector($value)
{
[$field, $path] = $this->wrapJsonFieldAndPath($value);
return 'json_unquote(json_extract('.$field.$path.'))';
}
/**
* Wrap the given JSON selector for boolean values.
*
* @param string $value
* @return string
*/
protected function wrapJsonBooleanSelector($value)
{
[$field, $path] = $this->wrapJsonFieldAndPath($value);
return 'json_extract('.$field.$path.')';
}
}