-
Notifications
You must be signed in to change notification settings - Fork 2
04 refs
In all the examples so far, the posts have referred to the same user, :u0
.
What if you want to create two posts, but you want them to belong to different
users? Here’s how you could do that:
(ns donut.datapotato-tutorial.04
(:require [donut.datapotato.core :as dc]))
(def potato-schema
{:user {:prefix :u}
:topic {:prefix :t
:relations {:owner-id [:user :id]}}
:post {:prefix :p
:relations {:topic-id [:topic :id]
:owner-id [:user :id]}}})
(def potato-db
{:schema potato-schema})
(defn ex-01
[]
(dc/add-ents potato-db {:post [{:count 1}
{:refs {:owner-id :my-own-sweet-user}}]}))
What’s new in this example is the map {:refs {:owner-id :my-own-sweet-user}}
.
It resulted in a post, :p0
, referring to a :user
ent named
:my-own-sweet-user
instead of :u0
. :p1
refers to :u0
, as we’ve seen
before. Let’s break this down.
In the potato-schema
, :post
includes this relations definition:
:relations {:owner-id [:user :id]}
This means, a ~:post~ refers to a user via the ~:owner-id~ attribute. Queries
are essentially telling datapotato, generate the minimal ent-db necessary for
me to retrieve the ents I’ve specified, so when you call the add-ents
function and instruct datapotato to generate a :post
, its default behavior is
to satisfy this schema definition by creating a :user
and naming it according
to its default naming system.
Internally, the ent db tracks that the :post
refers to a :user
via the
:owner-id
attribute, and when you have a query term that includes the
key/value pair :refs {:owner-id :my-own-sweet-user}
, you’re saying, I want
the user that ~:owner-id~ refers to to be named ~:my-own-sweet-user~. One
reason you might do this would be to write a test ensuring that users can’t
modify each others’ posts.
If you look back at the schema for this section, you’ll notice it introduced a
new ent type, :topic
, and ~:post~s reference ~:topic~s. What if you wanted to
create two topics, each with one post and each topic belonging to a different
user? Here’s how you could do that:
(defn ex-02
[]
(dc/add-ents potato-db {:topic [{:count 1}
{:refs {:owner-id :hamburglar}}]
:post [{:count 1}
{:refs {:topic-id :t1}}]}))
Before reading the explanation of how this works, indulge the educator in me and take a moment to write or say your own explanation. Quizzing yourself like this is an effective way to clarify and retain your understanding. There’s all kinds of studies that show it; it’s called “the testing effect” and it’s one of the best ways to learn.
Let’s break this query down term by term:
{:topic [{:count 1}
{:refs {:owner-id :hamburglar}}]
:post [{:count 1}
{:refs {:topic-id :t1}}]}
Under :topic
, {:count 1}
tells Datapotato to create a :topic
. It’s given
the default name :t0
. Since you didn’t specify any refs, it refers to the
default user, :u0
.
The next query term, {:refs {:owner-id :hamburglar}}
, instructs datapotato to
create a :topic
that refers to a user named, of all things, :hamburglar
.
This :topic
is given the default name of :t1
.
Under :post
, {:count 1}
tells Datapotato to create a :post
with a default
name and default refs. Therefore, :p0
refers to :t0
.
The next term, {:refs {:topic-id :t1}}
, tells datapotato that the next :post
should refer to the :topic
named :t1
. We specified the :t1
here because we
know that Datapotato’s naming system will produce that name for the second
:topic
specified in the query.
The point of all this is that you can rely on datapotato’s naming system to reliably and concisely establish the properties and relations of the ent db you want to generate. If you don’t want to keep track of Datapotato’s implicit names, you can name things explicitly:
(defn ex-03
[]
(dc/add-ents potato-db {:topic [{:ent-name :t0}
{:ent-name :t1
:refs {:owner-id :hamburglar}}]
:post [{:refs {:topic :tl0}}
{:refs {:topic :tl1}}]}))
What if you want to create a :topic
, but you don’t want to create the :user
it refers to? In that case, you have to override datapotato’s default behavior
with :datapotato.core/omit
:
(defn ex-04
[]
(dc/add-ents potato-db {:topic [{:refs {:owner-id ::dc/omit}}]}))
::dc/omit
prevents the referenced ent from even being created in the ent db.
It’s as if the :owner-id
relation didn’t exist in the potato schema.