diff --git a/lib/Service/StructureService.php b/lib/Service/StructureService.php new file mode 100644 index 0000000000..cf6e094c66 --- /dev/null +++ b/lib/Service/StructureService.php @@ -0,0 +1,124 @@ +tableService->getScheme($tableId); + $this->resolveChanges($currentSchema->jsonSerialize(), $updateSchema); + } + + public function resolveChanges(array $currentSchema, array $updateSchema): void { + $this->resolveColumnChanges($currentSchema, $updateSchema); + } + + public function addedColumns(): array { + return $this->addedColumns; + } + + public function removedColumns(): array { + return $this->removedColumns; + } + + public function modifiedColumn(): array { + return $this->modifiedColumns; + } + + protected function resolveColumnChanges(array $currentSchema, array $updateSchema): void { + $existingColumnMap = $this->getColumnMap($currentSchema['columns']); + $updatedColumnMap = $this->getColumnMap($updateSchema['columns']); + + $this->determineAddedColumns($existingColumnMap, $updatedColumnMap, $updateSchema); + $this->determineRemovedColumns($existingColumnMap, $updatedColumnMap, $currentSchema); + $this->determineModifiedColumns($existingColumnMap, $updatedColumnMap, $currentSchema, $updateSchema); + } + + protected function determineAddedColumns(array $existingColumnMap, array $updatedColumnMap, array $updateSchema): void { + $columnUuids = array_diff_key($updatedColumnMap, $existingColumnMap); + foreach ($columnUuids as $uuid) { + $this->addedColumns[$uuid] = $updateSchema['columns'][$updatedColumnMap[$uuid]['arrayIndex']]; + } + } + + protected function determineRemovedColumns(array $existingColumnMap, array $updatedColumnMap, array $currentSchema): void { + $columnUuids = array_diff_key($existingColumnMap, $updatedColumnMap); + foreach ($columnUuids as $uuid) { + $this->removedColumns[$uuid] = $currentSchema['columns'][$existingColumnMap[$uuid]['arrayIndex']]; + } + } + + protected function determineModifiedColumns(array $existingColumnMap, array $updatedColumnMap, array $currentSchema, array $updateSchema): void { + $updatedColumnUuids = array_keys(array_intersect_key($existingColumnMap, $updatedColumnMap)); + + $updatedColumnUuids = array_filter( + $updatedColumnUuids, + function (string $uuid) use ($currentSchema, $updateSchema, $existingColumnMap, $updatedColumnMap): bool { + $columnCurrent = $currentSchema['columns'][$existingColumnMap[$uuid]['arrayIndex']]; + $columnNew = $updateSchema['columns'][$updatedColumnMap[$uuid]['arrayIndex']]; + return $this->isColumnModified($columnNew, $columnCurrent); + } + ); + + foreach ($updatedColumnUuids as $uuid) { + $this->modifiedColumns[$uuid] = [ + 'from' => $currentSchema['columns'][$existingColumnMap[$uuid]['arrayIndex']], + 'to' => $updateSchema['columns'][$updatedColumnMap[$uuid]['arrayIndex']], + ]; + } + } + + protected function isColumnModified($columnA, $columnB): bool { + unset( + $columnA['id'], $columnB['id'], + $columnA['createdBy'], $columnB['createdBy'], + $columnA['createdByDisplayName'], $columnB['createdByDisplayName'], + $columnA['createdAt'], $columnB['createdAt'], + $columnA['lastEditBy'], $columnB['lastEditBy'], + $columnA['lastEditByDisplayName'], $columnB['lastEditByDisplayName'], + $columnA['lastEditAt'], $columnB['lastEditAt'], + $columnA['tableId'], $columnB['tableId'], + ); + $jsonColumnA = json_encode($columnA); + $jsonColumnB = json_encode($columnB); + // cannot use array_diff_assoc() is it does not deal with nested arrays + return $jsonColumnA !== $jsonColumnB; + } + + protected function getColumnMap(array $currentSchemaColumns): array { + $map = []; + foreach ($currentSchemaColumns as $i => $column) { + $map[$column['uuid']] = [ + 'arrayIndex' => $i, + 'id' => $column['id'], + ]; + } + return $map; + } +} diff --git a/tests/unit/Service/StructureServiceTest.php b/tests/unit/Service/StructureServiceTest.php new file mode 100644 index 0000000000..621bb7bd9a --- /dev/null +++ b/tests/unit/Service/StructureServiceTest.php @@ -0,0 +1,34 @@ +tableService = $this->createMock(TableService::class); + + $this->originalSchema = json_decode(file_get_contents(__DIR__ . '/../res/feature-list-schema.json'), true); + + $this->service = new StructureService($this->tableService); + } + + public function testNoChanges() { + $this->service->resolveChanges($this->originalSchema, $this->originalSchema); + $this->assertSame([], $this->service->addedColumns()); + $this->assertSame([], $this->service->removedColumns()); + $this->assertSame([], $this->service->modifiedColumn()); + } +}