Skip to content

Commit 740c9c8

Browse files
authored
Merge branch 'main' into create-bookmarks-1951107727
2 parents 7992fc3 + c225228 commit 740c9c8

File tree

8 files changed

+195
-95
lines changed

8 files changed

+195
-95
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
vendor
33
phpunit.xml
44
test
5-
.phpunit.result.cache
5+
.phpunit.result.cache

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"require": {
66
"guzzlehttp/guzzle": "^7.9",
77
"psr/http-client": "^1.0",
8-
"ext-json": "*",
8+
"ext-json": "*",
99
"php": "^8.1"
1010
},
1111
"require-dev": {

run.php

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/Transaction.php

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?php
2+
3+
namespace Neo4j\QueryAPI;
4+
5+
use Neo4j\QueryAPI\Exception\Neo4jException;
6+
use Neo4j\QueryAPI\Objects\ResultCounters;
7+
use Neo4j\QueryAPI\Results\ResultRow;
8+
use Neo4j\QueryAPI\Results\ResultSet;
9+
use Psr\Http\Client\ClientInterface;
10+
use stdClass;
11+
12+
class Transaction
13+
{
14+
public function __construct(
15+
private ClientInterface $client,
16+
private string $clusterAffinity,
17+
private string $transactionId
18+
) {
19+
}
20+
21+
/**
22+
* Execute a Cypher query within the transaction.
23+
*
24+
* @param string $query The Cypher query to be executed.
25+
* @param array $parameters Parameters for the query.
26+
* @return ResultSet The result rows in ResultSet format.
27+
* @throws Neo4jException If the response structure is invalid.
28+
*/
29+
public function run(string $query, array $parameters): ResultSet
30+
{
31+
$response = $this->client->post("/db/neo4j/query/v2/tx/{$this->transactionId}", [
32+
'headers' => [
33+
'neo4j-cluster-affinity' => $this->clusterAffinity,
34+
],
35+
'json' => [
36+
'statement' => $query,
37+
'parameters' => empty($parameters) ? new stdClass() : $parameters,
38+
'includeCounters' => true
39+
],
40+
]);
41+
42+
$responseBody = $response->getBody()->getContents();
43+
$data = json_decode($responseBody, true);
44+
45+
if (!isset($data['data']['fields'], $data['data']['values'])) {
46+
throw new Neo4jException([
47+
'message' => 'Unexpected response structure from Neo4j',
48+
'response' => $data,
49+
]);
50+
}
51+
52+
$keys = $data['data']['fields'];
53+
$values = $data['data']['values'];
54+
55+
if (empty($values)) {
56+
return new ResultSet([], new ResultCounters(
57+
containsUpdates: $data['counters']['containsUpdates'],
58+
nodesCreated: $data['counters']['nodesCreated'],
59+
nodesDeleted: $data['counters']['nodesDeleted'],
60+
propertiesSet: $data['counters']['propertiesSet'],
61+
relationshipsCreated: $data['counters']['relationshipsCreated'],
62+
relationshipsDeleted: $data['counters']['relationshipsDeleted'],
63+
labelsAdded: $data['counters']['labelsAdded'],
64+
labelsRemoved: $data['counters']['labelsRemoved'],
65+
indexesAdded: $data['counters']['indexesAdded'],
66+
indexesRemoved: $data['counters']['indexesRemoved'],
67+
constraintsAdded: $data['counters']['constraintsAdded'],
68+
constraintsRemoved: $data['counters']['constraintsRemoved'],
69+
containsSystemUpdates: $data['counters']['containsSystemUpdates'],
70+
systemUpdates: $data['counters']['systemUpdates']
71+
));
72+
}
73+
74+
$ogm = new OGM();
75+
$rows = array_map(function ($resultRow) use ($ogm, $keys) {
76+
$data = [];
77+
foreach ($keys as $index => $key) {
78+
$fieldData = $resultRow[$index] ?? null;
79+
$data[$key] = $ogm->map($fieldData);
80+
}
81+
return new ResultRow($data);
82+
}, $values);
83+
84+
return new ResultSet($rows, new ResultCounters(
85+
containsUpdates: $data['counters']['containsUpdates'],
86+
nodesCreated: $data['counters']['nodesCreated'],
87+
nodesDeleted: $data['counters']['nodesDeleted'],
88+
propertiesSet: $data['counters']['propertiesSet'],
89+
relationshipsCreated: $data['counters']['relationshipsCreated'],
90+
relationshipsDeleted: $data['counters']['relationshipsDeleted'],
91+
labelsAdded: $data['counters']['labelsAdded'],
92+
labelsRemoved: $data['counters']['labelsRemoved'],
93+
indexesAdded: $data['counters']['indexesAdded'],
94+
indexesRemoved: $data['counters']['indexesRemoved'],
95+
constraintsAdded: $data['counters']['constraintsAdded'],
96+
constraintsRemoved: $data['counters']['constraintsRemoved'],
97+
containsSystemUpdates: $data['counters']['containsSystemUpdates'],
98+
systemUpdates: $data['counters']['systemUpdates']
99+
));
100+
}
101+
102+
public function commit(): void
103+
{
104+
$this->client->post("/db/neo4j/query/v2/tx/{$this->transactionId}/commit", [
105+
'headers' => [
106+
'neo4j-cluster-affinity' => $this->clusterAffinity,
107+
],
108+
]);
109+
}
110+
111+
public function rollback(): void
112+
{
113+
$this->client->delete("/db/neo4j/query/v2/tx/{$this->transactionId}", [
114+
'headers' => [
115+
'neo4j-cluster-affinity' => $this->clusterAffinity,
116+
],
117+
]);
118+
}
119+
}

test.php

Lines changed: 0 additions & 54 deletions
This file was deleted.

test_curl.php

Lines changed: 0 additions & 2 deletions
This file was deleted.

tests/Integration/Neo4jQueryAPIIntegrationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public function testCreateBookmarks(): void
9393
//
9494

9595

96+
9697
/**
9798
* @throws GuzzleException
9899
*/

tests/Integration/ProfileTest.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
namespace Neo4j\QueryAPI\Tests\Integration;
4+
5+
use GuzzleHttp\Client;
6+
use GuzzleHttp\Handler\MockHandler;
7+
use GuzzleHttp\HandlerStack;
8+
use GuzzleHttp\Psr7\Response;
9+
use Neo4j\QueryAPI\Profile;
10+
use PHPUnit\Framework\TestCase;
11+
12+
class ProfileTest extends TestCase
13+
{
14+
public function testExecuteQuery(): void
15+
{
16+
$mockResponseData = [
17+
'result' => [
18+
'columns' => ['name'],
19+
'rows' => [['John Doe']],
20+
],
21+
'bookmarks' => ['bookmark1'],
22+
];
23+
24+
25+
$mock = new MockHandler([
26+
new Response(200, [], json_encode($mockResponseData))
27+
]);
28+
$handlerStack = HandlerStack::create($mock);
29+
30+
$mockClient = new Client(['handler' => $handlerStack]);
31+
32+
$profile = new Profile('http://mock-neo4j-url', 'user', 'password');
33+
$reflection = new \ReflectionClass(Profile::class);
34+
$clientProperty = $reflection->getProperty('client');
35+
$clientProperty->setValue($profile, $mockClient);
36+
37+
$query = 'MATCH (n:Person) RETURN n.name';
38+
$result = $profile->executeQuery($query);
39+
40+
$this->assertIsArray($result);
41+
$this->assertEquals($mockResponseData, $result);
42+
}
43+
44+
public function testFormatResponse(): void
45+
{
46+
$mockInputData = [
47+
'result' => [
48+
'columns' => ['name'],
49+
'rows' => [['John Doe']],
50+
],
51+
'profiledQueryPlan' => [
52+
'plan' => 'Mock Plan',
53+
],
54+
'bookmarks' => ['bookmark1'],
55+
];
56+
57+
$expectedOutput = [
58+
'data' => [
59+
'fields' => ['name'],
60+
'values' => [['John Doe']],
61+
],
62+
'profiledQueryPlan' => [
63+
'plan' => 'Mock Plan',
64+
],
65+
'bookmarks' => ['bookmark1'],
66+
];
67+
68+
$profile = new Profile('http://mock-neo4j-url', 'user', 'password');
69+
70+
$formattedResponse = $profile->formatResponse($mockInputData);
71+
$this->assertEquals($expectedOutput, $formattedResponse);
72+
}
73+
}

0 commit comments

Comments
 (0)