Skip to content

Commit 7cde281

Browse files
committed
Merge remote-tracking branch 'origin/main' into psalm
2 parents 5feec76 + 45dbd7a commit 7cde281

15 files changed

+695
-342
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

run.php

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

src/Neo4jQueryAPI.php

Lines changed: 76 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
use GuzzleHttp\Client;
77
use GuzzleHttp\Exception\GuzzleException;
88
use GuzzleHttp\Exception\RequestException;
9+
use Neo4j\QueryAPI\Objects\ChildQueryPlan;
10+
use Neo4j\QueryAPI\Objects\QueryArguments;
911
use Neo4j\QueryAPI\Objects\ResultCounters;
12+
use Neo4j\QueryAPI\Objects\ProfiledQueryPlan;
1013
use Neo4j\QueryAPI\Results\ResultRow;
1114
use Neo4j\QueryAPI\Results\ResultSet;
1215
use Neo4j\QueryAPI\Exception\Neo4jException;
@@ -37,7 +40,7 @@ public static function login(string $address, string $username, string $password
3740
'headers' => [
3841
'Authorization' => 'Basic ' . base64_encode("$username:$password"),
3942
'Content-Type' => 'application/vnd.neo4j.query',
40-
'Accept'=>'application/vnd.neo4j.query',
43+
'Accept' => 'application/vnd.neo4j.query',
4144
],
4245
]);
4346

@@ -80,6 +83,10 @@ public function run(string $cypher, array $parameters = [], string $database = '
8083
return new ResultRow($data);
8184
}, $values);
8285

86+
if (isset($data['profiledQueryPlan'])) {
87+
$profile = $this->createProfileData($data['profiledQueryPlan']);
88+
}
89+
8390
$resultCounters = new ResultCounters(
8491
containsUpdates: $data['counters']['containsUpdates'] ?? false,
8592
nodesCreated: $data['counters']['nodesCreated'] ?? 0,
@@ -97,22 +104,79 @@ public function run(string $cypher, array $parameters = [], string $database = '
97104
systemUpdates: $data['counters']['systemUpdates'] ?? 0
98105
);
99106

100-
$resultSet = new ResultSet($rows, $resultCounters, new Bookmarks($data['bookmarks'] ?? []));
101-
102-
103-
return $resultSet;
104-
105-
} catch (RequestException $e) {
106-
{
107-
$response = $e->getResponse();
108-
if ($response !== null) {
109-
$contents = $response->getBody()->getContents();
110-
$errorResponse = json_decode($contents, true);
107+
return new ResultSet(
108+
$rows,
109+
$resultCounters,
110+
new Bookmarks($data['bookmarks'] ?? []),
111+
$profile
112+
);
113+
} catch (RequestExceptionInterface $e) {
114+
$response = $e->getResponse();
115+
if ($response !== null) {
116+
$contents = $response->getBody()->getContents();
117+
$errorResponse = json_decode($contents, true);
111118

112119
throw Neo4jException::fromNeo4jResponse($errorResponse, $e);
113120
}
114121
}
115122
throw new RuntimeException('Error executing query: ' . $e->getMessage(), 0, $e);
116123
}
124+
125+
126+
public function beginTransaction(string $database = 'neo4j'): Transaction
127+
{
128+
$response = $this->client->post("/db/neo4j/query/v2/tx");
129+
130+
$clusterAffinity = $response->getHeaderLine('neo4j-cluster-affinity');
131+
$responseData = json_decode($response->getBody(), true);
132+
$transactionId = $responseData['transaction']['id'];
133+
134+
return new Transaction($this->client, $clusterAffinity, $transactionId);
135+
}
136+
137+
private function createProfileData(array $data): ProfiledQueryPlan
138+
{
139+
$arguments = $data['arguments'];
140+
141+
$queryArguments = new QueryArguments(
142+
$arguments['globalMemory'] ?? 0,
143+
$arguments['plannerImpl'] ?? '',
144+
$arguments['memory'] ?? 0,
145+
$arguments['stringRepresentation'] ?? '',
146+
is_string($arguments['runtime'] ?? '') ? $arguments['runtime'] : json_encode($arguments['runtime']),
147+
$arguments['runtimeImpl'] ?? '',
148+
$arguments['dbHits'] ?? 0,
149+
$arguments['batchSize'] ?? 0,
150+
$arguments['details'] ?? '',
151+
$arguments['plannerVersion'] ?? '',
152+
$arguments['pipelineInfo'] ?? '',
153+
$arguments['runtimeVersion'] ?? '',
154+
$arguments['id'] ?? 0,
155+
$arguments['estimatedRows'] ?? 0.0,
156+
is_string($arguments['planner'] ?? '') ? $arguments['planner'] : json_encode($arguments['planner']),
157+
$arguments['rows'] ?? 0
158+
);
159+
160+
$profiledQueryPlan = new ProfiledQueryPlan(
161+
$data['dbHits'],
162+
$data['records'],
163+
$data['hasPageCacheStats'],
164+
$data['pageCacheHits'],
165+
$data['pageCacheMisses'],
166+
$data['pageCacheHitRatio'],
167+
$data['time'],
168+
$data['operatorType'],
169+
$queryArguments
170+
);
171+
172+
foreach($data['children'] as $child) {
173+
$childQueryPlan = $this->createProfileData($child);
174+
175+
$profiledQueryPlan->addChild($childQueryPlan);
176+
}
177+
178+
return $profiledQueryPlan;
117179
}
180+
181+
118182
}

