From 6f4cfa52a1995714a6ee372f2a1ea9bfdc283ec2 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 1 Mar 2024 18:13:32 +0330 Subject: [PATCH 01/12] add generation to getColumns --- .../Database/Query/Processors/MySqlProcessor.php | 8 ++++++++ .../Query/Processors/PostgresProcessor.php | 9 ++++++++- .../Database/Query/Processors/SQLiteProcessor.php | 15 +++++++++++++++ .../Query/Processors/SqlServerProcessor.php | 4 ++++ .../Database/Schema/Grammars/MySqlGrammar.php | 3 ++- .../Database/Schema/Grammars/PostgresGrammar.php | 1 + .../Database/Schema/Grammars/SQLiteGrammar.php | 2 +- .../Database/Schema/Grammars/SqlServerGrammar.php | 2 ++ 8 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Query/Processors/MySqlProcessor.php b/src/Illuminate/Database/Query/Processors/MySqlProcessor.php index 989b7745d218..a8217ca4527d 100644 --- a/src/Illuminate/Database/Query/Processors/MySqlProcessor.php +++ b/src/Illuminate/Database/Query/Processors/MySqlProcessor.php @@ -24,6 +24,14 @@ public function processColumns($results) 'default' => $result->default, 'auto_increment' => $result->extra === 'auto_increment', 'comment' => $result->comment ?: null, + 'generation' => $result->expression ? [ + 'type' => match ($result->extra) { + 'STORED GENERATED' => 'stored', + 'VIRTUAL GENERATED' => 'virtual', + default => null, + }, + 'expression' => $result->expression, + ] : null, ]; }, $results); } diff --git a/src/Illuminate/Database/Query/Processors/PostgresProcessor.php b/src/Illuminate/Database/Query/Processors/PostgresProcessor.php index 71c3e862ca37..ce6467b4e494 100755 --- a/src/Illuminate/Database/Query/Processors/PostgresProcessor.php +++ b/src/Illuminate/Database/Query/Processors/PostgresProcessor.php @@ -97,9 +97,16 @@ public function processColumns($results) 'type' => $result->type, 'collation' => $result->collation, 'nullable' => (bool) $result->nullable, - 'default' => $autoincrement ? null : $result->default, + 'default' => $result->genrated ? null : $result->default, 'auto_increment' => $autoincrement, 'comment' => $result->comment, + 'generation' => $result->generated ? [ + 'type' => match ($result->generated) { + 's' => 'stored', + default => null, + }, + 'expression' => $result->default, + ] : null, ]; }, $results); } diff --git a/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php b/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php index 63cc84c067da..da3fa0da4566 100644 --- a/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php +++ b/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php @@ -26,6 +26,13 @@ public function processColumns($results, $sql = '') $matches ) === 1 ? strtolower($matches[1]) : null; + $isGenerated = in_array($result->extra, [2, 3]); + $expression = $isGenerated && preg_match( + '/\b'.preg_quote($result->name).'\b[^,]+\s+as\s+\(((?:[^()]+|\((?:[^()]+|\([^()]*\))*\))*)\)/i', + $sql, + $matches + ) === 1 ? $matches[1] : null; + return [ 'name' => $result->name, 'type_name' => strtok($type, '(') ?: '', @@ -35,6 +42,14 @@ public function processColumns($results, $sql = '') 'default' => $result->default, 'auto_increment' => $hasPrimaryKey && $result->primary && $type === 'integer', 'comment' => null, + 'generation' => $isGenerated ? [ + 'type' => match ((int) $result->extra) { + 3 => 'stored', + 2 => 'virtual', + default => null, + }, + 'expression' => $expression, + ] : null, ]; }, $results); } diff --git a/src/Illuminate/Database/Query/Processors/SqlServerProcessor.php b/src/Illuminate/Database/Query/Processors/SqlServerProcessor.php index 8c632060b025..5fcde7c437c4 100755 --- a/src/Illuminate/Database/Query/Processors/SqlServerProcessor.php +++ b/src/Illuminate/Database/Query/Processors/SqlServerProcessor.php @@ -82,6 +82,10 @@ public function processColumns($results) 'default' => $result->default, 'auto_increment' => (bool) $result->autoincrement, 'comment' => $result->comment, + 'generation' => $result->expression ? [ + 'type' => $result->persisted ? 'stored' : 'virtual', + 'expression' => $result->expression, + ] : null, ]; }, $results); } diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index aec73db6eef4..540e46b1b162 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -121,7 +121,8 @@ public function compileColumns($database, $table) return sprintf( 'select column_name as `name`, data_type as `type_name`, column_type as `type`, ' .'collation_name as `collation`, is_nullable as `nullable`, ' - .'column_default as `default`, column_comment as `comment`, extra as `extra` ' + .'column_default as `default`, column_comment as `comment`, ' + .'generation_expression as `expression`, extra as `extra` ' .'from information_schema.columns where table_schema = %s and table_name = %s ' .'order by ordinal_position asc', $this->quoteString($database), diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index aad87542d552..5aa785a88a75 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -123,6 +123,7 @@ public function compileColumns($schema, $table) .'(select tc.collcollate from pg_catalog.pg_collation tc where tc.oid = a.attcollation) as collation, ' .'not a.attnotnull as nullable, ' .'(select pg_get_expr(adbin, adrelid) from pg_attrdef where c.oid = pg_attrdef.adrelid and pg_attrdef.adnum = a.attnum) as default, ' + .'a.attgenerated as generated, ' .'col_description(c.oid, a.attnum) as comment ' .'from pg_attribute a, pg_class c, pg_type t, pg_namespace n ' .'where c.relname = %s and n.nspname = %s and a.attnum > 0 and a.attrelid = c.oid and a.atttypid = t.oid and n.oid = c.relnamespace ' diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index 5d969c3eaf93..edf96424552c 100644 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -89,7 +89,7 @@ public function compileViews() public function compileColumns($table) { return sprintf( - 'select name, type, not "notnull" as "nullable", dflt_value as "default", pk as "primary" ' + 'select name, type, not "notnull" as "nullable", dflt_value as "default", pk as "primary", hidden as "extra" ' .'from pragma_table_xinfo(%s) order by cid asc', $this->wrap(str_replace('.', '__', $table)) ); diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index b719f127f3dc..cc514e26a6c3 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -107,6 +107,7 @@ public function compileColumns($schema, $table) .'col.max_length as length, col.precision as precision, col.scale as places, ' .'col.is_nullable as nullable, def.definition as [default], ' .'col.is_identity as autoincrement, col.collation_name as collation, ' + .'com.definition as [expression], is_persisted as [persisted], ' .'cast(prop.value as nvarchar(max)) as comment ' .'from sys.columns as col ' .'join sys.types as type on col.user_type_id = type.user_type_id ' @@ -114,6 +115,7 @@ public function compileColumns($schema, $table) .'join sys.schemas as scm on obj.schema_id = scm.schema_id ' .'left join sys.default_constraints def on col.default_object_id = def.object_id and col.object_id = def.parent_object_id ' ."left join sys.extended_properties as prop on obj.object_id = prop.major_id and col.column_id = prop.minor_id and prop.name = 'MS_Description' " + .'left join sys.computed_columns as com on col.column_id = com.column_id ' ."where obj.type in ('U', 'V') and obj.name = %s and scm.name = %s " .'order by col.column_id', $this->quoteString($table), From f37f2c0ce926d104f1bdf9bf9d811fd6c8a31993 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 1 Mar 2024 18:21:02 +0330 Subject: [PATCH 02/12] add support for modifying generated column on sqlite --- .../Database/Schema/Grammars/SQLiteGrammar.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index edf96424552c..ba03d206e96f 100644 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -250,14 +250,22 @@ public function compileChange(Blueprint $blueprint, Fluent $command, Connection if ($column instanceof Fluent) { $name = $this->wrap($column); - $columnNames[] = $name; $autoIncrementColumn = $column->autoIncrement ? $column->name : $autoIncrementColumn; + if (is_null($column->virtualAs) && is_null($column->virtualAsJson) && + is_null($column->storedAs) && is_null($column->storedAsJson)) { + $columnNames[] = $name; + } + return $this->addModifiers($name.' '.$this->getType($column), $blueprint, $column); } else { $name = $this->wrap($column['name']); - $columnNames[] = $name; $autoIncrementColumn = $column['auto_increment'] ? $column['name'] : $autoIncrementColumn; + $isGenerated = ! is_null($column['generation']); + + if (! $isGenerated) { + $columnNames[] = $name; + } return $this->addModifiers($name.' '.$column['type'], $blueprint, new ColumnDefinition([ @@ -268,6 +276,10 @@ public function compileChange(Blueprint $blueprint, Fluent $command, Connection 'autoIncrement' => $column['auto_increment'], 'collation' => $column['collation'], 'comment' => $column['comment'], + 'virtualAs' => $isGenerated && $column['generation']['type'] === 'virtual' + ? $column['generation']['expression'] : null, + 'storedAs' => $isGenerated && $column['generation']['type'] === 'stored' + ? $column['generation']['expression'] : null, ]) ); } From 29c92ab783a25ba42c9691989964685dadb2e7ad Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 1 Mar 2024 18:21:23 +0330 Subject: [PATCH 03/12] add support for renaming generated column on legacy mysql --- src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 540e46b1b162..44ff9c430aa4 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -344,6 +344,10 @@ public function compileRenameColumn(Blueprint $blueprint, Fluent $command, Conne '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, ])); return sprintf('alter table %s change %s %s %s', From 51cbf366f625916651bf1591251abea0d1808bad Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 1 Mar 2024 18:21:47 +0330 Subject: [PATCH 04/12] add tests --- .../Database/DatabaseSchemaBlueprintTest.php | 6 ++ .../Database/SchemaBuilderTest.php | 82 +++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/tests/Database/DatabaseSchemaBlueprintTest.php b/tests/Database/DatabaseSchemaBlueprintTest.php index a9bb895ec0d1..0fc9318d3269 100755 --- a/tests/Database/DatabaseSchemaBlueprintTest.php +++ b/tests/Database/DatabaseSchemaBlueprintTest.php @@ -189,6 +189,7 @@ public function testNativeRenameColumnOnMysql57() $blueprint = new Blueprint('users', function ($table) { $table->renameColumn('name', 'title'); $table->renameColumn('id', 'key'); + $table->renameColumn('generated', 'new_generated'); }); $connection = m::mock(Connection::class); @@ -197,11 +198,13 @@ public function testNativeRenameColumnOnMysql57() $connection->shouldReceive('getSchemaBuilder->getColumns')->andReturn([ ['name' => 'name', 'type' => 'varchar(255)', 'type_name' => 'varchar', 'nullable' => true, 'collation' => 'utf8mb4_unicode_ci', 'default' => 'foo', 'comment' => null, 'auto_increment' => false], ['name' => 'id', 'type' => 'bigint unsigned', 'type_name' => 'bigint', 'nullable' => false, 'collation' => null, 'default' => null, 'comment' => 'lorem ipsum', 'auto_increment' => true], + ['name' => 'generated', 'type' => 'int', 'type_name' => 'int', 'nullable' => false, 'collation' => null, 'default' => null, 'comment' => null, 'auto_increment' => false, 'generation' => ['type' => 'stored', 'expression' => 'expression']], ]); $this->assertEquals([ "alter table `users` change `name` `title` varchar(255) collate 'utf8mb4_unicode_ci' null default 'foo'", "alter table `users` change `id` `key` bigint unsigned not null auto_increment comment 'lorem ipsum'", + 'alter table `users` change `generated` `new_generated` int as (expression) stored not null', ], $blueprint->toSql($connection, new MySqlGrammar)); } @@ -210,6 +213,7 @@ public function testNativeRenameColumnOnLegacyMariaDB() $blueprint = new Blueprint('users', function ($table) { $table->renameColumn('name', 'title'); $table->renameColumn('id', 'key'); + $table->renameColumn('generated', 'new_generated'); }); $connection = m::mock(Connection::class); @@ -218,11 +222,13 @@ public function testNativeRenameColumnOnLegacyMariaDB() $connection->shouldReceive('getSchemaBuilder->getColumns')->andReturn([ ['name' => 'name', 'type' => 'varchar(255)', 'type_name' => 'varchar', 'nullable' => true, 'collation' => 'utf8mb4_unicode_ci', 'default' => 'foo', 'comment' => null, 'auto_increment' => false], ['name' => 'id', 'type' => 'bigint unsigned', 'type_name' => 'bigint', 'nullable' => false, 'collation' => null, 'default' => null, 'comment' => 'lorem ipsum', 'auto_increment' => true], + ['name' => 'generated', 'type' => 'int', 'type_name' => 'int', 'nullable' => false, 'collation' => null, 'default' => null, 'comment' => null, 'auto_increment' => false, 'generation' => ['type' => 'stored', 'expression' => 'expression']], ]); $this->assertEquals([ "alter table `users` change `name` `title` varchar(255) collate 'utf8mb4_unicode_ci' null default 'foo'", "alter table `users` change `id` `key` bigint unsigned not null auto_increment comment 'lorem ipsum'", + 'alter table `users` change `generated` `new_generated` int as (expression) stored not null', ], $blueprint->toSql($connection, new MySqlGrammar)); } diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index 2abe2ceb8f02..0010a4917900 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -6,6 +6,7 @@ use Illuminate\Database\Schema\Grammars\SQLiteGrammar; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Str; class SchemaBuilderTest extends DatabaseTestCase { @@ -536,6 +537,87 @@ public function testAddingStoredColumnOnSqlite() $this->assertTrue(Schema::hasColumns('test', ['virtual_column', 'stored_column'])); } + public function testModifyingStoredColumnOnSqlite() + { + if ($this->driver !== 'sqlite') { + $this->markTestSkipped('Test requires a SQLite connection.'); + } + + Schema::create('test', function (Blueprint $table) { + $table->integer('price'); + $table->integer('virtual_price')->virtualAs('price - 2'); + $table->integer('stored_price')->storedAs('price - 4'); + $table->integer('virtual_price_changed')->virtualAs('price - 6'); + $table->integer('stored_price_changed')->storedAs('price - 8'); + }); + + DB::table('test')->insert(['price' => 100]); + + Schema::table('test', function (Blueprint $table) { + $table->integer('virtual_price_changed')->virtualAs('price - 5')->change(); + $table->integer('stored_price_changed')->storedAs('price - 7')->change(); + }); + + $this->assertEquals( + ['price' => 100, 'virtual_price' => 98, 'stored_price' => 96, 'virtual_price_changed' => 95, 'stored_price_changed' => 93], + (array) DB::table('test')->first() + ); + + $columns = Schema::getColumns('test'); + + $this->assertTrue(collect($columns)->contains( + fn ($column) => $column['name'] === 'virtual_price' && $column['generation']['type'] === 'virtual' + && $column['generation']['expression'] === 'price - 2' + )); + $this->assertTrue(collect($columns)->contains( + fn ($column) => $column['name'] === 'stored_price' && $column['generation']['type'] === 'stored' + && $column['generation']['expression'] === 'price - 4' + )); + $this->assertTrue(collect($columns)->contains( + fn ($column) => $column['name'] === 'virtual_price_changed' && $column['generation']['type'] === 'virtual' + && $column['generation']['expression'] === 'price - 5' + )); + $this->assertTrue(collect($columns)->contains( + fn ($column) => $column['name'] === 'stored_price_changed' && $column['generation']['type'] === 'stored' + && $column['generation']['expression'] === 'price - 7' + )); + } + + public function testGettingGeneratedColumns() + { + Schema::create('test', function (Blueprint $table) { + $table->integer('price'); + + if ($this->driver === 'sqlsrv') { + $table->computed('virtual_price', 'price - 5'); + $table->computed('stored_price', 'price - 10')->persisted(); + } else { + if ($this->driver !== 'pgsql') { + $table->integer('virtual_price')->virtualAs('price - 5'); + } + $table->integer('stored_price')->storedAs('price - 10'); + } + }); + + $columns = Schema::getColumns('test'); + + $this->assertTrue(collect($columns)->contains( + fn ($column) => $column['name'] === 'price' && is_null($column['generation']) + )); + if ($this->driver !== 'pgsql') { + $this->assertTrue(collect($columns)->contains( + fn ($column) => $column['name'] === 'virtual_price' && is_null($column['default']) + && $column['generation']['type'] === 'virtual' + && Str::wrap($column['generation']['expression'], '(', ')') === '(price - 5)' + )); + } + $this->assertTrue(collect($columns)->contains( + fn ($column) => $column['name'] === 'stored_price' && is_null($column['default']) + && $column['generation']['type'] === 'stored' + && Str::wrap($column['generation']['expression'], '(', ')') === '(price - 10)' + )); + } + public function testAddingMacros() { Schema::macro('foo', fn () => 'foo'); From 1e2b42af3fefa64c1405abe368bb1f8f154d0cb3 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 1 Mar 2024 18:47:36 +0330 Subject: [PATCH 05/12] force re-run tests From dc13b76cbc571ac986f236b62eab486711ee0653 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 1 Mar 2024 19:40:41 +0330 Subject: [PATCH 06/12] fix tests --- .../Query/Processors/PostgresProcessor.php | 2 +- tests/Database/DatabaseMariaDbProcessorTest.php | 6 +++--- tests/Database/DatabaseMySqlProcessorTest.php | 6 +++--- tests/Database/DatabasePostgresProcessorTest.php | 8 ++++---- tests/Database/DatabaseSQLiteProcessorTest.php | 6 +++--- tests/Integration/Database/SchemaBuilderTest.php | 16 +++++++++++++--- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/Illuminate/Database/Query/Processors/PostgresProcessor.php b/src/Illuminate/Database/Query/Processors/PostgresProcessor.php index ce6467b4e494..ad02ce442780 100755 --- a/src/Illuminate/Database/Query/Processors/PostgresProcessor.php +++ b/src/Illuminate/Database/Query/Processors/PostgresProcessor.php @@ -97,7 +97,7 @@ public function processColumns($results) 'type' => $result->type, 'collation' => $result->collation, 'nullable' => (bool) $result->nullable, - 'default' => $result->genrated ? null : $result->default, + 'default' => $result->generated ? null : $result->default, 'auto_increment' => $autoincrement, 'comment' => $result->comment, 'generation' => $result->generated ? [ diff --git a/tests/Database/DatabaseMariaDbProcessorTest.php b/tests/Database/DatabaseMariaDbProcessorTest.php index ecd3cae703a8..97c0cc90f479 100644 --- a/tests/Database/DatabaseMariaDbProcessorTest.php +++ b/tests/Database/DatabaseMariaDbProcessorTest.php @@ -16,9 +16,9 @@ public function testProcessColumns() ['name' => 'email', 'type_name' => 'varchar', 'type' => 'varchar(100)', 'collation' => 'collate', 'nullable' => 'YES', 'default' => 'NULL', 'extra' => 'on update CURRENT_TIMESTAMP', 'comment' => 'NULL'], ]; $expected = [ - ['name' => 'id', 'type_name' => 'bigint', 'type' => 'bigint', 'collation' => 'collate', 'nullable' => true, 'default' => '', 'auto_increment' => true, 'comment' => 'bar'], - ['name' => 'name', 'type_name' => 'varchar', 'type' => 'varchar(100)', 'collation' => 'collate', 'nullable' => false, 'default' => 'foo', 'auto_increment' => false, 'comment' => ''], - ['name' => 'email', 'type_name' => 'varchar', 'type' => 'varchar(100)', 'collation' => 'collate', 'nullable' => true, 'default' => 'NULL', 'auto_increment' => false, 'comment' => 'NULL'], + ['name' => 'id', 'type_name' => 'bigint', 'type' => 'bigint', 'collation' => 'collate', 'nullable' => true, 'default' => '', 'auto_increment' => true, 'comment' => 'bar', 'generation' => null], + ['name' => 'name', 'type_name' => 'varchar', 'type' => 'varchar(100)', 'collation' => 'collate', 'nullable' => false, 'default' => 'foo', 'auto_increment' => false, 'comment' => '', 'generation' => null], + ['name' => 'email', 'type_name' => 'varchar', 'type' => 'varchar(100)', 'collation' => 'collate', 'nullable' => true, 'default' => 'NULL', 'auto_increment' => false, 'comment' => 'NULL', 'generation' => null], ]; $this->assertEquals($expected, $processor->processColumns($listing)); diff --git a/tests/Database/DatabaseMySqlProcessorTest.php b/tests/Database/DatabaseMySqlProcessorTest.php index 5ac56b1ce990..9919ff975b34 100644 --- a/tests/Database/DatabaseMySqlProcessorTest.php +++ b/tests/Database/DatabaseMySqlProcessorTest.php @@ -16,9 +16,9 @@ public function testProcessColumns() ['name' => 'email', 'type_name' => 'varchar', 'type' => 'varchar(100)', 'collation' => 'collate', 'nullable' => 'YES', 'default' => 'NULL', 'extra' => 'on update CURRENT_TIMESTAMP', 'comment' => 'NULL'], ]; $expected = [ - ['name' => 'id', 'type_name' => 'bigint', 'type' => 'bigint', 'collation' => 'collate', 'nullable' => true, 'default' => '', 'auto_increment' => true, 'comment' => 'bar'], - ['name' => 'name', 'type_name' => 'varchar', 'type' => 'varchar(100)', 'collation' => 'collate', 'nullable' => false, 'default' => 'foo', 'auto_increment' => false, 'comment' => ''], - ['name' => 'email', 'type_name' => 'varchar', 'type' => 'varchar(100)', 'collation' => 'collate', 'nullable' => true, 'default' => 'NULL', 'auto_increment' => false, 'comment' => 'NULL'], + ['name' => 'id', 'type_name' => 'bigint', 'type' => 'bigint', 'collation' => 'collate', 'nullable' => true, 'default' => '', 'auto_increment' => true, 'comment' => 'bar', 'generation' => null], + ['name' => 'name', 'type_name' => 'varchar', 'type' => 'varchar(100)', 'collation' => 'collate', 'nullable' => false, 'default' => 'foo', 'auto_increment' => false, 'comment' => null, 'generation' => null], + ['name' => 'email', 'type_name' => 'varchar', 'type' => 'varchar(100)', 'collation' => 'collate', 'nullable' => true, 'default' => 'NULL', 'auto_increment' => false, 'comment' => 'NULL', 'generation' => null], ]; $this->assertEquals($expected, $processor->processColumns($listing)); diff --git a/tests/Database/DatabasePostgresProcessorTest.php b/tests/Database/DatabasePostgresProcessorTest.php index 8213fc68aba7..6fca3d3496ed 100644 --- a/tests/Database/DatabasePostgresProcessorTest.php +++ b/tests/Database/DatabasePostgresProcessorTest.php @@ -18,10 +18,10 @@ public function testProcessColumns() ['name' => 'birth_date', 'type_name' => 'timestamp', 'type' => 'timestamp(6) without time zone', 'collation' => '', 'nullable' => false, 'default' => '', 'comment' => ''], ]; $expected = [ - ['name' => 'id', 'type_name' => 'int4', 'type' => 'integer', 'collation' => '', 'nullable' => true, 'default' => null, 'auto_increment' => true, 'comment' => ''], - ['name' => 'name', 'type_name' => 'varchar', 'type' => 'character varying(100)', 'collation' => 'collate', 'nullable' => false, 'default' => '', 'auto_increment' => false, 'comment' => 'foo'], - ['name' => 'balance', 'type_name' => 'numeric', 'type' => 'numeric(8,2)', 'collation' => '', 'nullable' => true, 'default' => '4', 'auto_increment' => false, 'comment' => 'NULL'], - ['name' => 'birth_date', 'type_name' => 'timestamp', 'type' => 'timestamp(6) without time zone', 'collation' => '', 'nullable' => false, 'default' => '', 'auto_increment' => false, 'comment' => ''], + ['name' => 'id', 'type_name' => 'int4', 'type' => 'integer', 'collation' => '', 'nullable' => true, 'default' => "nextval('employee_id_seq'::regclass)", 'auto_increment' => true, 'comment' => '', 'generation' => null], + ['name' => 'name', 'type_name' => 'varchar', 'type' => 'character varying(100)', 'collation' => 'collate', 'nullable' => false, 'default' => '', 'auto_increment' => false, 'comment' => 'foo', 'generation' => null], + ['name' => 'balance', 'type_name' => 'numeric', 'type' => 'numeric(8,2)', 'collation' => '', 'nullable' => true, 'default' => '4', 'auto_increment' => false, 'comment' => 'NULL', 'generation' => null], + ['name' => 'birth_date', 'type_name' => 'timestamp', 'type' => 'timestamp(6) without time zone', 'collation' => '', 'nullable' => false, 'default' => '', 'auto_increment' => false, 'comment' => '', 'generation' => null], ]; $this->assertEquals($expected, $processor->processColumns($listing)); diff --git a/tests/Database/DatabaseSQLiteProcessorTest.php b/tests/Database/DatabaseSQLiteProcessorTest.php index 4aeb4438f7d7..7511686d40bd 100644 --- a/tests/Database/DatabaseSQLiteProcessorTest.php +++ b/tests/Database/DatabaseSQLiteProcessorTest.php @@ -17,9 +17,9 @@ public function testProcessColumns() ['name' => 'is_active', 'type' => 'tinyint(1)', 'nullable' => '0', 'default' => '1', 'primary' => '0'], ]; $expected = [ - ['name' => 'id', 'type_name' => 'integer', 'type' => 'integer', 'collation' => null, 'nullable' => false, 'default' => '', 'auto_increment' => true, 'comment' => null], - ['name' => 'name', 'type_name' => 'varchar', 'type' => 'varchar', 'collation' => null, 'nullable' => true, 'default' => 'foo', 'auto_increment' => false, 'comment' => null], - ['name' => 'is_active', 'type_name' => 'tinyint', 'type' => 'tinyint(1)', 'collation' => null, 'nullable' => false, 'default' => '1', 'auto_increment' => false, 'comment' => null], + ['name' => 'id', 'type_name' => 'integer', 'type' => 'integer', 'collation' => null, 'nullable' => false, 'default' => '', 'auto_increment' => true, 'comment' => null, 'generation' => null], + ['name' => 'name', 'type_name' => 'varchar', 'type' => 'varchar', 'collation' => null, 'nullable' => true, 'default' => 'foo', 'auto_increment' => false, 'comment' => null, 'generation' => null], + ['name' => 'is_active', 'type_name' => 'tinyint', 'type' => 'tinyint(1)', 'collation' => null, 'nullable' => false, 'default' => '1', 'auto_increment' => false, 'comment' => null, 'generation' => null], ]; $this->assertEquals($expected, $processor->processColumns($listing)); diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index 0010a4917900..c876727eec5c 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -6,7 +6,6 @@ use Illuminate\Database\Schema\Grammars\SQLiteGrammar; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; -use Illuminate\Support\Str; class SchemaBuilderTest extends DatabaseTestCase { @@ -608,13 +607,24 @@ public function testGettingGeneratedColumns() $this->assertTrue(collect($columns)->contains( fn ($column) => $column['name'] === 'virtual_price' && is_null($column['default']) && $column['generation']['type'] === 'virtual' - && Str::wrap($column['generation']['expression'], '(', ')') === '(price - 5)' + && match ($this->driver) { + 'mysql' => $column['generation']['expression'] === '(`price` - 5)', + 'mariadb' => $column['generation']['expression'] === '`price` - 5', + 'sqlsrv' => $column['generation']['expression'] === '([price]-(5))', + default => $column['generation']['expression'] === 'price - 5', + } )); } $this->assertTrue(collect($columns)->contains( fn ($column) => $column['name'] === 'stored_price' && is_null($column['default']) && $column['generation']['type'] === 'stored' - && Str::wrap($column['generation']['expression'], '(', ')') === '(price - 10)' + && match ($this->driver) { + 'mysql' => $column['generation']['expression'] === '(`price` - 10)', + 'mariadb' => $column['generation']['expression'] === '`price` - 10', + 'sqlsrv' => $column['generation']['expression'] === '([price]-(10))', + 'pgsql' => $column['generation']['expression'] === '(price - 10)', + default => $column['generation']['expression'] === 'price - 10', + } )); } From 5f94bf00cc3817f3c4a53882b8372b8d4956b5f2 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 1 Mar 2024 19:46:21 +0330 Subject: [PATCH 07/12] fix tests --- tests/Integration/Database/SchemaBuilderTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index c876727eec5c..58594d9714f6 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -608,8 +608,7 @@ public function testGettingGeneratedColumns() fn ($column) => $column['name'] === 'virtual_price' && is_null($column['default']) && $column['generation']['type'] === 'virtual' && match ($this->driver) { - 'mysql' => $column['generation']['expression'] === '(`price` - 5)', - 'mariadb' => $column['generation']['expression'] === '`price` - 5', + 'mysql', 'mariadb' => in_array($column['generation']['expression'], ['(`price` - 5)', '`price` - 5']), 'sqlsrv' => $column['generation']['expression'] === '([price]-(5))', default => $column['generation']['expression'] === 'price - 5', } @@ -619,8 +618,7 @@ public function testGettingGeneratedColumns() fn ($column) => $column['name'] === 'stored_price' && is_null($column['default']) && $column['generation']['type'] === 'stored' && match ($this->driver) { - 'mysql' => $column['generation']['expression'] === '(`price` - 10)', - 'mariadb' => $column['generation']['expression'] === '`price` - 10', + 'mysql', 'mariadb' => in_array($column['generation']['expression'], ['(`price` - 10)', '`price` - 10']), 'sqlsrv' => $column['generation']['expression'] === '([price]-(10))', 'pgsql' => $column['generation']['expression'] === '(price - 10)', default => $column['generation']['expression'] === 'price - 10', From ec1c139c17390aef42434fba08bf5653f8361cb5 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 1 Mar 2024 19:54:22 +0330 Subject: [PATCH 08/12] wip --- tests/Integration/Database/SchemaBuilderTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index 58594d9714f6..51334591558a 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -600,6 +600,8 @@ public function testGettingGeneratedColumns() $columns = Schema::getColumns('test'); + var_dump($columns); + $this->assertTrue(collect($columns)->contains( fn ($column) => $column['name'] === 'price' && is_null($column['generation']) )); From 1f55990153fcc91443791d434e56ad42ca5f3787 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 1 Mar 2024 20:05:36 +0330 Subject: [PATCH 09/12] wip --- tests/Integration/Database/SchemaBuilderTest.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index 51334591558a..f99fc19fa1d7 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -600,6 +600,7 @@ public function testGettingGeneratedColumns() $columns = Schema::getColumns('test'); + var_dump($this->driver); var_dump($columns); $this->assertTrue(collect($columns)->contains( @@ -610,7 +611,8 @@ public function testGettingGeneratedColumns() fn ($column) => $column['name'] === 'virtual_price' && is_null($column['default']) && $column['generation']['type'] === 'virtual' && match ($this->driver) { - 'mysql', 'mariadb' => in_array($column['generation']['expression'], ['(`price` - 5)', '`price` - 5']), + 'mysql' => $column['generation']['expression'] === '(`price` - 5)', + 'mariadb' => $column['generation']['expression'] === '`price` - 5', 'sqlsrv' => $column['generation']['expression'] === '([price]-(5))', default => $column['generation']['expression'] === 'price - 5', } @@ -620,7 +622,8 @@ public function testGettingGeneratedColumns() fn ($column) => $column['name'] === 'stored_price' && is_null($column['default']) && $column['generation']['type'] === 'stored' && match ($this->driver) { - 'mysql', 'mariadb' => in_array($column['generation']['expression'], ['(`price` - 10)', '`price` - 10']), + 'mysql' => $column['generation']['expression'] === '(`price` - 10)', + 'mariadb' => $column['generation']['expression'] === '`price` - 10', 'sqlsrv' => $column['generation']['expression'] === '([price]-(10))', 'pgsql' => $column['generation']['expression'] === '(price - 10)', default => $column['generation']['expression'] === 'price - 10', From 382d71006e0133cd7ca61c1a48e824e94d01826f Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 1 Mar 2024 20:16:35 +0330 Subject: [PATCH 10/12] fix tests --- tests/Integration/Database/SchemaBuilderTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index f99fc19fa1d7..c1eb1308a867 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -608,7 +608,7 @@ public function testGettingGeneratedColumns() )); if ($this->driver !== 'pgsql') { $this->assertTrue(collect($columns)->contains( - fn ($column) => $column['name'] === 'virtual_price' && is_null($column['default']) + fn ($column) => $column['name'] === 'virtual_price' && $column['generation']['type'] === 'virtual' && match ($this->driver) { 'mysql' => $column['generation']['expression'] === '(`price` - 5)', @@ -619,7 +619,7 @@ public function testGettingGeneratedColumns() )); } $this->assertTrue(collect($columns)->contains( - fn ($column) => $column['name'] === 'stored_price' && is_null($column['default']) + fn ($column) => $column['name'] === 'stored_price' && $column['generation']['type'] === 'stored' && match ($this->driver) { 'mysql' => $column['generation']['expression'] === '(`price` - 10)', From 2aab909379547f3aaf8d7bd726cc58b153cfae39 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Fri, 1 Mar 2024 20:24:54 +0330 Subject: [PATCH 11/12] wip --- tests/Integration/Database/SchemaBuilderTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index c1eb1308a867..dbf41b88db07 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -600,9 +600,6 @@ public function testGettingGeneratedColumns() $columns = Schema::getColumns('test'); - var_dump($this->driver); - var_dump($columns); - $this->assertTrue(collect($columns)->contains( fn ($column) => $column['name'] === 'price' && is_null($column['generation']) )); From 94a503dc8977581fd832e57414f5a357cab6b5c5 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 4 Mar 2024 09:03:45 -0600 Subject: [PATCH 12/12] Update SQLiteProcessor.php --- src/Illuminate/Database/Query/Processors/SQLiteProcessor.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php b/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php index da3fa0da4566..5ce6ecac48f7 100644 --- a/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php +++ b/src/Illuminate/Database/Query/Processors/SQLiteProcessor.php @@ -27,6 +27,7 @@ public function processColumns($results, $sql = '') ) === 1 ? strtolower($matches[1]) : null; $isGenerated = in_array($result->extra, [2, 3]); + $expression = $isGenerated && preg_match( '/\b'.preg_quote($result->name).'\b[^,]+\s+as\s+\(((?:[^()]+|\((?:[^()]+|\([^()]*\))*\))*)\)/i', $sql,