Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 66 additions & 25 deletions src/Neo4jQueryAPI.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;
use Neo4j\QueryAPI\Objects\ChildQueryPlan;
use Neo4j\QueryAPI\Objects\QueryArguments;
use Neo4j\QueryAPI\Objects\ResultCounters;
use Neo4j\QueryAPI\Objects\ProfiledQueryPlan;
use Neo4j\QueryAPI\Results\ResultRow;
use Neo4j\QueryAPI\Results\ResultSet;
use Neo4j\QueryAPI\Exception\Neo4jException;
Expand All @@ -27,18 +30,13 @@ public function __construct(Client $client)

public static function login(string $address, string $username, string $password): self
{
$username = 'neo4j';
$password = '9lWmptqBgxBOz8NVcTJjgs3cHPyYmsy63ui6Spmw1d0';
$connectionUrl = 'https://6f72daa1.databases.neo4j.io/db/neo4j/query/v2';


$client = new Client([
'base_uri' => rtrim($address, '/'),
'timeout' => 10.0,
'headers' => [
'Authorization' => 'Basic ' . base64_encode("$username:$password"),
'Content-Type' => 'application/vnd.neo4j.query',
'Accept'=>'application/vnd.neo4j.query',
'Accept' => 'application/vnd.neo4j.query',
],
]);

Expand Down Expand Up @@ -80,6 +78,10 @@ public function run(string $cypher, array $parameters = [], string $database = '
return new ResultRow($data);
}, $values);

if (isset($data['profiledQueryPlan'])) {
$profile = $this->createProfileData($data['profiledQueryPlan']);
}

$resultCounters = new ResultCounters(
containsUpdates: $data['counters']['containsUpdates'] ?? false,
nodesCreated: $data['counters']['nodesCreated'] ?? 0,
Expand All @@ -97,30 +99,25 @@ public function run(string $cypher, array $parameters = [], string $database = '
systemUpdates: $data['counters']['systemUpdates'] ?? 0
);

$resultSet = new ResultSet($rows, $resultCounters, new Bookmarks($data['bookmarks'] ?? []));


return $resultSet;

} catch (RequestException $e) {
{
$response = $e->getResponse();
if ($response !== null) {
$contents = $response->getBody()->getContents();
$errorResponse = json_decode($contents, true);
return new ResultSet(
$rows,
$resultCounters,
new Bookmarks($data['bookmarks'] ?? []),
$profile
);
} catch (RequestExceptionInterface $e) {
$response = $e->getResponse();
if ($response !== null) {
$contents = $response->getBody()->getContents();
$errorResponse = json_decode($contents, true);

throw Neo4jException::fromNeo4jResponse($errorResponse, $e);
}

throw $e;
}
throw new RuntimeException('Error executing query: ' . $e->getMessage(), 0, $e);

throw $e;
}
}




public function beginTransaction(string $database = 'neo4j'): Transaction
{
$response = $this->client->post("/db/neo4j/query/v2/tx");
Expand All @@ -129,8 +126,52 @@ public function beginTransaction(string $database = 'neo4j'): Transaction
$responseData = json_decode($response->getBody(), true);
$transactionId = $responseData['transaction']['id'];

return new Transaction($this->client, $clusterAffinity, $transactionId);
}

private function createProfileData(array $data): ProfiledQueryPlan
{
$arguments = $data['arguments'];

$queryArguments = new QueryArguments(
$arguments['globalMemory'] ?? 0,
$arguments['plannerImpl'] ?? '',
$arguments['memory'] ?? 0,
$arguments['stringRepresentation'] ?? '',
is_string($arguments['runtime'] ?? '') ? $arguments['runtime'] : json_encode($arguments['runtime']),
$arguments['runtimeImpl'] ?? '',
$arguments['dbHits'] ?? 0,
$arguments['batchSize'] ?? 0,
$arguments['details'] ?? '',
$arguments['plannerVersion'] ?? '',
$arguments['pipelineInfo'] ?? '',
$arguments['runtimeVersion'] ?? '',
$arguments['id'] ?? 0,
$arguments['estimatedRows'] ?? 0.0,
is_string($arguments['planner'] ?? '') ? $arguments['planner'] : json_encode($arguments['planner']),
$arguments['rows'] ?? 0
);

$profiledQueryPlan = new ProfiledQueryPlan(
$data['dbHits'],
$data['records'],
$data['hasPageCacheStats'],
$data['pageCacheHits'],
$data['pageCacheMisses'],
$data['pageCacheHitRatio'],
$data['time'],
$data['operatorType'],
$queryArguments
);

foreach($data['children'] as $child) {
$childQueryPlan = $this->createProfileData($child);

$profiledQueryPlan->addChild($childQueryPlan);
}

return new Transaction($this->client, $clusterAffinity, $transactionId);
return $profiledQueryPlan;
}


}
101 changes: 101 additions & 0 deletions src/Objects/ProfiledQueryPlan.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

namespace Neo4j\QueryAPI\Objects;

