Skip to content

Carried over data structures from neo4j php client #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ infection.html
/tmp/
/docs/.npm/
/docs/.config/
composer.lock
composer.lock
/.idea
141 changes: 23 additions & 118 deletions docs/constraint.md
Original file line number Diff line number Diff line change
@@ -1,125 +1,30 @@
# Constraint

Constraints are used to enforce specific data schemas within a database.
There are two different types of constraints, one for nodes and one for relationships.
They can be created as following:
Constraints are entities which contain the following attributes:

```php
use Syndesi\CypherDataStructures\Type\NodeConstraint;
use Syndesi\CypherDataStructures\Type\RelationConstraint;

$nodeConstraint = new NodeConstraint();
$relationConstraint = new RelationConstraint();

// note: the later examples use $someConstraint when the specific type does not matter
```

!> **Important**: Constraints are not part of the OpenCypher specification and are different for each database type.

!> **Note**: The creation of constraints might create internal indexes as well.
- **ConstraintName**: Zero or one constraint name, usually one. They are basically strings with validation. They must be
snake_case as per [Neo4j's examples](https://neo4j.com/docs/cypher-manual/current/constraints/examples/).
Constraint names can start with a single underscore, although this is reserved for internal logic.
You can overwrite the validation part by creating your own implementation of
`Syndesi\CypherDataStructures\Contract\ConstraintNameInterface`.
- **ConstraintType**: Defines how the constraint works, must be set manually.
- **For**: Can be either a `NodeLabel` or `RelationType`.
- **Properties**: Properties on which the constraint applies to. At least one is required.
- **Options**: Options which configure constraint dependant settings, usually empty.

## Name

The name of constraints must be unique across the whole database.
The name is usually written in [lowercase snake case](https://neo4j.com/docs/cypher-manual/current/constraints/examples/).
## Examples

```php
// set the name of a constraint:
$someConstraint->setName('some_name');

// get the name of a constraint:
$someConstraint->getName();
```

## For

Constraints are always created for a specific node or relationship label/type.

```php
// set the node label for a node label constraint:
$nodeConstraint->setFor('NodeLabel');

// set the relationship type for a relationship constraint:
$relationConstraint->setFor('RELATIONSHIP_TYPE');

// get the node label or relationship type from a constraint, depending on the constraint type:
$someConstraint->getFor();
```

## Type

Constraints have a specific type, e.g. `UNIQUE`. These types depend on the database as well as the database version.

!> **Important**: Depending on the database, not all constraint types are available for nodes as well as relationships.

```php
// set the type of constraint:
$someConstraint->setType('UNIQUE');

// get the type of constraint:
$someConstraint->getType();
```

## Properties

Constraints can specify the properties of a node/relationship on which they should act.

!> **Note**: Most of the time only the property names are important. Setting the property values to null is therefore
ok.

```php
// add property to a constraint with default value null:
$someConstraint->addProperty('propertyName');

// add multiple properties to a constraint:
$someConstraint->addProperties([
'id' => null,
'hello' => 'world :D'
]);

// check if a constraint has a specific property:
$someConstraint->hasProperty('id');

// get the value of a specific property:
$someConstraint->getProperty('id');

// get all properties from a constraint:
$someConstraint->getProperties();

// remove a specific property from a constraint:
$someConstraint->removeProperty('hello');

// remove all properties from a constraint:
$someConstraint->removeProperties();
```

## Options

Some constraints can be configured via options.
The example uses strings, but all types (arrays, integers etc.) are supported.

```php
// add a single option
$someConstraint->addOption('name', 'value');

// add multiple options
$someConstraint->addOptions([
'other.name' => 'other value',
'some.name' => 'some value'
]);

// check if constraint has option
$someConstraint->hasOption('name');

// get specific option from a constraint
$someConstraint->getOption('name');

// get all options from a constraint
$someConstraint->getOptions();

// remove a specific option from a constraint:
$someConstraint->removeOption('name');

// remove all options from a constraint:
$someConstraint->removeOptions();
use Syndesi\CypherDataStructures\Type\ConstraintName;
use Syndesi\CypherDataStructures\Type\Constraint;
use Syndesi\CypherDataStructures\Type\ConstraintType;
use Syndesi\CypherDataStructures\Type\NodeLabel;
use Syndesi\CypherDataStructures\Type\PropertyName;

$constraint = new Constraint();
$constraint
->setConstraintName(new ConstraintName('some_name'))
->setConstraintType(ConstraintType::UNIQUE)
->setFor(new NodeLabel('SomeNode'))
->addProperty(new PropertyName('id'));
```
12 changes: 12 additions & 0 deletions src/Contract/DateTimeConvertible.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Syndesi\CypherDataStructures\Contract;

use DateTimeInterface;

interface DateTimeConvertible
{
public function toDateTime(): DateTimeInterface;

public static function fromDateTime(DateTimeInterface $dateTime): self;
}
58 changes: 58 additions & 0 deletions src/Contract/OGM/HasPropertiesInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Neo4j PHP Client and Driver package.
*
* (c) Nagels <https://nagels.tech>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Syndesi\CypherDataStructures\Contract\OGM;

use BadMethodCallException;
use Syndesi\CypherDataStructures\Type\OGM\Dictionary;

/**
* Defines how an object with properties should behave.
*
* @psalm-immutable
*
* @template T
*/
interface HasPropertiesInterface
{
/**
* Returns the properties a map.
*
* @return Dictionary<T>
*/
public function getProperties(): Dictionary;

/**
* @param string $name
*
* @return T
*/
public function __get($name);

/**
* Always throws an exception as cypher objects are immutable.
*
* @param string $name
* @param T $value
*
* @throws BadMethodCallException
*/
public function __set($name, $value): void;

/**
* Checks to see if the property exists and is set.
*
* @param string $name
*/
public function __isset($name): bool;
}
50 changes: 50 additions & 0 deletions src/Contract/OGM/PointInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Neo4j PHP Client and Driver package.
*
* (c) Nagels <https://nagels.tech>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Syndesi\CypherDataStructures\Contract\OGM;

/**
* Defines a basic Point type in neo4j.
*
* @psalm-immutable
*
* @psalm-type Crs = 'wgs-84'|'wgs-84-3d'|'cartesian'|'cartesian-3d';
*/
interface PointInterface
{
/**
* Returns the x coordinate.
*/
public function getX(): float;

/**
* Returns the y coordinate.
*/
public function getY(): float;

/**
* Returns the Coordinates Reference System.
*
* @see https://en.wikipedia.org/wiki/Spatial_reference_system
*
* @return Crs
*/
public function getCrs(): string;

/**
* Returns the spacial reference identifier.
*
* @see https://en.wikipedia.org/wiki/Spatial_reference_system
*/
public function getSrid(): int;
}
18 changes: 18 additions & 0 deletions src/Contract/PackstreamConvertible.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Syndesi\CypherDataStructures\Contract;

/**
* A class whose instance can be converted to a data type in packstream.
*
* @see https://neo4j.com/docs/bolt/current/packstream/
*/
interface PackstreamConvertible
{
/**
* Returns the marker that identifies the class to packstream.
*
* @return int
*/
public function getPackstreamMarker(): int;
}
27 changes: 27 additions & 0 deletions src/Exception/PropertyDoesNotExistException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Neo4j PHP Client and Driver package.
*
* (c) Nagels <https://nagels.tech>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Syndesi\CypherDataStructures\Exception;

use RuntimeException;

/**
* Exception when accessing a property which does not exist.
*
* @psalm-immutable
*
* @psalm-suppress MutableDependency
*/
final class PropertyDoesNotExistException extends RuntimeException
{
}
28 changes: 28 additions & 0 deletions src/Exception/RuntimeTypeException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Neo4j PHP Client and Driver package.
*
* (c) Nagels <https://nagels.tech>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Syndesi\CypherDataStructures\Exception;

use RuntimeException;

use function get_debug_type;

final class RuntimeTypeException extends RuntimeException
{
public function __construct(mixed $value, string $type)
{
$actualType = get_debug_type($value);
$message = sprintf('Cannot cast %s to type: %s', $actualType, $type);
parent::__construct($message);
}
}
Loading