Skip to main content

Relationship

A relationship is used to create hierarchical or graph-like structures from entities. There are two types of relationships that are possible in Fractl - contains and between.

contains

A contains relationship creates a tree-like hierarchy where the root node is made up of a parent entity and the leaves are made of child entities. Child entities are said to be contained within the parent. An example is the relationship between department and employees.

Example

(entity :Acme/Department
{:No {:type :Int :guid true}
:Name {:type :String :unique true}})

(entity :Acme/Employee
{:Id :Identity
:Name {:type :String
:id true}
:FirstName :String
:LastName :String
;; other attributes ...
})

(relationship :Acme/WorksFor
{:meta {:contains [:Acme/Department :Acme/Employee]}})

Once an entity is declared to be contained by another entity, its instances may be created or queried only in the context of the parent instance. In the above example, an :Employee belongs to a :Department and is uniquely identified within the department by its :Name attribute. This means, employees with the same name may belong to different departments. The :id setting of :Name builds a unique path for each :Employee in the format "path://Acme/Department/<dept-no>/WorksFor/Employee/<employee-name>". The :Id attribute is declared as :Identity for the :Employee. It will be an auto-generated UUID that acts as the globally-unique identifier for an employee.

Example

;; Query a department by `:No`
{:Acme/Department {:No? 123} :as [:D]}
;; Create a new employee in the department
{:Acme/Employee
{:Name "emp01"
:FirstName "A"
:LastName "B"}
:-> [[:Acme/WorksFor :D]]})

The :-> tag creates a link between the new employee and the department :D via the :Acme/WorksFor relationship. Now the employee may be referred to only in the context of this relationship.

Example

;; query the employee
{:Acme/Employee {}
:-> [[:Acme/WorksFor? {:Acme/Department {:No? 123}} "emp01"]]})

The above query will succeed only if a :WorksFor relationship exists between the department 123 and the employee with :Name "emp01".

between

A between relationship creates a flat-graph structure with entity instances as nodes. All entities involved in a between relationship has equal status and the relationship-link could be established from either side. A common example of a between relationship is that of friendship between people.

Example

(entity :Social/Person
{:Email {:type :Email :guid true}
:FirstName :String
; ...
})

(relationship :Social/Friendship
{:meta {:between [:Social/Person :Social/Person]}})

The following pattern shows how to create a friendship relationship between two pre-existing persons:

{:Social/Person {:Email? "abc@social.org"} :as [:P1]}
{:Social/Person {:Email? "xyz@social.org"}
:-> [[{:Social/Friendship {}} :P1]]}

Unlike a :contains relationship, a :between relationship is persisted in the store just like an entity instance. This means a :between relationship can have its own attributes and can be created or queried just like entities. The following pattern directly queries an instance of :Friendship based on the two node attributes:

{:Social/Friendship
{:Person1? "xyz@social.org"
:Person2? "abc@social.org"}}

It's possible to customize the names of the node-attributes, as well as to have custom attributes:

(relationship :Social/Friendship
{:meta {:between [:Social/Person :Social/Person :as [:From :To]]}
:FriendsSince :Date})

The preceding declaration renames :Person1 as :From and :Person2 as :To. It also keeps track of the date and time when the friendship was created.

;; Creating a friendship

{:Social/Person {:Email? "abc@social.org"} :as [:P1]}
{:Social/Person {:Email? "xyz@social.org"}
:-> [[{:Social/Friendship {:FriendsSince "2022-12-30"}} :P1]]}

;; or

{:Social/Friendship
{:From "xyz@social.org"
:To "abc@social.org"
:FriendsSince "2022-12-30"}}

;; query by email
{:Social/Friendship
{:From? "abc@social.org"
:To? "xyz@social.org"}}

;; query all friendships for a person, established since a date
{:Social/Friendship
{:From? "abc@social.org"
:FriendsSince? [:>= "2022-01-01"]}}