• Start

Languages

/

PHP

/

Libraries

/

Surqlize (ORM)

Edges and graph

Model SurrealDB graph relations in Surqlize with edge models, traverse them in a SELECT, and create them with RELATE.

SurrealDB relation tables are represented by edge models. An edge model maps to a relation table and declares the models on each end, so traversals and RELATE statements are checked against your types.

An edge model extends Surqlize\Edge\Edge and uses the #[Edge] attribute with the relation table name and the in and out endpoint models.

use Surqlize\Attributes\Edge;
use Surqlize\Attributes\Schema;
use Surqlize\Edge\Edge as EdgeModel;

#[Edge('has_address', in: User::class, out: Address::class)]
#[Schema(HasAddressSchema::class)]
final class HasAddress extends EdgeModel
{
}

Edge models inherit RecordId $in and RecordId $out endpoint properties from Surqlize\Edge\Edge.

Use graph fields inside a model SELECT to traverse relations. Edge::out() and Edge::in() start a traversal in the given direction; chain another out() or in() to reach the far table, optionally with a predicate, then name it with as() and resolve it with fetch().

use App\Models\Address;
use App\Models\HasAddress;
use App\Models\User;
use Surqlize\Edge\Edge;

$query = User::select([
'name',
Edge::out(HasAddress::class)
->out(Address::class, fn ($address) => $address->postcode->includes('24'))
->as('address')
->fetch(),
])
->where(fn ($user) => $user->name->eq('beau'))
->fetch('address');

$query->compile();
// SELECT name, ->has_address->address[WHERE postcode INCLUDES '24'] AS address
// FROM user WHERE name = "beau" FETCH address

Edge::out() is a magic static call. If your static analysis setup struggles with it, use the explicit factory.

use Surqlize\Edge\GraphSelectField;
use Surqlize\Query\Ast\GraphDirection;

GraphSelectField::fromEdge(HasAddress::class, GraphDirection::Out)
->out(Address::class)
->as('address');

An edge instance can query its endpoint tables with in() and out(), which return model queries.

$edge = new HasAddress();

$users = $edge->in()
->select(fn ($user) => [$user->name])
->where(fn ($user) => $user->age->gt(27))
->collectModels();

$addresses = $edge->out()
->select(fn ($address) => [$address->postcode])
->collectModels();

Model::relate($from) starts a RELATE. Chain edge() with the edge class, with() for the target, and content() for data on the edge.

use Surqlize\Relate\Time;

User::relate($user)
->edge(HasAddress::class)
->with($address)
->content(['primary' => true])
->timeout(30, Time::Seconds)
->execute();

Both endpoint models must already have RecordId values. The builder validates that the source matches the edge's in endpoint and the target matches the out endpoint. Use set($key, $value) for a single field, and compile() or toSdkQuery() to inspect the statement instead of running it.

  • Models for the #[Edge] attribute

  • Schema to define the relation table

  • RELATE for the SurrealQL statement

Was this page helpful?