Fork me on GitHub
#juxt
<
2020-02-27
>
onetom09:02:27

im trying to make a throw-away datomic system using juxt/clip and try to clean up the created tmp db after stopping it. i can't seem to figure out how can i pass a (clip/ref) within the :stop operation:

(defn default-schema-from-file []
  (->> "datomic-schema.edn" io/resource slurp edn/read-string))

(defn tmp-in-mem-uri [] (str (gensym "datomic:-")))

(defn cleanup [uri conn]
  (prn [uri conn]) 
  (d/release conn)
  (d/delete-database uri))

(defn tmp-parts []
  {:datomic/schema
   {:start `(default-schema-from-file)}

   :datomic/uri
   {:start `(tmp-in-mem-uri)}

   :datomic/conn
   {:pre-start  `(d/create-database (clip/ref :datomic/uri))
    :start      `(d/connect (clip/ref :datomic/uri))
    :post-start `(d/transact ~'this (clip/ref :datomic/schema))
    :stop       `(cleanup (clip/ref :datomic/uri) ~'this)}})

onetom09:02:04

that (prn [uri conn]) debug statement prints:

[(clip/ref :datomic/uri) #object[datomic.peer.LocalConnection 0x63235b75 "[email protected]"]]
so the ~'this gets resolved as I expected but the (clip/ref :datomic/uri) doesn't

dominicm09:02:25

I think there's a comment in the source about confirming refs in stop make sense.

onetom09:02:53

yeah, i can see how it can pose unreconcilable constraints on the start/stop ordering... but in this case what shall i do? sounds like i would need to carry the dependencies of the stop process within the started component. but then will that component be still valid when im stopping the system?... 😕

onetom09:02:08

or i could try to tease out this info from the connection object using something like this:

(.dbname ^datomic.peer.LocalConnection (sys :datomic/conn))
=> "tmp-17692"

onetom09:02:47

i was trying to "inline" my small cleanup function as:

:stop       `(do (d/release (:conn ~'this))
                     (d/delete-database (:uri ~'this)))
then I got this error:
Execution error (ExceptionInfo) at juxt.clip.impl.core/evaluate-pseudo-clojure$fn (core.cljc:187).
Got null for function looking up symbol: do
this pseudo eval thing is quite fragile 😕 still no idea though how could be it done better...

onetom09:02:07

this feels like an ok compromise:

(defn cleanup-conn&db [{:keys [uri conn]}]
  (d/release conn)
  (d/delete-database uri))

(defn tmp-parts []
  {:datomic/schema
   {:start `(default-schema-from-file)}

   :datomic/uri
   {:start `(tmp-in-mem-uri)}

   :datomic/conn
   {:pre-start  `(d/create-database (clip/ref :datomic/uri))
    :start      `{:uri  (clip/ref :datomic/uri)
                  :conn (d/connect (clip/ref :datomic/uri))}
    :resolve    :conn
    :post-start `(d/transact (:conn ~'this) (clip/ref :datomic/schema))
    :stop       `(cleanup-conn&db ~'this)}})

(comment
  @(def sys-config {:components (tmp-parts)})
  @(def sys (clip/start sys-config))
  (clip/stop sys-config sys)
)

onetom10:02:43

hmm... im also wondering how can i make this thing more modular, so i can create multiple datomic connections. the use-case would be to create a migration program, which transforms one datomic db into another one. but then i would need uri/schema/conn for each instance... so a started system would look something like this:

{:source-123/schema [,,,]
 :source-123/uri    "datomic:"
 :source-123/data   {:uri  "datomic:"
                     :conn ^datomic.peer.Connection []}

 :dest-234/schema   [,,,]
 :dest-234/uri      "datomic:"
 :dest-234/data     {:uri  "datomic:"
                     :conn ^datomic.peer.Connection []}}

dominicm12:02:28

Macros don't work, yeah :)

dominicm12:02:49

I didn't want a full clojure interpreter.

dominicm12:02:12

I wanted something that wasn't inventing a new syntax/form that wrapped function calls.

👍 4
dominicm12:02:56

I think modularity and repetition is something I would address via transforms. This is essentially "tagging" your component with a key and having postwalk update it in some way.