-
Notifications
You must be signed in to change notification settings - Fork 2
06 generating records
We now know how to add ents to a potato db, but that’s not enough for test fixtures. We need to generate data that can get inserted into a database.
To do that, we need to introduce schemas for generating data, and we need to update our `potato-schema` and `potato-db` to use them:
(ns donut.datapotato-tutorial.06
(:require [donut.datapotato.core :as dc]
[malli.generator :as mg]))
(def User
[:map
[:id pos-int?]
[:username string?]])
(def Topic
[:map
[:id pos-int?]
[:owner-id pos-int?]
[:name string?]])
(def potato-schema
{:user {:prefix :u
:generate {:schema User}}
:topic {:prefix :t
:generate {:schema Topic}
:relations {:owner-id [:user :id]}}})
(def potato-db
{:schema potato-schema
:generate {:generator mg/generate}})
Here, we’re using malli to define schemas and generate data. You could also use
clojure.spec or plumatic schema. We’ve updated the potato-schema
to include a
:generate
key. This is where you place entity-type configuration for data
generation. The :schema
key tells datapotato which malli schema to use, but
you could also add a :generator
key if you want to configure a generator
function separately from the “global” one.
The :generate
key in potato-db
is where you define the global generator
function. The generator function should take one argument. When the generator
function gets called, it gets passed the [:generate :schema]
value for an
entity type.
You generate data by calling the function datapotato.core/generate
, passing it
a potato-db
and a query:
(defn ex-01
[]
(dc/generate potato-db {:user [{:count 1}]}))
This will generate a single user:
(ex-01)
{:u0 {:id 139, :username "Yp8BGKp6rM57xl8reh3h9xc534b4"}}
Internally, datapotato adds the ent :u01
to the potato db. Then it “visits”
the ent, using the data associated with it to generate a map. (More on visiting
in the next section). When the ent gets visited, datapotato can look up what
ent-type it is (:user
) and from there look up the [:generate :schema]
for
the ent. It passes that to the :generator
function, mg/generate
, and voila -
a map is born.
Sometimes you want to specify values for generated data. You can do that like so:
(defn ex-02
[]
(dc/generate potato-db {:user [{:count 1
:set {:username "nohohank"}}]}))
(ex-02)
;; =>
{:u0 {:id 8648164, :username "nohohank"}}
Here, we’re explicitly setting the :username
to "nohohank"
instead of using
a randomly generated value.
In the same way you can progressively add more ents, you can progressively generate more random data to be inserted:
(defn ex-03
[]
(let [result (dc/generate potato-db {:user [{:count 1
:set {:username "nohohank"}}]})]
(dc/generate result {:user [{:count 1
:set {:username "bartleby"}}]})))
(ex-03)
;; =>
{:u0 {:id 85793, :username "nohohank"}
:u1 {:id 2, :username "bartleby"}}
Just as ent dependencies are automatically added to a potato-db, generating data for a query will generate the data for all implicitly required records:
(defn ex-04
[]
(dc/generate potato-db {:topic [{:count 1}]}))
{:t0 {:id 4, :owner-id 40034, :name "Q"}
:u0 {:id 40034, :username "EK8g11"}}
If you want to generate a :topic
without generating the corresponding :user
,
you would do that like this:
(defn ex-05
[]
(dc/generate potato-db {:topic [{:count 1
:refs {:owner-id ::dc/omit}}]}))
;;=>
{:t0 {:id 6412307, :name "82D8m039P8l3T97nzv0mj7l88cGgu"}}
As you saw in an earlier section, ::dc/omit
causes datapotato to act as if a
relation doesn’t exist. In this case, we’re telling datapotato to act as if a
:topic
has not relationship to a :user
via its :owner-id
key.