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
?
: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:
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.
: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:
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]]
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With