Skip to content
This repository has been archived by the owner on Jun 4, 2024. It is now read-only.

Fix #168: Cannot define index on relation #35 #171

Merged
merged 15 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ Allow to set foreign key constraint in migrations for ON UPDATE event of row in

### `x-fk-column-name`

Provide custom column name in case of relationship column. Example:
Provide custom database table column name in case of relationship column. This will not reflect in models relations, faker etc. Example:

```yaml
components:
Expand Down
24 changes: 22 additions & 2 deletions src/lib/AttributeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -436,10 +436,30 @@ protected function prepareIndexes(array $indexes):array
}
$props = array_map('trim', explode(',', trim($props)));
$columns = [];
$xFkColumnNames = [];
foreach ($this->attributes as $key => $value) {
if (!empty($value->fkColName)) {
$xFkColumnNames[$value->fkColName] = $key;
}
}
foreach ($props as $prop) {
// for more info see test tests/specs/fk_col_name/fk_col_name.yaml
// File: ForeignKeyColumnNameTest::testIndexForColumnWithCustomName
// first check direct column names
if (!isset($this->attributes[$prop])) {
throw new InvalidDefinitionException('Invalid index definition - property ' . $prop
. ' not declared');
// then check x-fk-column-name
if (!in_array($prop, array_keys($xFkColumnNames))) {
// then check relations/reference e.g. `user`/`user_id`
$refPropName = (substr($prop, -3) === '_id') ? rtrim($prop, '_id') : null;
if ($refPropName && !isset($this->attributes[$refPropName])) {
throw new InvalidDefinitionException('Invalid index definition - property ' . $prop
. ' not declared');
} else {
$prop = $refPropName;
}
} else {
$prop = $xFkColumnNames[$prop];
}
}
$columns[] = $this->attributes[$prop]->columnName;
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/FakerStubResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public function resolve():?string
}

// column name ends with `_id`
if (substr($this->attribute->columnName, -strlen('_id'))==='_id') {
if (substr($this->attribute->columnName, -3) === '_id' || !empty($this->attribute->fkColName)) {
$config = $this->config;
if (!$config) {
$config = new Config;
Expand Down
21 changes: 11 additions & 10 deletions src/lib/migrations/BaseMigrationBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,14 @@ public function buildFresh():MigrationModel
$this->migration->addUpCode($builder->addPrimaryKey($tableName, $this->model->junctionCols))
->addDownCode($builder->dropPrimaryKey($tableName, $this->model->junctionCols));
}

foreach ($this->model->indexes as $index) {
$upCode = $index->isUnique ? $builder->addUniqueIndex($tableName, $index->name, $index->columns)
: $builder->addIndex($tableName, $index->name, $index->columns, $index->type);
$this->migration->addUpCode($upCode)
->addDownCode($builder->dropIndex($tableName, $index->name));
}

foreach ($this->model->getHasOneRelations() as $relation) {
$fkCol = $relation->getColumnName();
$refCol = $relation->getForeignName();
Expand All @@ -153,13 +161,6 @@ public function buildFresh():MigrationModel
}
}

foreach ($this->model->indexes as $index) {
$upCode = $index->isUnique ? $builder->addUniqueIndex($tableName, $index->name, $index->columns)
: $builder->addIndex($tableName, $index->name, $index->columns, $index->type);
$this->migration->addUpCode($upCode)
->addDownCode($builder->dropIndex($tableName, $index->name));
}

return $this->migration;
}

Expand Down Expand Up @@ -211,14 +212,14 @@ function (string $unknownColumn) {
}
$this->buildColumnChanges($current, $desired, $changedAttributes);
}
if (!$relation) {
$this->buildIndexChanges();
}
if ($relation) {
$this->buildRelationsForJunction($relation);
} else {
$this->buildRelations();
}
if (!$relation) {
$this->buildIndexChanges();
}
return $this->migration;
}

Expand Down
19 changes: 15 additions & 4 deletions src/lib/migrations/MigrationRecordBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ final class MigrationRecordBuilder
public const DROP_FK = MigrationRecordBuilder::INDENT . "\$this->dropForeignKey('%s', '%s');";
public const DROP_PK = MigrationRecordBuilder::INDENT . "\$this->dropPrimaryKey('%s', '%s');";
public const ADD_TABLE = MigrationRecordBuilder::INDENT . "\$this->createTable('%s', %s);";
public const ADD_UNIQUE = MigrationRecordBuilder::INDENT . "\$this->createIndex('%s', '%s', '%s', true);";
public const ADD_INDEX = MigrationRecordBuilder::INDENT . "\$this->createIndex('%s', '%s', '%s', %s);";
public const ADD_UNIQUE = MigrationRecordBuilder::INDENT . "\$this->createIndex('%s', '%s', %s, true);";
public const ADD_INDEX = MigrationRecordBuilder::INDENT . "\$this->createIndex('%s', '%s', %s, %s);";
public const DROP_COLUMN = MigrationRecordBuilder::INDENT . "\$this->dropColumn('%s', '%s');";
public const ADD_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('CREATE TYPE \"enum_%s_%s\" AS ENUM(%s)');";
public const DROP_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('DROP TYPE \"enum_%s_%s\"');";
Expand Down Expand Up @@ -231,13 +231,24 @@ public function addFk(string $fkName, string $tableAlias, string $fkCol, string

public function addUniqueIndex(string $tableAlias, string $indexName, array $columns):string
{
return sprintf(self::ADD_UNIQUE, $indexName, $tableAlias, implode(',', $columns));
return sprintf(
self::ADD_UNIQUE,
$indexName,
$tableAlias,
count($columns) === 1 ? "'{$columns[0]}'" : '["'.implode('", "', $columns).'"]'
);
}

public function addIndex(string $tableAlias, string $indexName, array $columns, ?string $using = null):string
{
$indexType = $using === null ? 'false' : "'".ColumnToCode::escapeQuotes($using)."'";
return sprintf(self::ADD_INDEX, $indexName, $tableAlias, implode(',', $columns), $indexType);
return sprintf(
self::ADD_INDEX,
$indexName,
$tableAlias,
count($columns) === 1 ? "'{$columns[0]}'" : '["'.implode('", "', $columns).'"]',
$indexType
);
}

public function addPrimaryKey(string $tableAlias, array $columns, string $pkName= null):string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function up()
]);
$this->createIndex('users_username_key', '{{%users}}', 'username', true);
$this->createIndex('users_email_key', '{{%users}}', 'email', true);
$this->createIndex('users_role_flags_index', '{{%users}}', 'role,flags', false);
$this->createIndex('users_role_flags_index', '{{%users}}', ["role", "flags"], false);
}

public function down()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ public function up()
'created_by_id' => $this->integer()->null()->defaultValue(null),
]);
$this->addPrimaryKey('pk_blog_posts_uid', '{{%blog_posts}}', 'uid');
$this->addForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}', 'category_id', '{{%categories}}', 'id');
$this->addForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}', 'created_by_id', '{{%users}}', 'id');
$this->createIndex('blog_posts_title_key', '{{%blog_posts}}', 'title', true);
$this->createIndex('blog_posts_slug_key', '{{%blog_posts}}', 'slug', true);
$this->addForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}', 'category_id', '{{%categories}}', 'id');
$this->addForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}', 'created_by_id', '{{%users}}', 'id');
}

public function down()
{
$this->dropIndex('blog_posts_slug_key', '{{%blog_posts}}');
$this->dropIndex('blog_posts_title_key', '{{%blog_posts}}');
$this->dropForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}');
$this->dropForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}');
$this->dropIndex('blog_posts_slug_key', '{{%blog_posts}}');
$this->dropIndex('blog_posts_title_key', '{{%blog_posts}}');
$this->dropPrimaryKey('pk_blog_posts_uid', '{{%blog_posts}}');
$this->dropTable('{{%blog_posts}}');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function up()
]);
$this->createIndex('users_username_key', '{{%users}}', 'username', true);
$this->createIndex('users_email_key', '{{%users}}', 'email', true);
$this->createIndex('users_role_flags_index', '{{%users}}', 'role,flags', false);
$this->createIndex('users_role_flags_index', '{{%users}}', ["role", "flags"], false);
}

public function down()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ public function up()
'created_by_id' => $this->integer()->null()->defaultValue(null),
]);
$this->addPrimaryKey('pk_blog_posts_uid', '{{%blog_posts}}', 'uid');
$this->addForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}', 'category_id', '{{%categories}}', 'id');
$this->addForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}', 'created_by_id', '{{%users}}', 'id');
$this->createIndex('blog_posts_title_key', '{{%blog_posts}}', 'title', true);
$this->createIndex('blog_posts_slug_key', '{{%blog_posts}}', 'slug', true);
$this->addForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}', 'category_id', '{{%categories}}', 'id');
$this->addForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}', 'created_by_id', '{{%users}}', 'id');
}

public function down()
{
$this->dropIndex('blog_posts_slug_key', '{{%blog_posts}}');
$this->dropIndex('blog_posts_title_key', '{{%blog_posts}}');
$this->dropForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}');
$this->dropForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}');
$this->dropIndex('blog_posts_slug_key', '{{%blog_posts}}');
$this->dropIndex('blog_posts_title_key', '{{%blog_posts}}');
$this->dropPrimaryKey('pk_blog_posts_uid', '{{%blog_posts}}');
$this->dropTable('{{%blog_posts}}');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function up()
]);
$this->createIndex('users_username_key', '{{%users}}', 'username', true);
$this->createIndex('users_email_key', '{{%users}}', 'email', true);
$this->createIndex('users_role_flags_index', '{{%users}}', 'role,flags', false);
$this->createIndex('users_role_flags_index', '{{%users}}', ["role", "flags"], false);
}

public function down()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ public function up()
'created_by_id' => $this->integer()->null()->defaultValue(null),
]);
$this->addPrimaryKey('pk_blog_posts_uid', '{{%blog_posts}}', 'uid');
$this->addForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}', 'category_id', '{{%categories}}', 'id');
$this->addForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}', 'created_by_id', '{{%users}}', 'id');
$this->createIndex('blog_posts_title_key', '{{%blog_posts}}', 'title', true);
$this->createIndex('blog_posts_slug_key', '{{%blog_posts}}', 'slug', true);
$this->addForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}', 'category_id', '{{%categories}}', 'id');
$this->addForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}', 'created_by_id', '{{%users}}', 'id');
}

public function down()
{
$this->dropIndex('blog_posts_slug_key', '{{%blog_posts}}');
$this->dropIndex('blog_posts_title_key', '{{%blog_posts}}');
$this->dropForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}');
$this->dropForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}');
$this->dropIndex('blog_posts_slug_key', '{{%blog_posts}}');
$this->dropIndex('blog_posts_title_key', '{{%blog_posts}}');
$this->dropPrimaryKey('pk_blog_posts_uid', '{{%blog_posts}}');
$this->dropTable('{{%blog_posts}}');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function safeUp()
]);
$this->createIndex('users_username_key', '{{%users}}', 'username', true);
$this->createIndex('users_email_key', '{{%users}}', 'email', true);
$this->createIndex('users_role_flags_index', '{{%users}}', 'role,flags', false);
$this->createIndex('users_role_flags_index', '{{%users}}', ["role", "flags"], false);
}

public function safeDown()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ public function safeUp()
'created_by_id' => $this->integer()->null()->defaultValue(null),
]);
$this->addPrimaryKey('pk_blog_posts_uid', '{{%blog_posts}}', 'uid');
$this->addForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}', 'category_id', '{{%categories}}', 'id');
$this->addForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}', 'created_by_id', '{{%users}}', 'id');
$this->createIndex('blog_posts_title_key', '{{%blog_posts}}', 'title', true);
$this->createIndex('blog_posts_slug_key', '{{%blog_posts}}', 'slug', true);
$this->addForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}', 'category_id', '{{%categories}}', 'id');
$this->addForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}', 'created_by_id', '{{%users}}', 'id');
}

public function safeDown()
{
$this->dropIndex('blog_posts_slug_key', '{{%blog_posts}}');
$this->dropIndex('blog_posts_title_key', '{{%blog_posts}}');
$this->dropForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}');
$this->dropForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}');
$this->dropIndex('blog_posts_slug_key', '{{%blog_posts}}');
$this->dropIndex('blog_posts_title_key', '{{%blog_posts}}');
$this->dropPrimaryKey('pk_blog_posts_uid', '{{%blog_posts}}');
$this->dropTable('{{%blog_posts}}');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public function up()
$this->alterColumn('{{%v2_users}}', 'created_at', $this->timestamp()->null()->defaultValue(null));
$this->dropIndex('v2_users_username_key', '{{%v2_users}}');
$this->createIndex('v2_users_login_key', '{{%v2_users}}', 'login', true);
$this->createIndex('v2_users_role_flags_hash_index', '{{%v2_users}}', 'role,flags', 'hash');
$this->createIndex('v2_users_role_flags_hash_index', '{{%v2_users}}', ["role", "flags"], 'hash');
}

public function down()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public function up()
$this->alterColumn('{{%v2_users}}', 'created_at', $this->timestamp()->null()->defaultValue(null));
$this->dropIndex('v2_users_username_key', '{{%v2_users}}');
$this->createIndex('v2_users_login_key', '{{%v2_users}}', 'login', true);
$this->createIndex('v2_users_role_flags_hash_index', '{{%v2_users}}', 'role,flags', 'hash');
$this->createIndex('v2_users_role_flags_hash_index', '{{%v2_users}}', ["role", "flags"], 'hash');
}

public function down()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function safeUp()
$this->alterColumn('{{%v2_users}}', 'created_at', "DROP DEFAULT");
$this->dropIndex('v2_users_username_key', '{{%v2_users}}');
$this->createIndex('v2_users_login_key', '{{%v2_users}}', 'login', true);
$this->createIndex('v2_users_role_flags_hash_index', '{{%v2_users}}', 'role,flags', 'hash');
$this->createIndex('v2_users_role_flags_hash_index', '{{%v2_users}}', ["role", "flags"], 'hash');
}

public function safeDown()
Expand Down
2 changes: 1 addition & 1 deletion tests/specs/fk_col_name/app/models/WebhookFaker.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function generateModel($attributes = [])
//$model->id = $uniqueFaker->numberBetween(0, 1000000);
$model->name = $faker->sentence;
$model->user_id = $faker->randomElement(\app\models\User::find()->select("id")->column());
$model->redelivery_of = $faker->numberBetween(0, 1000000);
$model->redelivery_of = $faker->randomElement(\app\models\Delivery::find()->select("id")->column());
if (!is_callable($attributes)) {
$model->setAttributes($attributes, false);
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

/**
* Table for Delivery
*/
class m200000_000000_create_table_deliveries extends \yii\db\Migration
{
public function up()
{
$this->createTable('{{%deliveries}}', [
'id' => $this->primaryKey(),
'title' => $this->text()->null(),
]);
}

public function down()
{
$this->dropTable('{{%deliveries}}');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

/**
* Table for User
*/
class m200000_000001_create_table_users extends \yii\db\Migration
{
public function up()
{
$this->createTable('{{%users}}', [
'id' => $this->primaryKey(),
'name' => $this->text()->notNull(),
]);
}

public function down()
{
$this->dropTable('{{%users}}');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

/**
* Table for Webhook
*/
class m200000_000002_create_table_webhooks extends \yii\db\Migration
{
public function up()
{
$this->createTable('{{%webhooks}}', [
'id' => $this->primaryKey(),
'name' => $this->string(255)->null()->defaultValue(null),
'user_id' => $this->integer()->null()->defaultValue(null),
'redelivery_of' => $this->integer()->null()->defaultValue(null),
'rd_abc_2' => $this->integer()->null()->defaultValue(null),
]);
$this->createIndex('webhooks_user_id_name_key', '{{%webhooks}}', ["user_id", "name"], true);
$this->createIndex('webhooks_redelivery_of_name_key', '{{%webhooks}}', ["redelivery_of", "name"], true);
$this->createIndex('webhooks_rd_abc_2_name_key', '{{%webhooks}}', ["rd_abc_2", "name"], true);
$this->addForeignKey('fk_webhooks_user_id_users_id', '{{%webhooks}}', 'user_id', '{{%users}}', 'id');
$this->addForeignKey('fk_webhooks_redelivery_of_deliveries_id', '{{%webhooks}}', 'redelivery_of', '{{%deliveries}}', 'id');
$this->addForeignKey('fk_webhooks_rd_abc_2_deliveries_id', '{{%webhooks}}', 'rd_abc_2', '{{%deliveries}}', 'id');
}

public function down()
{
$this->dropForeignKey('fk_webhooks_rd_abc_2_deliveries_id', '{{%webhooks}}');
$this->dropForeignKey('fk_webhooks_redelivery_of_deliveries_id', '{{%webhooks}}');
$this->dropForeignKey('fk_webhooks_user_id_users_id', '{{%webhooks}}');
$this->dropIndex('webhooks_rd_abc_2_name_key', '{{%webhooks}}');
$this->dropIndex('webhooks_redelivery_of_name_key', '{{%webhooks}}');
$this->dropIndex('webhooks_user_id_name_key', '{{%webhooks}}');
$this->dropTable('{{%webhooks}}');
}
}
Loading
Loading