Question

In the Datomic Schema doco - they mention a schema attribute called db/isComponent. This appears to refer to relationships defined by :db.type/ref.

The db/isComponent isn't used in the Seattle example. Is it fair to say that :db.type/ref relationships in Datomic are not 'enforced' (to use relational database foreign key dependency concepts) - unless you set them with db/isComponent?

Was it helpful?

Solution

Containment Relationships (:db.type/ref + :db/isComponent)

:db/isComponent is used to specify containment relationships i.e. the composition relation from UML. You can think of it as a "A has B" kind of relation. Modeling part of a simple blog is a clear example:

Article-Comments

In Datomic, if you use the :db/isComponent attribute as part of Article-Comments relationship above, retracting an article will retract all its comments too. For a full code sample, look at the Datomic: containment relationships i.e. db/isComponent gist.

Note there's nothing in Datomic that prevents you from adding the wrong kind of entity to a :db.type/ref attribute. In the sample above, Datomic would let you add a reference to an "Author" entity (instead of a Comment) without really caring. That's where foreign key constraints come into play.

Foreign key constraints (:db.type/ref + database functions)

Datomic defines relationships using the :db.type/ref attribute but doesn't really enforce anything about them. To use arbitrary foreign key constraints, you need to use database functions instead.

In the Seattle database you mention, :community/orgtype attributes are supposed to reference only a few allowed enum values (:community.orgtype/*) but there's actually no enforcement at runtime:

enter image description here

To show how arbitrary foreign key constraints can be implemented in Datomic, I wrote a database function (called add-fk) that prevents the wrong enum value from ever be associated with :community/orgtype attributes.

For a full code sample, look at the Datomic: database functions and foreign-key constraints gist. For example, the add-fk database function behavior is shown below:

 ;; will succeed
 [[:db/add #db/id [:db.part/user] :community/name "15th Ave Community"]
  [:add-fk #db/id [:db.part/user] :community/orgtype :community.orgtype/personal]])

 ;; will fail
 [[:db/add #db/id [:db.part/user] :community/name "15th Ave Community"]
  [:add-fk #db/id [:db.part/user] :community/orgtype :community.type/email-list]])
 ;; java.lang.Exception: :community.type/email-list is not one of 
 ;; [[:community.orgtype/community], [:community.orgtype/commercial], 
 ;; [:community.orgtype/personal], [:community.orgtype/nonprofit]]

OTHER TIPS

No. In Datomic, db/isComposite refers to composition (as opposed to aggregation) in the OOP/UML sense.

With db/isComposite set to true, when you retract an entity, all subcomponents are also retracted. When you touch an entity, all its subcomponent entities are touched recursively.

Consider 2 different relationship examples from eCommerce world:

1) Customer ---- UserPreferences

Typically this is composition. Preferences entity lifetime depends on Customer entity lifetime. In Datomic the userPreferences ref on Customer should have db/isComposite attribute set to true.

2) Customer ---- OrderItem

Typically this is aggregation. OrderItem can exist even when Customer was deleted. This is default type of ref in Datomic.

Relational model implements both dependencies as foreign keys, so in terms of representation the answer would be: yes, db/isComponent can be represented in RDBMS as a referential constraint (FOREIGN KEY) with CASCADE action but conceptually it is not equivalent.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top