diff --git a/README.md b/README.md index 1cd2090b..7fec4f9e 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,14 @@ Specify table indexes default: '{}' ``` +If raw DB expression is needed in index, then it must be for only one column. Example: + +```yaml + x-indexes: + - "gin(to_tsvector('english', search::text)):search" # valid + - "gin(to_tsvector('english', search::text)):search,column2" # invalid +``` + ### `x-db-default-expression` Ability to provide default value by database expression diff --git a/src/lib/AttributeResolver.php b/src/lib/AttributeResolver.php index 0063d8df..79ff91f6 100644 --- a/src/lib/AttributeResolver.php +++ b/src/lib/AttributeResolver.php @@ -425,12 +425,16 @@ protected function prepareIndexes(array $indexes):array foreach ($indexes as $index) { $unique = false; if (strpos($index, ':') !== false) { - [$indexType, $props] = explode(':', $index); + // [$indexType, $props] = explode(':', $index); + // if `$index` is `gin(to_tsvector('english', search::text)):search,prop2` + $props = strrchr($index, ':'); # `$props` is now `:search,prop2` + $props = substr($props, 1); # search,prop2 + $indexType = str_replace(':'.$props, '', $index); # `gin(to_tsvector('english', search::text))` } else { $props = $index; $indexType = null; } - if ($indexType === 'unique') { + if (strtolower((string) $indexType) === 'unique') { $indexType = null; $unique = true; } diff --git a/src/lib/migrations/MigrationRecordBuilder.php b/src/lib/migrations/MigrationRecordBuilder.php index 98ee03b8..1d4b0ed0 100644 --- a/src/lib/migrations/MigrationRecordBuilder.php +++ b/src/lib/migrations/MigrationRecordBuilder.php @@ -227,6 +227,7 @@ public function addFk(string $fkName, string $tableAlias, string $fkCol, string $onUpdate ); } + throw new \Exception('Cannot add foreign key'); } public function addUniqueIndex(string $tableAlias, string $indexName, array $columns):string @@ -242,11 +243,20 @@ public function addUniqueIndex(string $tableAlias, string $indexName, array $col public function addIndex(string $tableAlias, string $indexName, array $columns, ?string $using = null):string { $indexType = $using === null ? 'false' : "'".ColumnToCode::escapeQuotes($using)."'"; + + if ($using && (stripos($using, '(') !== false) && ApiGenerator::isPostgres()) { + // if `$using` is `gin(to_tsvector('english', search::text))` + $r = explode('(', $using, 2); + $indexType = "'".$r[0]."'"; # `gin` + $columnDbIndexExpression = substr($r[1], 0, -1); # to_tsvector('english', search::text) + $columns = [ColumnToCode::escapeQuotes($columnDbIndexExpression)]; + } + return sprintf( self::ADD_INDEX, $indexName, $tableAlias, - count($columns) === 1 ? "'{$columns[0]}'" : '["'.implode('", "', $columns).'"]', + count($columns) === 1 ? "'". $columns[0]."'" : '["'.implode('", "', $columns).'"]', $indexType ); } diff --git a/tests/specs/postgres_custom.yaml b/tests/specs/postgres_custom.yaml index e3d9a810..d6137a3d 100644 --- a/tests/specs/postgres_custom.yaml +++ b/tests/specs/postgres_custom.yaml @@ -35,7 +35,7 @@ components: Custom: x-table: v3_pgcustom x-indexes: - - "gin(to_tsvector('english', status)):search" + - "gin(to_tsvector('english', search::text)):search" required: - id properties: diff --git a/tests/specs/postgres_custom/migrations_pgsql_db/m200000_000000_change_table_v3_pgcustom.php b/tests/specs/postgres_custom/migrations_pgsql_db/m200000_000000_change_table_v3_pgcustom.php index a1ffe61a..37cb7765 100644 --- a/tests/specs/postgres_custom/migrations_pgsql_db/m200000_000000_change_table_v3_pgcustom.php +++ b/tests/specs/postgres_custom/migrations_pgsql_db/m200000_000000_change_table_v3_pgcustom.php @@ -17,7 +17,7 @@ public function safeUp() $this->alterColumn('{{%v3_pgcustom}}', 'json4', "SET DEFAULT '{\"foo\":\"bar\",\"bar\":\"baz\"}'"); $this->alterColumn('{{%v3_pgcustom}}', 'status', "SET DEFAULT 'draft'"); $this->alterColumn('{{%v3_pgcustom}}', 'status_x', "SET DEFAULT 'draft'"); - $this->createIndex('v3_pgcustom_search_gin_index', '{{%v3_pgcustom}}', 'search', 'gin(to_tsvector(\'english\', status))'); + $this->createIndex('v3_pgcustom_search_gin_index', '{{%v3_pgcustom}}', 'to_tsvector(\'english\', search::text)', 'gin'); } public function safeDown() diff --git a/tests/unit/MultiDbFreshMigrationTest.php b/tests/unit/MultiDbFreshMigrationTest.php index 366bfb0b..f2495903 100644 --- a/tests/unit/MultiDbFreshMigrationTest.php +++ b/tests/unit/MultiDbFreshMigrationTest.php @@ -26,6 +26,7 @@ public function testMaria() $this->assertInstanceOf(MySqlSchema::class, Yii::$app->db->schema); $testFile = Yii::getAlias('@specs/blog.php'); $this->runGenerator($testFile, $dbName); + $this->runActualMigrations($dbName, 5); $expectedFiles = $this->findExpectedFiles($testFile, $dbName); $actualFiles = $this->findActualFiles(); $this->assertEquals($expectedFiles, $actualFiles); @@ -39,6 +40,7 @@ public function testPostgres() $this->assertInstanceOf(PgSqlSchema::class, Yii::$app->db->schema); $testFile = Yii::getAlias('@specs/blog.php'); $this->runGenerator($testFile, $dbName); + $this->runActualMigrations($dbName, 5); $expectedFiles = $this->findExpectedFiles($testFile, $dbName); $actualFiles = $this->findActualFiles(); $this->assertEquals($expectedFiles, $actualFiles); @@ -52,6 +54,7 @@ public function testMysql() $this->assertInstanceOf(MySqlSchema::class, Yii::$app->db->schema); $testFile = Yii::getAlias('@specs/blog.php'); $this->runGenerator($testFile, $dbName); + $this->runActualMigrations($dbName, 5); $expectedFiles = $this->findExpectedFiles($testFile, $dbName); $actualFiles = $this->findActualFiles(); $this->assertEquals($expectedFiles, $actualFiles); diff --git a/tests/unit/MultiDbSecondaryMigrationTest.php b/tests/unit/MultiDbSecondaryMigrationTest.php index f20b3e93..36f9179c 100644 --- a/tests/unit/MultiDbSecondaryMigrationTest.php +++ b/tests/unit/MultiDbSecondaryMigrationTest.php @@ -22,6 +22,7 @@ public function testPostgresCustom() $this->assertInstanceOf(PgSqlSchema::class, Yii::$app->db->schema); $testFile = Yii::getAlias('@specs/postgres_custom.php'); $this->runGenerator($testFile, $dbName); + $this->runActualMigrations($dbName, 1); $expectedFiles = $this->findExpectedFiles($testFile, $dbName); $actualFiles = $this->findActualFiles(); $this->assertEquals($expectedFiles, $actualFiles); @@ -35,6 +36,7 @@ public function testMaria() $this->assertInstanceOf(MySqlSchema::class, Yii::$app->db->schema); $testFile = Yii::getAlias('@specs/blog_v2.php'); $this->runGenerator($testFile, $dbName); +// $this->runActualMigrations($dbName, 6); since PK is changed, no need to run actual migrations here $expectedFiles = $this->findExpectedFiles($testFile, $dbName); $actualFiles = $this->findActualFiles(); $this->assertEquals($expectedFiles, $actualFiles);