class ProfiledQueryPlan
{
private int $dbHits;
private int $records;
private bool $hasPageCacheStats;
private int $pageCacheHits;
private int $pageCacheMisses;
private float $pageCacheHitRatio;
private int $time;
private string $operatorType;
private QueryArguments $arguments;

/**
* @var list<ProfiledQueryPlan>
*/
private array $children;

public function __construct(
?int $dbHits = 0, // Default to 0 if null
?int $records = 0,
?bool $hasPageCacheStats = false,
?int $pageCacheHits = 0,
?int $pageCacheMisses = 0,
?float $pageCacheHitRatio = 0.0,
?int $time = 0,
?string $operatorType = '',
QueryArguments $arguments
) {
$this->dbHits = $dbHits ?? 0;
$this->records = $records ?? 0;
$this->hasPageCacheStats = $hasPageCacheStats ?? false;
$this->pageCacheHits = $pageCacheHits ?? 0;
$this->pageCacheMisses = $pageCacheMisses ?? 0;
$this->pageCacheHitRatio = $pageCacheHitRatio ?? 0.0;
$this->time = $time ?? 0;
$this->operatorType = $operatorType ?? '';
$this->arguments = $arguments;
}

public function getDbHits(): int
{
return $this->dbHits;
}

public function getRecords(): int
{
return $this->records;
}

public function hasPageCacheStats(): bool
{
return $this->hasPageCacheStats;
}

public function getPageCacheHits(): int
{
return $this->pageCacheHits;
}

public function getPageCacheMisses(): int
{
return $this->pageCacheMisses;
}

public function getPageCacheHitRatio(): float
{
return $this->pageCacheHitRatio;
}

public function getTime(): int
{
return $this->time;
}

public function getOperatorType(): string
{
return $this->operatorType;
}

public function getArguments(): QueryArguments
{
return $this->arguments;
}

/**
* @return list<ProfiledQueryPlan>
*/
public function getChildren(): array
{
return $this->children;
}

public function addChild(ProfiledQueryPlan $child): void
{
$this->children[] = $child;
}
}
139 changes: 139 additions & 0 deletions src/Objects/QueryArguments.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

namespace Neo4j\QueryAPI\Objects;

class QueryArguments
{
private int $globalMemory;
private string $plannerImpl;
private int $memory;
private string $stringRepresentation;
private string $runtime;
private string $runtimeImpl;
private int $dbHits;
private int $batchSize;
private string $details;
private string $plannerVersion;
private string $pipelineInfo;
private string $runtimeVersion;
private int $id;
private float $estimatedRows;
private string $planner;
private int $rows;

public function __construct(
?int $globalMemory = 0,
?string $plannerImpl = '',
?int $memory = 0,
?string $stringRepresentation = '',
$runtime = '',
?string $runtimeImpl = '',
?int $dbHits = 0,
?int $batchSize = 0,
?string $details = '',
?string $plannerVersion = '',
?string $pipelineInfo = '',
?string $runtimeVersion = '',
?int $id = 0,
?float $estimatedRows = 0.0,
?string $planner = '',
?int $rows = 0
) {
$this->globalMemory = $globalMemory ?? 0;
$this->plannerImpl = $plannerImpl ?? '';
$this->memory = $memory ?? 0;
$this->stringRepresentation = $stringRepresentation ?? '';
$this->runtime = is_string($runtime) ? $runtime : json_encode($runtime);
$this->runtimeImpl = $runtimeImpl ?? '';
$this->dbHits = $dbHits ?? 0;
$this->batchSize = $batchSize ?? 0;
$this->details = $details ?? '';
$this->plannerVersion = $plannerVersion ?? '';
$this->pipelineInfo = $pipelineInfo ?? '';
$this->runtimeVersion = $runtimeVersion ?? '';
$this->id = $id ?? 0;
$this->estimatedRows = $estimatedRows ?? 0.0;
$this->planner = $planner ?? '';
$this->rows = $rows ?? 0;
}

public function getGlobalMemory(): int
{
return $this->globalMemory;
}

public function getPlannerImpl(): string
{
return $this->plannerImpl;
}

public function getMemory(): int
{
return $this->memory;
}

public function getStringRepresentation(): string
{
return $this->stringRepresentation;
}

public function getRuntime(): string
{
return $this->runtime;
}

public function getRuntimeImpl(): string
{
return $this->runtimeImpl;
}

public function getDbHits(): int
{
return $this->dbHits;
}

public function getBatchSize(): int
{
return $this->batchSize;
}

public function getDetails(): string
{
return $this->details;
}

public function getPlannerVersion(): string
{
return $this->plannerVersion;
}

public function getPipelineInfo(): string
{
return $this->pipelineInfo;
}

public function getRuntimeVersion(): string
{
return $this->runtimeVersion;
}

public function getId(): int
{
return $this->id;
}

public function getEstimatedRows(): float
{
return $this->estimatedRows;
}

public function getPlanner(): string
{
return $this->planner;
}

public function getRows(): int
{
return $this->rows;
}
}
Loading
Loading