From aff41c50a4d2bf31b7cf59dc056e35b659c3a3c0 Mon Sep 17 00:00:00 2001 From: Christopher Lorke Date: Tue, 18 Sep 2018 19:53:00 +0200 Subject: [PATCH] Migrations from database. --- README.md | 1 - .../Repository/ElasticsearchMigration.php | 13 +- .../ElasticsearchMigrationStatus.php | 56 +++ .../Repository/ElasticsearchMigrations.php | 34 ++ .../ElasticsearchMigrationsAlias.php | 37 ++ .../ElasticsearchMigrationsCreateIndex.php | 38 ++ .../ElasticsearchMigrationsDeleteByQuery.php | 37 ++ .../ElasticsearchMigrationsReindex.php | 41 ++ .../ElasticsearchMigrationsUpdateByQuery.php | 39 ++ .../ElasticsearchMigrationsUpdateIndex.php | 43 ++ src/Console/Commands/ShowMigration.php | 8 +- src/Console/Commands/StartMigration.php | 8 +- .../ElasticsearchMigrationContract.php | 6 +- ...ElasticsearchMigrationDatabaseContract.php | 32 ++ .../ElasticsearchMigrationContract.php | 12 +- .../ElasticsearchMigrationStatusContract.php | 45 ++ .../ElasticsearchMigrationsAliasContract.php | 33 ++ .../ElasticsearchMigrationsContract.php | 27 ++ ...ticsearchMigrationsCreateIndexContract.php | 31 ++ ...csearchMigrationsDeleteByQueryContract.php | 33 ++ ...ElasticsearchMigrationsReindexContract.php | 37 ++ ...csearchMigrationsUpdateByQueryContract.php | 35 ++ ...ticsearchMigrationsUpdateIndexContract.php | 33 ++ ...e_elasticsearch_migration_status_table.php | 33 ++ ..._create_elasticsearch_migration_table.php} | 1 - ..._create_elasticsearch_migrations_table.php | 36 ++ ...e_elasticsearch_migrations_alias_table.php | 37 ++ ...icsearch_migrations_create_index_table.php | 36 ++ ...earch_migrations_delete_by_query_table.php | 37 ++ ...elasticsearch_migrations_reindex_table.php | 39 ++ ...earch_migrations_update_by_query_table.php | 38 ++ ...icsearch_migrations_update_index_table.php | 37 ++ src/ElasticsearchMigration.php | 25 +- src/ElasticsearchMigrationDatabase.php | 297 +++++++++++++ src/Models/Entity/ElasticsearchMigration.php | 14 +- .../Entity/ElasticsearchMigrationStatus.php | 24 ++ src/Models/Entity/ElasticsearchMigrations.php | 61 +++ .../Entity/ElasticsearchMigrationsAlias.php | 26 ++ .../ElasticsearchMigrationsCreateIndex.php | 25 ++ .../ElasticsearchMigrationsDeleteByQuery.php | 26 ++ .../Entity/ElasticsearchMigrationsReindex.php | 28 ++ .../ElasticsearchMigrationsUpdateByQuery.php | 27 ++ .../ElasticsearchMigrationsUpdateIndex.php | 26 ++ .../ElasticsearchMigrationServiceProvider.php | 82 +++- .../ElasticsearchMigrationStatusTest.php | 103 +++++ .../Repository/ElasticsearchMigrationTest.php | 65 +-- .../ElasticsearchMigrationsAliasTest.php | 59 +++ ...ElasticsearchMigrationsCreateIndexTest.php | 59 +++ ...asticsearchMigrationsDeleteByQueryTest.php | 59 +++ .../ElasticsearchMigrationsReindexTest.php | 59 +++ .../ElasticsearchMigrationsTest.php | 218 ++++++++++ ...asticsearchMigrationsUpdateByQueryTest.php | 59 +++ ...ElasticsearchMigrationsUpdateIndexTest.php | 59 +++ .../Console/Commands/ShowMigrationTest.php | 4 +- .../Console/Commands/StartMigrationTest.php | 188 +++++++- .../ElasticsearchMigrationDatabaseTest.php | 283 ++++++++++++ .../ElasticsearchMigrationTest.php | 401 +++++++++++++++++- 57 files changed, 3166 insertions(+), 84 deletions(-) create mode 100644 src/Business/Repository/ElasticsearchMigrationStatus.php create mode 100644 src/Business/Repository/ElasticsearchMigrations.php create mode 100644 src/Business/Repository/ElasticsearchMigrationsAlias.php create mode 100644 src/Business/Repository/ElasticsearchMigrationsCreateIndex.php create mode 100644 src/Business/Repository/ElasticsearchMigrationsDeleteByQuery.php create mode 100644 src/Business/Repository/ElasticsearchMigrationsReindex.php create mode 100644 src/Business/Repository/ElasticsearchMigrationsUpdateByQuery.php create mode 100644 src/Business/Repository/ElasticsearchMigrationsUpdateIndex.php create mode 100644 src/Contract/ElasticsearchMigrationDatabaseContract.php create mode 100644 src/Contract/Repository/ElasticsearchMigrationStatusContract.php create mode 100644 src/Contract/Repository/ElasticsearchMigrationsAliasContract.php create mode 100644 src/Contract/Repository/ElasticsearchMigrationsContract.php create mode 100644 src/Contract/Repository/ElasticsearchMigrationsCreateIndexContract.php create mode 100644 src/Contract/Repository/ElasticsearchMigrationsDeleteByQueryContract.php create mode 100644 src/Contract/Repository/ElasticsearchMigrationsReindexContract.php create mode 100644 src/Contract/Repository/ElasticsearchMigrationsUpdateByQueryContract.php create mode 100644 src/Contract/Repository/ElasticsearchMigrationsUpdateIndexContract.php create mode 100644 src/Database/Migrations/2018_09_11_000000_create_elasticsearch_migration_status_table.php rename src/Database/Migrations/{2018_09_11_000000_create_elasticsearch_migration_table.php => 2018_09_18_000000_create_elasticsearch_migration_table.php} (94%) create mode 100644 src/Database/Migrations/2018_09_22_000000_create_elasticsearch_migrations_table.php create mode 100644 src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_alias_table.php create mode 100644 src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_create_index_table.php create mode 100644 src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_delete_by_query_table.php create mode 100644 src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_reindex_table.php create mode 100644 src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_update_by_query_table.php create mode 100644 src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_update_index_table.php create mode 100644 src/ElasticsearchMigrationDatabase.php create mode 100644 src/Models/Entity/ElasticsearchMigrationStatus.php create mode 100644 src/Models/Entity/ElasticsearchMigrations.php create mode 100644 src/Models/Entity/ElasticsearchMigrationsAlias.php create mode 100644 src/Models/Entity/ElasticsearchMigrationsCreateIndex.php create mode 100644 src/Models/Entity/ElasticsearchMigrationsDeleteByQuery.php create mode 100644 src/Models/Entity/ElasticsearchMigrationsReindex.php create mode 100644 src/Models/Entity/ElasticsearchMigrationsUpdateByQuery.php create mode 100644 src/Models/Entity/ElasticsearchMigrationsUpdateIndex.php create mode 100644 tests/integration/Business/Repository/ElasticsearchMigrationStatusTest.php create mode 100644 tests/integration/Business/Repository/ElasticsearchMigrationsAliasTest.php create mode 100644 tests/integration/Business/Repository/ElasticsearchMigrationsCreateIndexTest.php create mode 100644 tests/integration/Business/Repository/ElasticsearchMigrationsDeleteByQueryTest.php create mode 100644 tests/integration/Business/Repository/ElasticsearchMigrationsReindexTest.php create mode 100644 tests/integration/Business/Repository/ElasticsearchMigrationsTest.php create mode 100644 tests/integration/Business/Repository/ElasticsearchMigrationsUpdateByQueryTest.php create mode 100644 tests/integration/Business/Repository/ElasticsearchMigrationsUpdateIndexTest.php create mode 100644 tests/integration/ElasticsearchMigrationDatabaseTest.php diff --git a/README.md b/README.md index 6030bcb..d5aef55 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,6 @@ Example: >php artisan triadev:elasticsearch:migration:show ## Roadmap -- migrations from database [Branch](https://github.com/triadev/LaravelElasticsearchMigration/tree/database_migrations) - create/delete templates - shrink index - split index diff --git a/src/Business/Repository/ElasticsearchMigration.php b/src/Business/Repository/ElasticsearchMigration.php index 1d17831..52bfeb6 100644 --- a/src/Business/Repository/ElasticsearchMigration.php +++ b/src/Business/Repository/ElasticsearchMigration.php @@ -1,7 +1,6 @@ find($migration); @@ -20,7 +18,6 @@ public function createOrUpdate( $dbMigration->migration = $migration; } - $dbMigration->status = $status; $dbMigration->saveOrFail(); return $dbMigration; @@ -36,14 +33,6 @@ public function find(string $migration): ?\Triadev\EsMigration\Models\Entity\Ela ->first(); } - /** - * @inheritdoc - */ - public function all(array $fields = ['*']) : Collection - { - return \Triadev\EsMigration\Models\Entity\ElasticsearchMigration::all($fields); - } - /** * @inheritdoc */ diff --git a/src/Business/Repository/ElasticsearchMigrationStatus.php b/src/Business/Repository/ElasticsearchMigrationStatus.php new file mode 100644 index 0000000..8dfdcbb --- /dev/null +++ b/src/Business/Repository/ElasticsearchMigrationStatus.php @@ -0,0 +1,56 @@ +find($migration); + + if (!$dbMigration) { + $dbMigration = new \Triadev\EsMigration\Models\Entity\ElasticsearchMigrationStatus(); + $dbMigration->migration = $migration; + } + + $dbMigration->status = $status; + $dbMigration->saveOrFail(); + + return $dbMigration; + } + + /** + * @inheritdoc + */ + public function find(string $migration): ?\Triadev\EsMigration\Models\Entity\ElasticsearchMigrationStatus + { + return \Triadev\EsMigration\Models\Entity\ElasticsearchMigrationStatus::where('migration', $migration) + ->orderBy('created_at', 'desc') + ->first(); + } + + /** + * @inheritdoc + */ + public function all(array $fields = ['*']) : Collection + { + return \Triadev\EsMigration\Models\Entity\ElasticsearchMigrationStatus::all($fields); + } + + /** + * @inheritdoc + */ + public function delete(string $migration) + { + if ($migration = $this->find($migration)) { + $migration->delete(); + } + } +} diff --git a/src/Business/Repository/ElasticsearchMigrations.php b/src/Business/Repository/ElasticsearchMigrations.php new file mode 100644 index 0000000..af338ef --- /dev/null +++ b/src/Business/Repository/ElasticsearchMigrations.php @@ -0,0 +1,34 @@ +migration_id = $migrationId; + $dbMigration->type = $type; + $dbMigration->index = $index; + + $dbMigration->saveOrFail(); + + return $dbMigration; + } + + /** + * @inheritdoc + */ + public function find(int $migrationsId): ?\Triadev\EsMigration\Models\Entity\ElasticsearchMigrations + { + return \Triadev\EsMigration\Models\Entity\ElasticsearchMigrations::where('id', $migrationsId) + ->first(); + } +} diff --git a/src/Business/Repository/ElasticsearchMigrationsAlias.php b/src/Business/Repository/ElasticsearchMigrationsAlias.php new file mode 100644 index 0000000..c5858b9 --- /dev/null +++ b/src/Business/Repository/ElasticsearchMigrationsAlias.php @@ -0,0 +1,37 @@ +migrations_id = $migrationsId; + $dbMigration->add = json_encode($add); + $dbMigration->remove = json_encode($remove); + $dbMigration->remove_indices = json_encode($removeIndices); + + $dbMigration->saveOrFail(); + + return $dbMigration; + } + + /** + * @inheritdoc + */ + public function find(int $migrationsId): ?\Triadev\EsMigration\Models\Entity\ElasticsearchMigrationsAlias + { + return \Triadev\EsMigration\Models\Entity\ElasticsearchMigrationsAlias::where('migrations_id', + $migrationsId) + ->first(); + } +} diff --git a/src/Business/Repository/ElasticsearchMigrationsCreateIndex.php b/src/Business/Repository/ElasticsearchMigrationsCreateIndex.php new file mode 100644 index 0000000..7a7b141 --- /dev/null +++ b/src/Business/Repository/ElasticsearchMigrationsCreateIndex.php @@ -0,0 +1,38 @@ +migrations_id = $migrationsId; + $dbMigration->mappings = json_encode($mappings); + + if (is_array($settings)) { + $dbMigration->settings = json_encode($settings); + } + + $dbMigration->saveOrFail(); + + return $dbMigration; + } + + /** + * @inheritdoc + */ + public function find(int $migrationsId): ?\Triadev\EsMigration\Models\Entity\ElasticsearchMigrationsCreateIndex + { + return \Triadev\EsMigration\Models\Entity\ElasticsearchMigrationsCreateIndex::where('migrations_id', + $migrationsId) + ->first(); + } +} diff --git a/src/Business/Repository/ElasticsearchMigrationsDeleteByQuery.php b/src/Business/Repository/ElasticsearchMigrationsDeleteByQuery.php new file mode 100644 index 0000000..cc3d26a --- /dev/null +++ b/src/Business/Repository/ElasticsearchMigrationsDeleteByQuery.php @@ -0,0 +1,37 @@ +migrations_id = $migrationsId; + $dbMigration->query = json_encode($query); + $dbMigration->type = $type; + $dbMigration->options = json_encode($options); + + $dbMigration->saveOrFail(); + + return $dbMigration; + } + + /** + * @inheritdoc + */ + public function find(int $migrationsId): ?\Triadev\EsMigration\Models\Entity\ElasticsearchMigrationsDeleteByQuery + { + return \Triadev\EsMigration\Models\Entity\ElasticsearchMigrationsDeleteByQuery::where('migrations_id', + $migrationsId) + ->first(); + } +} diff --git a/src/Business/Repository/ElasticsearchMigrationsReindex.php b/src/Business/Repository/ElasticsearchMigrationsReindex.php new file mode 100644 index 0000000..522dfae --- /dev/null +++ b/src/Business/Repository/ElasticsearchMigrationsReindex.php @@ -0,0 +1,41 @@ +migrations_id = $migrationsId; + $dbMigration->dest_index = $destIndex; + $dbMigration->refresh_source_index = $refreshSourceIndex; + $dbMigration->global = json_encode($global); + $dbMigration->source = json_encode($source); + $dbMigration->dest = json_encode($dest); + + $dbMigration->saveOrFail(); + + return $dbMigration; + } + + /** + * @inheritdoc + */ + public function find(int $migrationsId): ?\Triadev\EsMigration\Models\Entity\ElasticsearchMigrationsReindex + { + return \Triadev\EsMigration\Models\Entity\ElasticsearchMigrationsReindex::where('migrations_id', + $migrationsId) + ->first(); + } +} diff --git a/src/Business/Repository/ElasticsearchMigrationsUpdateByQuery.php b/src/Business/Repository/ElasticsearchMigrationsUpdateByQuery.php new file mode 100644 index 0000000..fc2702f --- /dev/null +++ b/src/Business/Repository/ElasticsearchMigrationsUpdateByQuery.php @@ -0,0 +1,39 @@ +migrations_id = $migrationsId; + $dbMigration->query = json_encode($query); + $dbMigration->type = $type; + $dbMigration->script = is_array($script) ? json_encode($script): null; + $dbMigration->options = json_encode($options); + + $dbMigration->saveOrFail(); + + return $dbMigration; + } + + /** + * F@inheritdoc + */ + public function find(int $migrationsId): ?\Triadev\EsMigration\Models\Entity\ElasticsearchMigrationsUpdateByQuery + { + return \Triadev\EsMigration\Models\Entity\ElasticsearchMigrationsUpdateByQuery::where('migrations_id', + $migrationsId) + ->first(); + } +} diff --git a/src/Business/Repository/ElasticsearchMigrationsUpdateIndex.php b/src/Business/Repository/ElasticsearchMigrationsUpdateIndex.php new file mode 100644 index 0000000..8a4b559 --- /dev/null +++ b/src/Business/Repository/ElasticsearchMigrationsUpdateIndex.php @@ -0,0 +1,43 @@ +migrations_id = $migrationsId; + $dbMigration->close_index = $closeIndex; + + if (is_array($mappings)) { + $dbMigration->mappings = json_encode($mappings); + } + + if (is_array($settings)) { + $dbMigration->settings = json_encode($settings); + } + + $dbMigration->saveOrFail(); + + return $dbMigration; + } + + /** + * @inheritdoc + */ + public function find(int $migrationsId): ?\Triadev\EsMigration\Models\Entity\ElasticsearchMigrationsUpdateIndex + { + return \Triadev\EsMigration\Models\Entity\ElasticsearchMigrationsUpdateIndex::where('migrations_id', + $migrationsId) + ->first(); + } +} diff --git a/src/Console/Commands/ShowMigration.php b/src/Console/Commands/ShowMigration.php index 834d5b6..186ea6f 100644 --- a/src/Console/Commands/ShowMigration.php +++ b/src/Console/Commands/ShowMigration.php @@ -2,7 +2,7 @@ namespace Triadev\EsMigration\Console\Commands; use Illuminate\Console\Command; -use Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationContract; +use Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationStatusContract; class ShowMigration extends Command { @@ -25,13 +25,13 @@ class ShowMigration extends Command /** * Execute the console command. * - * @param ElasticsearchMigrationContract $elasticsearchMigrationRepository + * @param ElasticsearchMigrationStatusContract $elasticsearchMigrationStatusRepository */ - public function handle(ElasticsearchMigrationContract $elasticsearchMigrationRepository) + public function handle(ElasticsearchMigrationStatusContract $elasticsearchMigrationStatusRepository) { $sortField = $this->argument('sortField'); - $migrations = $elasticsearchMigrationRepository->all(['migration', 'status', 'created_at', 'updated_at']); + $migrations = $elasticsearchMigrationStatusRepository->all(['migration', 'status', 'created_at', 'updated_at']); switch ($this->argument('sortOrder')) { case 'asc': diff --git a/src/Console/Commands/StartMigration.php b/src/Console/Commands/StartMigration.php index 232adbc..598fc43 100644 --- a/src/Console/Commands/StartMigration.php +++ b/src/Console/Commands/StartMigration.php @@ -12,7 +12,8 @@ class StartMigration extends Command * @var string */ protected $signature = 'triadev:elasticsearch:migration:start - {versions : versions of migrations}'; + {versions : versions of migrations} + {--source=file : source of migrations (file|database)}'; /** * The console command description. @@ -32,9 +33,10 @@ class StartMigration extends Command public function handle(ElasticsearchMigrationContract $elasticsearchMigration) { $versions = explode(',', $this->argument('versions')); - + $source = $this->option('source'); + foreach ($versions as $version) { - $elasticsearchMigration->migrate(trim($version)); + $elasticsearchMigration->migrate(trim($version), $source); } } } diff --git a/src/Contract/ElasticsearchMigrationContract.php b/src/Contract/ElasticsearchMigrationContract.php index 615a12f..4f840c4 100644 --- a/src/Contract/ElasticsearchMigrationContract.php +++ b/src/Contract/ElasticsearchMigrationContract.php @@ -6,14 +6,18 @@ interface ElasticsearchMigrationContract { + const MIGRATION_SOURCE_TYPE_FILE = 'file'; + const MIGRATION_SOURCE_TYPE_DATABASE = 'database'; + /** * Migrate * * @param string $version + * @param string $source * * @throws MigrationAlreadyDone * @throws FieldDatatypeMigrationFailed * @throws \Throwable */ - public function migrate(string $version); + public function migrate(string $version, string $source = self::MIGRATION_SOURCE_TYPE_FILE); } diff --git a/src/Contract/ElasticsearchMigrationDatabaseContract.php b/src/Contract/ElasticsearchMigrationDatabaseContract.php new file mode 100644 index 0000000..4b35947 --- /dev/null +++ b/src/Contract/ElasticsearchMigrationDatabaseContract.php @@ -0,0 +1,32 @@ +bigIncrements('id'); + $table->string('migration'); + $table->string('status'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('triadev_elasticsearch_migration_status'); + } +} diff --git a/src/Database/Migrations/2018_09_11_000000_create_elasticsearch_migration_table.php b/src/Database/Migrations/2018_09_18_000000_create_elasticsearch_migration_table.php similarity index 94% rename from src/Database/Migrations/2018_09_11_000000_create_elasticsearch_migration_table.php rename to src/Database/Migrations/2018_09_18_000000_create_elasticsearch_migration_table.php index 8dfefa9..cbf17f9 100644 --- a/src/Database/Migrations/2018_09_11_000000_create_elasticsearch_migration_table.php +++ b/src/Database/Migrations/2018_09_18_000000_create_elasticsearch_migration_table.php @@ -16,7 +16,6 @@ public function up() Schema::create('triadev_elasticsearch_migration', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('migration'); - $table->string('status'); $table->timestamps(); }); } diff --git a/src/Database/Migrations/2018_09_22_000000_create_elasticsearch_migrations_table.php b/src/Database/Migrations/2018_09_22_000000_create_elasticsearch_migrations_table.php new file mode 100644 index 0000000..9d21f3e --- /dev/null +++ b/src/Database/Migrations/2018_09_22_000000_create_elasticsearch_migrations_table.php @@ -0,0 +1,36 @@ +bigIncrements('id'); + $table->bigInteger('migration_id'); + $table->string('type'); + $table->string('index'); + $table->timestamps(); + + $table->foreign('migration_id')->references('id')->on('triadev_elasticsearch_migration'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('triadev_elasticsearch_migrations'); + } +} diff --git a/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_alias_table.php b/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_alias_table.php new file mode 100644 index 0000000..744e288 --- /dev/null +++ b/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_alias_table.php @@ -0,0 +1,37 @@ +bigIncrements('id'); + $table->bigInteger('migrations_id')->unique(); + $table->string('add'); + $table->string('remove'); + $table->string('remove_indices'); + $table->timestamps(); + + $table->foreign('migrations_id')->references('migration_id')->on('triadev_elasticsearch_migrations'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('triadev_elasticsearch_migrations_alias'); + } +} diff --git a/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_create_index_table.php b/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_create_index_table.php new file mode 100644 index 0000000..616639e --- /dev/null +++ b/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_create_index_table.php @@ -0,0 +1,36 @@ +bigIncrements('id'); + $table->bigInteger('migrations_id')->unique(); + $table->string('mappings'); + $table->string('settings')->nullable(); + $table->timestamps(); + + $table->foreign('migrations_id')->references('migration_id')->on('triadev_elasticsearch_migrations'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('triadev_elasticsearch_migrations_create_index'); + } +} diff --git a/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_delete_by_query_table.php b/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_delete_by_query_table.php new file mode 100644 index 0000000..e11ac82 --- /dev/null +++ b/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_delete_by_query_table.php @@ -0,0 +1,37 @@ +bigIncrements('id'); + $table->bigInteger('migrations_id')->unique(); + $table->string('query'); + $table->string('type')->nullable(); + $table->string('options'); + $table->timestamps(); + + $table->foreign('migrations_id')->references('migration_id')->on('triadev_elasticsearch_migrations'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('triadev_elasticsearch_migrations_delete_by_query'); + } +} diff --git a/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_reindex_table.php b/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_reindex_table.php new file mode 100644 index 0000000..942efc6 --- /dev/null +++ b/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_reindex_table.php @@ -0,0 +1,39 @@ +bigIncrements('id'); + $table->bigInteger('migrations_id')->unique(); + $table->string('dest_index'); + $table->boolean('refresh_source_index'); + $table->string('global'); + $table->string('source'); + $table->string('dest'); + $table->timestamps(); + + $table->foreign('migrations_id')->references('migration_id')->on('triadev_elasticsearch_migrations'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('triadev_elasticsearch_migrations_reindex'); + } +} diff --git a/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_update_by_query_table.php b/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_update_by_query_table.php new file mode 100644 index 0000000..e6de314 --- /dev/null +++ b/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_update_by_query_table.php @@ -0,0 +1,38 @@ +bigIncrements('id'); + $table->bigInteger('migrations_id')->unique(); + $table->string('query'); + $table->string('type')->nullable(); + $table->string('script')->nullable(); + $table->string('options'); + $table->timestamps(); + + $table->foreign('migrations_id')->references('migration_id')->on('triadev_elasticsearch_migrations'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('triadev_elasticsearch_migrations_update_by_query'); + } +} diff --git a/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_update_index_table.php b/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_update_index_table.php new file mode 100644 index 0000000..a003f6e --- /dev/null +++ b/src/Database/Migrations/2018_09_22_000001_create_elasticsearch_migrations_update_index_table.php @@ -0,0 +1,37 @@ +bigIncrements('id'); + $table->bigInteger('migrations_id')->unique(); + $table->string('mappings')->nullable(); + $table->string('settings')->nullable(); + $table->boolean('close_index'); + $table->timestamps(); + + $table->foreign('migrations_id')->references('migration_id')->on('triadev_elasticsearch_migrations'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('triadev_elasticsearch_migrations_update_index'); + } +} diff --git a/src/ElasticsearchMigration.php b/src/ElasticsearchMigration.php index ddcc1d6..1f30210 100644 --- a/src/ElasticsearchMigration.php +++ b/src/ElasticsearchMigration.php @@ -11,6 +11,7 @@ use Triadev\EsMigration\Business\Migration\UpdateByQuery; use Triadev\EsMigration\Business\Migration\UpdateIndex; use Triadev\EsMigration\Contract\ElasticsearchMigrationContract; +use Triadev\EsMigration\Contract\ElasticsearchMigrationDatabaseContract; use Triadev\EsMigration\Exception\MigrationAlreadyDone; use Triadev\EsMigration\Models\Migrations\CreateIndex as CreateIndexModel; @@ -29,7 +30,7 @@ class ElasticsearchMigration implements ElasticsearchMigrationContract /** @var string|null */ private $filePathMigrations; - /** @var \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationContract */ + /** @var \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationStatusContract */ private $migrationRepository; /** @@ -42,7 +43,7 @@ public function __construct() $this->filePathMigrations = config('triadev-elasticsearch-migration.migration.filePath'); $this->migrationRepository = app( - \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationContract::class + \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationStatusContract::class ); } @@ -67,7 +68,7 @@ private function buildElasticsearchClient() : Client /** * @inheritdoc */ - public function migrate(string $version) + public function migrate(string $version, string $source = 'file') { $migration = $this->migrationRepository->find($version); if ($migration && $migration->getAttribute('status') == 'done') { @@ -75,11 +76,19 @@ public function migrate(string $version) } try { - $migrations = require sprintf( - "%s/%s/migrations.php", - $this->filePathMigrations, - $version - ); + $migrations = []; + + if ($source == self::MIGRATION_SOURCE_TYPE_FILE) { + $migrations = require sprintf( + "%s/%s/migrations.php", + $this->filePathMigrations, + $version + ); + } elseif ($source == self::MIGRATION_SOURCE_TYPE_DATABASE) { + /** @var ElasticsearchMigrationDatabaseContract $elasticsearchDatabaseService */ + $elasticsearchDatabaseService = app(ElasticsearchMigrationDatabaseContract::class); + $migrations = $elasticsearchDatabaseService->getMigration($version); + } if (!empty($migrations)) { foreach ($migrations as $migration) { diff --git a/src/ElasticsearchMigrationDatabase.php b/src/ElasticsearchMigrationDatabase.php new file mode 100644 index 0000000..46eeeb9 --- /dev/null +++ b/src/ElasticsearchMigrationDatabase.php @@ -0,0 +1,297 @@ +elasticsearchMigrationRepository = $elasticsearchMigrationRepository; + $this->elasticsearchMigrationsRepository = $elasticsearchMigrationsRepository; + } + + /** + * @inheritdoc + */ + public function createMigration(string $migration): bool + { + try { + $this->elasticsearchMigrationRepository->createOrUpdate($migration); + } catch (\Throwable $e) { + return false; + } + + return true; + } + + /** + * @inheritdoc + */ + public function addMigration(string $migration, string $type, string $index, array $params = []) : bool + { + $dbMigration = $this->elasticsearchMigrationRepository->find($migration); + if (!$dbMigration) { + return false; + } + + try { + $migrations = $this->elasticsearchMigrationsRepository->create( + $dbMigration->getAttribute('id'), + $type, + $index + ); + + $migrationsId = $migrations->getAttribute('id'); + + switch ($type) { + case 'createIndex': + $this->createIndexMigration($migrationsId, $params); + break; + case 'updateIndex': + $this->updateIndexMigration($migrationsId, $params); + break; + case 'deleteIndex': + break; + case 'alias': + $this->aliasMigration($migrationsId, $params); + break; + case 'deleteByQuery': + $this->deleteByQueryMigration($migrationsId, $params); + break; + case 'updateByQuery': + $this->updateByQueryMigration($migrationsId, $params); + break; + case 'reindex': + $this->reindexMigration($migrationsId, $params); + break; + default: + break; + } + } catch (\Throwable $e) { + return false; + } + + return true; + } + + /** + * Get migration + * + * @param string $migration + * @return array + */ + public function getMigration(string $migration) : array + { + $migrations = []; + + if ($dbMigration = $this->elasticsearchMigrationRepository->find($migration)) { + foreach ($dbMigration->migrations()->getResults() as $dbMigration) { + /** @var ElasticsearchMigrations $dbMigration */ + $migrationByType = $dbMigration->migrationByType(); + if ($migrationByType) { + $migrationByType = is_object($migrationByType) ? $migrationByType->first() : $migrationByType; + + $index = $dbMigration->getAttribute('index'); + + switch ($dbMigration->getAttribute('type')) { + case 'createIndex': + if ($migrationByType instanceof ElasticsearchMigrationsCreateIndex) { + $settings = $migrationByType->getAttribute('settings'); + + $migrations[] = MigrationBuilder::createIndex( + $index, + json_decode($migrationByType->getAttribute('mappings'), true), + $settings != null ? json_decode($settings, true) : null + ); + } + break; + case 'updateIndex': + if ($migrationByType instanceof ElasticsearchMigrationsUpdateIndex) { + $mappings = $migrationByType->getAttribute('mappings'); + $settings = $migrationByType->getAttribute('settings'); + + $migrations[] = MigrationBuilder::updateIndex( + $index, + $mappings != null ? json_decode($mappings, true) : null, + $settings != null ? json_decode($settings, true) : null, + (bool)$migrationByType->getAttribute('close_index') + ); + } + break; + case 'deleteIndex': + $migrations[] = MigrationBuilder::deleteIndex($index); + break; + case 'alias': + if ($migrationByType instanceof ElasticsearchMigrationsAlias) { + $add = $migrationByType->getAttribute('add'); + $remove = $migrationByType->getAttribute('remove'); + $removeIndices = $migrationByType->getAttribute('remove_indices'); + + $migrations[] = MigrationBuilder::alias( + $index, + $add != null ? json_decode($add, true) : null, + $remove != null ? json_decode($remove, true) : null, + $removeIndices != null ? json_decode($removeIndices, true) : null + ); + } + break; + case 'deleteByQuery': + if ($migrationByType instanceof ElasticsearchMigrationsDeleteByQuery) { + $migrations[] = MigrationBuilder::deleteByQuery( + $index, + json_decode($migrationByType->getAttribute('query'), true), + $migrationByType->getAttribute('type'), + json_decode($migrationByType->getAttribute('options'), true) + ); + } + break; + case 'updateByQuery': + if ($migrationByType instanceof ElasticsearchMigrationsUpdateByQuery) { + $script = $migrationByType->getAttribute('script'); + + $migrations[] = MigrationBuilder::updateByQuery( + $index, + json_decode($migrationByType->getAttribute('query'), true), + $migrationByType->getAttribute('type'), + $script != null ? json_decode($script, true) : null, + json_decode($migrationByType->getAttribute('options'), true) + ); + } + break; + case 'reindex': + if ($migrationByType instanceof ElasticsearchMigrationsReindex) { + $migrations[] = MigrationBuilder::reindex( + $index, + $migrationByType->getAttribute('dest_index'), + (bool)$migrationByType->getAttribute('refresh_source_index'), + json_decode($migrationByType->getAttribute('global'), true), + json_decode($migrationByType->getAttribute('source'), true), + json_decode($migrationByType->getAttribute('dest'), true) + ); + } + break; + default: + break; + } + } + } + } + + return $migrations; + } + + private function createIndexMigration(int $migrationsId, array $params) + { + /** @var ElasticsearchMigrationsCreateIndexContract $repository */ + $repository = app(ElasticsearchMigrationsCreateIndexContract::class); + + $repository->create( + $migrationsId, + array_get($params, 'mappings'), + array_get($params, 'settings') + ); + } + + private function updateIndexMigration(int $migrationsId, array $params) + { + /** @var ElasticsearchMigrationsUpdateIndexContract $repository */ + $repository = app(ElasticsearchMigrationsUpdateIndexContract::class); + + $closeIndex = array_get($params, 'closeIndex'); + if (!$closeIndex) { + $closeIndex = false; + } + + $repository->create( + $migrationsId, + array_get($params, 'mappings'), + array_get($params, 'settings'), + $closeIndex + ); + } + + private function aliasMigration(int $migrationsId, array $params) + { + /** @var ElasticsearchMigrationsAliasContract $repository */ + $repository = app(ElasticsearchMigrationsAliasContract::class); + + $repository->create( + $migrationsId, + array_has($params, 'add') ? array_get($params, 'add') : [], + array_has($params, 'remove') ? array_get($params, 'remove') : [], + array_has($params, 'removeIndices') ? array_get($params, 'removeIndices') : [] + ); + } + + private function deleteByQueryMigration(int $migrationsId, array $params) + { + /** @var ElasticsearchMigrationsDeleteByQueryContract $repository */ + $repository = app(ElasticsearchMigrationsDeleteByQueryContract::class); + + $repository->create( + $migrationsId, + array_get($params, 'query'), + array_get($params, 'type'), + array_has($params, 'options') ? array_get($params, 'options') : [] + ); + } + + private function updateByQueryMigration(int $migrationsId, array $params) + { + /** @var ElasticsearchMigrationsUpdateByQueryContract $repository */ + $repository = app(ElasticsearchMigrationsUpdateByQueryContract::class); + + $repository->create( + $migrationsId, + array_get($params, 'query'), + array_get($params, 'type'), + array_get($params, 'script'), + array_has($params, 'options') ? array_get($params, 'options') : [] + ); + } + + private function reindexMigration(int $migrationsId, array $params) + { + /** @var ElasticsearchMigrationsReindexContract $repository */ + $repository = app(ElasticsearchMigrationsReindexContract::class); + + $refreshSourceIndex = array_get($params, 'refreshSourceIndex'); + if (!$refreshSourceIndex) { + $refreshSourceIndex = false; + } + + $repository->create( + $migrationsId, + array_get($params, 'destIndex'), + $refreshSourceIndex, + array_has($params, 'global') ? array_get($params, 'global') : [], + array_has($params, 'source') ? array_get($params, 'source') : [], + array_has($params, 'dest') ? array_get($params, 'dest') : [] + ); + } +} diff --git a/src/Models/Entity/ElasticsearchMigration.php b/src/Models/Entity/ElasticsearchMigration.php index 39c4d0a..c3ede19 100644 --- a/src/Models/Entity/ElasticsearchMigration.php +++ b/src/Models/Entity/ElasticsearchMigration.php @@ -2,6 +2,7 @@ namespace Triadev\EsMigration\Models\Entity; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\HasMany; class ElasticsearchMigration extends Model { @@ -18,7 +19,16 @@ class ElasticsearchMigration extends Model * @var array */ protected $fillable = [ - 'migration', - 'status' + 'migration' ]; + + /** + * Get migrations + * + * @return HasMany + */ + public function migrations() : HasMany + { + return $this->hasMany(ElasticsearchMigrations::class, 'migration_id'); + } } diff --git a/src/Models/Entity/ElasticsearchMigrationStatus.php b/src/Models/Entity/ElasticsearchMigrationStatus.php new file mode 100644 index 0000000..810af13 --- /dev/null +++ b/src/Models/Entity/ElasticsearchMigrationStatus.php @@ -0,0 +1,24 @@ +getAttribute('type')) { + case 'createIndex': + return $this->hasOne(ElasticsearchMigrationsCreateIndex::class, 'migrations_id'); + break; + case 'updateIndex': + return $this->hasOne(ElasticsearchMigrationsUpdateIndex::class, 'migrations_id'); + break; + case 'deleteIndex': + return 'deleteIndex'; + break; + case 'alias': + return $this->hasOne(ElasticsearchMigrationsAlias::class, 'migrations_id'); + break; + case 'deleteByQuery': + return $this->hasOne(ElasticsearchMigrationsDeleteByQuery::class, 'migrations_id'); + break; + case 'updateByQuery': + return $this->hasOne(ElasticsearchMigrationsUpdateByQuery::class, 'migrations_id'); + break; + case 'reindex': + return $this->hasOne(ElasticsearchMigrationsReindex::class, 'migrations_id'); + break; + default: + break; + } + + return null; + } +} diff --git a/src/Models/Entity/ElasticsearchMigrationsAlias.php b/src/Models/Entity/ElasticsearchMigrationsAlias.php new file mode 100644 index 0000000..c69d319 --- /dev/null +++ b/src/Models/Entity/ElasticsearchMigrationsAlias.php @@ -0,0 +1,26 @@ +app->bind( + \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationStatusContract::class, + function () { + return app()->make( + \Triadev\EsMigration\Business\Repository\ElasticsearchMigrationStatus::class + ); + } + ); + $this->app->bind( \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationContract::class, function () { - return app()->make(\Triadev\EsMigration\Business\Repository\ElasticsearchMigration::class); + return app()->make( + \Triadev\EsMigration\Business\Repository\ElasticsearchMigration::class + ); + } + ); + + $this->app->bind( + \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationsContract::class, + function () { + return app()->make( + \Triadev\EsMigration\Business\Repository\ElasticsearchMigrations::class + ); + } + ); + + $this->app->bind( + \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationsCreateIndexContract::class, + function () { + return app()->make( + \Triadev\EsMigration\Business\Repository\ElasticsearchMigrationsCreateIndex::class + ); + } + ); + + $this->app->bind( + \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationsUpdateIndexContract::class, + function () { + return app()->make( + \Triadev\EsMigration\Business\Repository\ElasticsearchMigrationsUpdateIndex::class + ); + } + ); + + $this->app->bind( + \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationsAliasContract::class, + function () { + return app()->make( + \Triadev\EsMigration\Business\Repository\ElasticsearchMigrationsAlias::class + ); + } + ); + + $this->app->bind( + \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationsDeleteByQueryContract::class, + function () { + return app()->make( + \Triadev\EsMigration\Business\Repository\ElasticsearchMigrationsDeleteByQuery::class + ); + } + ); + + $this->app->bind( + \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationsUpdateByQueryContract::class, + function () { + return app()->make( + \Triadev\EsMigration\Business\Repository\ElasticsearchMigrationsUpdateByQuery::class + ); + } + ); + + $this->app->bind( + \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationsReindexContract::class, + function () { + return app()->make( + \Triadev\EsMigration\Business\Repository\ElasticsearchMigrationsReindex::class + ); } ); } @@ -51,5 +127,9 @@ public function register() $this->app->singleton(ElasticsearchMigrationContract::class, function () { return app()->make(ElasticsearchMigration::class); }); + + $this->app->singleton(ElasticsearchMigrationDatabaseContract::class, function () { + return app()->make(ElasticsearchMigrationDatabase::class); + }); } } diff --git a/tests/integration/Business/Repository/ElasticsearchMigrationStatusTest.php b/tests/integration/Business/Repository/ElasticsearchMigrationStatusTest.php new file mode 100644 index 0000000..42e2094 --- /dev/null +++ b/tests/integration/Business/Repository/ElasticsearchMigrationStatusTest.php @@ -0,0 +1,103 @@ +repository = app(ElasticsearchMigrationStatusContract::class); + } + + /** + * @test + */ + public function it_creates_a_migration() + { + $this->assertNull($this->repository->find('1.0.0')); + + $this->repository->createOrUpdate('1.0.0', 'done'); + + $this->assertInstanceOf( + ElasticsearchMigrationStatus::class, + $this->repository->find('1.0.0') + ); + } + + /** + * @test + */ + public function it_updates_a_migration() + { + $this->assertNull($this->repository->find('1.0.0')); + + $this->repository->createOrUpdate('1.0.0', 'done'); + + $this->assertEquals('done', $this->repository->find('1.0.0')->status); + + $this->repository->createOrUpdate('1.0.0', 'error'); + + $this->assertEquals('error', $this->repository->find('1.0.0')->status); + } + + /** + * @test + */ + public function it_finds_a_migration() + { + $this->repository->createOrUpdate('1.0.0', 'done'); + + $migration = $this->repository->find('1.0.0'); + + $this->assertEquals('1.0.0', $migration->migration); + $this->assertEquals('done', $migration->status); + } + + /** + * @test + */ + public function it_gets_all_migrations() + { + $this->repository->createOrUpdate('1.0.0', 'done'); + $this->repository->createOrUpdate('1.0.1', 'error'); + + $migrations = $this->repository->all(); + + $this->assertCount(2, $migrations); + $this->assertArrayHasKey('id', $migrations->toArray()[0]); + $this->assertArrayHasKey('migration', $migrations->toArray()[0]); + $this->assertArrayHasKey('status', $migrations->toArray()[0]); + + $migrations = $this->repository->all(['migration', 'status']); + + $this->assertCount(2, $migrations); + $this->assertArrayNotHasKey('id', $migrations->toArray()[0]); + $this->assertArrayHasKey('migration', $migrations->toArray()[0]); + $this->assertArrayHasKey('status', $migrations->toArray()[0]); + } + + /** + * @test + */ + public function it_deletes_a_migration() + { + $this->repository->createOrUpdate('1.0.0', 'done'); + + $this->assertInstanceOf( + ElasticsearchMigrationStatus::class, + $this->repository->find('1.0.0') + ); + + $this->repository->delete('1.0.0'); + + $this->assertNull($this->repository->find('1.0.0')); + } +} diff --git a/tests/integration/Business/Repository/ElasticsearchMigrationTest.php b/tests/integration/Business/Repository/ElasticsearchMigrationTest.php index 42e05f5..bb9e07e 100644 --- a/tests/integration/Business/Repository/ElasticsearchMigrationTest.php +++ b/tests/integration/Business/Repository/ElasticsearchMigrationTest.php @@ -3,6 +3,7 @@ use Tests\TestCase; use Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationContract; +use Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationsContract; use Triadev\EsMigration\Models\Entity\ElasticsearchMigration; class ElasticsearchMigrationTest extends TestCase @@ -10,11 +11,15 @@ class ElasticsearchMigrationTest extends TestCase /** @var ElasticsearchMigrationContract */ private $repository; + /** @var ElasticsearchMigrationsContract */ + private $migrationsRepository; + public function setUp() { parent::setUp(); $this->repository = app(ElasticsearchMigrationContract::class); + $this->migrationsRepository = app(ElasticsearchMigrationsContract::class); } /** @@ -24,7 +29,7 @@ public function it_creates_a_migration() { $this->assertNull($this->repository->find('1.0.0')); - $this->repository->createOrUpdate('1.0.0', 'done'); + $this->repository->createOrUpdate('1.0.0'); $this->assertInstanceOf( ElasticsearchMigration::class, @@ -39,13 +44,12 @@ public function it_updates_a_migration() { $this->assertNull($this->repository->find('1.0.0')); - $this->repository->createOrUpdate('1.0.0', 'done'); + $this->repository->createOrUpdate('1.0.0'); - $this->assertEquals('done', $this->repository->find('1.0.0')->status); - - $this->repository->createOrUpdate('1.0.0', 'error'); - - $this->assertEquals('error', $this->repository->find('1.0.0')->status); + $this->assertInstanceOf( + ElasticsearchMigration::class, + $this->repository->find('1.0.0') + ); } /** @@ -53,51 +57,48 @@ public function it_updates_a_migration() */ public function it_finds_a_migration() { - $this->repository->createOrUpdate('1.0.0', 'done'); - - $migration = $this->repository->find('1.0.0'); + $this->repository->createOrUpdate('1.0.0'); - $this->assertEquals('1.0.0', $migration->migration); - $this->assertEquals('done', $migration->status); + $this->assertInstanceOf( + ElasticsearchMigration::class, + $this->repository->find('1.0.0') + ); } /** * @test */ - public function it_gets_all_migrations() + public function it_deletes_a_migration() { - $this->repository->createOrUpdate('1.0.0', 'done'); - $this->repository->createOrUpdate('1.0.1', 'error'); + $this->repository->createOrUpdate('1.0.0'); - $migrations = $this->repository->all(); + $this->assertInstanceOf( + ElasticsearchMigration::class, + $this->repository->find('1.0.0') + ); - $this->assertCount(2, $migrations); - $this->assertArrayHasKey('id', $migrations->toArray()[0]); - $this->assertArrayHasKey('migration', $migrations->toArray()[0]); - $this->assertArrayHasKey('status', $migrations->toArray()[0]); - - $migrations = $this->repository->all(['migration', 'status']); + $this->repository->delete('1.0.0'); - $this->assertCount(2, $migrations); - $this->assertArrayNotHasKey('id', $migrations->toArray()[0]); - $this->assertArrayHasKey('migration', $migrations->toArray()[0]); - $this->assertArrayHasKey('status', $migrations->toArray()[0]); + $this->assertNull($this->repository->find('1.0.0')); } /** * @test */ - public function it_deletes_a_migration() + public function it_gets_many_migrations() { - $this->repository->createOrUpdate('1.0.0', 'done'); - + $this->repository->createOrUpdate('1.0.0'); + $this->assertInstanceOf( ElasticsearchMigration::class, $this->repository->find('1.0.0') ); - - $this->repository->delete('1.0.0'); - $this->assertNull($this->repository->find('1.0.0')); + $this->migrationsRepository->create(1, 'create', 'phpunit'); + $this->migrationsRepository->create(1, 'update', 'phpunit'); + + $migration = $this->repository->find('1.0.0'); + + $this->assertEquals(2, $migration->migrations()->count()); } } diff --git a/tests/integration/Business/Repository/ElasticsearchMigrationsAliasTest.php b/tests/integration/Business/Repository/ElasticsearchMigrationsAliasTest.php new file mode 100644 index 0000000..2a94db6 --- /dev/null +++ b/tests/integration/Business/Repository/ElasticsearchMigrationsAliasTest.php @@ -0,0 +1,59 @@ +repository = app(ElasticsearchMigrationsAliasContract::class); + } + + /** + * @test + */ + public function it_creates_a_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(1, [], [], []); + + $this->assertInstanceOf( + ElasticsearchMigrationsAlias::class, + $this->repository->find(1) + ); + } + + /** + * @test + * @expectedException \Illuminate\Database\QueryException + */ + public function it_expected_a_sql_unique_exception() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(1, [], [], []); + $this->repository->create(1, [], [], []); + } + + /** + * @test + */ + public function it_finds_a_migration() + { + $this->repository->create(1, [], [], []); + + $this->assertInstanceOf( + ElasticsearchMigrationsAlias::class, + $this->repository->find(1) + ); + } +} diff --git a/tests/integration/Business/Repository/ElasticsearchMigrationsCreateIndexTest.php b/tests/integration/Business/Repository/ElasticsearchMigrationsCreateIndexTest.php new file mode 100644 index 0000000..2fa560e --- /dev/null +++ b/tests/integration/Business/Repository/ElasticsearchMigrationsCreateIndexTest.php @@ -0,0 +1,59 @@ +repository = app(ElasticsearchMigrationsCreateIndexContract::class); + } + + /** + * @test + */ + public function it_creates_a_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(1, [], null); + + $this->assertInstanceOf( + ElasticsearchMigrationsCreateIndex::class, + $this->repository->find(1) + ); + } + + /** + * @test + * @expectedException \Illuminate\Database\QueryException + */ + public function it_expected_a_sql_unique_exception() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(1, [], null); + $this->repository->create(1, [], null); + } + + /** + * @test + */ + public function it_finds_a_migration() + { + $this->repository->create(1, [], null); + + $this->assertInstanceOf( + ElasticsearchMigrationsCreateIndex::class, + $this->repository->find(1) + ); + } +} diff --git a/tests/integration/Business/Repository/ElasticsearchMigrationsDeleteByQueryTest.php b/tests/integration/Business/Repository/ElasticsearchMigrationsDeleteByQueryTest.php new file mode 100644 index 0000000..f9b7d61 --- /dev/null +++ b/tests/integration/Business/Repository/ElasticsearchMigrationsDeleteByQueryTest.php @@ -0,0 +1,59 @@ +repository = app(ElasticsearchMigrationsDeleteByQueryContract::class); + } + + /** + * @test + */ + public function it_creates_a_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(1, [], null, []); + + $this->assertInstanceOf( + ElasticsearchMigrationsDeleteByQuery::class, + $this->repository->find(1) + ); + } + + /** + * @test + * @expectedException \Illuminate\Database\QueryException + */ + public function it_expected_a_sql_unique_exception() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(1, [], null, []); + $this->repository->create(1, [], null, []); + } + + /** + * @test + */ + public function it_finds_a_migration() + { + $this->repository->create(1, [], null, []); + + $this->assertInstanceOf( + ElasticsearchMigrationsDeleteByQuery::class, + $this->repository->find(1) + ); + } +} diff --git a/tests/integration/Business/Repository/ElasticsearchMigrationsReindexTest.php b/tests/integration/Business/Repository/ElasticsearchMigrationsReindexTest.php new file mode 100644 index 0000000..0e30cb8 --- /dev/null +++ b/tests/integration/Business/Repository/ElasticsearchMigrationsReindexTest.php @@ -0,0 +1,59 @@ +repository = app(ElasticsearchMigrationsReindexContract::class); + } + + /** + * @test + */ + public function it_creates_a_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(1, 'destIndex', false, [], [], []); + + $this->assertInstanceOf( + ElasticsearchMigrationsReindex::class, + $this->repository->find(1) + ); + } + + /** + * @test + * @expectedException \Illuminate\Database\QueryException + */ + public function it_expected_a_sql_unique_exception() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(1, 'destIndex', false, [], [], []); + $this->repository->create(1, 'destIndex', false, [], [], []); + } + + /** + * @test + */ + public function it_finds_a_migration() + { + $this->repository->create(1, 'destIndex', false, [], [], []); + + $this->assertInstanceOf( + ElasticsearchMigrationsReindex::class, + $this->repository->find(1) + ); + } +} diff --git a/tests/integration/Business/Repository/ElasticsearchMigrationsTest.php b/tests/integration/Business/Repository/ElasticsearchMigrationsTest.php new file mode 100644 index 0000000..79cabcd --- /dev/null +++ b/tests/integration/Business/Repository/ElasticsearchMigrationsTest.php @@ -0,0 +1,218 @@ +repository = app(ElasticsearchMigrationsContract::class); + $this->createIndexRepository = app(ElasticsearchMigrationsCreateIndexContract::class); + $this->updateIndexRepository = app(ElasticsearchMigrationsUpdateIndexContract::class); + $this->aliasRepository = app(ElasticsearchMigrationsAliasContract::class); + $this->deleteByQueryRepository = app(ElasticsearchMigrationsDeleteByQueryContract::class); + $this->updateByQueryRepository = app(ElasticsearchMigrationsUpdateByQueryContract::class); + $this->reindexRepository = app(ElasticsearchMigrationsReindexContract::class); + } + + /** + * @test + */ + public function it_creates_a_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(2, 'createIndex', 'phpunit'); + $this->repository->create(2, 'createIndex', 'phpunit'); + + $this->assertInstanceOf( + ElasticsearchMigrations::class, + $this->repository->find(1) + ); + + $this->assertEquals(2, ElasticsearchMigrations::where('migration_id', '=', 2)->count()); + } + + /** + * @test + */ + public function it_finds_a_migration() + { + $this->repository->create(2, 'createIndex', 'phpunit'); + + $this->assertInstanceOf( + ElasticsearchMigrations::class, + $this->repository->find(1) + ); + } + + /** + * @test + */ + public function it_gets_create_index_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(2, 'createIndex', 'phpunit'); + + $this->createIndexRepository->create(1, [], null); + + $migrationByType = $this->repository->find(1)->migrationByType(); + + $this->assertEquals(1, $migrationByType->count()); + $this->assertEquals( + ElasticsearchMigrationsCreateIndex::class, + get_class($migrationByType->first()) + ); + } + + /** + * @test + */ + public function it_gets_update_index_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(2, 'updateIndex', 'phpunit'); + + $this->updateIndexRepository->create(1, [], null); + + $migrationByType = $this->repository->find(1)->migrationByType(); + + $this->assertEquals(1, $migrationByType->count()); + $this->assertEquals( + ElasticsearchMigrationsUpdateIndex::class, + get_class($migrationByType->first()) + ); + } + + /** + * @test + */ + public function it_gets_delete_index_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(2, 'deleteIndex', 'phpunit'); + + $this->assertEquals('deleteIndex', $this->repository->find(1)->migrationByType()); + } + + /** + * @test + */ + public function it_gets_alias_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(2, 'alias', 'phpunit'); + + $this->aliasRepository->create(1, [], [], []); + + $migrationByType = $this->repository->find(1)->migrationByType(); + + $this->assertEquals(1, $migrationByType->count()); + $this->assertEquals( + ElasticsearchMigrationsAlias::class, + get_class($migrationByType->first()) + ); + } + + /** + * @test + */ + public function it_gets_delete_by_query_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(2, 'deleteByQuery', 'phpunit'); + + $this->deleteByQueryRepository->create(1, [], null, []); + + $migrationByType = $this->repository->find(1)->migrationByType(); + + $this->assertEquals(1, $migrationByType->count()); + $this->assertEquals( + ElasticsearchMigrationsDeleteByQuery::class, + get_class($migrationByType->first()) + ); + } + + /** + * @test + */ + public function it_gets_update_by_query_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(2, 'updateByQuery', 'phpunit'); + + $this->updateByQueryRepository->create(1, [], null, null, []); + + $migrationByType = $this->repository->find(1)->migrationByType(); + + $this->assertEquals(1, $migrationByType->count()); + $this->assertEquals( + ElasticsearchMigrationsUpdateByQuery::class, + get_class($migrationByType->first()) + ); + } + + /** + * @test + */ + public function it_gets_reindex_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(2, 'reindex', 'phpunit'); + + $this->reindexRepository->create(1, 'dest_index', false, [], [], []); + + $migrationByType = $this->repository->find(1)->migrationByType(); + + $this->assertEquals(1, $migrationByType->count()); + $this->assertEquals( + ElasticsearchMigrationsReindex::class, + get_class($migrationByType->first()) + ); + } +} diff --git a/tests/integration/Business/Repository/ElasticsearchMigrationsUpdateByQueryTest.php b/tests/integration/Business/Repository/ElasticsearchMigrationsUpdateByQueryTest.php new file mode 100644 index 0000000..c5c2b68 --- /dev/null +++ b/tests/integration/Business/Repository/ElasticsearchMigrationsUpdateByQueryTest.php @@ -0,0 +1,59 @@ +repository = app(ElasticsearchMigrationsUpdateByQueryContract::class); + } + + /** + * @test + */ + public function it_creates_a_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(1, [], null, null, []); + + $this->assertInstanceOf( + ElasticsearchMigrationsUpdateByQuery::class, + $this->repository->find(1) + ); + } + + /** + * @test + * @expectedException \Illuminate\Database\QueryException + */ + public function it_expected_a_sql_unique_exception() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(1, [], null, null, []); + $this->repository->create(1, [], null, null, []); + } + + /** + * @test + */ + public function it_finds_a_migration() + { + $this->repository->create(1, [], null, null, []); + + $this->assertInstanceOf( + ElasticsearchMigrationsUpdateByQuery::class, + $this->repository->find(1) + ); + } +} diff --git a/tests/integration/Business/Repository/ElasticsearchMigrationsUpdateIndexTest.php b/tests/integration/Business/Repository/ElasticsearchMigrationsUpdateIndexTest.php new file mode 100644 index 0000000..8d753ca --- /dev/null +++ b/tests/integration/Business/Repository/ElasticsearchMigrationsUpdateIndexTest.php @@ -0,0 +1,59 @@ +repository = app(ElasticsearchMigrationsUpdateIndexContract::class); + } + + /** + * @test + */ + public function it_creates_a_migration() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(1, [], null, false); + + $this->assertInstanceOf( + ElasticsearchMigrationsUpdateIndex::class, + $this->repository->find(1) + ); + } + + /** + * @test + * @expectedException \Illuminate\Database\QueryException + */ + public function it_expected_a_sql_unique_exception() + { + $this->assertNull($this->repository->find(1)); + + $this->repository->create(1, [], null); + $this->repository->create(1, [], null); + } + + /** + * @test + */ + public function it_finds_a_migration() + { + $this->repository->create(1, [], null, false); + + $this->assertInstanceOf( + ElasticsearchMigrationsUpdateIndex::class, + $this->repository->find(1) + ); + } +} diff --git a/tests/integration/Console/Commands/ShowMigrationTest.php b/tests/integration/Console/Commands/ShowMigrationTest.php index 82d6a38..341afec 100644 --- a/tests/integration/Console/Commands/ShowMigrationTest.php +++ b/tests/integration/Console/Commands/ShowMigrationTest.php @@ -6,7 +6,7 @@ class ShowMigrationTest extends TestCase { - /** @var \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationContract */ + /** @var \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationStatusContract */ private $migrationRepository; public function setUp() @@ -14,7 +14,7 @@ public function setUp() parent::setUp(); $this->migrationRepository = app( - \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationContract::class + \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationStatusContract::class ); } diff --git a/tests/integration/Console/Commands/StartMigrationTest.php b/tests/integration/Console/Commands/StartMigrationTest.php index 65c43db..1c4703c 100644 --- a/tests/integration/Console/Commands/StartMigrationTest.php +++ b/tests/integration/Console/Commands/StartMigrationTest.php @@ -5,6 +5,7 @@ use Elasticsearch\ClientBuilder; use Tests\TestCase; use Triadev\EsMigration\Contract\ElasticsearchMigrationContract; +use Triadev\EsMigration\Contract\ElasticsearchMigrationDatabaseContract; class StartMigrationTest extends TestCase { @@ -14,14 +15,18 @@ class StartMigrationTest extends TestCase /** @var Client */ private $esClient; - /** @var \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationContract */ + /** @var \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationStatusContract */ private $migrationRepository; + /** @var ElasticsearchMigrationDatabaseContract */ + private $elasticsearchMigrationDatabaseService; + public function setUp() { parent::setUp(); $this->service = app(ElasticsearchMigrationContract::class); + $this->elasticsearchMigrationDatabaseService = app(ElasticsearchMigrationDatabaseContract::class); $this->esClient = $this->buildElasticsearchClient(); if ($this->esClient->indices()->exists(['index' => 'phpunit'])) { @@ -37,7 +42,7 @@ public function setUp() } $this->migrationRepository = app( - \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationContract::class + \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationStatusContract::class ); } @@ -70,7 +75,113 @@ public function it_creates_and_updates_mappings_and_settings_with_command() 'index' => 'phpunit' ])); - $this->artisan('triadev:elasticsearch:migration:start', ['versions' => '1.0.0']); + $this->artisan('triadev:elasticsearch:migration:start', [ + 'versions' => '1.0.0' + ])->assertExitCode(0); + + $this->assertTrue($this->esClient->indices()->exists(['index' => 'phpunit'])); + + $mapping = $this->esClient->indices()->getMapping([ + 'index' => 'phpunit', + 'type' => 'phpunit' + ]); + + $this->assertTrue(array_has($mapping, 'phpunit.mappings.phpunit.properties.title')); + $this->assertTrue(array_has($mapping, 'phpunit.mappings.phpunit.properties.description')); + + $settings = $this->esClient->indices()->getSettings([ + 'index' => 'phpunit' + ]); + + $this->assertEquals('60s', array_get($settings, 'phpunit.settings.index.refresh_interval')); + $this->assertEquals('custom', array_get($settings, 'phpunit.settings.index.analysis.analyzer.content.type')); + $this->assertEquals('whitespace', array_get($settings, 'phpunit.settings.index.analysis.analyzer.content.tokenizer')); + + $migration = $this->migrationRepository->find('1.0.0'); + + $this->assertEquals('1.0.0', $migration->migration); + $this->assertEquals('done', $migration->status); + } + + /** + * @test + */ + public function it_creates_and_updates_mappings_and_settings_with_command_with_database() + { + $this->assertNull($this->migrationRepository->find('1.0.0')); + + $this->assertFalse($this->esClient->indices()->exists([ + 'index' => 'phpunit' + ])); + + $this->assertTrue($this->elasticsearchMigrationDatabaseService->createMigration('1.0.0')); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + '1.0.0', + 'createIndex', + 'phpunit', + [ + 'mappings' => [ + 'phpunit' => [ + 'dynamic' => 'strict', + 'properties' => [ + 'title' => [ + 'type' => 'text' + ], + 'count' => [ + 'type' => 'integer' + ] + ] + ] + ], + 'settings' => [ + 'refresh_interval' => "30s" + ] + ] + )); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + '1.0.0', + 'updateIndex', + 'phpunit', + [ + 'mappings' => [ + 'phpunit' => [ + 'properties' => [ + 'description' => [ + 'type' => 'text' + ] + ] + ] + ], + 'settings' => [ + 'index' => [ + 'refresh_interval' => "60s" + ] + ] + ] + )); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + '1.0.0', + 'updateIndex', + 'phpunit', + [ + 'settings' => [ + 'analysis' => [ + 'analyzer' => [ + 'content' => [ + 'type' => 'custom', + 'tokenizer' => 'whitespace' + ] + ] + ] + ], + 'closeIndex' => true + ] + )); + + $this->artisan('triadev:elasticsearch:migration:start', [ + 'versions' => '1.0.0', + '--source' => 'database' + ])->assertExitCode(0); $this->assertTrue($this->esClient->indices()->exists(['index' => 'phpunit'])); @@ -108,11 +219,80 @@ public function it_starts_to_orchestra_migrations() 'index' => 'phpunit,phpunit_1.0.1' ])); - $this->artisan('triadev:elasticsearch:migration:start', ['versions' => '1.0.0, 1.0.1']); + $this->artisan('triadev:elasticsearch:migration:start', [ + 'versions' => '1.0.0, 1.0.1' + ])->assertExitCode(0); $this->assertTrue($this->esClient->indices()->exists(['index' => 'phpunit,phpunit_1.0.1'])); $this->assertEquals('done', $this->migrationRepository->find('1.0.0')->status); $this->assertEquals('done', $this->migrationRepository->find('1.0.1')->status); } + + /** + * @test + */ + public function it_starts_to_orchestra_migrations_with_database() + { + $this->assertNull($this->migrationRepository->find('1.0.0')); + $this->assertNull($this->migrationRepository->find('1.0.1')); + + $this->assertFalse($this->esClient->indices()->exists([ + 'index' => 'phpunit,phpunit_1.0.1' + ])); + + $this->assertTrue($this->elasticsearchMigrationDatabaseService->createMigration('1.0.0')); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + '1.0.0', + 'createIndex', + 'phpunit', + [ + 'mappings' => [ + 'phpunit' => [ + 'dynamic' => 'strict', + 'properties' => [ + 'title' => [ + 'type' => 'text' + ], + 'count' => [ + 'type' => 'integer' + ] + ] + ] + ] + ] + )); + + $this->assertTrue($this->elasticsearchMigrationDatabaseService->createMigration('1.0.1')); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + '1.0.1', + 'createIndex', + 'phpunit_1.0.1', + [ + 'mappings' => [ + 'phpunit' => [ + 'dynamic' => 'strict', + 'properties' => [ + 'title' => [ + 'type' => 'text' + ], + 'count' => [ + 'type' => 'integer' + ] + ] + ] + ] + ] + )); + + $this->artisan('triadev:elasticsearch:migration:start', [ + 'versions' => '1.0.0, 1.0.1', + '--source' => 'database' + ])->assertExitCode(0); + + $this->assertTrue($this->esClient->indices()->exists(['index' => 'phpunit,phpunit_1.0.1'])); + + $this->assertEquals('done', $this->migrationRepository->find('1.0.0')->status); + $this->assertEquals('done', $this->migrationRepository->find('1.0.1')->status); + } } diff --git a/tests/integration/ElasticsearchMigrationDatabaseTest.php b/tests/integration/ElasticsearchMigrationDatabaseTest.php new file mode 100644 index 0000000..913b8b0 --- /dev/null +++ b/tests/integration/ElasticsearchMigrationDatabaseTest.php @@ -0,0 +1,283 @@ +service = app(ElasticsearchMigrationDatabaseContract::class); + + $this->elasticsearchMigrationRepository = app(ElasticsearchMigrationContract::class); + $this->elasticsearchMigrationsRepository = app(ElasticsearchMigrationsContract::class); + } + + /** + * @test + */ + public function it_creates_migration() + { + $this->assertNull($this->elasticsearchMigrationRepository->find('1.0.0')); + + $this->assertTrue($this->service->createMigration('1.0.0')); + + $this->assertEquals(1, $this->elasticsearchMigrationRepository->find('1.0.0')->getAttribute('id')); + } + + /** + * @test + */ + public function it_adds_migration() + { + $this->assertFalse($this->service->addMigration('1.0.0', 'default', 'phpunit')); + $this->assertNull($this->elasticsearchMigrationsRepository->find(1)); + + $this->assertTrue($this->service->createMigration('1.0.0')); + + $this->assertTrue($this->service->addMigration('1.0.0', 'default', 'phpunit')); + + $this->assertEquals(1, $this->elasticsearchMigrationsRepository->find(1)->getAttribute('id')); + } + + /** + * @test + */ + public function it_adds_create_index_migration() + { + /** @var ElasticsearchMigrationsCreateIndexContract $repository */ + $repository = app(ElasticsearchMigrationsCreateIndexContract::class); + + $this->assertFalse($this->service->addMigration('1.0.0', 'createIndex', 'phpunit')); + $this->assertNull($this->elasticsearchMigrationsRepository->find(1)); + $this->assertNull($repository->find(1)); + + $this->assertTrue($this->service->createMigration('1.0.0')); + + $this->assertTrue($this->service->addMigration('1.0.0', 'createIndex', 'phpunit', [ + 'mappings' => [] + ])); + + $this->assertEquals(1, $this->elasticsearchMigrationsRepository->find(1)->getAttribute('id')); + + $migration = $repository->find(1); + $this->assertInstanceOf(ElasticsearchMigrationsCreateIndex::class, $migration); + $this->assertEquals(1, $migration->getAttribute('id')); + } + + /** + * @test + */ + public function it_adds_update_index_migration() + { + /** @var ElasticsearchMigrationsUpdateIndexContract $repository */ + $repository = app(ElasticsearchMigrationsUpdateIndexContract::class); + + $this->assertFalse($this->service->addMigration('1.0.0', 'updateIndex', 'phpunit')); + $this->assertNull($this->elasticsearchMigrationsRepository->find(1)); + $this->assertNull($repository->find(1)); + + $this->assertTrue($this->service->createMigration('1.0.0')); + + $this->assertTrue($this->service->addMigration('1.0.0', 'updateIndex', 'phpunit', [])); + + $this->assertEquals(1, $this->elasticsearchMigrationsRepository->find(1)->getAttribute('id')); + + $migration = $repository->find(1); + $this->assertInstanceOf(ElasticsearchMigrationsUpdateIndex::class, $migration); + $this->assertEquals(1, $migration->getAttribute('id')); + } + + /** + * @test + */ + public function it_adds_delete_index_migration() + { + $this->assertFalse($this->service->addMigration('1.0.0', 'deleteIndex', 'phpunit')); + $this->assertNull($this->elasticsearchMigrationsRepository->find(1)); + + $this->assertTrue($this->service->createMigration('1.0.0')); + + $this->assertTrue($this->service->addMigration('1.0.0', 'deleteIndex', 'phpunit', [])); + + $this->assertEquals(1, $this->elasticsearchMigrationsRepository->find(1)->getAttribute('id')); + } + + /** + * @test + */ + public function it_adds_alias_migration() + { + /** @var ElasticsearchMigrationsAliasContract $repository */ + $repository = app(ElasticsearchMigrationsAliasContract::class); + + $this->assertFalse($this->service->addMigration('1.0.0', 'alias', 'phpunit')); + $this->assertNull($this->elasticsearchMigrationsRepository->find(1)); + $this->assertNull($repository->find(1)); + + $this->assertTrue($this->service->createMigration('1.0.0')); + + $this->assertTrue($this->service->addMigration('1.0.0', 'alias', 'phpunit', [])); + + $this->assertEquals(1, $this->elasticsearchMigrationsRepository->find(1)->getAttribute('id')); + + $migration = $repository->find(1); + $this->assertInstanceOf(ElasticsearchMigrationsAlias::class, $migration); + $this->assertEquals(1, $migration->getAttribute('id')); + } + + /** + * @test + */ + public function it_adds_delete_by_query_migration() + { + /** @var ElasticsearchMigrationsDeleteByQueryContract $repository */ + $repository = app(ElasticsearchMigrationsDeleteByQueryContract::class); + + $this->assertFalse($this->service->addMigration('1.0.0', 'deleteByQuery', 'phpunit')); + $this->assertNull($this->elasticsearchMigrationsRepository->find(1)); + $this->assertNull($repository->find(1)); + + $this->assertTrue($this->service->createMigration('1.0.0')); + + $this->assertTrue($this->service->addMigration('1.0.0', 'deleteByQuery', 'phpunit', [ + 'query' => [] + ])); + + $this->assertEquals(1, $this->elasticsearchMigrationsRepository->find(1)->getAttribute('id')); + + $migration = $repository->find(1); + $this->assertInstanceOf(ElasticsearchMigrationsDeleteByQuery::class, $migration); + $this->assertEquals(1, $migration->getAttribute('id')); + } + + /** + * @test + */ + public function it_adds_update_by_query_migration() + { + /** @var ElasticsearchMigrationsUpdateByQueryContract $repository */ + $repository = app(ElasticsearchMigrationsUpdateByQueryContract::class); + + $this->assertFalse($this->service->addMigration('1.0.0', 'updateByQuery', 'phpunit')); + $this->assertNull($this->elasticsearchMigrationsRepository->find(1)); + $this->assertNull($repository->find(1)); + + $this->assertTrue($this->service->createMigration('1.0.0')); + + $this->assertTrue($this->service->addMigration('1.0.0', 'updateByQuery', 'phpunit', [ + 'query' => [] + ])); + + $this->assertEquals(1, $this->elasticsearchMigrationsRepository->find(1)->getAttribute('id')); + + $migration = $repository->find(1); + $this->assertInstanceOf(ElasticsearchMigrationsUpdateByQuery::class, $migration); + $this->assertEquals(1, $migration->getAttribute('id')); + } + + /** + * @test + */ + public function it_adds_reindex_migration() + { + /** @var ElasticsearchMigrationsReindexContract $repository */ + $repository = app(ElasticsearchMigrationsReindexContract::class); + + $this->assertFalse($this->service->addMigration('1.0.0', 'reindex', 'phpunit')); + $this->assertNull($this->elasticsearchMigrationsRepository->find(1)); + $this->assertNull($repository->find(1)); + + $this->assertTrue($this->service->createMigration('1.0.0')); + + $this->assertTrue($this->service->addMigration('1.0.0', 'reindex', 'phpunit', [ + 'destIndex' => 'phpunit' + ])); + + $this->assertEquals(1, $this->elasticsearchMigrationsRepository->find(1)->getAttribute('id')); + + $migration = $repository->find(1); + $this->assertInstanceOf(ElasticsearchMigrationsReindex::class, $migration); + $this->assertEquals(1, $migration->getAttribute('id')); + $this->assertEquals('phpunit', $migration->getAttribute('dest_index')); + } + + /** + * @test + */ + public function it_gets_migration() + { + $this->assertEquals([], $this->service->getMigration('1.0.0')); + + $this->assertTrue($this->service->createMigration('1.0.0')); + $this->assertTrue($this->service->addMigration('1.0.0', 'default', 'phpunit')); + $this->assertTrue($this->service->addMigration('1.0.0', 'createIndex', 'phpunit', [ + 'mappings' => [ + 'example' => [ + 'properties' => [ + 'title' => [ + 'type' => 'text' + ] + ] + ] + ] + ])); + $this->assertTrue($this->service->addMigration('1.0.0', 'updateIndex', 'phpunit', [])); + $this->assertTrue($this->service->addMigration('1.0.0', 'deleteIndex', 'phpunit', [])); + $this->assertTrue($this->service->addMigration('1.0.0', 'alias', 'phpunit', [])); + $this->assertTrue($this->service->addMigration('1.0.0', 'deleteByQuery', 'phpunit', [ + 'query' => [] + ])); + $this->assertTrue($this->service->addMigration('1.0.0', 'updateByQuery', 'phpunit', [ + 'query' => [] + ])); + $this->assertTrue($this->service->addMigration('1.0.0', 'reindex', 'phpunit', [ + 'destIndex' => 'phpunit' + ])); + + $migrations = $this->service->getMigration('1.0.0'); + + $this->assertCount(7, $migrations); + + $this->assertInstanceOf(CreateIndex::class, $migrations[0]); + $this->assertInstanceOf(UpdateIndex::class, $migrations[1]); + $this->assertInstanceOf(DeleteIndex::class, $migrations[2]); + $this->assertInstanceOf(Alias::class, $migrations[3]); + $this->assertInstanceOf(DeleteByQuery::class, $migrations[4]); + $this->assertInstanceOf(UpdateByQuery::class, $migrations[5]); + $this->assertInstanceOf(Reindex::class, $migrations[6]); + } +} diff --git a/tests/integration/ElasticsearchMigrationTest.php b/tests/integration/ElasticsearchMigrationTest.php index 974eab6..5802237 100644 --- a/tests/integration/ElasticsearchMigrationTest.php +++ b/tests/integration/ElasticsearchMigrationTest.php @@ -5,6 +5,7 @@ use Elasticsearch\ClientBuilder; use Tests\TestCase; use Triadev\EsMigration\Contract\ElasticsearchMigrationContract; +use Triadev\EsMigration\Contract\ElasticsearchMigrationDatabaseContract; use Triadev\EsMigration\Exception\FieldDatatypeMigrationFailed; class ElasticsearchMigrationTest extends TestCase @@ -15,14 +16,18 @@ class ElasticsearchMigrationTest extends TestCase /** @var Client */ private $esClient; - /** @var \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationContract */ + /** @var \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationStatusContract */ private $migrationRepository; + /** @var ElasticsearchMigrationDatabaseContract */ + private $elasticsearchMigrationDatabaseService; + public function setUp() { parent::setUp(); $this->service = app(ElasticsearchMigrationContract::class); + $this->elasticsearchMigrationDatabaseService = app(ElasticsearchMigrationDatabaseContract::class); $this->esClient = $this->buildElasticsearchClient(); if ($this->esClient->indices()->exists(['index' => 'phpunit'])) { @@ -38,8 +43,10 @@ public function setUp() } $this->migrationRepository = app( - \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationContract::class + \Triadev\EsMigration\Contract\Repository\ElasticsearchMigrationStatusContract::class ); + + $this->buildDatabaseTestData(); } private function buildElasticsearchClient() : Client @@ -60,6 +67,73 @@ private function buildElasticsearchClient() : Client return $clientBuilder->build(); } + private function buildDatabaseTestData() + { + $this->assertTrue($this->elasticsearchMigrationDatabaseService->createMigration('1.0.0')); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + '1.0.0', + 'createIndex', + 'phpunit', + [ + 'mappings' => [ + 'phpunit' => [ + 'dynamic' => 'strict', + 'properties' => [ + 'title' => [ + 'type' => 'text' + ], + 'count' => [ + 'type' => 'integer' + ] + ] + ] + ], + 'settings' => [ + 'refresh_interval' => "30s" + ] + ] + )); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + '1.0.0', + 'updateIndex', + 'phpunit', + [ + 'mappings' => [ + 'phpunit' => [ + 'properties' => [ + 'description' => [ + 'type' => 'text' + ] + ] + ] + ], + 'settings' => [ + 'index' => [ + 'refresh_interval' => "60s" + ] + ] + ] + )); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + '1.0.0', + 'updateIndex', + 'phpunit', + [ + 'settings' => [ + 'analysis' => [ + 'analyzer' => [ + 'content' => [ + 'type' => 'custom', + 'tokenizer' => 'whitespace' + ] + ] + ] + ], + 'closeIndex' => true + ] + )); + } + /** * @test */ @@ -99,6 +173,45 @@ public function it_creates_and_updates_mappings_and_settings() $this->assertEquals('done', $migration->status); } + /** + * @test + */ + public function it_creates_and_updates_mappings_and_settings_with_database() + { + $this->assertNull($this->migrationRepository->find('1.0.0')); + + $this->assertFalse($this->esClient->indices()->exists([ + 'index' => 'phpunit' + ])); + + $this->service->migrate('1.0.0', 'database'); + + $this->assertTrue($this->esClient->indices()->exists([ + 'index' => 'phpunit' + ])); + + $mapping = $this->esClient->indices()->getMapping([ + 'index' => 'phpunit', + 'type' => 'phpunit' + ]); + + $this->assertTrue(array_has($mapping, 'phpunit.mappings.phpunit.properties.title')); + $this->assertTrue(array_has($mapping, 'phpunit.mappings.phpunit.properties.description')); + + $settings = $this->esClient->indices()->getSettings([ + 'index' => 'phpunit' + ]); + + $this->assertEquals('60s', array_get($settings, 'phpunit.settings.index.refresh_interval')); + $this->assertEquals('custom', array_get($settings, 'phpunit.settings.index.analysis.analyzer.content.type')); + $this->assertEquals('whitespace', array_get($settings, 'phpunit.settings.index.analysis.analyzer.content.tokenizer')); + + $migration = $this->migrationRepository->find('1.0.0'); + + $this->assertEquals('1.0.0', $migration->migration); + $this->assertEquals('done', $migration->status); + } + /** * @test */ @@ -121,6 +234,35 @@ public function it_deletes_an_index() ])); } + /** + * @test + */ + public function it_deletes_an_index_with_database() + { + $this->assertFalse($this->esClient->indices()->exists([ + 'index' => 'phpunit' + ])); + + $this->service->migrate('1.0.0', 'database'); + + $this->assertTrue($this->esClient->indices()->exists([ + 'index' => 'phpunit' + ])); + + $this->assertTrue($this->elasticsearchMigrationDatabaseService->createMigration('delete_index')); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + 'delete_index', + 'deleteIndex', + 'phpunit' + )); + + $this->service->migrate('delete_index', 'database'); + + $this->assertFalse($this->esClient->indices()->exists([ + 'index' => 'phpunit' + ])); + } + /** * @test */ @@ -148,6 +290,57 @@ public function it_adds_and_deletes_an_alias() ])); } + /** + * @test + */ + public function it_adds_and_deletes_an_alias_with_database() + { + $this->service->migrate('1.0.0', 'database'); + + $this->assertFalse($this->esClient->indices()->existsAlias([ + 'name' => 'alias', + 'index' => 'phpunit' + ])); + + $this->assertTrue($this->elasticsearchMigrationDatabaseService->createMigration('add_alias')); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + 'add_alias', + 'alias', + 'phpunit', + [ + 'add' => [ + 'alias' + ] + ] + )); + + $this->service->migrate('add_alias', 'database'); + + $this->assertTrue($this->esClient->indices()->existsAlias([ + 'name' => 'alias', + 'index' => 'phpunit' + ])); + + $this->assertTrue($this->elasticsearchMigrationDatabaseService->createMigration('delete_alias')); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + 'delete_alias', + 'alias', + 'phpunit', + [ + 'remove' => [ + 'alias' + ] + ] + )); + + $this->service->migrate('delete_alias', 'database'); + + $this->assertFalse($this->esClient->indices()->existsAlias([ + 'name' => 'alias', + 'index' => 'phpunit' + ])); + } + /** * @test * @expectedException \Triadev\EsMigration\Exception\IndexNotExist @@ -208,6 +401,93 @@ public function it_reindex_an_index() ])); } + /** + * @test + */ + public function it_reindex_an_index_with_database() + { + $this->assertFalse($this->esClient->exists([ + 'id' => 'reindex_test', + 'index' => 'phpunit', + 'type' => 'phpunit' + ])); + + $this->assertFalse($this->esClient->exists([ + 'id' => 'reindex_test', + 'index' => 'phpunit_1.0.1', + 'type' => 'phpunit' + ])); + + $this->service->migrate('1.0.0', 'database'); + + $this->esClient->index([ + 'index' => 'phpunit', + 'type' => 'phpunit', + 'id' => 'reindex_test', + 'body' => [ + 'title' => 'Title' + ] + ]); + + $this->assertTrue($this->esClient->exists([ + 'id' => 'reindex_test', + 'index' => 'phpunit', + 'type' => 'phpunit' + ])); + + $this->assertFalse($this->esClient->exists([ + 'id' => 'reindex_test', + 'index' => 'phpunit_1.0.1', + 'type' => 'phpunit' + ])); + + $this->assertTrue($this->elasticsearchMigrationDatabaseService->createMigration('1.0.1')); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + '1.0.1', + 'createIndex', + 'phpunit_1.0.1', + [ + 'mappings' => [ + 'phpunit' => [ + 'dynamic' => 'strict', + 'properties' => [ + 'title' => [ + 'type' => 'text' + ], + 'count' => [ + 'type' => 'integer' + ] + ] + ] + ], + 'settings' => [ + 'refresh_interval' => "30s" + ] + ] + )); + + $this->service->migrate('1.0.1', 'database'); + + $this->assertTrue($this->elasticsearchMigrationDatabaseService->createMigration('reindex')); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + 'reindex', + 'reindex', + 'phpunit', + [ + 'destIndex' => 'phpunit_1.0.1', + 'refreshSourceIndex' => true + ] + )); + + $this->service->migrate('reindex', 'database'); + + $this->assertTrue($this->esClient->exists([ + 'id' => 'reindex_test', + 'index' => 'phpunit_1.0.1', + 'type' => 'phpunit' + ])); + } + /** * @test */ @@ -243,6 +523,59 @@ public function it_deletes_documents_by_query() ])); } + /** + * @test + */ + public function it_deletes_documents_by_query_with_database() + { + $this->service->migrate('1.0.0', 'database'); + + $this->esClient->index([ + 'index' => 'phpunit', + 'type' => 'phpunit', + 'id' => 'reindex_test', + 'body' => [ + 'title' => 'Title' + ] + ]); + + $this->esClient->indices()->refresh([ + 'index' => 'phpunit' + ]); + + $this->assertTrue($this->esClient->exists([ + 'id' => 'reindex_test', + 'index' => 'phpunit', + 'type' => 'phpunit' + ])); + + $this->assertTrue($this->elasticsearchMigrationDatabaseService->createMigration('delete_by_query')); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + 'delete_by_query', + 'deleteByQuery', + 'phpunit', + [ + 'query' => [ + 'match' => [ + 'title' => 'Title' + ] + ], + 'type' => 'phpunit', + 'options' => [ + 'conflicts' => 'proceed' + ] + ] + )); + + $this->service->migrate('delete_by_query', 'database'); + + $this->assertFalse($this->esClient->exists([ + 'id' => 'reindex_test', + 'index' => 'phpunit', + 'type' => 'phpunit' + ])); + } + /** * @test */ @@ -285,6 +618,70 @@ public function it_updates_documents_by_query() ); } + /** + * @test + */ + public function it_updates_documents_by_query_with_database() + { + $this->service->migrate('1.0.0', 'database'); + + $this->esClient->index([ + 'index' => 'phpunit', + 'type' => 'phpunit', + 'id' => 'reindex_test', + 'body' => [ + 'title' => 'Title', + 'count' => 1 + ] + ]); + + $this->esClient->indices()->refresh([ + 'index' => 'phpunit' + ]); + + $this->assertEquals( + 1, + $this->esClient->get([ + 'id' => 'reindex_test', + 'index' => 'phpunit', + 'type' => 'phpunit' + ])['_source']['count'] + ); + + $this->assertTrue($this->elasticsearchMigrationDatabaseService->createMigration('update_by_query')); + $this->assertTrue($this->elasticsearchMigrationDatabaseService->addMigration( + 'update_by_query', + 'updateByQuery', + 'phpunit', + [ + 'query' => [ + 'match' => [ + 'title' => 'Title' + ] + ], + 'type' => 'phpunit', + 'script' => [ + 'source' => 'ctx._source.count++', + 'lang' => 'painless' + ], + 'options' => [ + 'conflicts' => 'proceed' + ] + ] + )); + + $this->service->migrate('update_by_query', 'database'); + + $this->assertEquals( + 2, + $this->esClient->get([ + 'id' => 'reindex_test', + 'index' => 'phpunit', + 'type' => 'phpunit' + ])['_source']['count'] + ); + } + /** * @test * @expectedException \Triadev\EsMigration\Exception\MigrationAlreadyDone