Skip to content

Commit

Permalink
Add .refs(), more ON DELETE examples
Browse files Browse the repository at this point in the history
  • Loading branch information
Dhghomon committed Dec 30, 2024
1 parent 5cde628 commit 3f09115
Showing 1 changed file with 206 additions and 6 deletions.
212 changes: 206 additions & 6 deletions src/content/doc-surrealql/datamodel/references.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,6 @@ Because the `owners` field on `comic_book` looks for any and all references, it
This can be fixed by changing the single field of type `references` to two fields, one of which is a `references<person>`, and the other a `references<publisher>`.

```surql
REMOVE TABLE person;
REMOVE TABLE comic_book;
REMOVE TABLE publisher;
REMOVE TABLE book;
DEFINE FIELD comics ON person TYPE option<array<record<comic_book>>> REFERENCE;
DEFINE FIELD products ON publisher TYPE option<array<record<comic_book|book>>> REFERENCE;
DEFINE FIELD owners ON comic_book TYPE references<person>;
Expand Down Expand Up @@ -146,6 +141,48 @@ SELECT * FROM comic_book;
]
```

## Using the `.refs()` method

The `.refs()` method can be called on a record to find references to it in the same way that a field can be defined as a `references`. Similar to defining a field of type `references`, this function can also narrow down the references to a record by only returning references from a certain table, or a certain table and field name.

```surql
DEFINE FIELD comics ON person TYPE option<array<record<comic_book>>> REFERENCE;
DEFINE FIELD borrowed_comics ON person TYPE option<array<record<comic_book>>> REFERENCE;
CREATE person:one SET comics = [comic_book:one];
CREATE person:two SET borrowed_comics = [comic_book:one];
CREATE comic_book:one SET title = "Loki, God of Stories";
-- All references
comic_book:one.refs();
-- All references from 'person' records
comic_book:one.refs('person');
-- All references from 'person' records via a field 'comics'
comic_book:one.refs('person', 'comics');
```

```surql title="Output"
-------- Query --------
[
person:two,
person:one
]
-------- Query --------
[
person:two,
person:one
]
-------- Query --------
[
person:one
]
```

## Specifying deletion behaviour

When keeping track of references, it is very likely that you will want some behaviour to happen when a reference is deleted. Take the following example of a `person` who owns a `comic_book`, which is later deleted. However, a follow-up `SELECT * FROM person` still shows the comic book.
Expand Down Expand Up @@ -188,6 +225,169 @@ A query using `INFO FOR TABLE person` shows that the actual statement created us

This `ON DELETE` clause can be modified to have some other behaviour besides ignoring when a reference is deleted.

### ON DELETE IGNORE

As shown in the previous section, this is the default behaviour for references.

```surql
-- Default, behaviour, so identical to:
-- DEFINE FIELD friends ON person TYPE option<array<record<person>>> REFERENCE;
DEFINE FIELD friends ON person TYPE option<array<record<person>>> REFERENCE ON DELETE IGNORE;
DEFINE FIELD friended_by ON person TYPE references<person, friends>;
CREATE person:one SET friends = [person:two];
CREATE person:two;
DELETE person:one;
person:two.*;
```

As the deletion of `person:one` is ignored when calculating the `friended_by` field, it will still show `person:one` even though the record itself has been deleted.

```surql
{
friended_by: [
person:one
],
id: person:two
}
```

### ON DELETE UNSET

`ON DELETE UNSET` will unset (remove) any linked records that are deleted. This can be thought of as the opposite of `ON DELETE IGNORE`.

```surql
DEFINE FIELD comments ON person TYPE option<array<record<comment>>> REFERENCE ON DELETE UNSET;
DEFINE FIELD author ON comment TYPE references;
CREATE person:one;
UPDATE person:one SET comments += (CREATE ONLY comment SET text = "Estonia is bigger than I expected!").id;
-- Give this one a parameter name so it can be deleted later
LET $comment = CREATE ONLY comment SET text = "I don't get the joke here?";
UPDATE person:one SET comments += $comment.id;
-- Now delete it
DELETE $comment;
-- Only one comment shows up for person:one now
person:one.comments.*.*;
```

```surql title="Output of person:one queries"
-------- Query --------
[
{
author: [
person:one
],
id: comment:idxhzumaggzb7g3ym6bl,
text: 'Estonia is bigger than I expected!'
},
{
author: [
person:one
],
id: comment:58uasmx4s0vdjjehfyjz,
text: "I don't get the joke here?"
}
]
-------- Query --------
[
{
author: [
person:one
],
id: comment:uma97u2j2q4tlamzc9yv,
text: 'Estonia is bigger than I expected!'
}
]
```

### ON DELETE CASCADE

The `ON DELETE CASCADE` will cause a record to be deleted if any record it references is deleted. This is useful for records that should not exist if a record that links to them no longer exists.

```surql
REMOVE DATABASE db;
DEFINE FIELD author ON comment TYPE record<person> REFERENCE ON DELETE CASCADE;
DEFINE FIELD comments ON person TYPE references;
CREATE person:one;
CREATE comment SET author = person:one, text = "5/10 for this blog post. The problems I have with it are...";
CREATE comment SET author = person:one, text = "WOW! I never knew you could cut a rope with an arrow.";
-- Show all the details of comments for 'person:one'
person:one.comments.*.*;
DELETE person:one;
-- Comments no longer exist
SELECT * FROM comment;
```

```surql title="Output"
-------- Query --------
[
{
author: person:one,
id: comment:8msvp0egg8cdlyu4vvn9,
text: 'WOW! I never knew you could cut a rope with an arrow.'
},
{
author: person:one,
id: comment:i72qfjy59vbn81hk6lrm,
text: '5/10 for this blog post. The problems I have with it are...'
}
]
-------- Query --------
[]
-------- Query --------
[]
```

### ON DELETE REJECT

`ON DELETE REJECT` will outright make it impossible to delete a record that is referenced from somewhere else.
`ON DELETE REJECT` will outright make it impossible to delete a record that is referenced from somewhere else. For example, consider the case in which a house should not be demolished (deleted) until it has been disconnected from utilities such as gas, water, electricity, and so on. This can be simulated in a schema by adding a `REFERENCE ON DELETE REJECT` to the `utility` table, making it impossible for any `house` to be deleted if they link to it.

```surql
DEFINE FIELD connected_to ON utility TYPE option<array<record<house>>> REFERENCE ON DELETE REJECT;
DEFINE FIELD using ON house TYPE references<utility>;
CREATE house:one;
CREATE utility:gas, utility:water SET connected_to = [house:one];
```

At this point, the `using` field on `house:one` automatically picks up the two references,

```surql
house:one.*;
DELETE house:one;
```

```surql title="Output"
-------- Query --------
{
id: house:one,
using: [
utility:gas,
utility:water
]
}
-------- Query --------
'Cannot delete `house:one` as it is referenced by `utility:gas` with an ON DELETE REJECT clause'
```

UPDATE utility:gas SET connected_to -= house:one;
UPDATE utility:water SET connected_to -= house:one;

DELETE house:one;
```

0 comments on commit 3f09115

Please sign in to comment.