Syndesi/neo4j-sync-bundle

View on GitHub
src/Statement/BatchMergeNodeStatementBuilder.php

Summary

Maintainability
A
3 hrs
Test Coverage
A
100%
<?php

declare(strict_types=1);

namespace Syndesi\Neo4jSyncBundle\Statement;

use Laudis\Neo4j\Databags\Statement;
use Syndesi\Neo4jSyncBundle\Contract\BatchNodeStatementBuilderInterface;
use Syndesi\Neo4jSyncBundle\Exception\InvalidArgumentException;
use Syndesi\Neo4jSyncBundle\Exception\MissingPropertyException;
use Syndesi\Neo4jSyncBundle\Exception\UnsupportedPropertyNameException;
use Syndesi\Neo4jSyncBundle\ValueObject\Node;

class BatchMergeNodeStatementBuilder implements BatchNodeStatementBuilderInterface
{
    /**
     * @param Node[] $nodes Important: All nodes need to be of the same type
     *
     * @return Statement[]
     *
     * @throws MissingPropertyException
     * @throws UnsupportedPropertyNameException
     * @throws InvalidArgumentException
     */
    public static function build(array $nodes): array
    {
        if (empty($nodes)) {
            return [];
        }
        foreach ($nodes as $node) {
            if (!($node instanceof Node)) {
                throw new InvalidArgumentException('All nodes need to be of type node.');
            }
            if (!$node->getLabel()->isEqualTo($nodes[0]->getLabel())) {
                throw new InvalidArgumentException('All nodes need to be for the same node label');
            }
        }
        $batch = [];
        foreach ($nodes as $node) {
            $properties = [];
            foreach ($node->getProperties() as $property) {
                if ($property->getName() === $node->getIdentifier()->getName()) {
                    // id is not a property, it cannot be changed once set
                    continue;
                }
                $properties[$property->getName()] = $property->getValue();
            }
            $batch[] = [
                'id' => $node->getIdentifier()->getValue(),
                'properties' => $properties,
            ];
        }

        return [new Statement(
            sprintf(
                "UNWIND \$batch as row\n".
                "MERGE (n:%s {%s: row.id})\n".
                "SET n += row.properties",
                (string) $nodes[0]->getLabel(),
                $nodes[0]->getIdentifier()->getName()
            ),
            [
                'batch' => $batch,
            ]
        )];
    }
}