Links​

Links define a specific relationship between two object types.

See the Modeling Relations guide for a breakdown of how to model one-to-one, one-to-many, and many-to-many relationships in EdgeDB.

  1. type Person {
  2. link best_friend -> Person;
  3. }

Links are directional; they have a source (the object type on which they are declared) and a target (the type they point to).

All links have a cardinality: either single or multi. The default is single (a “to-one” link). Use the multi keyword to declare a “to-many” link.

  1. type Person {
  2. multi link friends -> Person;
  3. }

All links are either optional or required; the default is optional. Use the required keyword to declare a required link. A required link must point to at least one target instance. In this scenario, every Person must have a best_friend:

  1. type Person {
  2. required link best_friend -> Person;
  3. }

Links with cardinality multi can also be required; required multi links must point to at least one target object.

  1. type Person {
  2. property name -> str;
  3. }
  4. type GroupChat {
  5. required multi link members -> Person;
  6. }

In this scenario, each GroupChat must contain at least one person. Attempting to create a GroupChat with no members would fail.

Exclusive constraints​

You can add an exclusive constraint to a link to guarantee that no other instances can link to the same target(s).

  1. type Person {
  2. property name -> str;
  3. }
  4. type GroupChat {
  5. required multi link members -> Person {
  6. constraint exclusive;
  7. }
  8. }

In the GroupChat example, the GroupChat.members link is now exclusive. No two GroupChats can link to the same Person; put differently, no Person can be a member of multiple GroupChats.

The combination of link cardinality and exclusive constraints are sufficient to model all kinds of relations: one-to-one, one-to-many, and many-to-many. For details, read the Modeling Relations guide.

Default values​

Like properties, links can declare a default value in the form of an EdgeQL expression, which will be executed upon insertion. In the example below, new people are automatically assigned three random friends.

  1. type Person {
  2. required property name -> str;
  3. multi link friends -> Person {
  4. default := (select Person order by random() limit 3);
  5. }
  6. }

In EdgeDB, links can store properties. Like object types, links can contain properties. Link properties can be used to store metadata about links, such as when it was created or the nature/strength of the relationship.

  1. type Person {
  2. property name -> str;
  3. multi link family_members -> Person {
  4. property relationship -> str;
  5. }
  6. }

Above, we model a family tree with a single Person type. The Person. family_members link is a many-to-many relation; each family_members link can contain a string relationship describing the relationship of the two individuals.

Due to how they’re persisted under the hood, link properties must always be single and optional.

For a full guide on modeling, inserting, updating, and querying link properties, see the Using Link Properties guide.

Deletion policies​

Links can declare their own deletion policy. When the target of a link is deleted, there are 4 possible actions that can be taken:

  • restrict (default) - Any attempt to delete the target object immediately raises an exception.

  • delete source - when the target of a link is deleted, the source is also deleted. This is useful for implementing cascading deletes.

    There is a limit to the depth of a deletion cascade due to an upstream stack size limitation.

  • allow - the target object is deleted and is removed from the set of the link targets.

  • deferred restrict - any attempt to delete the target object raises an exception at the end of the transaction, unless by that time this object is no longer in the set of link targets.

To set a policy:

  1. type MessageThread {
  2. property name -> str;
  3. }
  4. type Message {
  5. link chat -> MessageThread {
  6. on target delete delete source;
  7. }
  8. }

Links can have abstract targets, in which case the link is considered polymorphic. Consider the following schema:

  1. abstract type Person {
  2. property name -> str;
  3. }
  4. type Hero extending Person {
  5. # additional fields
  6. }
  7. type Villain extending Person {
  8. # additional fields
  9. }

The abstract type Person has two concrete subtypes: Hero and Villain. Despite being abstract, Person can be used as a link target in concrete object types.

  1. type Movie {
  2. property title -> str;
  3. multi link characters -> Person;
  4. }

In practice, the Movie.characters link can point to a Hero, Villain, or any other non-abstract subtype of Person. For details on how to write queries on such a link, refer to the Polymorphic Queries docs

It’s possible to define abstract links that aren’t tied to a particular source or target. If you’re declaring several links with the same set of properties, annotations, constraints, or indexes, abstract links can be used to eliminate repetitive SDL.

  1. abstract link link_with_strength {
  2. property strength -> float64;
  3. index on (__subject__@strength);
  4. }
  5. type Person {
  6. multi link friends extending link_with_strength -> Person;
  7. }

See also

SDL > Links

DDL > Links

Introspection > Object types