Syndesi/neo4j-sync-bundle

View on GitHub
src/Command/IndexListCommand.php

Summary

Maintainability
B
4 hrs
Test Coverage
F
0%
<?php

declare(strict_types=1);

namespace Syndesi\Neo4jSyncBundle\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Syndesi\Neo4jSyncBundle\Contract\Neo4jClientInterface;
use Syndesi\Neo4jSyncBundle\Enum\IndexType;
use Syndesi\Neo4jSyncBundle\Event\GetAllIndicesEvent;
use Syndesi\Neo4jSyncBundle\Exception\Neo4jSyncException;
use Syndesi\Neo4jSyncBundle\Exception\UnsupportedNodeLabelException;
use Syndesi\Neo4jSyncBundle\Exception\UnsupportedRelationLabelException;
use Syndesi\Neo4jSyncBundle\Statement\GetIndicesStatementBuilder;
use Syndesi\Neo4jSyncBundle\ValueObject\Index;
use Syndesi\Neo4jSyncBundle\ValueObject\IndexName;
use Syndesi\Neo4jSyncBundle\ValueObject\NodeLabel;
use Syndesi\Neo4jSyncBundle\ValueObject\Property;
use Syndesi\Neo4jSyncBundle\ValueObject\RelationLabel;

class IndexListCommand extends Command
{
    protected static $defaultName = 'neo4j-sync:index:list';

    public function __construct(
        private Neo4jClientInterface $client,
        private EventDispatcherInterface $eventDispatcher
    ) {
        parent::__construct();
    }

    /**
     * @throws Neo4jSyncException
     * @throws UnsupportedRelationLabelException
     * @throws UnsupportedNodeLabelException
     */
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $existingIndices = $this->getNeo4jIndices();

        $event = new GetAllIndicesEvent();
        /** @var GetAllIndicesEvent $getAllIndicesEvent */
        $getAllIndicesEvent = $this->eventDispatcher->dispatch($event, $event::NAME);
        $definedIndices = $getAllIndicesEvent->getIndices();

        $rowElements = [];
        foreach ($definedIndices as $index) {
            $rowElements[(string) $index->getName()] = [
                'index' => $index,
                'defined' => true,
                'exists' => false,
                'conflict' => false,
            ];
        }
        foreach ($existingIndices as $index) {
            if (array_key_exists((string) $index->getName(), $rowElements)) {
                if ($index->isEqualTo($rowElements[(string) $index->getName()]['index'])) {
                    $rowElements[(string) $index->getName()]['exists'] = true;
                } else {
                    $rowElements[(string) $index->getName()]['conflict'] = true;
                    $rowElements[sprintf("%s (database)", (string) $index->getName())] = [
                        'index' => $index,
                        'defined' => false,
                        'exists' => true,
                        'conflict' => true,
                    ];
                }
            } else {
                $rowElements[sprintf("%s (database)", (string) $index->getName())] = [
                    'index' => $index,
                    'defined' => false,
                    'exists' => true,
                    'conflict' => false,
                ];
            }
        }

        $rows = [];
        ksort($rowElements);
        foreach ($rowElements as $rowElement) {
            $index = $rowElement['index'];
            $propertiesString = [];
            foreach ($index->getProperties() as $property) {
                $propertiesString[] = $property->getName();
            }
            $propertiesString = implode($propertiesString);
            $rows[] = [
                (string) $index->getName(),
                sprintf(
                    "%s (%s)",
                    (string) $index->getLabel(),
                    $index->getLabel() instanceof NodeLabel ? 'Node' : 'Relation'
                ),
                $index->getType()->value,
                $propertiesString,
                $rowElement['defined'] ? 'yes' : '-',
                $rowElement['exists'] ? 'yes' : 'no',
                $rowElement['conflict'] ? 'yes' : '-',
            ];
        }

        $table = new Table($output);
        $table
            ->setHeaders(['Name', 'On', 'Type', 'Properties', 'Defined in Code', 'Exists in Database', 'Conflict'])
            ->setRows($rows);
        $table->render();

        return Command::SUCCESS;
    }

    /**
     * @return Index[]
     *
     * @throws UnsupportedRelationLabelException
     * @throws UnsupportedNodeLabelException
     * @throws Neo4jSyncException
     */
    private function getNeo4jIndices(): array
    {
        $res = $this->client->runStatement(GetIndicesStatementBuilder::build()[0]);
        $indices = [];
        foreach ($res as $element) {
            $label = null;
            if ('NODE' == $element->get('entityType')) {
                $label = new NodeLabel($element->get('labelsOrTypes')[0]);
            } elseif ('RELATIONSHIP' == $element->get('entityType')) {
                $label = new RelationLabel($element->get('labelsOrTypes')[0]);
            } else {
                throw new Neo4jSyncException(sprintf("Index on unsupported type %s", $element->get('labelsOrTypes')[0]));
            }
            $properties = [];
            foreach ($element->get('properties') as $property) {
                $properties[] = new Property($property);
            }
            $indices[] = new Index(
                new IndexName($element->get('name')),
                $label,
                $properties,
                IndexType::from($element->get('type'))
            );
        }

        return $indices;
    }
}