From 54483a27ca494e72b7e239a20e1281e24c07ddde Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 2 May 2024 16:46:30 +0200 Subject: [PATCH 1/5] Failing test case for #168, can not define index for a relation key --- ...m200000_000000_create_table_deliveries.php | 20 +++ .../m200000_000001_create_table_users.php | 20 +++ .../m200000_000002_create_table_webhooks.php | 29 ++++ .../app/models/BaseModelFaker.php | 144 ++++++++++++++++++ .../fk_col_name_index/app/models/Delivery.php | 10 ++ .../app/models/DeliveryFaker.php | 41 +++++ .../fk_col_name_index/app/models/User.php | 10 ++ .../app/models/UserFaker.php | 41 +++++ .../fk_col_name_index/app/models/Webhook.php | 10 ++ .../app/models/WebhookFaker.php | 53 +++++++ .../app/models/base/Delivery.php | 26 ++++ .../app/models/base/User.php | 27 ++++ .../app/models/base/Webhook.php | 44 ++++++ .../fk_col_name_index/fk_col_name_index.php | 13 ++ .../fk_col_name_index/fk_col_name_index.yaml | 54 +++++++ tests/unit/ForeignKeyColumnNameTest.php | 16 ++ 16 files changed, 558 insertions(+) create mode 100644 tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000000_create_table_deliveries.php create mode 100644 tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000001_create_table_users.php create mode 100644 tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000002_create_table_webhooks.php create mode 100644 tests/specs/fk_col_name_index/app/models/BaseModelFaker.php create mode 100644 tests/specs/fk_col_name_index/app/models/Delivery.php create mode 100644 tests/specs/fk_col_name_index/app/models/DeliveryFaker.php create mode 100644 tests/specs/fk_col_name_index/app/models/User.php create mode 100644 tests/specs/fk_col_name_index/app/models/UserFaker.php create mode 100644 tests/specs/fk_col_name_index/app/models/Webhook.php create mode 100644 tests/specs/fk_col_name_index/app/models/WebhookFaker.php create mode 100644 tests/specs/fk_col_name_index/app/models/base/Delivery.php create mode 100644 tests/specs/fk_col_name_index/app/models/base/User.php create mode 100644 tests/specs/fk_col_name_index/app/models/base/Webhook.php create mode 100644 tests/specs/fk_col_name_index/fk_col_name_index.php create mode 100644 tests/specs/fk_col_name_index/fk_col_name_index.yaml diff --git a/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000000_create_table_deliveries.php b/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000000_create_table_deliveries.php new file mode 100644 index 00000000..e88d0ea9 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000000_create_table_deliveries.php @@ -0,0 +1,20 @@ +createTable('{{%deliveries}}', [ + 'id' => $this->primaryKey(), + 'title' => $this->text()->null(), + ]); + } + + public function down() + { + $this->dropTable('{{%deliveries}}'); + } +} diff --git a/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000001_create_table_users.php b/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000001_create_table_users.php new file mode 100644 index 00000000..e6e9afe4 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000001_create_table_users.php @@ -0,0 +1,20 @@ +createTable('{{%users}}', [ + 'id' => $this->primaryKey(), + 'name' => $this->text()->notNull(), + ]); + } + + public function down() + { + $this->dropTable('{{%users}}'); + } +} diff --git a/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000002_create_table_webhooks.php b/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000002_create_table_webhooks.php new file mode 100644 index 00000000..cf3b0845 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/migrations_mysql_db/m200000_000002_create_table_webhooks.php @@ -0,0 +1,29 @@ +createTable('{{%webhooks}}', [ + 'id' => $this->primaryKey(), + 'name' => $this->text()->null(), + 'user_id' => $this->integer()->null()->defaultValue(null), + 'redelivery_of' => $this->integer()->null()->defaultValue(null), + ]); + $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'); + // TOOD add index names + $this->createIndex('...', '{{%webhooks}}', ['user_id', 'name'], true); + $this->createIndex('...', '{{%webhooks}}', ['redelivery_of', 'name'], true); + } + + public function down() + { + $this->dropForeignKey('fk_webhooks_redelivery_of_deliveries_id', '{{%webhooks}}'); + $this->dropForeignKey('fk_webhooks_user_id_users_id', '{{%webhooks}}'); + $this->dropTable('{{%webhooks}}'); + } +} diff --git a/tests/specs/fk_col_name_index/app/models/BaseModelFaker.php b/tests/specs/fk_col_name_index/app/models/BaseModelFaker.php new file mode 100644 index 00000000..c367fbb4 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/models/BaseModelFaker.php @@ -0,0 +1,144 @@ +faker = FakerFactory::create(str_replace('-', '_', \Yii::$app->language)); + $this->uniqueFaker = new UniqueGenerator($this->faker); + } + + abstract public function generateModel($attributes = []); + + public function getFaker():Generator + { + return $this->faker; + } + + public function getUniqueFaker():UniqueGenerator + { + return $this->uniqueFaker; + } + + public function setFaker(Generator $faker):void + { + $this->faker = $faker; + } + + public function setUniqueFaker(UniqueGenerator $faker):void + { + $this->uniqueFaker = $faker; + } + + /** + * Generate and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::makeOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::makeOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function makeOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + $model = $fakeBuilder->generateModel($attributes); + return $model; + } + + /** + * Generate, save and return model + * @param array|callable $attributes + * @param UniqueGenerator|null $uniqueFaker + * @return \yii\db\ActiveRecord + * @example MyFaker::saveOne(['user_id' => 1, 'title' => 'foo']); + * @example MyFaker::saveOne( function($model, $faker) { + * $model->scenario = 'create'; + * $model->setAttributes(['user_id' => 1, 'title' => $faker->sentence]); + * return $model; + * }); + */ + public static function saveOne($attributes = [], ?UniqueGenerator $uniqueFaker = null) + { + $model = static::makeOne($attributes, $uniqueFaker); + $model->save(); + return $model; + } + + /** + * Generate and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::make(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::make(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function make(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + return $model; + }, range(0, $number -1)); + } + + /** + * Generate, save and return multiple models + * @param int $number + * @param array|callable $commonAttributes + * @return \yii\db\ActiveRecord[]|array + * @example TaskFaker::save(5, ['project_id'=>1, 'user_id' => 2]); + * @example TaskFaker::save(5, function($model, $faker, $uniqueFaker) { + * $model->setAttributes(['name' => $uniqueFaker->username, 'state'=>$faker->boolean(20)]); + * return $model; + * }); + */ + public static function save(int $number, $commonAttributes = [], ?UniqueGenerator $uniqueFaker = null):array + { + if ($number < 1) { + return []; + } + $fakeBuilder = new static(); + if ($uniqueFaker !== null) { + $fakeBuilder->setUniqueFaker($uniqueFaker); + } + return array_map(function () use ($commonAttributes, $fakeBuilder) { + $model = $fakeBuilder->generateModel($commonAttributes); + $model->save(); + return $model; + }, range(0, $number -1)); + } +} diff --git a/tests/specs/fk_col_name_index/app/models/Delivery.php b/tests/specs/fk_col_name_index/app/models/Delivery.php new file mode 100644 index 00000000..1249e2b3 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/models/Delivery.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new Delivery(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->title = $faker->sentence; + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } +} diff --git a/tests/specs/fk_col_name_index/app/models/User.php b/tests/specs/fk_col_name_index/app/models/User.php new file mode 100644 index 00000000..9b837d6e --- /dev/null +++ b/tests/specs/fk_col_name_index/app/models/User.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new User(); + //$model->id = $uniqueFaker->numberBetween(0, 1000000); + $model->name = $faker->sentence; + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } +} diff --git a/tests/specs/fk_col_name_index/app/models/Webhook.php b/tests/specs/fk_col_name_index/app/models/Webhook.php new file mode 100644 index 00000000..e02ca284 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/models/Webhook.php @@ -0,0 +1,10 @@ +generateModels(['author_id' => 1]); + * $model = (new PostFaker())->generateModels(function($model, $faker, $uniqueFaker) { + * $model->scenario = 'create'; + * $model->author_id = 1; + * return $model; + * }); + **/ + public function generateModel($attributes = []) + { + $faker = $this->faker; + $uniqueFaker = $this->uniqueFaker; + $model = new Webhook(); + //$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); + if (!is_callable($attributes)) { + $model->setAttributes($attributes, false); + } else { + $model = $attributes($model, $faker, $uniqueFaker); + } + return $model; + } + + public static function dependentOn() + { + return [ + // just model class names + 'User', + 'Delivery', + + ]; + } +} diff --git a/tests/specs/fk_col_name_index/app/models/base/Delivery.php b/tests/specs/fk_col_name_index/app/models/base/Delivery.php new file mode 100644 index 00000000..ae7cbd83 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/models/base/Delivery.php @@ -0,0 +1,26 @@ + [['title'], 'trim'], + 'title_string' => [['title'], 'string'], + ]; + } +} diff --git a/tests/specs/fk_col_name_index/app/models/base/User.php b/tests/specs/fk_col_name_index/app/models/base/User.php new file mode 100644 index 00000000..d76c3f4d --- /dev/null +++ b/tests/specs/fk_col_name_index/app/models/base/User.php @@ -0,0 +1,27 @@ + [['name'], 'trim'], + 'required' => [['name'], 'required'], + 'name_string' => [['name'], 'string'], + ]; + } +} diff --git a/tests/specs/fk_col_name_index/app/models/base/Webhook.php b/tests/specs/fk_col_name_index/app/models/base/Webhook.php new file mode 100644 index 00000000..8746e8f0 --- /dev/null +++ b/tests/specs/fk_col_name_index/app/models/base/Webhook.php @@ -0,0 +1,44 @@ + [['name'], 'trim'], + 'user_id_integer' => [['user_id'], 'integer'], + 'user_id_exist' => [['user_id'], 'exist', 'targetRelation' => 'User'], + 'redelivery_of_integer' => [['redelivery_of'], 'integer'], + 'redelivery_of_exist' => [['redelivery_of'], 'exist', 'targetRelation' => 'RedeliveryOf'], + 'name_string' => [['name'], 'string'], + ]; + } + + public function getUser() + { + return $this->hasOne(\app\models\User::class, ['id' => 'user_id']); + } + + public function getRedeliveryOf() + { + return $this->hasOne(\app\models\Delivery::class, ['id' => 'redelivery_of']); + } +} diff --git a/tests/specs/fk_col_name_index/fk_col_name_index.php b/tests/specs/fk_col_name_index/fk_col_name_index.php new file mode 100644 index 00000000..e952e245 --- /dev/null +++ b/tests/specs/fk_col_name_index/fk_col_name_index.php @@ -0,0 +1,13 @@ + '@specs/fk_col_name_index/fk_col_name_index.yaml', + 'generateUrls' => false, + 'generateModels' => true, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => true, + 'generateModelFaker' => true, +]; diff --git a/tests/specs/fk_col_name_index/fk_col_name_index.yaml b/tests/specs/fk_col_name_index/fk_col_name_index.yaml new file mode 100644 index 00000000..fb4976ce --- /dev/null +++ b/tests/specs/fk_col_name_index/fk_col_name_index.yaml @@ -0,0 +1,54 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: ID not in rules test +paths: + /: + get: + summary: List + operationId: list + responses: + '200': + description: The information + +components: + schemas: + User: + type: object + description: Test model for model code generation that should not contain id column in rules + required: + - id + - name + properties: + id: + type: integer + name: + type: string + Delivery: + x-table: deliveries + required: + - id + properties: + id: + type: integer + title: + type: string + Webhook: + x-indexes: + - 'unique:user_id,name' + - 'unique:redelivery_of,name' + type: object + description: example for x-fk-column-name + properties: + id: + type: integer + name: + type: string + user: + $ref: '#/components/schemas/User' # this will automatically create `user_id` column + redelivery_of: + allOf: + - $ref: '#/components/schemas/Delivery' + # this will automatically create `redelivery_of_id` column, but to avoid that use below extension + - x-fk-column-name: redelivery_of # this will create `redelivery_of` column instead of `redelivery_of_id` + diff --git a/tests/unit/ForeignKeyColumnNameTest.php b/tests/unit/ForeignKeyColumnNameTest.php index 24401ea5..119bfdf8 100644 --- a/tests/unit/ForeignKeyColumnNameTest.php +++ b/tests/unit/ForeignKeyColumnNameTest.php @@ -30,4 +30,20 @@ public function testIndex() $this->checkFiles($actualFiles, $expectedFiles); $this->runActualMigrations('mysql', 3); } + + public function testIndexForColumnWithCustomName() + { + // default DB is Mysql ---------------------------------- + + $testFile = Yii::getAlias("@specs/fk_col_name_index/fk_col_name_index.php"); + $this->runGenerator($testFile, 'mysql'); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/fk_col_name_index/app"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + $this->runActualMigrations('mysql', 3); + } } From 6332fba106c3ff8d7e1ff92c7fefb91113a6a19e Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Thu, 2 May 2024 21:04:34 +0530 Subject: [PATCH 2/5] Attempt to fix Github Action failing setup --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index f36f7f87..b567199d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,7 +31,7 @@ services: ports: - '13306:3306' volumes: - - ./tests/tmp/mysql:/var/lib/mysql:rw + - mysql:/var/lib/mysql:rw environment: TZ: UTC MYSQL_ALLOW_EMPTY_PASSWORD: 1 From 3d835dcf9973cdddb5c7550b65c4243de1aa9866 Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Thu, 2 May 2024 21:28:54 +0530 Subject: [PATCH 3/5] Attempt 2 --- Makefile | 6 +++++- docker-compose.yml | 3 ++- tests/.gitignore | 5 ++++- tests/tmp/mysql/.gitignore | 4 ++++ 4 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 tests/tmp/mysql/.gitignore diff --git a/Makefile b/Makefile index e550c0f4..30c92116 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,11 @@ test: clean_all: docker-compose down - sudo rm -rf tests/tmp/* + # sudo rm -rf tests/tmp/* + sudo rm -rf tests/tmp/app/* + sudo rm -rf tests/tmp/docker_app/* + sudo rm -rf tests/tmp/maria/* + sudo rm -rf tests/tmp/cache/* clean: sudo rm -rf tests/tmp/app/* diff --git a/docker-compose.yml b/docker-compose.yml index b567199d..57bc5b45 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,7 +31,8 @@ services: ports: - '13306:3306' volumes: - - mysql:/var/lib/mysql:rw + - ./tests/tmp/mysql:/var/lib/mysql:rw + # - mysql:/var/lib/mysql environment: TZ: UTC MYSQL_ALLOW_EMPTY_PASSWORD: 1 diff --git a/tests/.gitignore b/tests/.gitignore index cad23091..5f8b7fa8 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1 +1,4 @@ -/tmp \ No newline at end of file +/tmp/cache +/tmp/docker_app +/tmp/maria +# !/tmp/mysql/.gitignore diff --git a/tests/tmp/mysql/.gitignore b/tests/tmp/mysql/.gitignore new file mode 100644 index 00000000..222e4b49 --- /dev/null +++ b/tests/tmp/mysql/.gitignore @@ -0,0 +1,4 @@ +# .gitignore +* +./../* +!.gitignore From a77282ac260650d534d5bd5357bdea9ef49fa9e7 Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Thu, 2 May 2024 21:51:24 +0530 Subject: [PATCH 4/5] 3 --- Makefile | 1 + docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 30c92116..01e1c3fd 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,7 @@ clean_all: sudo rm -rf tests/tmp/docker_app/* sudo rm -rf tests/tmp/maria/* sudo rm -rf tests/tmp/cache/* + sudo rm -rf tests/tmp/postgres/* clean: sudo rm -rf tests/tmp/app/* diff --git a/docker-compose.yml b/docker-compose.yml index 57bc5b45..78559c7c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,7 +27,7 @@ services: - maria tty: true mysql: - image: mysql:8 + image: mysql:8.0.37 ports: - '13306:3306' volumes: From 31a85b3b4f3de5ad3195866a374e5fd676ec47da Mon Sep 17 00:00:00 2001 From: Sohel Ahmed Mesaniya Date: Thu, 2 May 2024 21:59:48 +0530 Subject: [PATCH 5/5] Cleanup --- Makefile | 7 +------ docker-compose.yml | 1 - tests/.gitignore | 5 +---- tests/tmp/mysql/.gitignore | 4 ---- 4 files changed, 2 insertions(+), 15 deletions(-) delete mode 100644 tests/tmp/mysql/.gitignore diff --git a/Makefile b/Makefile index 01e1c3fd..e550c0f4 100644 --- a/Makefile +++ b/Makefile @@ -25,12 +25,7 @@ test: clean_all: docker-compose down - # sudo rm -rf tests/tmp/* - sudo rm -rf tests/tmp/app/* - sudo rm -rf tests/tmp/docker_app/* - sudo rm -rf tests/tmp/maria/* - sudo rm -rf tests/tmp/cache/* - sudo rm -rf tests/tmp/postgres/* + sudo rm -rf tests/tmp/* clean: sudo rm -rf tests/tmp/app/* diff --git a/docker-compose.yml b/docker-compose.yml index 78559c7c..68a9c9bc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -32,7 +32,6 @@ services: - '13306:3306' volumes: - ./tests/tmp/mysql:/var/lib/mysql:rw - # - mysql:/var/lib/mysql environment: TZ: UTC MYSQL_ALLOW_EMPTY_PASSWORD: 1 diff --git a/tests/.gitignore b/tests/.gitignore index 5f8b7fa8..ceeb05b4 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,4 +1 @@ -/tmp/cache -/tmp/docker_app -/tmp/maria -# !/tmp/mysql/.gitignore +/tmp diff --git a/tests/tmp/mysql/.gitignore b/tests/tmp/mysql/.gitignore deleted file mode 100644 index 222e4b49..00000000 --- a/tests/tmp/mysql/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# .gitignore -* -./../* -!.gitignore