From 223c070927352455495b3c72ed847d575df11d7a Mon Sep 17 00:00:00 2001
From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com>
Date: Tue, 24 Dec 2024 14:01:44 +0900
Subject: [PATCH 01/15] Start some content on references
---
.../doc-surrealql/datamodel/records.mdx | 2 +-
.../doc-surrealql/datamodel/references.mdx | 117 ++++++++++++++++++
src/content/doc-surrealql/datamodel/sets.mdx | 2 +-
.../doc-surrealql/datamodel/strings.mdx | 2 +-
src/content/doc-surrealql/datamodel/uuid.mdx | 2 +-
.../doc-surrealql/datamodel/values.mdx | 2 +-
.../doc-surrealql/statements/define/field.mdx | 17 +++
7 files changed, 139 insertions(+), 5 deletions(-)
create mode 100644 src/content/doc-surrealql/datamodel/references.mdx
diff --git a/src/content/doc-surrealql/datamodel/records.mdx b/src/content/doc-surrealql/datamodel/records.mdx
index d6bf410ba..50c768550 100644
--- a/src/content/doc-surrealql/datamodel/records.mdx
+++ b/src/content/doc-surrealql/datamodel/records.mdx
@@ -90,7 +90,7 @@ SELECT friends.friends.friends.name FROM person:tobie;
You've now seen how to create records using randomly generated ids, or specific record ids. This is just the beginning! The power and flexibility which is possible with the remote record fetching functionality within queries opens up a whole new set of possibilities for storing and querying traditional data, and connected datasets. Take a look at the next chapter to understand how futures can be used to dynamically compute values only when retrieved.
-Also checkout this explainer video on using record links in SurrealDB:
+Also check out this explainer video on using record links in SurrealDB:
diff --git a/src/content/doc-surrealql/datamodel/references.mdx b/src/content/doc-surrealql/datamodel/references.mdx
new file mode 100644
index 000000000..11b98345d
--- /dev/null
+++ b/src/content/doc-surrealql/datamodel/references.mdx
@@ -0,0 +1,117 @@
+---
+sidebar_position: 17
+sidebar_label: Record references
+title: Record references | SurrealQL
+description: One of the most powerful features of SurrealDB is the ability to traverse from record-to-record without the need for traditional SQL JOINs. Each record ID points directly to a specific record in the database.
+
+---
+
+import Since from '@components/shared/Since.astro'
+
+# Record references
+
+
+
+## Basic concepts
+
+Reference tracking begins by adding a `REFERENCE` clause to any `DEFINE FIELD` statement, as long as the field is a `record` or array of records.
+
+```surql
+DEFINE FIELD comics ON person TYPE option>> REFERENCE;
+```
+
+Any referencing record can then be picked up on the referenced record by creating a field of type `references`.
+
+```surql
+DEFINE FIELD owners ON comic_book TYPE references;
+```
+
+```surql
+CREATE person:one, person:two SET comics = [comic_book:one];
+CREATE comic_book:one SET title = "Loki, God of Stories";
+SELECT * FROM comic_book;
+```
+
+The linking records will now be picked up automatically from the `comic_book` side.
+
+```surql title="Output"
+[
+ {
+ id: comic_book:one,
+ owners: [
+ person:one,
+ person:two
+ ],
+ title: 'Loki, God of Stories'
+ }
+]
+```
+
+## Specifying linking tables
+
+The following is similar to the previous example, except that the `comic_book` is now being linked to from two sources, one of which is a `publisher` which publishes both books and comic books.
+
+```surql
+DEFINE FIELD comics ON person TYPE option>> REFERENCE;
+DEFINE FIELD products ON publisher TYPE option>> REFERENCE;
+DEFINE FIELD owners ON comic_book TYPE references;
+
+CREATE person:one, person:two SET comics = [comic_book:one];
+CREATE publisher:one SET products = [comic_book:one, book:one];
+CREATE comic_book:one SET title = "Loki, God of Stories";
+SELECT * FROM comic_book;
+```
+
+Because the `owners` field on `comic_book` looks for any and all references, it now includes the publisher as an owner, which is not ideal.
+
+```surql title="Output"
+[
+ {
+ id: comic_book:one,
+ owners: [
+ person:one,
+ person:two,
+ publisher:one
+ ],
+ title: 'Loki, God of Stories'
+ }
+]
+```
+
+This can be fixed by changing the single field of type `references` to two fields, one of which is a `references`, and the other a `references`.
+
+```surql
+REMOVE TABLE person;
+REMOVE TABLE comic_book;
+REMOVE TABLE publisher;
+REMOVE TABLE book;
+
+DEFINE FIELD comics ON person TYPE option>> REFERENCE;
+DEFINE FIELD products ON publisher TYPE option>> REFERENCE;
+DEFINE FIELD owners ON comic_book TYPE references;
+DEFINE FIELD publisher ON comic_book TYPE references;
+
+CREATE person:one, person:two SET comics = [comic_book:one];
+CREATE publisher:one SET products = [comic_book:one, book:one];
+CREATE comic_book:one SET title = "Loki, God of Stories";
+SELECT * FROM comic_book;
+```
+
+```surql title="Output"
+[
+ {
+ id: comic_book:one,
+ owners: [
+ person:one,
+ person:two
+ ],
+ publisher: [
+ publisher:one
+ ],
+ title: 'Loki, God of Stories'
+ }
+]
+```
+
+## Specifying linking tables and/or field names
+
diff --git a/src/content/doc-surrealql/datamodel/sets.mdx b/src/content/doc-surrealql/datamodel/sets.mdx
index 03e133f9b..1bbeded86 100644
--- a/src/content/doc-surrealql/datamodel/sets.mdx
+++ b/src/content/doc-surrealql/datamodel/sets.mdx
@@ -1,5 +1,5 @@
---
-sidebar_position: 17
+sidebar_position: 18
sidebar_label: Sets
title: Sets | SurrealQL
description: A set is a collection type of deduplicated values that can have a maximum size limit.
diff --git a/src/content/doc-surrealql/datamodel/strings.mdx b/src/content/doc-surrealql/datamodel/strings.mdx
index 4cef162cf..510aee13e 100644
--- a/src/content/doc-surrealql/datamodel/strings.mdx
+++ b/src/content/doc-surrealql/datamodel/strings.mdx
@@ -1,5 +1,5 @@
---
-sidebar_position: 18
+sidebar_position: 19
sidebar_label: Strings
title: Strings | SurrealQL
description: Strings can be used to store text values. All string values can include Unicode values, emojis, tab characters, and line breaks.
diff --git a/src/content/doc-surrealql/datamodel/uuid.mdx b/src/content/doc-surrealql/datamodel/uuid.mdx
index 92220a07b..f64acd74e 100644
--- a/src/content/doc-surrealql/datamodel/uuid.mdx
+++ b/src/content/doc-surrealql/datamodel/uuid.mdx
@@ -1,5 +1,5 @@
---
-sidebar_position: 19
+sidebar_position: 20
sidebar_label: UUIDs
title: UUIDs | SurrealQL
description: UUID values in SurrealQL represent UUID values
diff --git a/src/content/doc-surrealql/datamodel/values.mdx b/src/content/doc-surrealql/datamodel/values.mdx
index 070c43106..4c8343881 100644
--- a/src/content/doc-surrealql/datamodel/values.mdx
+++ b/src/content/doc-surrealql/datamodel/values.mdx
@@ -1,5 +1,5 @@
---
-sidebar_position: 20
+sidebar_position: 21
sidebar_label: Values
title: Values | SurrealQL
description: Every type in SurrealDB is a value
diff --git a/src/content/doc-surrealql/statements/define/field.mdx b/src/content/doc-surrealql/statements/define/field.mdx
index 06f6d0258..72f643ac0 100644
--- a/src/content/doc-surrealql/statements/define/field.mdx
+++ b/src/content/doc-surrealql/statements/define/field.mdx
@@ -21,6 +21,14 @@ The `DEFINE FIELD` statement allows you to instantiate a named field on a table,
```syntax title="SurrealQL Syntax"
DEFINE FIELD [ OVERWRITE | IF NOT EXISTS ] @name ON [ TABLE ] @table
[ [ FLEXIBLE ] TYPE @type ]
+ [ REFERENCE
+ [ ON DELETE REJECT |
+ ON DELETE CASCADE |
+ ON DELETE IGNORE |
+ ON DELETE REJECT |
+ ON DELETE UNSET |
+ ON DELETE THEN @expression ]
+ ]
[ DEFAULT @expression ]
[ READONLY ]
[ VALUE @expression ]
@@ -507,3 +515,12 @@ DEFINE FIELD filter ON TABLE search_settings TYPE
| { type: "Snowball", language: string }
| { type: "Uppercase" };
```
+
+
+## Defining a reference
+
+
+
+A field that is a record link (type `record`, `option`, `array>`, and so on) can be defined as a `REFERENCE`. If this clause is used, any linked to record will be able to define a field of its own of type `references` which will be aware of the incoming links.
+
+For more information, see [the page in the datamodel section on references](/docs/surrealql/datamodel/references).
\ No newline at end of file
From 8ded302f59340c6d98f50416f3de81d91bd0b46c Mon Sep 17 00:00:00 2001
From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com>
Date: Tue, 24 Dec 2024 16:23:00 +0900
Subject: [PATCH 02/15] Add more content
---
.../doc-surrealql/datamodel/references.mdx | 78 ++++++++++++++++++-
1 file changed, 77 insertions(+), 1 deletion(-)
diff --git a/src/content/doc-surrealql/datamodel/references.mdx b/src/content/doc-surrealql/datamodel/references.mdx
index 11b98345d..c58a66e91 100644
--- a/src/content/doc-surrealql/datamodel/references.mdx
+++ b/src/content/doc-surrealql/datamodel/references.mdx
@@ -113,5 +113,81 @@ SELECT * FROM comic_book;
]
```
-## Specifying linking tables and/or field names
+## Specifying linking tables and field names
+A field of type `references` can be further narrowed down to specify not just the table name, but also the field name of the referring record.
+
+In the comic book example, this can be used to keep track of which people own comic books (via a `comics` field on the `person` table), versus those who borrow those (via a separate `borrowed_comics`) field. Any `comic_book` can keep track of these separately by defining one field with the type `references`, and another field with the type `references`.
+
+```surql
+DEFINE FIELD comics ON person TYPE option>> REFERENCE;
+DEFINE FIELD borrowed_comics ON person TYPE option>> REFERENCE;
+DEFINE FIELD owned_by ON comic_book TYPE references;
+DEFINE FIELD borrowed_by ON comic_book TYPE references;
+
+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";
+SELECT * FROM comic_book;
+```
+
+```surql title="Output"
+[
+ {
+ borrowed_by: [
+ person:two
+ ],
+ id: comic_book:one,
+ owned_by: [
+ person:one
+ ],
+ title: 'Loki, God of Stories'
+ }
+]
+```
+
+## 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.
+
+```surql
+DEFINE FIELD comics ON person TYPE option>> REFERENCE;
+DEFINE FIELD owned_by ON comic_book TYPE references;
+
+CREATE comic_book:one SET title = "Loki, God of Stories";
+CREATE person:one SET comics = [comic_book:one];
+DELETE comic_book:one;
+SELECT * FROM person;
+```
+
+```surql title="Output"
+[
+ {
+ comics: [
+ comic_book:one
+ ],
+ id: person:one
+ }
+]
+```
+
+A query using `INFO FOR TABLE person` shows that the actual statement created using `REFERENCE` does not finish at this point, but includes the clause `ON DELETE IGNORE`.
+
+```surql
+{
+ events: {},
+ fields: {
+ comics: 'DEFINE FIELD comics ON person TYPE option>> REFERENCE ON DELETE IGNORE PERMISSIONS FULL',
+ "comics[*]": 'DEFINE FIELD comics[*] ON person TYPE record REFERENCE ON DELETE IGNORE PERMISSIONS FULL'
+ },
+ indexes: {},
+ lives: {},
+ tables: {}
+}
+```
+
+This `ON DELETE` clause can be modified to have some other behaviour besides ignoring when a reference is deleted.
+
+### ON DELETE REJECT
+
+`ON DELETE REJECT` will outright make it impossible to delete a record that is referenced from somewhere else.
\ No newline at end of file
From 5cde628e62ae6439fd43e6a0b9b23ba78b8a35c4 Mon Sep 17 00:00:00 2001
From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com>
Date: Mon, 30 Dec 2024 10:49:43 +0900
Subject: [PATCH 03/15] record::refs() examples
---
.../functions/database/record.mdx | 103 +++++++++++++++++-
1 file changed, 102 insertions(+), 1 deletion(-)
diff --git a/src/content/doc-surrealql/functions/database/record.mdx b/src/content/doc-surrealql/functions/database/record.mdx
index 469156c87..12810530b 100644
--- a/src/content/doc-surrealql/functions/database/record.mdx
+++ b/src/content/doc-surrealql/functions/database/record.mdx
@@ -34,6 +34,10 @@ These functions can be used to retrieve specific metadata from a SurrealDB Recor
Extracts and returns the table name from a SurrealDB Record ID
+
@@ -83,7 +87,104 @@ RETURN record::id(person:tobie);
"tobie"
```
-
+## `record::refs`
+
+
+
+The `record::refs` function returns the record IDs of any records that have a [record link](/docs/surrealql/datamodel/records) along with a `REFERENCES` clause.
+
+```surql title="API DEFINITION"
+record::refs(record) -> array
+record::refs(record, $table_name: string) -> array
+record::refs(record, $table_name: string, $field_name: string) -> array
+```
+
+This function can be used on its own to return all references to a single record.
+
+```surql
+DEFINE FIELD best_friend ON person TYPE option> REFERENCE;
+
+-- Both Billy and Bobby think Gaston is their best friend
+CREATE person:billy, person:bobby SET best_friend = person:gaston;
+-- But not Gaston
+CREATE person:gaston SET best_friend = NONE;
+
+person:gaston.refs();
+```
+
+```surql title="Output"
+[
+ person:billy,
+ person:bobby
+]
+```
+
+It can be followed by a single string to filter references to only include those from a certain table.
+
+```surql
+DEFINE FIELD located_in ON city TYPE option> REFERENCE;
+DEFINE FIELD located_in ON state TYPE option> REFERENCE;
+
+CREATE country:germany;
+CREATE state:bavaria, city:munich SET located_in = country:germany;
+
+country:germany.refs('city');
+country:germany.refs('state');
+```
+
+```surql title="Output"
+-------- Query --------
+
+[
+ city:munich
+]
+
+-------- Query --------
+
+[
+ state:bavaria
+]
+```
+
+If followed by a second string, it will filter references by table name as well as field name.
+
+```surql
+DEFINE FIELD owner ON dog TYPE option> REFERENCE;
+DEFINE FIELD acquaintances ON dog TYPE option>> REFERENCE;
+DEFINE FIELD roommates ON cat TYPE option> REFERENCE;
+DEFINE FIELD acquaintances ON cat TYPE option>> REFERENCE;
+
+CREATE person:one, person:two, person:three;
+CREATE dog:mr_bark SET owner = person:one, acquaintances = [person:two, person:three];
+CREATE cat:mr_meow SET roommates = [person:one], acquaintances = [person:two, person:three];
+
+-- All the dogs that consider person:one the owner
+person:one.refs('dog', 'owner');
+-- All the cats that consider person:one the roommate
+person:one.refs('cat', 'roommate');
+-- All the dogs acquainted with person:two
+person:two.refs('dog', 'acquaintances');
+```
+
+```surql title="Output"
+-------- Query --------
+
+[
+ dog:mr_bark
+]
+
+-------- Query --------
+
+[
+ cat:mr_meow
+]
+
+-------- Query --------
+
+[
+ dog:mr_bark
+]
+```
## `record::tb`
From 3f09115500887eac84e14d0d4c86feb677c03f2a Mon Sep 17 00:00:00 2001
From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com>
Date: Mon, 30 Dec 2024 12:38:16 +0900
Subject: [PATCH 04/15] Add .refs(), more ON DELETE examples
---
.../doc-surrealql/datamodel/references.mdx | 212 +++++++++++++++++-
1 file changed, 206 insertions(+), 6 deletions(-)
diff --git a/src/content/doc-surrealql/datamodel/references.mdx b/src/content/doc-surrealql/datamodel/references.mdx
index c58a66e91..03a0d46f3 100644
--- a/src/content/doc-surrealql/datamodel/references.mdx
+++ b/src/content/doc-surrealql/datamodel/references.mdx
@@ -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`, and the other a `references`.
```surql
-REMOVE TABLE person;
-REMOVE TABLE comic_book;
-REMOVE TABLE publisher;
-REMOVE TABLE book;
-
DEFINE FIELD comics ON person TYPE option>> REFERENCE;
DEFINE FIELD products ON publisher TYPE option>> REFERENCE;
DEFINE FIELD owners ON comic_book TYPE references;
@@ -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>> REFERENCE;
+DEFINE FIELD borrowed_comics ON person TYPE option>> 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.
@@ -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>> REFERENCE;
+DEFINE FIELD friends ON person TYPE option>> REFERENCE ON DELETE IGNORE;
+DEFINE FIELD friended_by ON person TYPE references;
+
+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>> 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 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.
\ No newline at end of file
+`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>> REFERENCE ON DELETE REJECT;
+DEFINE FIELD using ON house TYPE references;
+
+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;
+```
+
From d24e178cba531bb3fb102d32118b1f1e2efaaca3 Mon Sep 17 00:00:00 2001
From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com>
Date: Mon, 30 Dec 2024 14:04:51 +0900
Subject: [PATCH 05/15] Record links now have some advantages that only graphs
had previously
---
src/content/doc-surrealql/statements/relate.mdx | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/content/doc-surrealql/statements/relate.mdx b/src/content/doc-surrealql/statements/relate.mdx
index 43263ac4b..0184ed9c5 100644
--- a/src/content/doc-surrealql/statements/relate.mdx
+++ b/src/content/doc-surrealql/statements/relate.mdx
@@ -19,10 +19,11 @@ Otherwise, edge tables behave like normal tables in terms of [updating](/docs/su
Another option for connecting data is using [record links](/docs/surrealql/datamodel/records). Record links consist of a field with record IDs that serve as uni-directional links. The key differences are that graph relations have the following benefits over record links:
-- They are kept in a separate table as opposed to a field inside a record.
-- Offer bi-directional querying.
-- Offer referential integrity.
-- Allow you to store data alongside the relationship.
+- Graph relations are kept in a separate table as opposed to a field inside a record.
+- Graph relations you to store data alongside the relationship.
+- Graph relations have their own syntax that makes it easy to build and visualize edge queries.
+
+Graph relations also offer built-in bi-directional querying and referential integrity. As of SurrealDB 2.2.0, record links also offer these two advantages if they are defined inside a [`DEFINE FIELD`](/docs/surrealql/statements/define/field) statement using the `REFERENCES` clause. For more information, see [the page on record references](/docs/surrealql/datamodel/references).
### Statement syntax
From 53f47276c78764fc6765032902eb396eeea1a2be Mon Sep 17 00:00:00 2001
From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com>
Date: Tue, 31 Dec 2024 11:04:16 +0900
Subject: [PATCH 06/15] Add ON DELETE THEN
---
.../doc-surrealql/datamodel/references.mdx | 49 +++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/src/content/doc-surrealql/datamodel/references.mdx b/src/content/doc-surrealql/datamodel/references.mdx
index 03a0d46f3..408ccff79 100644
--- a/src/content/doc-surrealql/datamodel/references.mdx
+++ b/src/content/doc-surrealql/datamodel/references.mdx
@@ -385,9 +385,58 @@ DELETE house:one;
'Cannot delete `house:one` as it is referenced by `utility:gas` with an ON DELETE REJECT clause'
```
+```surql
UPDATE utility:gas SET connected_to -= house:one;
UPDATE utility:water SET connected_to -= house:one;
DELETE house:one;
```
+### ON DELETE THEN
+
+The `ON DELETE THEN` clause allows custom logic to take place when a reference is deleted. This clause includes a parameters called `$this` to refer to the record in question, and `$reference` for the reference.
+
+In the following example, a `person` record's `comments` field will remove any comments when they are deleted, but also add the same comment to a different field called `deleted_comments`.
+
+```surql
+DEFINE FIELD comments ON person TYPE option>> REFERENCE ON DELETE THEN {
+ UPDATE $this SET
+ deleted_comments += $reference,
+ comments -= $reference;
+};
+DEFINE FIELD author ON comment TYPE references;
+
+CREATE person:one SET comments += (CREATE ONLY comment SET text = "Estonia is bigger than I expected!").id;
+LET $comment = CREATE ONLY comment SET text = "I don't get the joke here?";
+UPDATE person:one SET comments += $comment.id;
+DELETE $comment;
+SELECT * FROM person:one;
+```
+
+```surql title="person:one before and after comment is deleted"
+-------- Query --------
+
+[
+ {
+ comments: [
+ comment:lbeyh2icushpwo0ak5ux,
+ comment:90tdnyoa14cge2ocmep7
+ ],
+ id: person:one
+ }
+]
+
+-------- Query --------
+
+[
+ {
+ comments: [
+ comment:lbeyh2icushpwo0ak5ux
+ ],
+ deleted_comments: [
+ comment:90tdnyoa14cge2ocmep7
+ ],
+ id: person:one
+ }
+]
+```
\ No newline at end of file
From cacee66ad6d529150882527fe89c9f4070fb67d9 Mon Sep 17 00:00:00 2001
From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com>
Date: Tue, 31 Dec 2024 13:55:55 +0900
Subject: [PATCH 07/15] Start rewrite of graph relations page
---
.../reference-guide/graph_relations.mdx | 53 +++++++++++++++++--
1 file changed, 48 insertions(+), 5 deletions(-)
diff --git a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx
index 7addb6dd0..781e7bfea 100644
--- a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx
+++ b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx
@@ -15,7 +15,7 @@ The first item to take into account when using graph relations is whether they a
SurrealDB has two main ways to create relations between one record and another: record links, and graph relations.
-A record link is a simple pointer from one record to another, a link that exists any time a record holds the record ID of another record. Record links are the most efficient method because record IDs are direct pointers to the data of a record, and do not require a table scan.
+A record link is a simple pointer from one record to another, a link that exists any time a record holds the record ID of another record. Record links are extremely efficient because record IDs are direct pointers to the data of a record, and do not require a table scan.
Take the following example that creates one `user` who has written two `comment`s.
@@ -32,7 +32,7 @@ UPDATE $new_user SET comments += (CREATE ONLY comment SET
.id;
```
-Querying a record link is easy as the link is unidirectional with nothing in between. In this case, the linked comments are simply a field on a `user` record and accessing them is as simple as any other field on a `user` record.
+Querying a record link is easy as the link by default is unidirectional with nothing in between. In this case, the linked comments are simply a field on a `user` record and accessing them is as simple as any other field on a `user` record.
```surql
SELECT
@@ -59,7 +59,7 @@ FROM user;
]
```
-The unidirectionality of a record link is also a limitation, because the only way to query in the other direction is by using a subquery. With some knowledge of SurrealQL this is certainly doable, but a case like this is an indication that a graph link may be the better solution.
+Until SurrealDB version 2.2.0, record links were strictly unidirectional. The only way to query in the other direction was by using a subquery, which made graph edges the only option for bidirectional links.
```surql
SELECT
@@ -97,7 +97,49 @@ FROM comment;
]
```
-The other limitation is that there is no metadata about the context in which the comment was created. Take the following metadata for instance which contains information about a user's current location, operating system, and mood. Where does this data belong?
+Since version 2.2.0, a record link can be bidirectional by [defining a field](/docs/surrealql/statements/define/field) with the `REFERENCE` clause, allowing referenced records to define a field or use the `.refs()` method to track incoming references.
+
+```surql
+DEFINE FIELD comments ON user TYPE option>> REFERENCE;
+DEFINE FIELD author ON comment TYPE references;
+
+LET $new_user = CREATE ONLY user SET name = "User McUserson";
+-- Create a new comment, use the output to update the user
+UPDATE $new_user SET comments += (CREATE ONLY comment:one SET
+ text = "I learned something new!",
+ created_at = time::now())
+ .id;
+UPDATE $new_user SET comments += (CREATE ONLY comment:two SET
+ text = "I don't get it, can you explain?",
+ created_at = time::now())
+ .id;
+
+-- 'author' field is populated with the 'user' who wrote the comment
+SELECT * FROM ONLY comment:one;
+-- Or use .refs() to grab the references
+comment:one.refs();
+```
+
+```surql title="Output"
+-------- Query --------
+
+{
+ author: [
+ user:ie8yc8woe0rwo5cgln57
+ ],
+ created_at: d'2024-12-31T04:51:47.504Z',
+ id: comment:one,
+ text: 'I learned something new!'
+}
+
+-------- Query --------
+
+[
+ user:ie8yc8woe0rwo5cgln57
+]
+```
+
+The main limitation is that there is no metadata about the context in which the comment was created. Take the following metadata for instance which contains information about a user's current location, operating system, and mood. Where does this data belong?
```surql
{
@@ -247,7 +289,8 @@ RELATE person:two->friends_with->person:one;
-------- Query --------
-"Database index `only_one_friendship` already contains '[person:one, person:two]', with record `friends_with:dblidwpc44qqz5bvioiu`"
+"Database index `only_one_friendship` already contains '[person:one, person:two]',
+with record `friends_with:dblidwpc44qqz5bvioiu`"
```
### Querying a graph relation between equals
From b754af7816f91f556691cc6b40843c638c05078e Mon Sep 17 00:00:00 2001
From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com>
Date: Thu, 2 Jan 2025 10:45:33 +0900
Subject: [PATCH 08/15] Some more content
---
.../reference-guide/graph_relations.mdx | 42 +++++++++++++++++--
1 file changed, 38 insertions(+), 4 deletions(-)
diff --git a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx
index 781e7bfea..389365ccf 100644
--- a/src/content/doc-surrealdb/reference-guide/graph_relations.mdx
+++ b/src/content/doc-surrealdb/reference-guide/graph_relations.mdx
@@ -59,7 +59,7 @@ FROM user;
]
```
-Until SurrealDB version 2.2.0, record links were strictly unidirectional. The only way to query in the other direction was by using a subquery, which made graph edges the only option for bidirectional links.
+Until SurrealDB version 2.2.0, record links were strictly unidirectional. The only way to query in the other direction was by using a subquery, which made graph edges the only easy option for bidirectional links.
```surql
SELECT
@@ -68,6 +68,13 @@ SELECT
-- for the id of the current comment
(SELECT id, name FROM user WHERE $parent.id IN comments) AS author
FROM comment;
+
+-- Equivalent graph query is much easier
+-- to read and write
+SELECT
+ *,
+ <-wrote<-author
+FROM comment;
```
```surql
@@ -139,7 +146,19 @@ comment:one.refs();
]
```
-The main limitation is that there is no metadata about the context in which the comment was created. Take the following metadata for instance which contains information about a user's current location, operating system, and mood. Where does this data belong?
+If your use case involves bidirectional links, consider the following items to make a decision.
+
+Record links are preferred if:
+
+* Performance is of the utmost importance.
+
+Graph links are preferred if:
+
+* You want to create links without touching the database schema.
+* You want to put together complex queries that take advantage of SurrealQL's expressive arrow syntax, like `->wrote->comment<-wrote<-person->wrote->comment FROM person`.
+* You want to
+
+Finally, graph links arle not just preferred but almost certainly necessary if you need to keep metadata about the context in which a link is created. Take the following metadata for the examples above involving a user and its comments which contains information about a user's current location, operating system, and mood. Where does this data belong?
```surql
{
@@ -149,7 +168,18 @@ The main limitation is that there is no metadata about the context in which the
}
```
-This metadata isn't information about the user as a whole, nor the comment itself. It's information about the moment in time in which the `user` and `comment` were linked, and thus is best stored in a separate table. If this sort of metadata is necessary, then a graph table is the ideal solution.
+This metadata isn't information about the user as a whole, nor the comment itself. It's information about the moment in time in which the `user` and `comment` were linked, and thus is best stored in a separate table.
+
+Or you might have some information about the link itself, which would also belong nowhere else but inside a graph table.
+
+```surql
+{
+ friends_since: d'2024-12-31T06:43:21.981Z',
+ friendship_strength: 0.4
+}
+```
+
+If this sort of metadata is necessary, then a graph table is the ideal solution.
## Creating a graph relation
@@ -599,4 +629,8 @@ While developed for graph relations in particular, this path can be used in any
For more details on SurrealDB's recursive syntax, see the following pages:
* [Idioms: recursive paths](/docs/surrealql/datamodel/idioms#recursive-paths)
-* [Chapter 8 of Aeon's Surreal Renaissance](/learn/book/chapter-08#longer-relational-queries)
\ No newline at end of file
+* [Chapter 8 of Aeon's Surreal Renaissance](/learn/book/chapter-08#longer-relational-queries)
+
+### When links are deleted
+
+Mention how graph tables are deleted if the records involved are deleted, while record links have the fancy clauses
\ No newline at end of file
From 9ac2585c5afbe5cbc05e4aaf9c2c0f810ef0a6a7 Mon Sep 17 00:00:00 2001
From: Dave MacLeod <56599343+Dhghomon@users.noreply.github.com>
Date: Thu, 2 Jan 2025 12:14:42 +0900
Subject: [PATCH 09/15] Last changes to references.mdx page
---
.../doc-surrealql/datamodel/references.mdx | 20 +++++++++----------
.../doc-surrealql/statements/define/field.mdx | 6 +++++-
2 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/src/content/doc-surrealql/datamodel/references.mdx b/src/content/doc-surrealql/datamodel/references.mdx
index 408ccff79..a5893440f 100644
--- a/src/content/doc-surrealql/datamodel/references.mdx
+++ b/src/content/doc-surrealql/datamodel/references.mdx
@@ -32,7 +32,7 @@ CREATE comic_book:one SET title = "Loki, God of Stories";
SELECT * FROM comic_book;
```
-The linking records will now be picked up automatically from the `comic_book` side.
+In the example above, the referencing records will now be picked up automatically from the `comic_book` side.
```surql title="Output"
[
@@ -62,7 +62,7 @@ CREATE comic_book:one SET title = "Loki, God of Stories";
SELECT * FROM comic_book;
```
-Because the `owners` field on `comic_book` looks for any and all references, it now includes the publisher as an owner, which is not ideal.
+As the `owners` field on `comic_book` only includes a general `references` clause, it will show any and all references to a `comic_book` record. It will thus show the publisher as one of the `owners`, which is not ideal.
```surql title="Output"
[
@@ -110,7 +110,7 @@ SELECT * FROM comic_book;
## Specifying linking tables and field names
-A field of type `references` can be further narrowed down to specify not just the table name, but also the field name of the referring record.
+A field of type `references` can be further narrowed down to specify not just the table name, but also the field name of the referencing record.
In the comic book example, this can be used to keep track of which people own comic books (via a `comics` field on the `person` table), versus those who borrow those (via a separate `borrowed_comics`) field. Any `comic_book` can keep track of these separately by defining one field with the type `references`, and another field with the type `references`.
@@ -143,7 +143,7 @@ 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.
+To dynamically find references to a record instead of using a `DEFINE FIELD` statement, the `.refs()` method can be used. 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. However, a `DEFINE FIELD` which includes a `REFERENCE` clause is still necessary in order to set up the reference tracking in the first place.
```surql
DEFINE FIELD comics ON person TYPE option>> REFERENCE;
@@ -185,7 +185,7 @@ comic_book:one.refs('person', 'comics');
## 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.
+When working with record links, it is very likely that you will want some behaviour to happen when a referencing link is deleted. Take the following example of a `person` who owns a `comic_book`, which is later deleted. Despite the deletion, a follow-up `SELECT * FROM person` still shows the comic book.
```surql
DEFINE FIELD comics ON person TYPE option>> REFERENCE;
@@ -208,7 +208,7 @@ SELECT * FROM person;
]
```
-A query using `INFO FOR TABLE person` shows that the actual statement created using `REFERENCE` does not finish at this point, but includes the clause `ON DELETE IGNORE`.
+A query using `INFO FOR TABLE person` shows that the actual statement created using `REFERENCE` does not finish at this point, but includes the clause `ON DELETE IGNORE`. This is the default behaviour for references.
```surql
{
@@ -223,11 +223,11 @@ 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.
+This `ON DELETE` clause can be modified to have some other behaviour when a reference is deleted.
### ON DELETE IGNORE
-As shown in the previous section, this is the default behaviour for references.
+As shown in the previous section, `ON DELETE IGNORE` is the default behaviour for references and this clause will be added automatically if not specified. It can be added manually to a statement to hint to others reading the code that this behaviour is desired.
```surql
-- Default, behaviour, so identical to:
@@ -309,8 +309,6 @@ person:one.comments.*.*;
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 REFERENCE ON DELETE CASCADE;
DEFINE FIELD comments ON person TYPE references;
@@ -394,7 +392,7 @@ DELETE house:one;
### ON DELETE THEN
-The `ON DELETE THEN` clause allows custom logic to take place when a reference is deleted. This clause includes a parameters called `$this` to refer to the record in question, and `$reference` for the reference.
+The `ON DELETE THEN` clause allows for custom logic when a reference is deleted. This clause includes a parameters called `$this` to refer to the record in question, and `$reference` for the reference.
In the following example, a `person` record's `comments` field will remove any comments when they are deleted, but also add the same comment to a different field called `deleted_comments`.
diff --git a/src/content/doc-surrealql/statements/define/field.mdx b/src/content/doc-surrealql/statements/define/field.mdx
index 72f643ac0..e576362cb 100644
--- a/src/content/doc-surrealql/statements/define/field.mdx
+++ b/src/content/doc-surrealql/statements/define/field.mdx
@@ -78,7 +78,7 @@ DEFINE FIELD user_id ON TABLE user TYPE uuid|int;
### Array type
-You can also set a field to have the array data type. The array data type can be used to store a list of values. You can also set the data type of the array's contents.
+You can also set a field to have the array data type. The array data type can be used to store a list of values. You can also set the data type of the array's contents, as well as the maximum number of items that it can hold.
```surql
-- Set a field to have the array data type
@@ -89,6 +89,10 @@ DEFINE FIELD posts ON TABLE user TYPE array;
-- Set a field to have the array object data type
DEFINE FIELD emails ON TABLE user TYPE array