diff --git a/Contributing.md b/Contributing.md
new file mode 100644
index 0000000..d7c41ee
--- /dev/null
+++ b/Contributing.md
@@ -0,0 +1,94 @@
+# Contributing to Neo4j QueryAPI he PHP Client
+
+Thank you for your interest in contributing to the Neo4j QueryAPI PHP Client! We welcome all contributions, whether it's bug fixes, feature enhancements, or documentation improvements.
+
+## Getting Started
+
+1. **Fork the Repository**\
+ Click the "Fork" button at the top right of the repository page.
+
+2. **Clone Your Fork**
+
+ ```bash
+ git clone https://github.com/your-username/Neo4j-Client.git
+ cd Neo4j-Client
+ ```
+
+3. **Set Up the Environment**
+
+ - Ensure you have PHP installed (compatible with PHP < 7.1).
+ - Install dependencies using Composer:
+
+ ```bash
+ composer install
+ ```
+
+ - Copy the `phpunit.dist.xml` file to `phpunit.xml` and configure the necessary environment variables like `NEO4J_ADDRESS`, `NEO4J_USERNAME`, `NEO4J_PASSWORD`.
+
+
+
+4. **Run Tests**\
+ Our tests use PHPUnit. To run tests:
+
+ ```bash
+ composer/phpunit
+ ```
+
+## Code Guidelines
+
+- Ensure your code is **PSR-12 compliant**.
+- Use **Psalm** for static analysis. Run:
+ ```bash
+ composer psalm
+ ```
+- Apply **code style fixes** using:
+ ```bash
+ composer cs:fix
+ ```
+
+## Making Changes
+
+1. **Create a New Branch**\
+ Use a descriptive branch name:
+
+ ```bash
+ git checkout -b fix/issue-123
+ ```
+
+2. **Make Your Edits**\
+ Ensure all tests pass and code is properly formatted.
+
+3. **Commit Your Changes**\
+ Write clear commit messages:
+
+ ```bash
+ git commit -m "Fix: Corrected query parsing for ProfiledQueryPlan"
+ ```
+
+4. **Push Your Branch**
+
+ ```bash
+ git push origin fix/issue-123
+ ```
+
+## Submitting a Pull Request
+
+1. Go to your forked repository on GitHub.
+2. Click on the "New pull request" button.
+3. Select your branch and submit the pull request.
+4. Add a clear description of the changes you made.
+
+## Review Process
+
+- All PRs are reviewed by the maintainers.
+- Ensure CI tests pass before requesting a review.
+- Be open to feedback and make revisions as needed.
+
+## Reporting Issues
+
+If you spot a bug or want to suggest a new feature, please [open an issue](https://github.com/NagelsIT/Neo4j-Client/issues) and provide detailed information.
+
+---
+
+We appreciate your contribution — let’s build something powerful together!
+
diff --git a/README.md b/README.md
index 9935454..88ad470 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,138 @@
+Neo4jQueryAPI client
+
+The Neo4j QueryAPI client is for developers and data engineers who want to interact programmatically with Neo4j databases — running queries, handling results, and managing database configurations. It offers:
+
+- Easy configuration to pick and choose drivers
+- An intuitive API for smooth query execution
+- Extensibility for custom use cases
+- Built and tested under close collaboration with the official Neo4j driver team
+- Easier to start with, just need a client to any neo4j instance
+- Fully typed with Psalm and CS fixed for code quality
+- It does not supports Bolt, Rather compatible with HTTP, and auto-routed drivers
+
+
+
# Query API
-Usage example:
+A PHP client for Neo4j, a graph database.
+
+## Installation
+
+You can install the package via Composer:
+
+```sh
+composer require this-repo/neo4j-client
+```
+
+## Usage
+
+### Connecting to Neo4j
```php
use Neo4j\QueryAPI\Neo4jQueryAPI;
-use Neo4j\QueryAPI\Objects\Authentication;
+use Neo4j\QueryAPI\Authentication\AuthenticateInterface;
+
+$client = Neo4jQueryAPI::login('http://localhost:7474', new AuthenticateInterface('username', 'password'));
+```
+
+### Running a Query
+
+```php
+$query = 'MATCH (n) RETURN n';
+$result = $client->run($query);
+
+foreach ($result as $record) {
+ print_r($record);
+}
+```
+
+### Transactions
+
+#### Begin a Transaction
+
+```php
+$transaction = $client->beginTransaction();
+```
+
+#### Run a Query in a Transaction
+
+```php
+$query = 'CREATE (n:Person {name: $name}) RETURN n';
+$parameters = ['name' => 'John Doe'];
+$result = $transaction->run($query, $parameters);
+```
+
+#### Commit a Transaction
+
+```php
+$transaction->commit();
+```
+
+#### Rollback a Transaction
+
+```php
+$transaction->rollback();
+```
+
+## Testing
+
+To run the tests, execute the following command:
+
+```sh
+vendor/bin/phpunit
+```
+
+Cypher values and types map to these php types and classes:
+
+| Cypher | PHP |
+|--------------------|:-----------------:|
+| Single name | |
+| Integer | ``` * int ``` |
+| Float | ``` * float ``` |
+| Boolean | ``` * bool ``` |
+| Null | ``` * null ``` |
+| String | ``` * string ``` |
+| Array | |
+| Date | |
+| Duration | |
+| 2D Point | |
+| 3D Point | |
+| Cartesian 2D Point | |
+| Cartesian 3D Point | |
+| Node | |
+| Path | |
+| Map | |
+| Exact name | |
+| Bookmarks | Yes |
+
+## Diving deeper:
+
+| Feature | Supported? |
+|----------|:-------------:|
+| Authentication | Yes |
+| Transaction | Yes |
+| HTTP | Yes |
+| Cluster | Yes |
+| Aura | Partly (recent versions) |
+| Bookmarks | Yes |
+
+> **_NOTE:_** It supports neo4j databases versions > 5.25 (which has QueryAPI enabled.)
+
+
+
+## Contributing
+
+Please see CONTRIBUTING for details.
+
+## Security
+
+If you discover any security-related issues, please email *security@nagels.tech* instead of using the issue tracker.
+
+## Credits
+
+- [Your Name](https://github.com/your-github-username)
+- [All Contributors](https://github.com/your-repo/neo4j-client/graphs/contributors)
+
+## License
-$client = Neo4jQueryAPI::login('https://myaddress.com', Authentication::bearer('mytokken'))
-```
\ No newline at end of file
+The MIT License (MIT). Please see License File for more information.
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 107ee37..c6d022e 100644
--- a/composer.json
+++ b/composer.json
@@ -51,7 +51,8 @@
"scripts": {
"cs": "vendor/bin/php-cs-fixer fix --dry-run --diff --allow-risky=yes",
"cs:fix": "vendor/bin/php-cs-fixer fix --allow-risky=yes",
- "psalm": "vendor/bin/psalm --no-cache --show-info=true"
+ "psalm": "vendor/bin/psalm --no-cache --show-info=true",
+ "phpunit" : "vendor/bin/phpunit"
}
}
diff --git a/phpunit.dist.xml b/phpunit.dist.xml
index 0067675..158b08f 100644
--- a/phpunit.dist.xml
+++ b/phpunit.dist.xml
@@ -13,5 +13,9 @@
-->
+
+
+
+
diff --git a/src/Neo4jQueryAPI.php b/src/Neo4jQueryAPI.php
index 332ac78..8e59605 100644
--- a/src/Neo4jQueryAPI.php
+++ b/src/Neo4jQueryAPI.php
@@ -4,7 +4,6 @@
use Http\Discovery\Psr17FactoryDiscovery;
use Http\Discovery\Psr18ClientDiscovery;
-use http\Exception\RuntimeException;
use InvalidArgumentException;
use Neo4j\QueryAPI\Exception\Neo4jException;
use Psr\Http\Client\ClientInterface;
@@ -16,20 +15,15 @@
final class Neo4jQueryAPI
{
- private Configuration $config;
-
public function __construct(
private ClientInterface $client,
private ResponseParser $responseParser,
private Neo4jRequestFactory $requestFactory,
- ?Configuration $config = null
+ private Configuration $config
) {
- $this->config = $config ?? new Configuration(baseUri: 'http://myaddress'); // Default configuration if not provided
+
}
- /**
- * @api
- */
public static function login(string $address = null, ?AuthenticateInterface $auth = null, ?Configuration $config = null): self
{
$config = $config ?? new Configuration(baseUri: $address ?? '');
@@ -57,19 +51,18 @@ public static function login(string $address = null, ?AuthenticateInterface $aut
);
}
- /**
- * @api
- */
- public function create(Configuration $configuration, AuthenticateInterface $auth = null): self
+ public static function create(Configuration $configuration, AuthenticateInterface $auth = null): self
{
return self::login(auth: $auth, config: $configuration);
}
+
public function getConfig(): Configuration
{
return $this->config;
}
+
/**
* Executes a Cypher query.
*/
@@ -122,7 +115,7 @@ private function handleRequestException(RequestExceptionInterface $e): void
$response = method_exists($e, 'getResponse') ? $e->getResponse() : null;
if ($response instanceof ResponseInterface) {
- $errorResponse = json_decode((string) $response->getBody(), true);
+ $errorResponse = json_decode((string)$response->getBody(), true);
throw Neo4jException::fromNeo4jResponse($errorResponse, $e);
}
diff --git a/src/Neo4jRequestFactory.php b/src/Neo4jRequestFactory.php
index 3003af2..bd78fbf 100644
--- a/src/Neo4jRequestFactory.php
+++ b/src/Neo4jRequestFactory.php
@@ -8,9 +8,6 @@
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\StreamFactoryInterface;
-/**
- * @api
- */
class Neo4jRequestFactory
{
public function __construct(
diff --git a/src/OGM.php b/src/OGM.php
index 65517fd..72b6c40 100644
--- a/src/OGM.php
+++ b/src/OGM.php
@@ -8,9 +8,6 @@
use Neo4j\QueryAPI\Objects\Path;
use InvalidArgumentException;
-/**
- * @api
- */
class OGM
{
/**
@@ -57,14 +54,14 @@ private function mapNode(array $nodeData): Node
{
return new Node(
labels: $nodeData['_labels'] ?? [],
- properties: $this->mapProperties($nodeData['_properties'] ?? []) // ✅ Fix: Ensure properties exist
+ properties: $this->mapProperties($nodeData['_properties'] ?? [])
);
}
private function mapRelationship(array $relationshipData): Relationship
{
return new Relationship(
- type: $relationshipData['_type'] ?? 'UNKNOWN', // ✅ Fix: Default to 'UNKNOWN'
+ type: $relationshipData['_type'] ?? 'UNKNOWN',
properties: $this->mapProperties($relationshipData['_properties'] ?? [])
);
}
diff --git a/src/Objects/Authentication.php b/src/Objects/Authentication.php
index 166c746..9dd0f1d 100644
--- a/src/Objects/Authentication.php
+++ b/src/Objects/Authentication.php
@@ -7,9 +7,6 @@
use Neo4j\QueryAPI\Authentication\BearerAuthentication;
use Neo4j\QueryAPI\Authentication\NoAuth;
-/**
- * @api
- */
class Authentication
{
public static function basic(string $username, string $password): AuthenticateInterface
@@ -32,9 +29,6 @@ public static function fromEnvironment(): AuthenticateInterface
);
}
-
-
-
public static function noAuth(): AuthenticateInterface
{
return new NoAuth();
diff --git a/src/Objects/Bookmarks.php b/src/Objects/Bookmarks.php
index a79215a..d158552 100644
--- a/src/Objects/Bookmarks.php
+++ b/src/Objects/Bookmarks.php
@@ -4,10 +4,7 @@
use JsonSerializable;
-/**
- * @api
- */
-class Bookmarks implements \Countable, JsonSerializable
+final class Bookmarks implements \Countable, JsonSerializable
{
public function __construct(private array $bookmarks)
{
diff --git a/src/Objects/Node.php b/src/Objects/Node.php
index 4fe6e84..2bf695b 100644
--- a/src/Objects/Node.php
+++ b/src/Objects/Node.php
@@ -6,9 +6,6 @@
* Represents a Neo4j Node with labels and properties.
*/
-/**
- * @api
- */
class Node
{
/**
@@ -33,19 +30,8 @@ public function __construct(array $labels, array $properties)
$this->properties = $properties;
}
- /**
- * Get the labels of the node.
- * @api
- * @return string[] Array of labels.
- */
- public function getLabels(): array
- {
- return $this->labels;
- }
-
/**
* Get the properties of the node.
- * @api
* @return array Associative array of properties.
*/
public function getProperties(): array
@@ -55,7 +41,6 @@ public function getProperties(): array
/**
* Convert the Node object to an array representation.
- * @api
* @return array Node data as an array.
*/
public function toArray(): array
diff --git a/src/Objects/Path.php b/src/Objects/Path.php
index 2d15c2a..bdfb28c 100644
--- a/src/Objects/Path.php
+++ b/src/Objects/Path.php
@@ -6,20 +6,17 @@
* Represents a path in a Neo4j graph, consisting of nodes and relationships.
*/
-/**
- * @api
- */
class Path
{
/**
* @var Node[] Array of nodes in the path.
*/
- private array $nodes;
+ public readonly array $nodes;
/**
* @var Relationship[] Array of relationships in the path.
*/
- private array $relationships;
+ public readonly array $relationships;
/**
* Path constructor.
@@ -33,23 +30,4 @@ public function __construct(array $nodes, array $relationships)
$this->relationships = $relationships;
}
- /**
- * Get the nodes in the path.
- * @api
- * @return Node[] Array of nodes.
- */
- public function getNodes(): array
- {
- return $this->nodes;
- }
-
- /**
- * Get the relationships in the path.
- * @api
- * @return Relationship[] Array of relationships.
- */
- public function getRelationships(): array
- {
- return $this->relationships;
- }
}
diff --git a/src/Objects/Person.php b/src/Objects/Person.php
index b1f0431..cc937c8 100644
--- a/src/Objects/Person.php
+++ b/src/Objects/Person.php
@@ -6,9 +6,6 @@
* @psalm-suppress UnusedClass
* Represents a Person node in the Neo4j graph.
*/
-/**
- * @api
- */
class Person extends Node
{
/**
diff --git a/src/Objects/Point.php b/src/Objects/Point.php
index 721abe4..4a79ec5 100644
--- a/src/Objects/Point.php
+++ b/src/Objects/Point.php
@@ -5,10 +5,6 @@
/**
* Represents a point with x, y, z coordinates, and SRID (Spatial Reference System Identifier).
*/
-/**
- * @api
- */
-
class Point
{
/**
@@ -25,46 +21,6 @@ public function __construct(
) {
}
- /**
- * Get the x coordinate of the point.
- * @api
- * @return float x coordinate value.
- */
- public function getX(): float
- {
- return $this->x;
- }
-
- /**
- * Get the y coordinate of the point.
- * @api
- * @return float y coordinate value.
- */
- public function getY(): float
- {
- return $this->y;
- }
-
- /**
- * Get the z coordinate of the point.
- * @api
- * @return float|null z coordinate value, or null if not applicable.
- */
- public function getZ(): float|null
- {
- return $this->z;
- }
-
- /**
- * Get the SRID (Spatial Reference System Identifier) of the point.
- * @api
- * @return int SRID value.
- */
- public function getSrid(): int
- {
- return $this->srid;
- }
-
/**
* Convert the Point object to a string representation.
*
diff --git a/src/Objects/ProfiledQueryPlanArguments.php b/src/Objects/ProfiledQueryPlanArguments.php
index 889c49a..74e4c48 100644
--- a/src/Objects/ProfiledQueryPlanArguments.php
+++ b/src/Objects/ProfiledQueryPlanArguments.php
@@ -2,9 +2,6 @@
namespace Neo4j\QueryAPI\Objects;
-/**
- * @api
- */
class ProfiledQueryPlanArguments
{
public function __construct(
diff --git a/src/Objects/Relationship.php b/src/Objects/Relationship.php
index 156e311..9d441f3 100644
--- a/src/Objects/Relationship.php
+++ b/src/Objects/Relationship.php
@@ -6,20 +6,17 @@
* Represents a relationship in a Neo4j graph, with a type and associated properties.
*/
-/**
- * @api
- */
class Relationship
{
/**
* @var string The type of the relationship (e.g., "FRIENDS_WITH", "WORKS_FOR").
*/
- private string $type;
+ public readonly string $type;
/**
* @var array Associative array of properties for the relationship.
*/
- private array $properties;
+ public readonly array $properties;
/**
* Relationship constructor.
@@ -33,23 +30,4 @@ public function __construct(string $type, array $properties = [])
$this->properties = $properties;
}
- /**
- * Get the type of the relationship.
- * @api
- * @return string The type of the relationship.
- */
- public function getType(): string
- {
- return $this->type;
- }
-
- /**
- * Get the properties of the relationship.
- * @api
- * @return array Associative array of properties.
- */
- public function getProperties(): array
- {
- return $this->properties;
- }
}
diff --git a/src/Objects/ResultCounters.php b/src/Objects/ResultCounters.php
index d041e1c..08669b9 100644
--- a/src/Objects/ResultCounters.php
+++ b/src/Objects/ResultCounters.php
@@ -2,9 +2,6 @@
namespace Neo4j\QueryAPI\Objects;
-/**
- * @api
- */
class ResultCounters
{
public function __construct(
diff --git a/src/Results/ResultSet.php b/src/Results/ResultSet.php
index 63be9b1..5660aec 100644
--- a/src/Results/ResultSet.php
+++ b/src/Results/ResultSet.php
@@ -12,7 +12,6 @@
use Traversable;
/**
- * @api
* @template TValue
* @implements IteratorAggregate
*/
@@ -22,11 +21,11 @@ class ResultSet implements IteratorAggregate, Countable
* @param list $rows
*/
public function __construct(
- private readonly array $rows,
- private readonly ?ResultCounters $counters = null,
- private readonly Bookmarks $bookmarks,
- private readonly ?ProfiledQueryPlan $profiledQueryPlan,
- private readonly AccessMode $accessMode
+ public readonly array $rows,
+ public readonly ?ResultCounters $counters = null,
+ public readonly Bookmarks $bookmarks,
+ public readonly ?ProfiledQueryPlan $profiledQueryPlan,
+ public readonly AccessMode $accessMode
) {
}
@@ -44,14 +43,7 @@ public function getQueryCounters(): ?ResultCounters
return $this->counters;
}
- public function getProfiledQueryPlan(): ?ProfiledQueryPlan
- {
- return $this->profiledQueryPlan;
- }
- /**
- * @api
- */
#[\Override]
public function count(): int
{
diff --git a/src/Transaction.php b/src/Transaction.php
index 0e85c5f..ec6d45e 100644
--- a/src/Transaction.php
+++ b/src/Transaction.php
@@ -35,7 +35,7 @@ public function run(string $query, array $parameters): ResultSet
{
$request = $this->requestFactory->buildTransactionRunRequest($query, $parameters, $this->transactionId, $this->clusterAffinity);
- $response = null; // ✅ Ensures response is always defined
+ $response = null;
try {
$response = $this->client->sendRequest($request);
@@ -75,7 +75,6 @@ public function rollback(): void
*/
private function handleRequestException(RequestExceptionInterface $e): void
{
- // ✅ Corrected: Check if exception has a response
$response = method_exists($e, 'getResponse') ? $e->getResponse() : null;
if ($response instanceof ResponseInterface) {
diff --git a/tests/CreatesQueryAPI.php b/tests/CreatesQueryAPI.php
new file mode 100644
index 0000000..c4b4465
--- /dev/null
+++ b/tests/CreatesQueryAPI.php
@@ -0,0 +1,26 @@
+api = Neo4jQueryAPI::create(
+ new Configuration(baseUri: $neo4jAddress, accessMode: $accessMode),
+ Authentication::fromEnvironment()
+ );
+ }
+}
diff --git a/tests/Integration/AccessModesIntegrationTest.php b/tests/Integration/AccessModesIntegrationTest.php
new file mode 100644
index 0000000..f3aee9c
--- /dev/null
+++ b/tests/Integration/AccessModesIntegrationTest.php
@@ -0,0 +1,48 @@
+createQueryAPI();
+ }
+
+ #[DoesNotPerformAssertions]
+ public function testRunWithWriteAccessMode(): void
+ {
+ $this->api->run("CREATE (n:Person {name: 'Alice'}) RETURN n");
+ }
+
+ #[DoesNotPerformAssertions]
+ public function testRunWithReadAccessMode(): void
+ {
+ $this->createQueryAPI(AccessMode::READ);
+ $this->api->run("MATCH (n) RETURN COUNT(n)");
+ }
+
+ public function testReadModeWithWriteQuery(): void
+ {
+ $this->createQueryAPI(AccessMode::READ);
+ $this->expectException(Neo4jException::class);
+ $this->api->run("CREATE (n:Test {name: 'Test Node'})");
+ }
+
+ #[DoesNotPerformAssertions]
+ public function testWriteModeWithReadQuery(): void
+ {
+ $this->api->run("MATCH (n:Test) RETURN n");
+ }
+}
diff --git a/tests/Integration/BookmarksIntegrationTest.php b/tests/Integration/BookmarksIntegrationTest.php
new file mode 100644
index 0000000..d63b444
--- /dev/null
+++ b/tests/Integration/BookmarksIntegrationTest.php
@@ -0,0 +1,37 @@
+createQueryAPI();
+ }
+
+
+ public function testCreateBookmarks(): void
+ {
+ $result = $this->api->run('CREATE (x:Node {hello: "world"})');
+
+ $bookmarks = $result->getBookmarks() ?? new Bookmarks([]);
+
+ $result = $this->api->run('CREATE (x:Node {hello: "world2"})');
+ $bookmarks->addBookmarks($result->getBookmarks());
+
+ $result = $this->api->run('MATCH (x:Node {hello: "world2"}) RETURN x');
+ $bookmarks->addBookmarks($result->getBookmarks());
+
+ $this->assertCount(1, $result);
+ }
+
+}
diff --git a/tests/Integration/DataTypesIntegrationTest.php b/tests/Integration/DataTypesIntegrationTest.php
new file mode 100644
index 0000000..bf83ce2
--- /dev/null
+++ b/tests/Integration/DataTypesIntegrationTest.php
@@ -0,0 +1,613 @@
+createQueryAPI();
+ }
+
+ public function testWithExactNames(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.name' => 'bob1']),
+ new ResultRow(['n.name' => 'alicy']),
+ ],
+ new ResultCounters(),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run('MATCH (n:Person) WHERE n.name IN $names RETURN n.name', [
+ 'names' => ['bob1', 'alicy']
+ ]);
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $bookmarks = $results->getBookmarks() ?? new Bookmarks([]);
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithSingleName(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.name' => 'bob1']),
+ ],
+ new ResultCounters(),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run('MATCH (n:Person) WHERE n.name = $name RETURN n.name LIMIT 1', [
+ 'name' => 'bob1'
+ ]);
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithInteger(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.age' => 30]),
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 1,
+ propertiesSet: 1,
+ labelsAdded: 1,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run('CREATE (n:Person {age: $age}) RETURN n.age', [
+ 'age' => 30
+ ]);
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+
+ public function testWithFloat(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.height' => 1.75]),
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 1,
+ propertiesSet: 1,
+ labelsAdded: 1,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run('CREATE (n:Person {height: $height}) RETURN n.height', [
+ 'height' => 1.75
+ ]);
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithNull(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.middleName' => null]),
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 1,
+ propertiesSet: 0,
+ labelsAdded: 1,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run('CREATE (n:Person {middleName: $middleName}) RETURN n.middleName', [
+ 'middleName' => null
+ ]);
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithBoolean(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.isActive' => true]),
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 1,
+ propertiesSet: 1,
+ labelsAdded: 1,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run('CREATE (n:Person {isActive: $isActive}) RETURN n.isActive', [
+ 'isActive' => true
+ ]);
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithString(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.name' => 'Alice']),
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 1,
+ propertiesSet: 1,
+ labelsAdded: 1,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run('CREATE (n:Person {name: $name}) RETURN n.name', [
+ 'name' => 'Alice'
+ ]);
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithArray(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.name' => 'bob1']),
+ new ResultRow(['n.name' => 'alicy'])
+ ],
+ new ResultCounters(
+ containsUpdates: false,
+ nodesCreated: 0,
+ propertiesSet: 0,
+ labelsAdded: 0,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run(
+ 'MATCH (n:Person) WHERE n.name IN $names RETURN n.name',
+ ['names' => ['bob1', 'alicy']]
+ );
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithDate(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.date' => '2024-12-11T11:00:00Z'])
+
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 1,
+ propertiesSet: 1,
+ labelsAdded: 1,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run(
+ 'CREATE (n:Person {date: datetime($date)}) RETURN n.date',
+ ['date' => "2024-12-11T11:00:00Z"]
+ );
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithDuration(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.duration' => 'P14DT16H12M']),
+
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 1,
+ propertiesSet: 1,
+ labelsAdded: 1,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run(
+ 'CREATE (n:Person {duration: duration($duration)}) RETURN n.duration',
+ ['duration' => 'P14DT16H12M'],
+ );
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithWGS84_2DPoint(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.Point' => 'SRID=4326;POINT (1.2 3.4)']),
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 1,
+ propertiesSet: 1,
+ labelsAdded: 1,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run(
+ 'CREATE (n:Person {Point: point($Point)}) RETURN n.Point',
+ [
+ 'Point' => [
+ 'longitude' => 1.2,
+ 'latitude' => 3.4,
+ 'crs' => 'wgs-84',
+ ]]
+ );
+
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithWGS84_3DPoint(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.Point' => new Point(1.2, 3.4, 4.2, 4979)]),
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 1,
+ propertiesSet: 1,
+ labelsAdded: 1,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run(
+ 'CREATE (n:Person {Point: point({longitude: $longitude, latitude: $latitude, height: $height, srid: $srid})}) RETURN n.Point',
+ [
+ 'longitude' => 1.2,
+ 'latitude' => 3.4,
+ 'height' => 4.2,
+ 'srid' => 4979,
+ ]
+ );
+
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithCartesian2DPoint(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.Point' => new Point(10.5, 20.7, null, 7203)]),
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 1,
+ propertiesSet: 1,
+ labelsAdded: 1,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run(
+ 'CREATE (n:Person {Point: point({x: $x, y: $y, srid: $srid})}) RETURN n.Point',
+ [
+ 'x' => 10.5,
+ 'y' => 20.7,
+ 'srid' => 7203,
+ ]
+ );
+
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithCartesian3DPoint(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['n.Point' => new Point(10.5, 20.7, 30.9, 9157)]),
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 1,
+ propertiesSet: 1,
+ labelsAdded: 1,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run(
+ 'CREATE (n:Person {Point: point({x: $x, y: $y, z: $z, srid: $srid})}) RETURN n.Point',
+ [
+ 'x' => 10.5,
+ 'y' => 20.7,
+ 'z' => 30.9,
+ 'srid' => 9157,
+ ]
+ );
+
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithNode(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow([
+ 'node' => [
+ 'properties' => [
+ 'name' => 'Ayush',
+ 'location' => 'New York',
+ 'age' => '30'
+ ],
+ 'labels' => [
+ 0 => 'Person'
+ ]
+
+ ]
+ ]),
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 1,
+ propertiesSet: 3,
+ labelsAdded: 1,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run(
+ 'CREATE (n:Person {name: $name, age: $age, location: $location}) RETURN {labels: labels(n), properties: properties(n)} AS node',
+ [
+ 'name' => 'Ayush',
+ 'age' => 30,
+ 'location' => 'New York',
+ ]
+ );
+
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithPath(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['node1' => [
+ 'labels' => ['Person'],
+ 'properties' => [
+ 'name' => 'A',
+ ],
+ ],
+ 'node2' => [
+ 'labels' => ['Person'],
+ 'properties' => [
+ 'name' => 'B',
+ ],
+ ],
+ 'relationshipTypes' => ['FRIENDS'],
+ ]),
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 2,
+ propertiesSet: 2,
+ relationshipsCreated: 1,
+ labelsAdded: 2,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run(
+ 'CREATE (a:Person {name: $name1}), (b:Person {name: $name2}),
+ (a)-[r:FRIENDS]->(b)
+ RETURN {labels: labels(a), properties: properties(a)} AS node1,
+ {labels: labels(b), properties: properties(b)} AS node2,
+ collect(type(r)) AS relationshipTypes',
+ [
+ 'name1' => 'A',
+ 'name2' => 'B',
+ ]
+ );
+
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+
+ public function testWithMap(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow(['map' => [
+ 'hello' => 'hello',
+ ],
+ ]),
+ ],
+ new ResultCounters(
+ containsUpdates: false,
+ nodesCreated: 0,
+ propertiesSet: 0,
+ labelsAdded: 0,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run(
+ 'RETURN {hello: "hello"} AS map',
+ []
+ );
+
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+
+ public function testWithRelationship(): void
+ {
+ $expected = new ResultSet(
+ [
+ new ResultRow([
+ 'node1' => [
+ 'labels' => ['Person'],
+ 'properties' => [
+ 'name' => 'Ayush',
+ 'age' => 30,
+ 'location' => 'New York',
+ ],
+ ],
+ 'node2' => [
+ 'labels' => ['Person'],
+ 'properties' => [
+ 'name' => 'John',
+ 'age' => 25,
+ 'location' => 'Los Angeles',
+ ],
+ ],
+ 'relationshipType' => 'FRIEND_OF',
+ ]),
+ ],
+ new ResultCounters(
+ containsUpdates: true,
+ nodesCreated: 2,
+ propertiesSet: 6,
+ relationshipsCreated: 1,
+ labelsAdded: 2,
+ ),
+ new Bookmarks([]),
+ null,
+ AccessMode::WRITE
+ );
+
+ $results = $this->api->run(
+ 'CREATE (p1:Person {name: $name1, age: $age1, location: $location1}),
+ (p2:Person {name: $name2, age: $age2, location: $location2}),
+ (p1)-[r:FRIEND_OF]->(p2)
+ RETURN {labels: labels(p1), properties: properties(p1)} AS node1,
+ {labels: labels(p2), properties: properties(p2)} AS node2,
+ type(r) AS relationshipType',
+ [
+ 'name1' => 'Ayush',
+ 'age1' => 30,
+ 'location1' => 'New York',
+ 'name2' => 'John',
+ 'age2' => 25,
+ 'location2' => 'Los Angeles'
+ ]
+ );
+
+
+ $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
+ $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
+ $bookmarks = $results->getBookmarks() ?: [];
+ $this->assertCount(1, $bookmarks);
+ }
+}
diff --git a/tests/Integration/Neo4jOGMTest.php b/tests/Integration/Neo4jOGMTest.php
index de6dc0b..60d50cc 100644
--- a/tests/Integration/Neo4jOGMTest.php
+++ b/tests/Integration/Neo4jOGMTest.php
@@ -23,7 +23,6 @@ protected function setUp(): void
public function testWithNode(): void
{
- // Ensure the property $ogm is referenced
$nodeData = [
'$type' => 'Node',
'_value' => [
@@ -36,10 +35,9 @@ public function testWithNode(): void
$this->assertEquals('Ayush', $node->getProperties()['name']['_value']);
}
- // Example of using $ogm in another test
public function testWithSimpleRelationship(): void
{
- // Mapping the Relationship
+
$relationshipData = [
'$type' => 'Relationship',
'_value' => [
@@ -49,10 +47,9 @@ public function testWithSimpleRelationship(): void
];
$relationship = $this->ogm->map($relationshipData);
- $this->assertEquals('FRIENDS', $relationship->getType());
+ $this->assertEquals('FRIENDS', $relationship->type);
}
- // More tests...
public function testWithPath(): void
{
$pathData = [
@@ -63,7 +60,7 @@ public function testWithPath(): void
'_value' => [
'_labels' => ['Person'],
'_properties' => [
- 'name' => ['_value' => 'A'], // ✅ Now correctly wrapped
+ 'name' => ['_value' => 'A'],
],
],
],
@@ -79,7 +76,7 @@ public function testWithPath(): void
'_value' => [
'_labels' => ['Person'],
'_properties' => [
- 'name' => ['_value' => 'B'], // ✅ Now correctly wrapped
+ 'name' => ['_value' => 'B'],
],
],
],
@@ -88,11 +85,10 @@ public function testWithPath(): void
$path = $this->ogm->map($pathData);
- // Assertions
- $this->assertCount(2, $path->getNodes());
- $this->assertCount(1, $path->getRelationships());
- $this->assertEquals('A', $path->getNodes()[0]->getProperties()['name']['_value']);
- $this->assertEquals('B', $path->getNodes()[1]->getProperties()['name']['_value']);
+ $this->assertCount(2, $path->nodes);
+ $this->assertCount(1, $path->relationships);
+ $this->assertEquals('A', $path->nodes[0]->getProperties()['name']['_value']);
+ $this->assertEquals('B', $path->nodes[1]->getProperties()['name']['_value']);
}
}
diff --git a/tests/Integration/Neo4jQueryAPIIntegrationTest.php b/tests/Integration/Neo4jQueryAPIIntegrationTest.php
index ba7a74d..1dce152 100644
--- a/tests/Integration/Neo4jQueryAPIIntegrationTest.php
+++ b/tests/Integration/Neo4jQueryAPIIntegrationTest.php
@@ -2,28 +2,16 @@
namespace Neo4j\QueryAPI\Tests\Integration;
-use GuzzleHttp\Client;
-use GuzzleHttp\Handler\MockHandler;
-use GuzzleHttp\HandlerStack;
use Neo4j\QueryAPI\Exception\Neo4jException;
use Neo4j\QueryAPI\Neo4jQueryAPI;
-use Neo4j\QueryAPI\Neo4jRequestFactory;
use Neo4j\QueryAPI\Objects\Authentication;
use Neo4j\QueryAPI\Objects\Node;
-use Neo4j\QueryAPI\Objects\Point;
-use Neo4j\QueryAPI\Objects\ProfiledQueryPlan;
use Neo4j\QueryAPI\Objects\Bookmarks;
use Neo4j\QueryAPI\Objects\ResultCounters;
-use Neo4j\QueryAPI\OGM;
use Neo4j\QueryAPI\Results\ResultRow;
use Neo4j\QueryAPI\Results\ResultSet;
-use Nyholm\Psr7\Factory\Psr17Factory;
use PHPUnit\Framework\TestCase;
use Neo4j\QueryAPI\Enums\AccessMode;
-use Neo4j\QueryAPI\ResponseParser;
-use Neo4j\QueryAPI\Configuration;
-use GuzzleHttp\Psr7\Response;
-use RuntimeException;
final class Neo4jQueryAPIIntegrationTest extends TestCase
{
@@ -89,293 +77,6 @@ public function testCounters(): void
$this->assertEquals(1, $queryCounters->getNodesCreated());
}
- public function testCreateBookmarks(): void
- {
- $result = $this->api->run('CREATE (x:Node {hello: "world"})');
-
- $bookmarks = $result->getBookmarks() ?? new Bookmarks([]);
-
- $result = $this->api->run('CREATE (x:Node {hello: "world2"})');
- $bookmarks->addBookmarks($result->getBookmarks());
-
- $result = $this->api->run('MATCH (x:Node {hello: "world2"}) RETURN x');
- $bookmarks->addBookmarks($result->getBookmarks());
-
- $this->assertCount(1, $result);
- }
-
-
-
-
- public function testProfileExistence(): void
- {
- $query = "PROFILE MATCH (n:Person) RETURN n.name";
- $result = $this->api->run($query);
- $this->assertNotNull($result->getProfiledQueryPlan(), "profiled query plan not found");
- }
-
- public function testProfileCreateQueryExistence(): void
- {
- $query = "
- PROFILE UNWIND range(1, 100) AS i
- CREATE (:Person {
- name: 'Person' + toString(i),
- id: i,
- job: CASE
- WHEN i % 2 = 0 THEN 'Engineer'
- ELSE 'Artist'
- END,
- age: 1 + i - 1
- });
- ";
-
- $result = $this->api->run($query);
-
- $this->assertNotNull($result->getProfiledQueryPlan(), "profiled query plan not found");
- }
-
- public function testProfileCreateMovieQueryExistence(): void
- {
- $query = "
- PROFILE UNWIND range(1, 50) AS i
- CREATE (:Movie {
- year: 2000 + i,
- genre: CASE
- WHEN i % 2 = 0 THEN 'Action'
- ELSE 'Comedy'
- END,
- title: 'Movie' + toString(i)
- });
- ";
-
- $result = $this->api->run($query);
-
- $this->assertNotNull($result->getProfiledQueryPlan(), "profiled query plan not found");
- }
-
- public function testProfileCreateFriendsQueryExistence(): void
- {
- $query = "
- PROFILE UNWIND range(1, 100) AS i
- UNWIND range(1, 100) AS j
- MATCH (a:Person {id: i}), (b:Person {id: j})
- WHERE a.id <> b.id AND rand() < 0.1
- CREATE (a)-[:FRIENDS]->(b);
- ";
-
- $result = $this->api->run($query);
-
-
- $this->assertNotNull($result->getProfiledQueryPlan(), "profiled query plan not found");
- }
-
- public function testProfileCreateWatchedRelationshipExistence(): void
- {
-
- $query = "
- PROFILE UNWIND range(1, 50) AS i
- MATCH (p:Person), (m:Movie {year: 2000 + i})
- CREATE (p)-[:WATCHED]->(m);
- ";
-
- $result = $this->api->run($query);
-
- $this->assertNotNull($result->getProfiledQueryPlan(), "profiled query plan not found");
- }
-
- public function testProfileCreateWatchedWithFilters(): void
- {
- $query = "
- PROFILE UNWIND range(1, 50) AS i
- MATCH (p:Person), (m:Movie {year: 2000 + i})
- WHERE p.age > 25 AND m.genre = 'Action'
- CREATE (p)-[:WATCHED]->(m);
- ";
-
- $result = $this->api->run($query);
- $this->assertNotNull($result->getProfiledQueryPlan(), "profiled query plan not found");
- }
-
- public function testProfileCreateKnowsBidirectionalRelationships(): void
- {
- $query = "
- PROFILE UNWIND range(1, 100) AS i
- UNWIND range(1, 100) AS j
- MATCH (a:Person {id: i}), (b:Person {id: j})
- WHERE a.id < b.id AND rand() < 0.1
- CREATE (a)-[:KNOWS]->(b), (b)-[:KNOWS]->(a);
- ";
-
- $result = $this->api->run($query);
- $this->assertNotNull($result->getProfiledQueryPlan(), "profiled query plan not found");
-
- $body = file_get_contents(__DIR__ . '/../resources/responses/complex-query-profile.json');
-
- if ($body === false) {
- throw new RuntimeException('Failed to read the file: ' . __DIR__ . '/../resources/responses/complex-query-profile.json');
- }
-
- $mockSack = new MockHandler([
- new Response(200, [], $body),
- ]);
-
- $handler = HandlerStack::create($mockSack);
- $client = new Client(['handler' => $handler]);
-
- $neo4jAddress = getenv('NEO4J_ADDRESS');
- if (!is_string($neo4jAddress) || trim($neo4jAddress) === '') {
- throw new RuntimeException('NEO4J_ADDRESS is not set.');
- }
-
-
- $auth = Authentication::fromEnvironment();
-
- $api = new Neo4jQueryAPI(
- $client,
- new ResponseParser(new OGM()),
- new Neo4jRequestFactory(
- new Psr17Factory(),
- new Psr17Factory(),
- new Configuration($neo4jAddress),
- $auth
- )
- );
-
-
- $result = $api->run($query);
-
- $plan = $result->getProfiledQueryPlan();
- $this->assertNotNull($plan, "The result of the query should not be null.");
-
- $expected = require __DIR__ . '/../resources/expected/complex-query-profile.php';
-
- $this->assertEquals($expected->getProfiledQueryPlan(), $plan, "Profiled query plan does not match the expected value.");
- }
-
- public function testProfileCreateActedInRelationships(): void
- {
- $query = "
- PROFILE UNWIND range(1, 50) AS i
- MATCH (p:Person {id: i}), (m:Movie {year: 2000 + i})
- WHERE p.job = 'Artist'
- CREATE (p)-[:ACTED_IN]->(m);
- ";
-
- $result = $this->api->run($query);
- $this->assertNotNull($result->getProfiledQueryPlan(), "profiled query plan not found");
- }
-
- public function testChildQueryPlanExistence(): void
- {
- $result = $this->api->run("PROFILE MATCH (n:Person {name: 'Alice'}) RETURN n.name");
-
- $profiledQueryPlan = $result->getProfiledQueryPlan();
- $this->assertNotNull($profiledQueryPlan);
- $this->assertNotEmpty($profiledQueryPlan->children);
-
- foreach ($profiledQueryPlan->children as $child) {
- $this->assertInstanceOf(ProfiledQueryPlan::class, $child);
- }
- }
- //
- // public function testImpersonatedUserSuccess(): void
- // {
- // $this->markTestSkipped("stuck");
- //
- // $result = $this->api->run(
- // "PROFILE MATCH (n:Person {name: 'Alice'}) RETURN n.name",
- // [],
- // $this->config->database,
- // new Bookmarks([]),
- // 'HAPPYBDAY'
- // );
- //
- // $impersonatedUser = $result->getImpersonatedUser();
- // $this->assertNotNull($impersonatedUser, "Impersonated user should not be null.");
- // }
-
- // //
- // //
- // public function testImpersonatedUserFailure(): void
- // {
- // $this->markTestSkipped("stuck");
- // $this->expectException(Neo4jException::class);
- //
- //
- // $this->api->run(
- // "PROFILE MATCH (n:Person {name: 'Alice'}) RETURN n.name",
- // [],
- // 'neo4j',
- // null,
- // 'invalidUser'
- // );
- // }
-
- // //
- // #[DoesNotPerformAssertions]
- // public function testRunWithWriteAccessMode(): void
- // {
- // $result = $this->api->run(
- // "CREATE (n:Person {name: 'Alice'}) RETURN n",
- // [],
- // 'neo4j',
- // null,
- // null,
- // AccessMode::WRITE
- // );
- //
- // }
- //
- // #[DoesNotPerformAssertions]
- // public function testRunWithReadAccessMode(): void
- // {
- // $result = $this->api->run(
- // "MATCH (n) RETURN COUNT(n)",
- // [],
- // 'neo4j',
- // null,
- // null,
- // AccessMode::READ
- // );
- // }
-
- //
- // public function testReadModeWithWriteQuery(): void
- // {
- // $this->expectException(Neo4jException::class);
- // $this->expectExceptionMessage("Writing in read access mode not allowed. Attempted write to neo4j");
- //
- // try {
- // $this->api->run(
- // "CREATE (n:Test {name: 'Test Node'})",
- // [],
- // $this->config->database,
- // new Bookmarks([]),
- // null,
- // AccessMode::WRITE
- // );
- // } catch (Neo4jException $e) {
- // error_log('Caught expected Neo4jException: ' . $e->getMessage());
- // throw $e;
- // }
- // }
- //
- //
- // #[DoesNotPerformAssertions]
- // public function testWriteModeWithReadQuery(): void
- // {
- // $this->api->run(
- // "MATCH (n:Test) RETURN n",
- // [],
- // 'neo4j',
- // null,
- // null,
- // AccessMode::WRITE
- // //cos write encapsulates read
- // );
- // }
-
-
private function clearDatabase(): void
{
$this->api->run('MATCH (n) DETACH DELETE n', []);
@@ -402,608 +103,4 @@ public function testInvalidQueryException(): void
}
}
- public function testWithExactNames(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.name' => 'bob1']),
- new ResultRow(['n.name' => 'alicy']),
- ],
- new ResultCounters(),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run('MATCH (n:Person) WHERE n.name IN $names RETURN n.name', [
- 'names' => ['bob1', 'alicy']
- ]);
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
-
- // Ensure results are not empty
- $this->assertNotEmpty(iterator_to_array($results), 'No results returned from query.');
-
- $filteredResults = array_values(array_filter(
- iterator_to_array($results),
- fn (ResultRow $row) => in_array($row['n.name'] ?? '', ['bob1', 'alicy'], true)
- ));
-
- $this->assertEquals(iterator_to_array($expected), $filteredResults);
-
- $bookmarks = $results->getBookmarks() ?? new Bookmarks([]);
- $this->assertCount(1, $bookmarks);
- }
-
-
- public function testWithSingleName(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.name' => 'bob1']),
- ],
- new ResultCounters(),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run('MATCH (n:Person) WHERE n.name = $name RETURN n.name LIMIT 1', [
- 'name' => 'bob1'
- ]);
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
-
- $filteredResults = array_slice(iterator_to_array($results), 0, 1);
- $this->assertEquals(iterator_to_array($expected), $filteredResults);
-
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithInteger(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.age' => 30]),
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 1,
- propertiesSet: 1,
- labelsAdded: 1,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run('CREATE (n:Person {age: $age}) RETURN n.age', [
- 'age' => 30
- ]);
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
-
- public function testWithFloat(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.height' => 1.75]),
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 1,
- propertiesSet: 1,
- labelsAdded: 1,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run('CREATE (n:Person {height: $height}) RETURN n.height', [
- 'height' => 1.75
- ]);
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithNull(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.middleName' => null]),
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 1,
- propertiesSet: 0,
- labelsAdded: 1,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run('CREATE (n:Person {middleName: $middleName}) RETURN n.middleName', [
- 'middleName' => null
- ]);
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithBoolean(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.isActive' => true]),
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 1,
- propertiesSet: 1,
- labelsAdded: 1,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run('CREATE (n:Person {isActive: $isActive}) RETURN n.isActive', [
- 'isActive' => true
- ]);
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithString(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.name' => 'Alice']),
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 1,
- propertiesSet: 1,
- labelsAdded: 1,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run('CREATE (n:Person {name: $name}) RETURN n.name', [
- 'name' => 'Alice'
- ]);
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithArray(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.name' => 'bob1']),
- new ResultRow(['n.name' => 'alicy'])
- ],
- new ResultCounters(
- containsUpdates: false,
- nodesCreated: 0,
- propertiesSet: 0,
- labelsAdded: 0,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run(
- 'MATCH (n:Person) WHERE n.name IN $names RETURN n.name',
- ['names' => ['bob1', 'alicy']]
- );
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithDate(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.date' => '2024-12-11T11:00:00Z'])
-
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 1,
- propertiesSet: 1,
- labelsAdded: 1,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run(
- 'CREATE (n:Person {date: datetime($date)}) RETURN n.date',
- ['date' => "2024-12-11T11:00:00Z"]
- );
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithDuration(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.duration' => 'P14DT16H12M']),
-
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 1,
- propertiesSet: 1,
- labelsAdded: 1,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run(
- 'CREATE (n:Person {duration: duration($duration)}) RETURN n.duration',
- ['duration' => 'P14DT16H12M'],
- );
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithWGS84_2DPoint(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.Point' => 'SRID=4326;POINT (1.2 3.4)']),
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 1,
- propertiesSet: 1,
- labelsAdded: 1,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run(
- 'CREATE (n:Person {Point: point($Point)}) RETURN n.Point',
- [
- 'Point' => [
- 'longitude' => 1.2,
- 'latitude' => 3.4,
- 'crs' => 'wgs-84',
- ]]
- );
-
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithWGS84_3DPoint(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.Point' => new Point(1.2, 3.4, 4.2, 4979)]),
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 1,
- propertiesSet: 1,
- labelsAdded: 1,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run(
- 'CREATE (n:Person {Point: point({longitude: $longitude, latitude: $latitude, height: $height, srid: $srid})}) RETURN n.Point',
- [
- 'longitude' => 1.2,
- 'latitude' => 3.4,
- 'height' => 4.2,
- 'srid' => 4979,
- ]
- );
-
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithCartesian2DPoint(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.Point' => new Point(10.5, 20.7, null, 7203)]),
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 1,
- propertiesSet: 1,
- labelsAdded: 1,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run(
- 'CREATE (n:Person {Point: point({x: $x, y: $y, srid: $srid})}) RETURN n.Point',
- [
- 'x' => 10.5,
- 'y' => 20.7,
- 'srid' => 7203,
- ]
- );
-
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithCartesian3DPoint(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['n.Point' => new Point(10.5, 20.7, 30.9, 9157)]),
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 1,
- propertiesSet: 1,
- labelsAdded: 1,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run(
- 'CREATE (n:Person {Point: point({x: $x, y: $y, z: $z, srid: $srid})}) RETURN n.Point',
- [
- 'x' => 10.5,
- 'y' => 20.7,
- 'z' => 30.9,
- 'srid' => 9157,
- ]
- );
-
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithNode(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow([
- 'node' => [
- 'properties' => [
- 'name' => 'Ayush',
- 'location' => 'New York',
- 'age' => '30'
- ],
- 'labels' => [
- 0 => 'Person'
- ]
-
- ]
- ]),
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 1,
- propertiesSet: 3,
- labelsAdded: 1,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run(
- 'CREATE (n:Person {name: $name, age: $age, location: $location}) RETURN {labels: labels(n), properties: properties(n)} AS node',
- [
- 'name' => 'Ayush',
- 'age' => 30,
- 'location' => 'New York',
- ]
- );
-
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithPath(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['node1' => [
- 'labels' => ['Person'],
- 'properties' => [
- 'name' => 'A',
- ],
- ],
- 'node2' => [
- 'labels' => ['Person'],
- 'properties' => [
- 'name' => 'B',
- ],
- ],
- 'relationshipTypes' => ['FRIENDS'],
- ]),
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 2,
- propertiesSet: 2,
- relationshipsCreated: 1,
- labelsAdded: 2,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run(
- 'CREATE (a:Person {name: $name1}), (b:Person {name: $name2}),
- (a)-[r:FRIENDS]->(b)
- RETURN {labels: labels(a), properties: properties(a)} AS node1,
- {labels: labels(b), properties: properties(b)} AS node2,
- collect(type(r)) AS relationshipTypes',
- [
- 'name1' => 'A',
- 'name2' => 'B',
- ]
- );
-
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
-
- public function testWithMap(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow(['map' => [
- 'hello' => 'hello',
- ],
- ]),
- ],
- new ResultCounters(
- containsUpdates: false,
- nodesCreated: 0,
- propertiesSet: 0,
- labelsAdded: 0,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run(
- 'RETURN {hello: "hello"} AS map',
- []
- );
-
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
-
- public function testWithRelationship(): void
- {
- $expected = new ResultSet(
- [
- new ResultRow([
- 'node1' => [
- 'labels' => ['Person'],
- 'properties' => [
- 'name' => 'Ayush',
- 'age' => 30,
- 'location' => 'New York',
- ],
- ],
- 'node2' => [
- 'labels' => ['Person'],
- 'properties' => [
- 'name' => 'John',
- 'age' => 25,
- 'location' => 'Los Angeles',
- ],
- ],
- 'relationshipType' => 'FRIEND_OF',
- ]),
- ],
- new ResultCounters(
- containsUpdates: true,
- nodesCreated: 2,
- propertiesSet: 6,
- relationshipsCreated: 1,
- labelsAdded: 2,
- ),
- new Bookmarks([]),
- null,
- AccessMode::WRITE
- );
-
- $results = $this->api->run(
- 'CREATE (p1:Person {name: $name1, age: $age1, location: $location1}),
- (p2:Person {name: $name2, age: $age2, location: $location2}),
- (p1)-[r:FRIEND_OF]->(p2)
- RETURN {labels: labels(p1), properties: properties(p1)} AS node1,
- {labels: labels(p2), properties: properties(p2)} AS node2,
- type(r) AS relationshipType',
- [
- 'name1' => 'Ayush',
- 'age1' => 30,
- 'location1' => 'New York',
- 'name2' => 'John',
- 'age2' => 25,
- 'location2' => 'Los Angeles'
- ]
- );
-
-
- $this->assertEquals($expected->getQueryCounters(), $results->getQueryCounters());
- $this->assertEquals(iterator_to_array($expected), iterator_to_array($results));
- $bookmarks = $results->getBookmarks() ?: [];
- $this->assertCount(1, $bookmarks);
- }
}
diff --git a/tests/Integration/Neo4jTransactionIntegrationTest.php b/tests/Integration/Neo4jTransactionIntegrationTest.php
index a4e7087..9033ba8 100644
--- a/tests/Integration/Neo4jTransactionIntegrationTest.php
+++ b/tests/Integration/Neo4jTransactionIntegrationTest.php
@@ -6,6 +6,7 @@
use Neo4j\QueryAPI\Objects\Authentication;
use GuzzleHttp\Exception\GuzzleException;
use Neo4j\QueryAPI\Neo4jQueryAPI;
+use Neo4j\QueryAPI\Tests\CreatesQueryAPI;
use PHPUnit\Framework\TestCase;
use RuntimeException;
@@ -14,23 +15,14 @@
*/
class Neo4jTransactionIntegrationTest extends TestCase
{
- /** @psalm-suppress PropertyNotSetInConstructor */
- private Neo4jQueryAPI $api;
+ use CreatesQueryAPI;
- /**
- * @throws GuzzleException
- */
#[\Override]
- public function setUp(): void
+ protected function setUp(): void
{
parent::setUp();
- $address = is_string(getenv('NEO4J_ADDRESS')) ? getenv('NEO4J_ADDRESS') : '';
-
- if ($address === '') {
- throw new RuntimeException('NEO4J_ADDRESS is not set.');
- }
-
+ $this->createQueryAPI();
$this->api = $this->initializeApi();
$this->clearDatabase();
$this->populateTestData();
diff --git a/tests/Integration/ProfiledQueryPlanIntegrationTest.php b/tests/Integration/ProfiledQueryPlanIntegrationTest.php
new file mode 100644
index 0000000..922e8f9
--- /dev/null
+++ b/tests/Integration/ProfiledQueryPlanIntegrationTest.php
@@ -0,0 +1,75 @@
+createQueryAPI();
+ }
+
+ public function testProfileExistence(): void
+ {
+ $query = "PROFILE MATCH (n:Person) RETURN n.name";
+ $result = $this->api->run($query);
+ $this->assertNotNull($result->profiledQueryPlan, "Profiled query plan not found");
+ }
+
+ public function testProfileCreateQueryExistence(): void
+ {
+ $query = "
+ PROFILE UNWIND range(1, 100) AS i
+ CREATE (:Person {
+ name: 'Person' + toString(i),
+ id: i,
+ job: CASE
+ WHEN i % 2 = 0 THEN 'Engineer'
+ ELSE 'Artist'
+ END,
+ age: 1 + i - 1
+ });
+ ";
+
+ $result = $this->api->run($query);
+ $this->assertNotNull($result->profiledQueryPlan, "Profiled query plan not found");
+ }
+
+ public function testProfileCreateMovieQueryExistence(): void
+ {
+ $query = "
+ PROFILE UNWIND range(1, 50) AS i
+ CREATE (:Movie {
+ year: 2000 + i,
+ genre: CASE
+ WHEN i % 2 = 0 THEN 'Action'
+ ELSE 'Comedy'
+ END,
+ title: 'Movie' + toString(i)
+ });
+ ";
+
+ $result = $this->api->run($query);
+ $this->assertNotNull($result->profiledQueryPlan, "Profiled query plan not found");
+ }
+
+ public function testProfileCreateFriendsQueryExistence(): void
+ {
+ $query = "
+ PROFILE MATCH (a:Person), (b:Person)
+ WHERE a.name = 'Alice' AND b.name = 'Bob'
+ CREATE (a)-[:FRIENDS_WITH]->(b);
+ ";
+
+ $result = $this->api->run($query);
+ $this->assertNotNull($result->profiledQueryPlan, "Profiled query plan not found");
+ }
+}
diff --git a/tests/Unit/Neo4jQueryAPIUnitTest.php b/tests/Unit/Neo4jQueryAPIUnitTest.php
index 5dae33d..16ca56a 100644
--- a/tests/Unit/Neo4jQueryAPIUnitTest.php
+++ b/tests/Unit/Neo4jQueryAPIUnitTest.php
@@ -71,7 +71,8 @@ public function testRunSuccess(): void
Psr17FactoryDiscovery::findStreamFactory(),
new Configuration($this->address),
Authentication::fromEnvironment()
- )
+ ),
+ new Configuration($this->address)
);
$neo4jQueryAPI->run('MATCH (n:Person) RETURN n LIMIT 5');