暂存
This commit is contained in:
+1983
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,247 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Database\Query\Expression;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Fluent;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class BlueprintState
|
||||
{
|
||||
/**
|
||||
* The blueprint instance.
|
||||
*
|
||||
* @var \Illuminate\Database\Schema\Blueprint
|
||||
*/
|
||||
protected $blueprint;
|
||||
|
||||
/**
|
||||
* The connection instance.
|
||||
*
|
||||
* @var \Illuminate\Database\Connection
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* The columns.
|
||||
*
|
||||
* @var \Illuminate\Database\Schema\ColumnDefinition[]
|
||||
*/
|
||||
private $columns;
|
||||
|
||||
/**
|
||||
* The primary key.
|
||||
*
|
||||
* @var \Illuminate\Database\Schema\IndexDefinition|null
|
||||
*/
|
||||
private $primaryKey;
|
||||
|
||||
/**
|
||||
* The indexes.
|
||||
*
|
||||
* @var \Illuminate\Database\Schema\IndexDefinition[]
|
||||
*/
|
||||
private $indexes;
|
||||
|
||||
/**
|
||||
* The foreign keys.
|
||||
*
|
||||
* @var \Illuminate\Database\Schema\ForeignKeyDefinition[]
|
||||
*/
|
||||
private $foreignKeys;
|
||||
|
||||
/**
|
||||
* Create a new blueprint state instance.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param \Illuminate\Database\Connection $connection
|
||||
*/
|
||||
public function __construct(Blueprint $blueprint, Connection $connection)
|
||||
{
|
||||
$this->blueprint = $blueprint;
|
||||
$this->connection = $connection;
|
||||
|
||||
$schema = $connection->getSchemaBuilder();
|
||||
$table = $blueprint->getTable();
|
||||
|
||||
$this->columns = (new Collection($schema->getColumns($table)))->map(fn ($column) => new ColumnDefinition([
|
||||
'name' => $column['name'],
|
||||
'type' => $column['type_name'],
|
||||
'full_type_definition' => $column['type'],
|
||||
'nullable' => $column['nullable'],
|
||||
'default' => is_null($column['default']) ? null : new Expression(Str::wrap($column['default'], '(', ')')),
|
||||
'autoIncrement' => $column['auto_increment'],
|
||||
'collation' => $column['collation'],
|
||||
'comment' => $column['comment'],
|
||||
'virtualAs' => ! is_null($column['generation']) && $column['generation']['type'] === 'virtual'
|
||||
? $column['generation']['expression']
|
||||
: null,
|
||||
'storedAs' => ! is_null($column['generation']) && $column['generation']['type'] === 'stored'
|
||||
? $column['generation']['expression']
|
||||
: null,
|
||||
]))->all();
|
||||
|
||||
[$primary, $indexes] = (new Collection($schema->getIndexes($table)))->map(fn ($index) => new IndexDefinition([
|
||||
'name' => match (true) {
|
||||
$index['primary'] => 'primary',
|
||||
$index['unique'] => 'unique',
|
||||
default => 'index',
|
||||
},
|
||||
'index' => $index['name'],
|
||||
'columns' => $index['columns'],
|
||||
]))->partition(fn ($index) => $index->name === 'primary');
|
||||
|
||||
$this->indexes = $indexes->all();
|
||||
$this->primaryKey = $primary->first();
|
||||
|
||||
$this->foreignKeys = (new Collection($schema->getForeignKeys($table)))->map(fn ($foreignKey) => new ForeignKeyDefinition([
|
||||
'columns' => $foreignKey['columns'],
|
||||
'on' => new Expression($foreignKey['foreign_table']),
|
||||
'references' => $foreignKey['foreign_columns'],
|
||||
'onUpdate' => $foreignKey['on_update'],
|
||||
'onDelete' => $foreignKey['on_delete'],
|
||||
]))->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the primary key.
|
||||
*
|
||||
* @return \Illuminate\Database\Schema\IndexDefinition|null
|
||||
*/
|
||||
public function getPrimaryKey()
|
||||
{
|
||||
return $this->primaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the columns.
|
||||
*
|
||||
* @return \Illuminate\Database\Schema\ColumnDefinition[]
|
||||
*/
|
||||
public function getColumns()
|
||||
{
|
||||
return $this->columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the indexes.
|
||||
*
|
||||
* @return \Illuminate\Database\Schema\IndexDefinition[]
|
||||
*/
|
||||
public function getIndexes()
|
||||
{
|
||||
return $this->indexes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the foreign keys.
|
||||
*
|
||||
* @return \Illuminate\Database\Schema\ForeignKeyDefinition[]
|
||||
*/
|
||||
public function getForeignKeys()
|
||||
{
|
||||
return $this->foreignKeys;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the blueprint's state.
|
||||
*
|
||||
* @param \Illuminate\Support\Fluent $command
|
||||
* @return void
|
||||
*/
|
||||
public function update(Fluent $command)
|
||||
{
|
||||
switch ($command->name) {
|
||||
case 'alter':
|
||||
// Already handled...
|
||||
break;
|
||||
|
||||
case 'add':
|
||||
$this->columns[] = $command->column;
|
||||
break;
|
||||
|
||||
case 'change':
|
||||
foreach ($this->columns as &$column) {
|
||||
if ($column->name === $command->column->name) {
|
||||
$column = $command->column;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'renameColumn':
|
||||
foreach ($this->columns as $column) {
|
||||
if ($column->name === $command->from) {
|
||||
$column->name = $command->to;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->primaryKey) {
|
||||
$this->primaryKey->columns = str_replace($command->from, $command->to, $this->primaryKey->columns);
|
||||
}
|
||||
|
||||
foreach ($this->indexes as $index) {
|
||||
$index->columns = str_replace($command->from, $command->to, $index->columns);
|
||||
}
|
||||
|
||||
foreach ($this->foreignKeys as $foreignKey) {
|
||||
$foreignKey->columns = str_replace($command->from, $command->to, $foreignKey->columns);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'dropColumn':
|
||||
$this->columns = array_values(
|
||||
array_filter($this->columns, fn ($column) => ! in_array($column->name, $command->columns))
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case 'primary':
|
||||
$this->primaryKey = $command;
|
||||
break;
|
||||
|
||||
case 'unique':
|
||||
case 'index':
|
||||
$this->indexes[] = $command;
|
||||
break;
|
||||
|
||||
case 'renameIndex':
|
||||
foreach ($this->indexes as $index) {
|
||||
if ($index->index === $command->from) {
|
||||
$index->index = $command->to;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'foreign':
|
||||
$this->foreignKeys[] = $command;
|
||||
break;
|
||||
|
||||
case 'dropPrimary':
|
||||
$this->primaryKey = null;
|
||||
break;
|
||||
|
||||
case 'dropIndex':
|
||||
case 'dropUnique':
|
||||
$this->indexes = array_values(
|
||||
array_filter($this->indexes, fn ($index) => $index->index !== $command->index)
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case 'dropForeign':
|
||||
$this->foreignKeys = array_values(
|
||||
array_filter($this->foreignKeys, fn ($fk) => $fk->columns !== $command->columns)
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
+782
@@ -0,0 +1,782 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Database\PostgresConnection;
|
||||
use Illuminate\Support\Traits\Macroable;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
use RuntimeException;
|
||||
|
||||
class Builder
|
||||
{
|
||||
use Macroable;
|
||||
|
||||
/**
|
||||
* The database connection instance.
|
||||
*
|
||||
* @var \Illuminate\Database\Connection
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* The schema grammar instance.
|
||||
*
|
||||
* @var \Illuminate\Database\Schema\Grammars\Grammar
|
||||
*/
|
||||
protected $grammar;
|
||||
|
||||
/**
|
||||
* The Blueprint resolver callback.
|
||||
*
|
||||
* @var \Closure(\Illuminate\Database\Connection, string, \Closure|null): \Illuminate\Database\Schema\Blueprint
|
||||
*/
|
||||
protected $resolver;
|
||||
|
||||
/**
|
||||
* The default string length for migrations.
|
||||
*
|
||||
* @var non-negative-int|null
|
||||
*/
|
||||
public static $defaultStringLength = 255;
|
||||
|
||||
/**
|
||||
* The default time precision for migrations.
|
||||
*/
|
||||
public static ?int $defaultTimePrecision = 0;
|
||||
|
||||
/**
|
||||
* The default relationship morph key type.
|
||||
*
|
||||
* @var 'int'|'uuid'|'ulid'
|
||||
*/
|
||||
public static $defaultMorphKeyType = 'int';
|
||||
|
||||
/**
|
||||
* Create a new database Schema manager.
|
||||
*
|
||||
* @param \Illuminate\Database\Connection $connection
|
||||
*/
|
||||
public function __construct(Connection $connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->grammar = $connection->getSchemaGrammar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default string length for migrations.
|
||||
*
|
||||
* @param non-negative-int $length
|
||||
* @return void
|
||||
*/
|
||||
public static function defaultStringLength($length)
|
||||
{
|
||||
static::$defaultStringLength = $length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default time precision for migrations.
|
||||
*/
|
||||
public static function defaultTimePrecision(?int $precision): void
|
||||
{
|
||||
static::$defaultTimePrecision = $precision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default morph key type for migrations.
|
||||
*
|
||||
* @param string $type
|
||||
* @return void
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function defaultMorphKeyType(string $type)
|
||||
{
|
||||
if (! in_array($type, ['int', 'uuid', 'ulid'])) {
|
||||
throw new InvalidArgumentException("Morph key type must be 'int', 'uuid', or 'ulid'.");
|
||||
}
|
||||
|
||||
static::$defaultMorphKeyType = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default morph key type for migrations to UUIDs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function morphUsingUuids()
|
||||
{
|
||||
static::defaultMorphKeyType('uuid');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default morph key type for migrations to ULIDs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function morphUsingUlids()
|
||||
{
|
||||
static::defaultMorphKeyType('ulid');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a database in the schema.
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function createDatabase($name)
|
||||
{
|
||||
return $this->connection->statement(
|
||||
$this->grammar->compileCreateDatabase($name)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a database from the schema if the database exists.
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function dropDatabaseIfExists($name)
|
||||
{
|
||||
return $this->connection->statement(
|
||||
$this->grammar->compileDropDatabaseIfExists($name)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the schemas that belong to the connection.
|
||||
*
|
||||
* @return list<array{name: string, path: string|null, default: bool}>
|
||||
*/
|
||||
public function getSchemas()
|
||||
{
|
||||
return $this->connection->getPostProcessor()->processSchemas(
|
||||
$this->connection->selectFromWriteConnection($this->grammar->compileSchemas())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given table exists.
|
||||
*
|
||||
* @param string $table
|
||||
* @return bool
|
||||
*/
|
||||
public function hasTable($table)
|
||||
{
|
||||
[$schema, $table] = $this->parseSchemaAndTable($table);
|
||||
|
||||
$table = $this->connection->getTablePrefix().$table;
|
||||
|
||||
if ($sql = $this->grammar->compileTableExists($schema, $table)) {
|
||||
return (bool) $this->connection->scalar($sql);
|
||||
}
|
||||
|
||||
foreach ($this->getTables($schema ?? $this->getCurrentSchemaName()) as $value) {
|
||||
if (strtolower($table) === strtolower($value['name'])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given view exists.
|
||||
*
|
||||
* @param string $view
|
||||
* @return bool
|
||||
*/
|
||||
public function hasView($view)
|
||||
{
|
||||
[$schema, $view] = $this->parseSchemaAndTable($view);
|
||||
|
||||
$view = $this->connection->getTablePrefix().$view;
|
||||
|
||||
foreach ($this->getViews($schema ?? $this->getCurrentSchemaName()) as $value) {
|
||||
if (strtolower($view) === strtolower($value['name'])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tables that belong to the connection.
|
||||
*
|
||||
* @param string|string[]|null $schema
|
||||
* @return list<array{name: string, schema: string|null, schema_qualified_name: string, size: int|null, comment: string|null, collation: string|null, engine: string|null}>
|
||||
*/
|
||||
public function getTables($schema = null)
|
||||
{
|
||||
return $this->connection->getPostProcessor()->processTables(
|
||||
$this->connection->selectFromWriteConnection($this->grammar->compileTables($schema))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of the tables that belong to the connection.
|
||||
*
|
||||
* @param string|string[]|null $schema
|
||||
* @param bool $schemaQualified
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getTableListing($schema = null, $schemaQualified = true)
|
||||
{
|
||||
return array_column(
|
||||
$this->getTables($schema),
|
||||
$schemaQualified ? 'schema_qualified_name' : 'name'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the views that belong to the connection.
|
||||
*
|
||||
* @param string|string[]|null $schema
|
||||
* @return list<array{name: string, schema: string|null, schema_qualified_name: string, definition: string}>
|
||||
*/
|
||||
public function getViews($schema = null)
|
||||
{
|
||||
return $this->connection->getPostProcessor()->processViews(
|
||||
$this->connection->selectFromWriteConnection($this->grammar->compileViews($schema))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user-defined types that belong to the connection.
|
||||
*
|
||||
* @param string|string[]|null $schema
|
||||
* @return list<array{name: string, schema: string, type: string, type: string, category: string, implicit: bool}>
|
||||
*/
|
||||
public function getTypes($schema = null)
|
||||
{
|
||||
return $this->connection->getPostProcessor()->processTypes(
|
||||
$this->connection->selectFromWriteConnection($this->grammar->compileTypes($schema))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given table has a given column.
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $column
|
||||
* @return bool
|
||||
*/
|
||||
public function hasColumn($table, $column)
|
||||
{
|
||||
return in_array(
|
||||
strtolower($column), array_map(strtolower(...), $this->getColumnListing($table))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given table has given columns.
|
||||
*
|
||||
* @param string $table
|
||||
* @param array<string> $columns
|
||||
* @return bool
|
||||
*/
|
||||
public function hasColumns($table, array $columns)
|
||||
{
|
||||
$tableColumns = array_map(strtolower(...), $this->getColumnListing($table));
|
||||
|
||||
foreach ($columns as $column) {
|
||||
if (! in_array(strtolower($column), $tableColumns)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a table builder callback if the given table has a given column.
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $column
|
||||
* @param \Closure $callback
|
||||
* @return void
|
||||
*/
|
||||
public function whenTableHasColumn(string $table, string $column, Closure $callback)
|
||||
{
|
||||
if ($this->hasColumn($table, $column)) {
|
||||
$this->table($table, fn (Blueprint $table) => $callback($table));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a table builder callback if the given table doesn't have a given column.
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $column
|
||||
* @param \Closure $callback
|
||||
* @return void
|
||||
*/
|
||||
public function whenTableDoesntHaveColumn(string $table, string $column, Closure $callback)
|
||||
{
|
||||
if (! $this->hasColumn($table, $column)) {
|
||||
$this->table($table, fn (Blueprint $table) => $callback($table));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a table builder callback if the given table has a given index.
|
||||
*
|
||||
* @param string $table
|
||||
* @param string|array $index
|
||||
* @param \Closure $callback
|
||||
* @param string|null $type
|
||||
* @return void
|
||||
*/
|
||||
public function whenTableHasIndex(string $table, string|array $index, Closure $callback, ?string $type = null)
|
||||
{
|
||||
if ($this->hasIndex($table, $index, $type)) {
|
||||
$this->table($table, fn (Blueprint $table) => $callback($table));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a table builder callback if the given table doesn't have a given index.
|
||||
*
|
||||
* @param string $table
|
||||
* @param string|array $index
|
||||
* @param \Closure $callback
|
||||
* @param string|null $type
|
||||
* @return void
|
||||
*/
|
||||
public function whenTableDoesntHaveIndex(string $table, string|array $index, Closure $callback, ?string $type = null)
|
||||
{
|
||||
if (! $this->hasIndex($table, $index, $type)) {
|
||||
$this->table($table, fn (Blueprint $table) => $callback($table));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data type for the given column name.
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $column
|
||||
* @param bool $fullDefinition
|
||||
* @return string
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getColumnType($table, $column, $fullDefinition = false)
|
||||
{
|
||||
$columns = $this->getColumns($table);
|
||||
|
||||
foreach ($columns as $value) {
|
||||
if (strtolower($value['name']) === strtolower($column)) {
|
||||
return $fullDefinition ? $value['type'] : $value['type_name'];
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException("There is no column with name '$column' on table '$table'.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the column listing for a given table.
|
||||
*
|
||||
* @param string $table
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getColumnListing($table)
|
||||
{
|
||||
return array_column($this->getColumns($table), 'name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the columns for a given table.
|
||||
*
|
||||
* @param string $table
|
||||
* @return list<array{name: string, type: string, type_name: string, nullable: bool, default: mixed, auto_increment: bool, comment: string|null, generation: array{type: string, expression: string|null}|null}>
|
||||
*/
|
||||
public function getColumns($table)
|
||||
{
|
||||
[$schema, $table] = $this->parseSchemaAndTable($table);
|
||||
|
||||
$table = $this->connection->getTablePrefix().$table;
|
||||
|
||||
return $this->connection->getPostProcessor()->processColumns(
|
||||
$this->connection->selectFromWriteConnection(
|
||||
$this->grammar->compileColumns($schema, $table)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the indexes for a given table.
|
||||
*
|
||||
* @param string $table
|
||||
* @return list<array{name: string, columns: list<string>, type: string, unique: bool, primary: bool}>
|
||||
*/
|
||||
public function getIndexes($table)
|
||||
{
|
||||
[$schema, $table] = $this->parseSchemaAndTable($table);
|
||||
|
||||
$table = $this->connection->getTablePrefix().$table;
|
||||
|
||||
return $this->connection->getPostProcessor()->processIndexes(
|
||||
$this->connection->selectFromWriteConnection(
|
||||
$this->grammar->compileIndexes($schema, $table)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of the indexes for a given table.
|
||||
*
|
||||
* @param string $table
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getIndexListing($table)
|
||||
{
|
||||
return array_column($this->getIndexes($table), 'name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given table has a given index.
|
||||
*
|
||||
* @param string $table
|
||||
* @param string|array $index
|
||||
* @param string|null $type
|
||||
* @return bool
|
||||
*/
|
||||
public function hasIndex($table, $index, $type = null)
|
||||
{
|
||||
$type = is_null($type) ? $type : strtolower($type);
|
||||
|
||||
foreach ($this->getIndexes($table) as $value) {
|
||||
$typeMatches = is_null($type)
|
||||
|| ($type === 'primary' && $value['primary'])
|
||||
|| ($type === 'unique' && $value['unique'])
|
||||
|| $type === $value['type'];
|
||||
|
||||
if (($value['name'] === $index || $value['columns'] === $index) && $typeMatches) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the foreign keys for a given table.
|
||||
*
|
||||
* @param string $table
|
||||
* @return array
|
||||
*/
|
||||
public function getForeignKeys($table)
|
||||
{
|
||||
[$schema, $table] = $this->parseSchemaAndTable($table);
|
||||
|
||||
$table = $this->connection->getTablePrefix().$table;
|
||||
|
||||
return $this->connection->getPostProcessor()->processForeignKeys(
|
||||
$this->connection->selectFromWriteConnection(
|
||||
$this->grammar->compileForeignKeys($schema, $table)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify a table on the schema.
|
||||
*
|
||||
* @param string $table
|
||||
* @param \Closure $callback
|
||||
* @return void
|
||||
*/
|
||||
public function table($table, Closure $callback)
|
||||
{
|
||||
$this->build($this->createBlueprint($table, $callback));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new table on the schema.
|
||||
*
|
||||
* @param string $table
|
||||
* @param \Closure $callback
|
||||
* @return void
|
||||
*/
|
||||
public function create($table, Closure $callback)
|
||||
{
|
||||
$this->build(tap($this->createBlueprint($table), function ($blueprint) use ($callback) {
|
||||
$blueprint->create();
|
||||
|
||||
$callback($blueprint);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a table from the schema.
|
||||
*
|
||||
* @param string $table
|
||||
* @return void
|
||||
*/
|
||||
public function drop($table)
|
||||
{
|
||||
$this->build(tap($this->createBlueprint($table), function ($blueprint) {
|
||||
$blueprint->drop();
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a table from the schema if it exists.
|
||||
*
|
||||
* @param string $table
|
||||
* @return void
|
||||
*/
|
||||
public function dropIfExists($table)
|
||||
{
|
||||
$this->build(tap($this->createBlueprint($table), function ($blueprint) {
|
||||
$blueprint->dropIfExists();
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop columns from a table schema.
|
||||
*
|
||||
* @param string $table
|
||||
* @param string|array<string> $columns
|
||||
* @return void
|
||||
*/
|
||||
public function dropColumns($table, $columns)
|
||||
{
|
||||
$this->table($table, function (Blueprint $blueprint) use ($columns) {
|
||||
$blueprint->dropColumn($columns);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all tables from the database.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function dropAllTables()
|
||||
{
|
||||
throw new LogicException('This database driver does not support dropping all tables.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all views from the database.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function dropAllViews()
|
||||
{
|
||||
throw new LogicException('This database driver does not support dropping all views.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all types from the database.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function dropAllTypes()
|
||||
{
|
||||
throw new LogicException('This database driver does not support dropping all types.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename a table on the schema.
|
||||
*
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
* @return void
|
||||
*/
|
||||
public function rename($from, $to)
|
||||
{
|
||||
$this->build(tap($this->createBlueprint($from), function ($blueprint) use ($to) {
|
||||
$blueprint->rename($to);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable foreign key constraints.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function enableForeignKeyConstraints()
|
||||
{
|
||||
return $this->connection->statement(
|
||||
$this->grammar->compileEnableForeignKeyConstraints()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable foreign key constraints.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function disableForeignKeyConstraints()
|
||||
{
|
||||
return $this->connection->statement(
|
||||
$this->grammar->compileDisableForeignKeyConstraints()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable foreign key constraints during the execution of a callback.
|
||||
*
|
||||
* @template TReturn
|
||||
*
|
||||
* @param (\Closure(): TReturn) $callback
|
||||
* @return TReturn
|
||||
*/
|
||||
public function withoutForeignKeyConstraints(Closure $callback)
|
||||
{
|
||||
$this->disableForeignKeyConstraints();
|
||||
|
||||
try {
|
||||
return $callback();
|
||||
} finally {
|
||||
$this->enableForeignKeyConstraints();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the vector extension on the schema if it does not exist.
|
||||
*
|
||||
* @param string|null $schema
|
||||
* @return void
|
||||
*/
|
||||
public function ensureVectorExtensionExists($schema = null)
|
||||
{
|
||||
$this->ensureExtensionExists('vector', $schema);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new extension on the schema if it does not exist.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|null $schema
|
||||
* @return void
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function ensureExtensionExists($name, $schema = null)
|
||||
{
|
||||
if (! $this->getConnection() instanceof PostgresConnection) {
|
||||
throw new RuntimeException('Extensions are only supported by Postgres.');
|
||||
}
|
||||
|
||||
$name = $this->getConnection()->getSchemaGrammar()->wrap($name);
|
||||
|
||||
$this->getConnection()->statement(match (filled($schema)) {
|
||||
true => "create extension if not exists {$name} schema {$this->getConnection()->getSchemaGrammar()->wrap($schema)}",
|
||||
false => "create extension if not exists {$name}",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the blueprint to build / modify the table.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @return void
|
||||
*/
|
||||
protected function build(Blueprint $blueprint)
|
||||
{
|
||||
$blueprint->build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new command set with a Closure.
|
||||
*
|
||||
* @param string $table
|
||||
* @param \Closure|null $callback
|
||||
* @return \Illuminate\Database\Schema\Blueprint
|
||||
*/
|
||||
protected function createBlueprint($table, ?Closure $callback = null)
|
||||
{
|
||||
$connection = $this->connection;
|
||||
|
||||
if (isset($this->resolver)) {
|
||||
return call_user_func($this->resolver, $connection, $table, $callback);
|
||||
}
|
||||
|
||||
return Container::getInstance()->make(Blueprint::class, compact('connection', 'table', 'callback'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of the current schemas for the connection.
|
||||
*
|
||||
* @return string[]|null
|
||||
*/
|
||||
public function getCurrentSchemaListing()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default schema name for the connection.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCurrentSchemaName()
|
||||
{
|
||||
return $this->getCurrentSchemaListing()[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given database object reference and extract the schema and table.
|
||||
*
|
||||
* @param string $reference
|
||||
* @param string|bool|null $withDefaultSchema
|
||||
* @return array{string|null, string}
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function parseSchemaAndTable($reference, $withDefaultSchema = null)
|
||||
{
|
||||
$segments = explode('.', $reference);
|
||||
|
||||
if (count($segments) > 2) {
|
||||
throw new InvalidArgumentException(
|
||||
"Using three-part references is not supported, you may use `Schema::connection('{$segments[0]}')` instead."
|
||||
);
|
||||
}
|
||||
|
||||
$table = $segments[1] ?? $segments[0];
|
||||
|
||||
$schema = match (true) {
|
||||
isset($segments[1]) => $segments[0],
|
||||
is_string($withDefaultSchema) => $withDefaultSchema,
|
||||
$withDefaultSchema => $this->getCurrentSchemaName(),
|
||||
default => null,
|
||||
};
|
||||
|
||||
return [$schema, $table];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the database connection instance.
|
||||
*
|
||||
* @return \Illuminate\Database\Connection
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Schema Blueprint resolver callback.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Database\Connection, string, \Closure|null): \Illuminate\Database\Schema\Blueprint $resolver
|
||||
* @return void
|
||||
*/
|
||||
public function blueprintResolver(Closure $resolver)
|
||||
{
|
||||
$this->resolver = $resolver;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Illuminate\Support\Fluent;
|
||||
|
||||
/**
|
||||
* @method $this after(string $column) Place the column "after" another column (MySQL)
|
||||
* @method $this always(bool $value = true) Used as a modifier for generatedAs() (PostgreSQL)
|
||||
* @method $this autoIncrement() Set INTEGER columns as auto-increment (primary key)
|
||||
* @method $this change() Change the column
|
||||
* @method $this charset(string $charset) Specify a character set for the column (MySQL)
|
||||
* @method $this collation(string $collation) Specify a collation for the column
|
||||
* @method $this comment(string $comment) Add a comment to the column (MySQL/PostgreSQL)
|
||||
* @method $this default(mixed $value) Specify a "default" value for the column
|
||||
* @method $this first() Place the column "first" in the table (MySQL)
|
||||
* @method $this from(int $startingValue) Set the starting value of an auto-incrementing field (MySQL/PostgreSQL)
|
||||
* @method $this fulltext(bool|string $indexName = null) Add a fulltext index
|
||||
* @method $this generatedAs(string|\Illuminate\Contracts\Database\Query\Expression $expression = null) Create a SQL compliant identity column (PostgreSQL)
|
||||
* @method $this instant() Specify that algorithm=instant should be used for the column operation (MySQL)
|
||||
* @method $this index(bool|string $indexName = null) Add an index
|
||||
* @method $this invisible() Specify that the column should be invisible to "SELECT *" (MySQL)
|
||||
* @method $this lock(('none'|'shared'|'default'|'exclusive') $value) Specify the DDL lock mode for the column operation (MySQL)
|
||||
* @method $this nullable(bool $value = true) Allow NULL values to be inserted into the column
|
||||
* @method $this persisted() Mark the computed generated column as persistent (SQL Server)
|
||||
* @method $this primary(bool $value = true) Add a primary index
|
||||
* @method $this spatialIndex(bool|string $indexName = null) Add a spatial index
|
||||
* @method $this vectorIndex(bool|string $indexName = null) Add a vector index
|
||||
* @method $this startingValue(int $startingValue) Set the starting value of an auto-incrementing field (MySQL/PostgreSQL)
|
||||
* @method $this storedAs(string|\Illuminate\Contracts\Database\Query\Expression $expression) Create a stored generated column (MySQL/PostgreSQL/SQLite)
|
||||
* @method $this type(string $type) Specify a type for the column
|
||||
* @method $this unique(bool|string $indexName = null) Add a unique index
|
||||
* @method $this unsigned() Set the INTEGER column as UNSIGNED (MySQL)
|
||||
* @method $this useCurrent() Set the TIMESTAMP column to use CURRENT_TIMESTAMP as default value
|
||||
* @method $this useCurrentOnUpdate() Set the TIMESTAMP column to use CURRENT_TIMESTAMP when updating (MySQL)
|
||||
* @method $this virtualAs(string|\Illuminate\Contracts\Database\Query\Expression $expression) Create a virtual generated column (MySQL/PostgreSQL/SQLite)
|
||||
*/
|
||||
class ColumnDefinition extends Fluent
|
||||
{
|
||||
//
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Illuminate\Support\Stringable;
|
||||
|
||||
class ForeignIdColumnDefinition extends ColumnDefinition
|
||||
{
|
||||
/**
|
||||
* The schema builder blueprint instance.
|
||||
*
|
||||
* @var \Illuminate\Database\Schema\Blueprint
|
||||
*/
|
||||
protected $blueprint;
|
||||
|
||||
/**
|
||||
* Create a new foreign ID column definition.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param array $attributes
|
||||
*/
|
||||
public function __construct(Blueprint $blueprint, $attributes = [])
|
||||
{
|
||||
parent::__construct($attributes);
|
||||
|
||||
$this->blueprint = $blueprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a foreign key constraint on this column referencing the "id" column of the conventionally related table.
|
||||
*
|
||||
* @param string|null $table
|
||||
* @param string|null $column
|
||||
* @param string|null $indexName
|
||||
* @return \Illuminate\Database\Schema\ForeignKeyDefinition
|
||||
*/
|
||||
public function constrained($table = null, $column = null, $indexName = null)
|
||||
{
|
||||
$table ??= $this->table;
|
||||
$column ??= $this->referencesModelColumn ?? 'id';
|
||||
|
||||
return $this->references($column, $indexName)->on($table ?? (new Stringable($this->name))->beforeLast('_'.$column)->plural());
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify which column this foreign ID references on another table.
|
||||
*
|
||||
* @param string $column
|
||||
* @param string|null $indexName
|
||||
* @return \Illuminate\Database\Schema\ForeignKeyDefinition
|
||||
*/
|
||||
public function references($column, $indexName = null)
|
||||
{
|
||||
return $this->blueprint->foreign($this->name, $indexName)->references($column);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Illuminate\Support\Fluent;
|
||||
|
||||
/**
|
||||
* @method ForeignKeyDefinition deferrable(bool $value = true) Set the foreign key as deferrable (PostgreSQL)
|
||||
* @method ForeignKeyDefinition initiallyImmediate(bool $value = true) Set the default time to check the constraint (PostgreSQL)
|
||||
* @method ForeignKeyDefinition lock(('none'|'shared'|'default'|'exclusive') $value) Specify the DDL lock mode for the foreign key operation (MySQL)
|
||||
* @method ForeignKeyDefinition on(string $table) Specify the referenced table
|
||||
* @method ForeignKeyDefinition onDelete(('cascade'|'restrict'|'set null'|'no action') $action) Add an ON DELETE action
|
||||
* @method ForeignKeyDefinition onUpdate(('cascade'|'restrict'|'set null'|'no action') $action) Add an ON UPDATE action
|
||||
* @method ForeignKeyDefinition references(string|string[] $columns) Specify the referenced column(s)
|
||||
*/
|
||||
class ForeignKeyDefinition extends Fluent
|
||||
{
|
||||
/**
|
||||
* Indicate that updates should cascade.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function cascadeOnUpdate()
|
||||
{
|
||||
return $this->onUpdate('cascade');
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that updates should be restricted.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function restrictOnUpdate()
|
||||
{
|
||||
return $this->onUpdate('restrict');
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that updates should set the foreign key value to null.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function nullOnUpdate()
|
||||
{
|
||||
return $this->onUpdate('set null');
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that updates should have "no action".
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function noActionOnUpdate()
|
||||
{
|
||||
return $this->onUpdate('no action');
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that deletes should cascade.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function cascadeOnDelete()
|
||||
{
|
||||
return $this->onDelete('cascade');
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that deletes should be restricted.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function restrictOnDelete()
|
||||
{
|
||||
return $this->onDelete('restrict');
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that deletes should set the foreign key value to null.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function nullOnDelete()
|
||||
{
|
||||
return $this->onDelete('set null');
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that deletes should have "no action".
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function noActionOnDelete()
|
||||
{
|
||||
return $this->onDelete('no action');
|
||||
}
|
||||
}
|
||||
+541
@@ -0,0 +1,541 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema\Grammars;
|
||||
|
||||
use Illuminate\Contracts\Database\Query\Expression;
|
||||
use Illuminate\Database\Concerns\CompilesJsonPaths;
|
||||
use Illuminate\Database\Grammar as BaseGrammar;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Fluent;
|
||||
use RuntimeException;
|
||||
use UnitEnum;
|
||||
|
||||
use function Illuminate\Support\enum_value;
|
||||
|
||||
abstract class Grammar extends BaseGrammar
|
||||
{
|
||||
use CompilesJsonPaths;
|
||||
|
||||
/**
|
||||
* The possible column modifiers.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $modifiers = [];
|
||||
|
||||
/**
|
||||
* If this Grammar supports schema changes wrapped in a transaction.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $transactions = false;
|
||||
|
||||
/**
|
||||
* The commands to be executed outside of create or alter command.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fluentCommands = [];
|
||||
|
||||
/**
|
||||
* Compile a create database command.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
public function compileCreateDatabase($name)
|
||||
{
|
||||
return sprintf('create database %s',
|
||||
$this->wrapValue($name),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a drop database if exists command.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
public function compileDropDatabaseIfExists($name)
|
||||
{
|
||||
return sprintf('drop database if exists %s',
|
||||
$this->wrapValue($name)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the query to determine the schemas.
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function compileSchemas()
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support retrieving schemas.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the query to determine if the given table exists.
|
||||
*
|
||||
* @param string|null $schema
|
||||
* @param string $table
|
||||
* @return string|null
|
||||
*/
|
||||
public function compileTableExists($schema, $table)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the query to determine the tables.
|
||||
*
|
||||
* @param string|string[]|null $schema
|
||||
* @return string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function compileTables($schema)
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support retrieving tables.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the query to determine the views.
|
||||
*
|
||||
* @param string|string[]|null $schema
|
||||
* @return string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function compileViews($schema)
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support retrieving views.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the query to determine the user-defined types.
|
||||
*
|
||||
* @param string|string[]|null $schema
|
||||
* @return string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function compileTypes($schema)
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support retrieving user-defined types.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the query to determine the columns.
|
||||
*
|
||||
* @param string|null $schema
|
||||
* @param string $table
|
||||
* @return string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function compileColumns($schema, $table)
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support retrieving columns.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the query to determine the indexes.
|
||||
*
|
||||
* @param string|null $schema
|
||||
* @param string $table
|
||||
* @return string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function compileIndexes($schema, $table)
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support retrieving indexes.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a vector index key command.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param \Illuminate\Support\Fluent $command
|
||||
* @return void
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function compileVectorIndex(Blueprint $blueprint, Fluent $command)
|
||||
{
|
||||
throw new RuntimeException('The database driver in use does not support vector indexes.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the query to determine the foreign keys.
|
||||
*
|
||||
* @param string|null $schema
|
||||
* @param string $table
|
||||
* @return string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function compileForeignKeys($schema, $table)
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support retrieving foreign keys.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a rename column command.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param \Illuminate\Support\Fluent $command
|
||||
* @return list<string>|string
|
||||
*/
|
||||
public function compileRenameColumn(Blueprint $blueprint, Fluent $command)
|
||||
{
|
||||
return sprintf('alter table %s rename column %s to %s',
|
||||
$this->wrapTable($blueprint),
|
||||
$this->wrap($command->from),
|
||||
$this->wrap($command->to)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a change column command into a series of SQL statements.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param \Illuminate\Support\Fluent $command
|
||||
* @return list<string>|string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function compileChange(Blueprint $blueprint, Fluent $command)
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support modifying columns.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a fulltext index key command.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param \Illuminate\Support\Fluent $command
|
||||
* @return string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function compileFulltext(Blueprint $blueprint, Fluent $command)
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support fulltext index creation.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a drop fulltext index command.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param \Illuminate\Support\Fluent $command
|
||||
* @return string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function compileDropFullText(Blueprint $blueprint, Fluent $command)
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support fulltext index removal.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a foreign key command.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param \Illuminate\Support\Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function compileForeign(Blueprint $blueprint, Fluent $command)
|
||||
{
|
||||
// We need to prepare several of the elements of the foreign key definition
|
||||
// before we can create the SQL, such as wrapping the tables and convert
|
||||
// an array of columns to comma-delimited strings for the SQL queries.
|
||||
$sql = sprintf('alter table %s add constraint %s ',
|
||||
$this->wrapTable($blueprint),
|
||||
$this->wrap($command->index)
|
||||
);
|
||||
|
||||
// Once we have the initial portion of the SQL statement we will add on the
|
||||
// key name, table name, and referenced columns. These will complete the
|
||||
// main portion of the SQL statement and this SQL will almost be done.
|
||||
$sql .= sprintf('foreign key (%s) references %s (%s)',
|
||||
$this->columnize($command->columns),
|
||||
$this->wrapTable($command->on),
|
||||
$this->columnize((array) $command->references)
|
||||
);
|
||||
|
||||
// Once we have the basic foreign key creation statement constructed we can
|
||||
// build out the syntax for what should happen on an update or delete of
|
||||
// the affected columns, which will get something like "cascade", etc.
|
||||
if (! is_null($command->onDelete)) {
|
||||
$sql .= " on delete {$command->onDelete}";
|
||||
}
|
||||
|
||||
if (! is_null($command->onUpdate)) {
|
||||
$sql .= " on update {$command->onUpdate}";
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a drop foreign key command.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param \Illuminate\Support\Fluent $command
|
||||
* @return string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function compileDropForeign(Blueprint $blueprint, Fluent $command)
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support dropping foreign keys.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the blueprint's added column definitions.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @return array
|
||||
*/
|
||||
protected function getColumns(Blueprint $blueprint)
|
||||
{
|
||||
$columns = [];
|
||||
|
||||
foreach ($blueprint->getAddedColumns() as $column) {
|
||||
$columns[] = $this->getColumn($blueprint, $column);
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the column definition.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param \Illuminate\Database\Schema\ColumnDefinition $column
|
||||
* @return string
|
||||
*/
|
||||
protected function getColumn(Blueprint $blueprint, $column)
|
||||
{
|
||||
// Each of the column types has their own compiler functions, which are tasked
|
||||
// with turning the column definition into its SQL format for this platform
|
||||
// used by the connection. The column's modifiers are compiled and added.
|
||||
$sql = $this->wrap($column).' '.$this->getType($column);
|
||||
|
||||
return $this->addModifiers($sql, $blueprint, $column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL for the column data type.
|
||||
*
|
||||
* @param \Illuminate\Support\Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function getType(Fluent $column)
|
||||
{
|
||||
return $this->{'type'.ucfirst($column->type)}($column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the column definition for a generated, computed column type.
|
||||
*
|
||||
* @param \Illuminate\Support\Fluent $column
|
||||
* @return void
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function typeComputed(Fluent $column)
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support the computed type.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the column definition for a vector type.
|
||||
*
|
||||
* @param \Illuminate\Support\Fluent $column
|
||||
* @return string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function typeVector(Fluent $column)
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support the vector type.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the column definition for a tsvector type.
|
||||
*
|
||||
* @param \Illuminate\Support\Fluent $column
|
||||
* @return string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function typeTsvector(Fluent $column)
|
||||
{
|
||||
throw new RuntimeException('This database driver does not support the tsvector type.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the column definition for a raw column type.
|
||||
*
|
||||
* @param \Illuminate\Support\Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function typeRaw(Fluent $column)
|
||||
{
|
||||
return $column->offsetGet('definition');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the column modifiers to the definition.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param \Illuminate\Support\Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function addModifiers($sql, Blueprint $blueprint, Fluent $column)
|
||||
{
|
||||
foreach ($this->modifiers as $modifier) {
|
||||
if (method_exists($this, $method = "modify{$modifier}")) {
|
||||
$sql .= $this->{$method}($blueprint, $column);
|
||||
}
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the command with a given name if it exists on the blueprint.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param string $name
|
||||
* @return \Illuminate\Support\Fluent|null
|
||||
*/
|
||||
protected function getCommandByName(Blueprint $blueprint, $name)
|
||||
{
|
||||
$commands = $this->getCommandsByName($blueprint, $name);
|
||||
|
||||
if (count($commands) > 0) {
|
||||
return array_first($commands);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the commands with a given name.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param string $name
|
||||
* @return array
|
||||
*/
|
||||
protected function getCommandsByName(Blueprint $blueprint, $name)
|
||||
{
|
||||
return array_filter($blueprint->getCommands(), function ($value) use ($name) {
|
||||
return $value->name == $name;
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if a command with a given name exists on the blueprint.
|
||||
*
|
||||
* @param \Illuminate\Database\Schema\Blueprint $blueprint
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasCommand(Blueprint $blueprint, $name)
|
||||
{
|
||||
foreach ($blueprint->getCommands() as $command) {
|
||||
if ($command->name === $name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a prefix to an array of values.
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param array<string> $values
|
||||
* @return array<string>
|
||||
*/
|
||||
public function prefixArray($prefix, array $values)
|
||||
{
|
||||
return array_map(function ($value) use ($prefix) {
|
||||
return $prefix.' '.$value;
|
||||
}, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a table in keyword identifiers.
|
||||
*
|
||||
* @param mixed $table
|
||||
* @param string|null $prefix
|
||||
* @return string
|
||||
*/
|
||||
public function wrapTable($table, $prefix = null)
|
||||
{
|
||||
return parent::wrapTable(
|
||||
$table instanceof Blueprint ? $table->getTable() : $table,
|
||||
$prefix
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a value in keyword identifiers.
|
||||
*
|
||||
* @param \Illuminate\Support\Fluent|\Illuminate\Contracts\Database\Query\Expression|string $value
|
||||
* @return string
|
||||
*/
|
||||
public function wrap($value)
|
||||
{
|
||||
return parent::wrap(
|
||||
$value instanceof Fluent ? $value->name : $value,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a value so that it can be used in "default" clauses.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
protected function getDefaultValue($value)
|
||||
{
|
||||
if ($value instanceof Expression) {
|
||||
return $this->getValue($value);
|
||||
}
|
||||
|
||||
if ($value instanceof UnitEnum) {
|
||||
return "'".str_replace("'", "''", enum_value($value))."'";
|
||||
}
|
||||
|
||||
return is_bool($value)
|
||||
? "'".(int) $value."'"
|
||||
: "'".str_replace("'", "''", $value)."'";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fluent commands for the grammar.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFluentCommands()
|
||||
{
|
||||
return $this->fluentCommands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this Grammar supports schema changes wrapped in a transaction.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function supportsSchemaTransactions()
|
||||
{
|
||||
return $this->transactions;
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema\Grammars;
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Fluent;
|
||||
|
||||
class MariaDbGrammar extends MySqlGrammar
|
||||
{
|
||||
/** @inheritDoc */
|
||||
public function compileRenameColumn(Blueprint $blueprint, Fluent $command)
|
||||
{
|
||||
if (version_compare($this->connection->getServerVersion(), '10.5.2', '<')) {
|
||||
return $this->compileLegacyRenameColumn($blueprint, $command);
|
||||
}
|
||||
|
||||
return parent::compileRenameColumn($blueprint, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the column definition for a uuid type.
|
||||
*
|
||||
* @param \Illuminate\Support\Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function typeUuid(Fluent $column)
|
||||
{
|
||||
if (version_compare($this->connection->getServerVersion(), '10.7.0', '<')) {
|
||||
return 'char(36)';
|
||||
}
|
||||
|
||||
return 'uuid';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the column definition for a spatial Geometry type.
|
||||
*
|
||||
* @param \Illuminate\Support\Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function typeGeometry(Fluent $column)
|
||||
{
|
||||
$subtype = $column->subtype ? strtolower($column->subtype) : null;
|
||||
|
||||
if (! in_array($subtype, ['point', 'linestring', 'polygon', 'geometrycollection', 'multipoint', 'multilinestring', 'multipolygon'])) {
|
||||
$subtype = null;
|
||||
}
|
||||
|
||||
return sprintf('%s%s',
|
||||
$subtype ?? 'geometry',
|
||||
$column->srid ? ' ref_system_id='.$column->srid : ''
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the given JSON selector.
|
||||
*
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
protected function wrapJsonSelector($value)
|
||||
{
|
||||
[$field, $path] = $this->wrapJsonFieldAndPath($value);
|
||||
|
||||
return 'json_value('.$field.$path.')';
|
||||
}
|
||||
}
|
||||
+1435
File diff suppressed because it is too large
Load Diff
+1347
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1045
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Illuminate\Support\Fluent;
|
||||
|
||||
/**
|
||||
* @method $this algorithm(string $algorithm) Specify an algorithm for the index (MySQL/PostgreSQL)
|
||||
* @method $this deferrable(bool $value = true) Specify that the unique index is deferrable (PostgreSQL)
|
||||
* @method $this initiallyImmediate(bool $value = true) Specify the default time to check the unique index constraint (PostgreSQL)
|
||||
* @method $this language(string $language) Specify a language for the full text index (PostgreSQL)
|
||||
* @method $this lock(('none'|'shared'|'default'|'exclusive') $value) Specify the DDL lock mode for the index operation (MySQL)
|
||||
* @method $this nullsNotDistinct(bool $value = true) Specify that the null values should not be treated as distinct (PostgreSQL)
|
||||
* @method $this online(bool $value = true) Specify that index creation should not lock the table (PostgreSQL/SqlServer)
|
||||
*/
|
||||
class IndexDefinition extends Fluent
|
||||
{
|
||||
//
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
class MariaDbBuilder extends MySqlBuilder
|
||||
{
|
||||
//
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||
|
||||
class MariaDbSchemaState extends MySqlSchemaState
|
||||
{
|
||||
/**
|
||||
* Load the given schema file into the database.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function load($path)
|
||||
{
|
||||
$versionInfo = $this->detectClientVersion();
|
||||
|
||||
$command = 'mariadb '.$this->connectionString($versionInfo).' --database="${:LARAVEL_LOAD_DATABASE}" < "${:LARAVEL_LOAD_PATH}"';
|
||||
|
||||
$process = $this->makeProcess($command)->setTimeout(null);
|
||||
|
||||
$process->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [
|
||||
'LARAVEL_LOAD_PATH' => $path,
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base dump command arguments for MariaDB as a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function baseDumpCommand()
|
||||
{
|
||||
$versionInfo = $this->detectClientVersion();
|
||||
|
||||
$command = 'mariadb-dump '.$this->connectionString($versionInfo).' --no-tablespaces --skip-add-locks --skip-comments --skip-set-charset --tz-utc';
|
||||
|
||||
return $command.' "${:LARAVEL_LOAD_DATABASE}"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the MariaDB client version.
|
||||
*
|
||||
* @return array{version: string, isMariaDb: bool}
|
||||
*/
|
||||
protected function detectClientVersion(): array
|
||||
{
|
||||
// Minimum version of MariaDB that supports the mariadb command...
|
||||
$version = '10.5.2';
|
||||
|
||||
try {
|
||||
$versionOutput = $this->makeProcess('mariadb --version')->mustRun()->getOutput();
|
||||
|
||||
if (preg_match('/(\d+\.\d+\.\d+)/', $versionOutput, $matches)) {
|
||||
$version = $matches[1];
|
||||
}
|
||||
} catch (ProcessFailedException) {
|
||||
}
|
||||
|
||||
return [
|
||||
'isMariaDb' => true,
|
||||
'version' => $version,
|
||||
];
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
class MySqlBuilder extends Builder
|
||||
{
|
||||
/**
|
||||
* Drop all tables from the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropAllTables()
|
||||
{
|
||||
$tables = $this->getTableListing($this->getCurrentSchemaListing());
|
||||
|
||||
if (empty($tables)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->disableForeignKeyConstraints();
|
||||
|
||||
try {
|
||||
$this->connection->statement(
|
||||
$this->grammar->compileDropAllTables($tables)
|
||||
);
|
||||
} finally {
|
||||
$this->enableForeignKeyConstraints();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all views from the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropAllViews()
|
||||
{
|
||||
$views = array_column($this->getViews($this->getCurrentSchemaListing()), 'schema_qualified_name');
|
||||
|
||||
if (empty($views)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->connection->statement(
|
||||
$this->grammar->compileDropAllViews($views)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of current schemas for the connection.
|
||||
*
|
||||
* @return string[]|null
|
||||
*/
|
||||
public function getCurrentSchemaListing()
|
||||
{
|
||||
return [$this->connection->getDatabaseName()];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class MySqlSchemaState extends SchemaState
|
||||
{
|
||||
/**
|
||||
* Dump the database's schema into a file.
|
||||
*
|
||||
* @param \Illuminate\Database\Connection $connection
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function dump(Connection $connection, $path)
|
||||
{
|
||||
$this->executeDumpProcess($this->makeProcess(
|
||||
$this->baseDumpCommand().' --routines --result-file="${:LARAVEL_LOAD_PATH}" --no-data'
|
||||
), $this->output, array_merge($this->baseVariables($this->connection->getConfig()), [
|
||||
'LARAVEL_LOAD_PATH' => $path,
|
||||
]));
|
||||
|
||||
$this->removeAutoIncrementingState($path);
|
||||
|
||||
if ($this->hasMigrationTable()) {
|
||||
$this->appendMigrationData($path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the auto-incrementing state from the given schema dump.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
protected function removeAutoIncrementingState(string $path)
|
||||
{
|
||||
$this->files->put($path, preg_replace(
|
||||
'/\s+AUTO_INCREMENT=[0-9]+/iu',
|
||||
'',
|
||||
$this->files->get($path)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the migration data to the schema dump.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
protected function appendMigrationData(string $path)
|
||||
{
|
||||
$process = $this->executeDumpProcess($this->makeProcess(
|
||||
$this->baseDumpCommand().' '.$this->getMigrationTable().' --no-create-info --skip-extended-insert --skip-routines --compact --complete-insert'
|
||||
), null, array_merge($this->baseVariables($this->connection->getConfig()), [
|
||||
//
|
||||
]));
|
||||
|
||||
$this->files->append($path, $process->getOutput());
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the given schema file into the database.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function load($path)
|
||||
{
|
||||
$versionInfo = $this->detectClientVersion();
|
||||
|
||||
$command = 'mysql '.$this->connectionString($versionInfo).' --database="${:LARAVEL_LOAD_DATABASE}" < "${:LARAVEL_LOAD_PATH}"';
|
||||
|
||||
$process = $this->makeProcess($command)->setTimeout(null);
|
||||
|
||||
$process->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [
|
||||
'LARAVEL_LOAD_PATH' => $path,
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base dump command arguments for MySQL as a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function baseDumpCommand()
|
||||
{
|
||||
$versionInfo = $this->detectClientVersion();
|
||||
|
||||
$command = 'mysqldump '.$this->connectionString($versionInfo).' --no-tablespaces --skip-add-locks --skip-comments --skip-set-charset --tz-utc --column-statistics=0';
|
||||
|
||||
if (! $this->connection->isMaria()) {
|
||||
$command .= ' --set-gtid-purged=OFF';
|
||||
}
|
||||
|
||||
return $command.' "${:LARAVEL_LOAD_DATABASE}"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a basic connection string (--socket, --host, --port, --user, --password) for the database.
|
||||
*
|
||||
* @param array{version: string, isMariaDb: bool} $versionInfo
|
||||
* @return string
|
||||
*/
|
||||
protected function connectionString(array $versionInfo)
|
||||
{
|
||||
$value = ' --user="${:LARAVEL_LOAD_USER}" --password="${:LARAVEL_LOAD_PASSWORD}"';
|
||||
|
||||
$config = $this->connection->getConfig();
|
||||
|
||||
$value .= $config['unix_socket'] ?? false
|
||||
? ' --socket="${:LARAVEL_LOAD_SOCKET}"'
|
||||
: ' --host="${:LARAVEL_LOAD_HOST}" --port="${:LARAVEL_LOAD_PORT}"';
|
||||
|
||||
if (isset($config['options'][PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_CA : \PDO::MYSQL_ATTR_SSL_CA])) {
|
||||
$value .= ' --ssl-ca="${:LARAVEL_LOAD_SSL_CA}"';
|
||||
}
|
||||
|
||||
if (isset($config['options'][PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_CERT : \PDO::MYSQL_ATTR_SSL_CERT])) {
|
||||
$value .= ' --ssl-cert="${:LARAVEL_LOAD_SSL_CERT}"';
|
||||
}
|
||||
|
||||
if (isset($config['options'][PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_KEY : \PDO::MYSQL_ATTR_SSL_KEY])) {
|
||||
$value .= ' --ssl-key="${:LARAVEL_LOAD_SSL_KEY}"';
|
||||
}
|
||||
|
||||
$verifyCertOption = PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_VERIFY_SERVER_CERT : \PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT;
|
||||
|
||||
if (isset($config['options'][$verifyCertOption]) && $config['options'][$verifyCertOption] === false) {
|
||||
if (version_compare($versionInfo['version'], '5.7.11', '>=') && ! $versionInfo['isMariaDb']) {
|
||||
$value .= ' --ssl-mode=DISABLED';
|
||||
} else {
|
||||
$value .= ' --ssl=off';
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base variables for a dump / load command.
|
||||
*
|
||||
* @param array $config
|
||||
* @return array
|
||||
*/
|
||||
protected function baseVariables(array $config)
|
||||
{
|
||||
$config['host'] ??= '';
|
||||
|
||||
return [
|
||||
'LARAVEL_LOAD_SOCKET' => $config['unix_socket'] ?? '',
|
||||
'LARAVEL_LOAD_HOST' => is_array($config['host']) ? $config['host'][0] : $config['host'],
|
||||
'LARAVEL_LOAD_PORT' => $config['port'] ?? '',
|
||||
'LARAVEL_LOAD_USER' => $config['username'],
|
||||
'LARAVEL_LOAD_PASSWORD' => $config['password'] ?? '',
|
||||
'LARAVEL_LOAD_DATABASE' => $config['database'],
|
||||
'LARAVEL_LOAD_SSL_CA' => $config['options'][PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_CA : \PDO::MYSQL_ATTR_SSL_CA] ?? '',
|
||||
'LARAVEL_LOAD_SSL_CERT' => $config['options'][PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_CERT : \PDO::MYSQL_ATTR_SSL_CERT] ?? '',
|
||||
'LARAVEL_LOAD_SSL_KEY' => $config['options'][PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_KEY : \PDO::MYSQL_ATTR_SSL_KEY] ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given dump process.
|
||||
*
|
||||
* @param \Symfony\Component\Process\Process $process
|
||||
* @param callable $output
|
||||
* @param array $variables
|
||||
* @param int $depth
|
||||
* @return \Symfony\Component\Process\Process
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
protected function executeDumpProcess(Process $process, $output, array $variables, int $depth = 0)
|
||||
{
|
||||
if ($depth > 30) {
|
||||
throw new Exception('Dump execution exceeded maximum depth of 30.');
|
||||
}
|
||||
|
||||
try {
|
||||
$process->setTimeout(null)->mustRun($output, $variables);
|
||||
} catch (Exception $e) {
|
||||
if (Str::contains($e->getMessage(), ['column-statistics', 'column_statistics'])) {
|
||||
return $this->executeDumpProcess(Process::fromShellCommandLine(
|
||||
str_replace(' --column-statistics=0', '', $process->getCommandLine())
|
||||
), $output, $variables, $depth + 1);
|
||||
}
|
||||
|
||||
if (str_contains($e->getMessage(), 'set-gtid-purged')) {
|
||||
return $this->executeDumpProcess(Process::fromShellCommandLine(
|
||||
str_replace(' --set-gtid-purged=OFF', '', $process->getCommandLine())
|
||||
), $output, $variables, $depth + 1);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $process;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the MySQL client version.
|
||||
*
|
||||
* @return array{version: string, isMariaDb: bool}
|
||||
*/
|
||||
protected function detectClientVersion(): array
|
||||
{
|
||||
[$version, $isMariaDb] = ['8.0.0', false];
|
||||
|
||||
try {
|
||||
$versionOutput = $this->makeProcess('mysql --version')->mustRun()->getOutput();
|
||||
|
||||
if (preg_match('/(\d+\.\d+\.\d+)/', $versionOutput, $matches)) {
|
||||
$version = $matches[1];
|
||||
}
|
||||
|
||||
$isMariaDb = stripos($versionOutput, 'mariadb') !== false;
|
||||
} catch (ProcessFailedException) {
|
||||
}
|
||||
|
||||
return [
|
||||
'version' => $version,
|
||||
'isMariaDb' => $isMariaDb,
|
||||
];
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Illuminate\Database\Concerns\ParsesSearchPath;
|
||||
|
||||
class PostgresBuilder extends Builder
|
||||
{
|
||||
use ParsesSearchPath;
|
||||
|
||||
/**
|
||||
* Drop all tables from the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropAllTables()
|
||||
{
|
||||
$tables = [];
|
||||
|
||||
$excludedTables = $this->connection->getConfig('dont_drop') ?? ['spatial_ref_sys'];
|
||||
|
||||
foreach ($this->getTables($this->getCurrentSchemaListing()) as $table) {
|
||||
if (empty(array_intersect([$table['name'], $table['schema_qualified_name']], $excludedTables))) {
|
||||
$tables[] = $table['schema_qualified_name'];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($tables)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->connection->statement(
|
||||
$this->grammar->compileDropAllTables($tables)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all views from the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropAllViews()
|
||||
{
|
||||
$views = array_column($this->getViews($this->getCurrentSchemaListing()), 'schema_qualified_name');
|
||||
|
||||
if (empty($views)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->connection->statement(
|
||||
$this->grammar->compileDropAllViews($views)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all types from the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropAllTypes()
|
||||
{
|
||||
$types = [];
|
||||
$domains = [];
|
||||
|
||||
foreach ($this->getTypes($this->getCurrentSchemaListing()) as $type) {
|
||||
if (! $type['implicit']) {
|
||||
if ($type['type'] === 'domain') {
|
||||
$domains[] = $type['schema_qualified_name'];
|
||||
} else {
|
||||
$types[] = $type['schema_qualified_name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($types)) {
|
||||
$this->connection->statement($this->grammar->compileDropAllTypes($types));
|
||||
}
|
||||
|
||||
if (! empty($domains)) {
|
||||
$this->connection->statement($this->grammar->compileDropAllDomains($domains));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current schemas for the connection.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getCurrentSchemaListing()
|
||||
{
|
||||
return array_map(
|
||||
fn ($schema) => $schema === '$user' ? $this->connection->getConfig('username') : $schema,
|
||||
$this->parseSearchPath(
|
||||
$this->connection->getConfig('search_path')
|
||||
?: $this->connection->getConfig('schema')
|
||||
?: 'public'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class PostgresSchemaState extends SchemaState
|
||||
{
|
||||
/**
|
||||
* Dump the database's schema into a file.
|
||||
*
|
||||
* @param \Illuminate\Database\Connection $connection
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function dump(Connection $connection, $path)
|
||||
{
|
||||
$commands = new Collection([
|
||||
$this->baseDumpCommand().' --schema-only > '.$path,
|
||||
]);
|
||||
|
||||
if ($this->hasMigrationTable()) {
|
||||
$commands->push($this->baseDumpCommand().' -t '.$this->getMigrationTable().' --data-only >> '.$path);
|
||||
}
|
||||
|
||||
$commands->map(function ($command, $path) {
|
||||
$this->makeProcess($command)->mustRun($this->output, array_merge($this->baseVariables($this->connection->getConfig()), [
|
||||
'LARAVEL_LOAD_PATH' => $path,
|
||||
]));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the given schema file into the database.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function load($path)
|
||||
{
|
||||
$command = 'pg_restore --no-owner --no-acl --clean --if-exists --host="${:LARAVEL_LOAD_HOST}" --port="${:LARAVEL_LOAD_PORT}" --username="${:LARAVEL_LOAD_USER}" --dbname="${:LARAVEL_LOAD_DATABASE}" "${:LARAVEL_LOAD_PATH}"';
|
||||
|
||||
if (str_ends_with($path, '.sql')) {
|
||||
$command = 'psql --file="${:LARAVEL_LOAD_PATH}" --host="${:LARAVEL_LOAD_HOST}" --port="${:LARAVEL_LOAD_PORT}" --username="${:LARAVEL_LOAD_USER}" --dbname="${:LARAVEL_LOAD_DATABASE}"';
|
||||
}
|
||||
|
||||
$process = $this->makeProcess($command);
|
||||
|
||||
$process->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [
|
||||
'LARAVEL_LOAD_PATH' => $path,
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the application's migration table.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getMigrationTable(): string
|
||||
{
|
||||
[$schema, $table] = $this->connection->getSchemaBuilder()->parseSchemaAndTable($this->migrationTable, withDefaultSchema: true);
|
||||
|
||||
return $schema.'.'.$this->connection->getTablePrefix().$table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base dump command arguments for PostgreSQL as a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function baseDumpCommand()
|
||||
{
|
||||
return 'pg_dump --no-owner --no-acl --host="${:LARAVEL_LOAD_HOST}" --port="${:LARAVEL_LOAD_PORT}" --username="${:LARAVEL_LOAD_USER}" --dbname="${:LARAVEL_LOAD_DATABASE}"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base variables for a dump / load command.
|
||||
*
|
||||
* @param array $config
|
||||
* @return array
|
||||
*/
|
||||
protected function baseVariables(array $config)
|
||||
{
|
||||
$config['host'] ??= '';
|
||||
|
||||
return [
|
||||
'LARAVEL_LOAD_HOST' => is_array($config['host']) ? $config['host'][0] : $config['host'],
|
||||
'LARAVEL_LOAD_PORT' => $config['port'] ?? '',
|
||||
'LARAVEL_LOAD_USER' => $config['username'],
|
||||
'PGPASSWORD' => $config['password'],
|
||||
'LARAVEL_LOAD_DATABASE' => $config['database'],
|
||||
];
|
||||
}
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class SQLiteBuilder extends Builder
|
||||
{
|
||||
/**
|
||||
* Create a database in the schema.
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function createDatabase($name)
|
||||
{
|
||||
return File::put($name, '') !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a database from the schema if the database exists.
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function dropDatabaseIfExists($name)
|
||||
{
|
||||
return ! File::exists($name) || File::delete($name);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getTables($schema = null)
|
||||
{
|
||||
try {
|
||||
$withSize = $this->connection->scalar($this->grammar->compileDbstatExists());
|
||||
} catch (QueryException) {
|
||||
$withSize = false;
|
||||
}
|
||||
|
||||
if (version_compare($this->connection->getServerVersion(), '3.37.0', '<')) {
|
||||
$schema ??= array_column($this->getSchemas(), 'name');
|
||||
|
||||
$tables = [];
|
||||
|
||||
foreach (Arr::wrap($schema) as $name) {
|
||||
$tables = array_merge($tables, $this->connection->selectFromWriteConnection(
|
||||
$this->grammar->compileLegacyTables($name, $withSize)
|
||||
));
|
||||
}
|
||||
|
||||
return $this->connection->getPostProcessor()->processTables($tables);
|
||||
}
|
||||
|
||||
return $this->connection->getPostProcessor()->processTables(
|
||||
$this->connection->selectFromWriteConnection(
|
||||
$this->grammar->compileTables($schema)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getViews($schema = null)
|
||||
{
|
||||
$schema ??= array_column($this->getSchemas(), 'name');
|
||||
|
||||
$views = [];
|
||||
|
||||
foreach (Arr::wrap($schema) as $name) {
|
||||
$views = array_merge($views, $this->connection->selectFromWriteConnection(
|
||||
$this->grammar->compileViews($name)
|
||||
));
|
||||
}
|
||||
|
||||
return $this->connection->getPostProcessor()->processViews($views);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function getColumns($table)
|
||||
{
|
||||
[$schema, $table] = $this->parseSchemaAndTable($table);
|
||||
|
||||
$table = $this->connection->getTablePrefix().$table;
|
||||
|
||||
return $this->connection->getPostProcessor()->processColumns(
|
||||
$this->connection->selectFromWriteConnection($this->grammar->compileColumns($schema, $table)),
|
||||
$this->connection->scalar($this->grammar->compileSqlCreateStatement($schema, $table))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all tables from the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropAllTables()
|
||||
{
|
||||
foreach ($this->getCurrentSchemaListing() as $schema) {
|
||||
$database = $schema === 'main'
|
||||
? $this->connection->getDatabaseName()
|
||||
: (array_column($this->getSchemas(), 'path', 'name')[$schema] ?: ':memory:');
|
||||
|
||||
if ($database !== ':memory:' &&
|
||||
! str_contains($database, '?mode=memory') &&
|
||||
! str_contains($database, '&mode=memory')
|
||||
) {
|
||||
$this->refreshDatabaseFile($database);
|
||||
} else {
|
||||
$this->pragma('writable_schema', 1);
|
||||
|
||||
$this->connection->statement($this->grammar->compileDropAllTables($schema));
|
||||
|
||||
$this->pragma('writable_schema', 0);
|
||||
|
||||
$this->connection->statement($this->grammar->compileRebuild($schema));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all views from the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropAllViews()
|
||||
{
|
||||
foreach ($this->getCurrentSchemaListing() as $schema) {
|
||||
$this->pragma('writable_schema', 1);
|
||||
|
||||
$this->connection->statement($this->grammar->compileDropAllViews($schema));
|
||||
|
||||
$this->pragma('writable_schema', 0);
|
||||
|
||||
$this->connection->statement($this->grammar->compileRebuild($schema));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value for the given pragma name or set the given value.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function pragma($key, $value = null)
|
||||
{
|
||||
return is_null($value)
|
||||
? $this->connection->scalar($this->grammar->pragma($key))
|
||||
: $this->connection->statement($this->grammar->pragma($key, $value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty the database file.
|
||||
*
|
||||
* @param string|null $path
|
||||
* @return void
|
||||
*/
|
||||
public function refreshDatabaseFile($path = null)
|
||||
{
|
||||
file_put_contents($path ?? $this->connection->getDatabaseName(), '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of current schemas for the connection.
|
||||
*
|
||||
* @return string[]|null
|
||||
*/
|
||||
public function getCurrentSchemaListing()
|
||||
{
|
||||
return ['main'];
|
||||
}
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
abstract class SchemaState
|
||||
{
|
||||
/**
|
||||
* The connection instance.
|
||||
*
|
||||
* @var \Illuminate\Database\Connection
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* The filesystem instance.
|
||||
*
|
||||
* @var \Illuminate\Filesystem\Filesystem
|
||||
*/
|
||||
protected $files;
|
||||
|
||||
/**
|
||||
* The name of the application's migration table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $migrationTable = 'migrations';
|
||||
|
||||
/**
|
||||
* The process factory callback.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
protected $processFactory;
|
||||
|
||||
/**
|
||||
* The output callable instance.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* Create a new dumper instance.
|
||||
*
|
||||
* @param \Illuminate\Database\Connection $connection
|
||||
* @param \Illuminate\Filesystem\Filesystem|null $files
|
||||
* @param callable|null $processFactory
|
||||
*/
|
||||
public function __construct(Connection $connection, ?Filesystem $files = null, ?callable $processFactory = null)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
|
||||
$this->files = $files ?: new Filesystem;
|
||||
|
||||
$this->processFactory = $processFactory ?: function (...$arguments) {
|
||||
return Process::fromShellCommandline(...$arguments)->setTimeout(null);
|
||||
};
|
||||
|
||||
$this->handleOutputUsing(function () {
|
||||
//
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the database's schema into a file.
|
||||
*
|
||||
* @param \Illuminate\Database\Connection $connection
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
abstract public function dump(Connection $connection, $path);
|
||||
|
||||
/**
|
||||
* Load the given schema file into the database.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
abstract public function load($path);
|
||||
|
||||
/**
|
||||
* Create a new process instance.
|
||||
*
|
||||
* @param mixed ...$arguments
|
||||
* @return \Symfony\Component\Process\Process
|
||||
*/
|
||||
public function makeProcess(...$arguments)
|
||||
{
|
||||
return call_user_func($this->processFactory, ...$arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current connection has a migration table.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasMigrationTable(): bool
|
||||
{
|
||||
return $this->connection->getSchemaBuilder()->hasTable($this->migrationTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the application's migration table.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getMigrationTable(): string
|
||||
{
|
||||
return $this->connection->getTablePrefix().$this->migrationTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the name of the application's migration table.
|
||||
*
|
||||
* @param string $table
|
||||
* @return $this
|
||||
*/
|
||||
public function withMigrationTable(string $table)
|
||||
{
|
||||
$this->migrationTable = $table;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the callback that should be used to handle process output.
|
||||
*
|
||||
* @param callable $output
|
||||
* @return $this
|
||||
*/
|
||||
public function handleOutputUsing(callable $output)
|
||||
{
|
||||
$this->output = $output;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class SqlServerBuilder extends Builder
|
||||
{
|
||||
/**
|
||||
* Drop all tables from the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropAllTables()
|
||||
{
|
||||
$this->connection->statement($this->grammar->compileDropAllForeignKeys());
|
||||
|
||||
$this->connection->statement($this->grammar->compileDropAllTables());
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop all views from the database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropAllViews()
|
||||
{
|
||||
$this->connection->statement($this->grammar->compileDropAllViews());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default schema name for the connection.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCurrentSchemaName()
|
||||
{
|
||||
return Arr::first($this->getSchemas(), fn ($schema) => $schema['default'])['name'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Illuminate\Database\Schema;
|
||||
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class SqliteSchemaState extends SchemaState
|
||||
{
|
||||
/**
|
||||
* Dump the database's schema into a file.
|
||||
*
|
||||
* @param \Illuminate\Database\Connection $connection
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function dump(Connection $connection, $path)
|
||||
{
|
||||
$process = $this->makeProcess($this->baseCommand().' ".schema --indent"')
|
||||
->setTimeout(null)
|
||||
->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [
|
||||
//
|
||||
]));
|
||||
|
||||
$migrations = preg_replace('/CREATE TABLE sqlite_.+?\);[\r\n]+/is', '', $process->getOutput());
|
||||
|
||||
$this->files->put($path, $migrations.PHP_EOL);
|
||||
|
||||
if ($this->hasMigrationTable()) {
|
||||
$this->appendMigrationData($path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the migration data to the schema dump.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
protected function appendMigrationData(string $path)
|
||||
{
|
||||
$process = $this->makeProcess(
|
||||
$this->baseCommand().' ".dump \''.$this->getMigrationTable().'\'"'
|
||||
)->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [
|
||||
//
|
||||
]));
|
||||
|
||||
$migrations = (new Collection(preg_split("/\r\n|\n|\r/", $process->getOutput())))
|
||||
->filter(fn ($line) => preg_match('/^\s*(--|INSERT\s)/iu', $line) === 1 && $line !== '')
|
||||
->all();
|
||||
|
||||
$this->files->append($path, implode(PHP_EOL, $migrations).PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the given schema file into the database.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function load($path)
|
||||
{
|
||||
$database = $this->connection->getDatabaseName();
|
||||
|
||||
if ($database === ':memory:' ||
|
||||
str_contains($database, '?mode=memory') ||
|
||||
str_contains($database, '&mode=memory')
|
||||
) {
|
||||
$this->connection->getPdo()->exec($this->files->get($path));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$process = $this->makeProcess($this->baseCommand().' < "${:LARAVEL_LOAD_PATH}"');
|
||||
|
||||
$process->mustRun(null, array_merge($this->baseVariables($this->connection->getConfig()), [
|
||||
'LARAVEL_LOAD_PATH' => $path,
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base sqlite command arguments as a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function baseCommand()
|
||||
{
|
||||
return 'sqlite3 "${:LARAVEL_LOAD_DATABASE}"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base variables for a dump / load command.
|
||||
*
|
||||
* @param array $config
|
||||
* @return array
|
||||
*/
|
||||
protected function baseVariables(array $config)
|
||||
{
|
||||
return [
|
||||
'LARAVEL_LOAD_DATABASE' => $config['database'],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user