src/Objects/ProfiledQueryPlan.php

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
namespace Neo4j\QueryAPI\Objects;
4+
5+
class ProfiledQueryPlan
6+
{
7+
private int $dbHits;
8+
private int $records;
9+
private bool $hasPageCacheStats;
10+
private int $pageCacheHits;
11+
private int $pageCacheMisses;
12+
private float $pageCacheHitRatio;
13+
private int $time;
14+
private string $operatorType;
15+
private QueryArguments $arguments;
16+
17+
/**
18+
* @var list<ProfiledQueryPlan>
19+
*/
20+
private array $children;
21+
22+
public function __construct(
23+
?int $dbHits = 0, // Default to 0 if null
24+
?int $records = 0,
25+
?bool $hasPageCacheStats = false,
26+
?int $pageCacheHits = 0,
27+
?int $pageCacheMisses = 0,
28+
?float $pageCacheHitRatio = 0.0,
29+
?int $time = 0,
30+
?string $operatorType = '',
31+
QueryArguments $arguments
32+
) {
33+
$this->dbHits = $dbHits ?? 0;
34+
$this->records = $records ?? 0;
35+
$this->hasPageCacheStats = $hasPageCacheStats ?? false;
36+
$this->pageCacheHits = $pageCacheHits ?? 0;
37+
$this->pageCacheMisses = $pageCacheMisses ?? 0;
38+
$this->pageCacheHitRatio = $pageCacheHitRatio ?? 0.0;
39+
$this->time = $time ?? 0;
40+
$this->operatorType = $operatorType ?? '';
41+
$this->arguments = $arguments;
42+
}
43+
44+
public function getDbHits(): int
45+
{
46+
return $this->dbHits;
47+
}
48+
49+
public function getRecords(): int
50+
{
51+
return $this->records;
52+
}
53+
54+
public function hasPageCacheStats(): bool
55+
{
56+
return $this->hasPageCacheStats;
57+
}
58+
59+
public function getPageCacheHits(): int
60+
{
61+
return $this->pageCacheHits;
62+
}
63+
64+
public function getPageCacheMisses(): int
65+
{
66+
return $this->pageCacheMisses;
67+
}
68+
69+
public function getPageCacheHitRatio(): float
70+
{
71+
return $this->pageCacheHitRatio;
72+
}
73+
74+
public function getTime(): int
75+
{
76+
return $this->time;
77+
}
78+
79+
public function getOperatorType(): string
80+
{
81+
return $this->operatorType;
82+
}
83+
84+
public function getArguments(): QueryArguments
85+
{
86+
return $this->arguments;
87+
}
88+
89+
/**
90+
* @return list<ProfiledQueryPlan>
91+
*/
92+
public function getChildren(): array
93+
{
94+
return $this->children;
95+
}
96+
97+
public function addChild(ProfiledQueryPlan $child): void
98+
{
99+
$this->children[] = $child;
100+
}
101+
}

0 commit comments

Comments
 (0)