diff --git a/.gitignore b/.gitignore index 2ace794d..9ac6f606 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ vendor phpunit.xml test -.phpunit.result.cache \ No newline at end of file +.phpunit.result.cache diff --git a/composer.json b/composer.json index ca9895e5..5e0b0293 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "require": { "guzzlehttp/guzzle": "^7.9", "psr/http-client": "^1.0", - "ext-json": "*", + "ext-json": "*", "php": "^8.1" }, "require-dev": { diff --git a/run.php b/run.php deleted file mode 100644 index a3b7d0e9..00000000 --- a/run.php +++ /dev/null @@ -1,37 +0,0 @@ - $query, -]); - -$headers = [ - 'Authorization' => 'Basic ' . $auth, - 'Content-Type' => 'application/json', - 'Accept' => 'application/json', -]; - - -$client = new Client(); - -$response = $client->post('https://6f72daa1.databases.neo4j.io/db/neo4j/query/v2/tx', [ - 'headers' => $headers, - 'body' => $payload, -]); -$responseData = json_decode($response->getBody(), true); - -print_r($responseData); \ No newline at end of file diff --git a/src/Transaction.php b/src/Transaction.php new file mode 100644 index 00000000..b824a772 --- /dev/null +++ b/src/Transaction.php @@ -0,0 +1,119 @@ +client->post("/db/neo4j/query/v2/tx/{$this->transactionId}", [ + 'headers' => [ + 'neo4j-cluster-affinity' => $this->clusterAffinity, + ], + 'json' => [ + 'statement' => $query, + 'parameters' => empty($parameters) ? new stdClass() : $parameters, + 'includeCounters' => true + ], + ]); + + $responseBody = $response->getBody()->getContents(); + $data = json_decode($responseBody, true); + + if (!isset($data['data']['fields'], $data['data']['values'])) { + throw new Neo4jException([ + 'message' => 'Unexpected response structure from Neo4j', + 'response' => $data, + ]); + } + + $keys = $data['data']['fields']; + $values = $data['data']['values']; + + if (empty($values)) { + return new ResultSet([], new ResultCounters( + containsUpdates: $data['counters']['containsUpdates'], + nodesCreated: $data['counters']['nodesCreated'], + nodesDeleted: $data['counters']['nodesDeleted'], + propertiesSet: $data['counters']['propertiesSet'], + relationshipsCreated: $data['counters']['relationshipsCreated'], + relationshipsDeleted: $data['counters']['relationshipsDeleted'], + labelsAdded: $data['counters']['labelsAdded'], + labelsRemoved: $data['counters']['labelsRemoved'], + indexesAdded: $data['counters']['indexesAdded'], + indexesRemoved: $data['counters']['indexesRemoved'], + constraintsAdded: $data['counters']['constraintsAdded'], + constraintsRemoved: $data['counters']['constraintsRemoved'], + containsSystemUpdates: $data['counters']['containsSystemUpdates'], + systemUpdates: $data['counters']['systemUpdates'] + )); + } + + $ogm = new OGM(); + $rows = array_map(function ($resultRow) use ($ogm, $keys) { + $data = []; + foreach ($keys as $index => $key) { + $fieldData = $resultRow[$index] ?? null; + $data[$key] = $ogm->map($fieldData); + } + return new ResultRow($data); + }, $values); + + return new ResultSet($rows, new ResultCounters( + containsUpdates: $data['counters']['containsUpdates'], + nodesCreated: $data['counters']['nodesCreated'], + nodesDeleted: $data['counters']['nodesDeleted'], + propertiesSet: $data['counters']['propertiesSet'], + relationshipsCreated: $data['counters']['relationshipsCreated'], + relationshipsDeleted: $data['counters']['relationshipsDeleted'], + labelsAdded: $data['counters']['labelsAdded'], + labelsRemoved: $data['counters']['labelsRemoved'], + indexesAdded: $data['counters']['indexesAdded'], + indexesRemoved: $data['counters']['indexesRemoved'], + constraintsAdded: $data['counters']['constraintsAdded'], + constraintsRemoved: $data['counters']['constraintsRemoved'], + containsSystemUpdates: $data['counters']['containsSystemUpdates'], + systemUpdates: $data['counters']['systemUpdates'] + )); + } + + public function commit(): void + { + $this->client->post("/db/neo4j/query/v2/tx/{$this->transactionId}/commit", [ + 'headers' => [ + 'neo4j-cluster-affinity' => $this->clusterAffinity, + ], + ]); + } + + public function rollback(): void + { + $this->client->delete("/db/neo4j/query/v2/tx/{$this->transactionId}", [ + 'headers' => [ + 'neo4j-cluster-affinity' => $this->clusterAffinity, + ], + ]); + } +} diff --git a/test.php b/test.php deleted file mode 100644 index e368e600..00000000 --- a/test.php +++ /dev/null @@ -1,54 +0,0 @@ - $query, -]); - -$headers = [ - 'Authorization' => 'Basic ' . $auth, - 'Content-Type' => 'application/json', - 'Accept' => 'application/json', -]; - - -$client = new Client(); - -$response = $client->post('https://6f72daa1.databases.neo4j.io/db/neo4j/query/v2/tx', [ - 'headers' => $headers, - 'body' => $payload, -]); -$clusterAffinity = $response->getHeaderLine('neo4j-cluster-affinity'); -$responseData = json_decode($response->getBody(), true); -$headers['neo4j-cluster-affinity'] = $clusterAffinity; - -$transactionId = $responseData['transaction']['id']; - -/*$response = $client->delete('http://localhost:7474/db/neo4j/query/v2/tx/' . $transactionId, [ - 'headers' => $headers, - 'body' => $payload, -]);*/ -$responseData = json_decode($response->getBody(), true); - - -//$commitUrl = 'https://6f72daa1.databases.neo4j.io/db/neo4j/tx/' . $responseData['transaction']['id'] . '/query/v2/commit'; -$response = $client->post('http://localhost:7474/db/neo4j/query/v2/tx/' . $transactionId . '/commit', [ - 'headers' => $headers, - 'body' => $payload, -]); -$responseData = json_decode($response->getBody(), true); -print_r($responseData); - diff --git a/test_curl.php b/test_curl.php deleted file mode 100644 index 61ace196..00000000 --- a/test_curl.php +++ /dev/null @@ -1,2 +0,0 @@ -run('CREATE (x:Human {name: $name})', ['name' => $name]); // Pass the array here + $tsx->run("CREATE (x:Human {name: \$name})", ['name' => $name]); // Validate that the node does not exist in the database before the transaction is committed - $results = $this->api->run('MATCH (x:Human {name: $name}) RETURN x', ['name' => $name]); + $results = $this->api->run("MATCH (x:Human {name: \$name}) RETURN x", ['name' => $name]); $this->assertCount(0, $results); // Validate that the node exists within the transaction - $results = $tsx->run('MATCH (x:Human {name: $name}) RETURN x', ['name' => $name]); + $results = $tsx->run("MATCH (x:Human {name: \$name}) RETURN x", ['name' => $name]); $this->assertCount(1, $results); // Commit the transaction $tsx->commit(); // Validate that the node now exists in the database - $results = $this->api->run('MATCH (x:Human {name: $name}) RETURN x', ['name' => $name]); - $this->assertCount(0, $results); + $results = $this->api->run("MATCH (x:Human {name: \$name}) RETURN x", ['name' => $name]); + $this->assertCount(1, $results); // Updated to expect 1 result } + /** * @throws GuzzleException */ diff --git a/tests/Integration/ProfileTest.php b/tests/Integration/ProfileTest.php new file mode 100644 index 00000000..c2ed7116 --- /dev/null +++ b/tests/Integration/ProfileTest.php @@ -0,0 +1,73 @@ + [ + 'columns' => ['name'], + 'rows' => [['John Doe']], + ], + 'bookmarks' => ['bookmark1'], + ]; + + + $mock = new MockHandler([ + new Response(200, [], json_encode($mockResponseData)) + ]); + $handlerStack = HandlerStack::create($mock); + + $mockClient = new Client(['handler' => $handlerStack]); + + $profile = new Profile('http://mock-neo4j-url', 'user', 'password'); + $reflection = new \ReflectionClass(Profile::class); + $clientProperty = $reflection->getProperty('client'); + $clientProperty->setValue($profile, $mockClient); + + $query = 'MATCH (n:Person) RETURN n.name'; + $result = $profile->executeQuery($query); + + $this->assertIsArray($result); + $this->assertEquals($mockResponseData, $result); + } + + public function testFormatResponse(): void + { + $mockInputData = [ + 'result' => [ + 'columns' => ['name'], + 'rows' => [['John Doe']], + ], + 'profiledQueryPlan' => [ + 'plan' => 'Mock Plan', + ], + 'bookmarks' => ['bookmark1'], + ]; + + $expectedOutput = [ + 'data' => [ + 'fields' => ['name'], + 'values' => [['John Doe']], + ], + 'profiledQueryPlan' => [ + 'plan' => 'Mock Plan', + ], + 'bookmarks' => ['bookmark1'], + ]; + + $profile = new Profile('http://mock-neo4j-url', 'user', 'password'); + + $formattedResponse = $profile->formatResponse($mockInputData); + $this->assertEquals($expectedOutput, $formattedResponse); + } +}