Fork me on GitHub
#juxt
<
2020-02-18
>
onetom04:02:44

im trying to use juxt/clip based on the docs, i was expecting that i will be able to use this in the :post-start expression, since it's receiving an implicit target, but it seems not to be the case:

(clip/start {:components {:a {:start 1}
                            :b {:start 2 
                                :post-start `(prn this (clip/ref :a))}}})
am i doing something wrong? what's the simplest way to get access to that implicit parameter? in other words, how can i explicitly refer to the implicit parameter in the :post-start expression?

dominicm08:02:34

You should be able to, definitely. Lemme refresh my memory, one sec :)

dominicm08:02:58

The code for this is in the post start function

dominicm08:02:29

Oh, is it because you're using backtick? And you're getting a namespaced this?

onetom09:02:45

ok, so how should this situation look like then?

dominicm09:02:26

In the exact example above, you could use a single quote instead.

👍 4
onetom04:02:35

now that im asking, i came up with this:

(clip/start {:components {:a {:start 1}
                            :b {:start 2 
                                :post-start `(prn (clip/ref :b) (clip/ref :a))}}})
while it works, im a bit concerned, because post-start is described as being run before the component is passed in to other components where its clip/refered. im wondering if it just works by accident or not? it would be good if the docs mention such a use-case or have some tests for it at least. what i was trying to achieve with this is to have a datomic seed data transaction, where the seed data (which is the datomic schema for new) is provided as a component too

dominicm08:02:31

I'm surprised this works. I'm using tarjans algorithm which I guess doesn't care about this? I wouldn't expect it to keep working forever if I changed the way the environment works or something.

👍 4
onetom07:02:13

would it make sense to support something like this:

(with-open [sys (clip/start sys-config)]
  (work-with sys)
  ; exception happens
  ...)
and the system is closed for sure. it feels like it would be a useful construct while developing a system config, which has a webserver in it for example...

dominicm08:02:30

That's an interesting idea. One problem is that I'd have to return an object so I could extend it to Closeable. One option is a with-system macro? What do you think?

onetom08:02:44

for now i think i will just make something like this with-system: http://pedestal.io/guides/pedestal-with-component#_testing

onetom08:02:34

Isn't the PersistentHashMap and object already?

onetom08:02:03

but with-open is not the most intuitive name anyway, so probably a macro is better. it could be clip/with or clip/let ? and just keep the let-style options, so cursive can recognize it as a let

onetom08:02:02

might even make sense to allow creating multiple systems, so you can test how they interact, without spawning them in separate processes... i remember i did something like this before. created 2 systems but reused the same database in them.

dominicm08:02:33

I don't own PersistentHashMap, so I shouldn't extend it to an interface I don't own, Closeable

dominicm08:02:52

With is what I'd expect I think.

onetom08:02:30

sure, i was hoping that on a per-instance basis it's possible to sneak in some .close method. after all with-open doesn't care about the object types either, just tries to call .close on them..

onetom08:02:48

btw, this implementation seems to work at 1st glance:

(defmacro with
  [[bound-var binding-expr] & body]
  `(let [system-config# ~binding-expr
         ~bound-var (clip/start system-config#)]
     (try
       ~@body
       (finally
         (clip/stop system-config# ~bound-var)))))

dominicm11:02:16

I don't know of any way to do that unfortunately. I'm not sure we should even if we could.

dominicm11:02:44

That macro looks good! If you wanted multiple bindings to be possible, maybe you could make it recursive?

onetom04:02:26

i just tried to integrate it into a test suite as a before-each hook and im not sure if it's a good idea to make it recursive, because of that implicit clip/start. that would mean u can only start systems using this with construct, but intuitively i wrote the following code first:

(declare ^:dynamic q)

(use-fixtures
  :each (fn [test-case]
          (sys/with [sys {:components (merge sys/datomic sys/graphql)}
                     {:keys [graphql/schema-fn]} sys
                     schema (schema-fn)]
            (binding [q (fn [query] (gql/execute schema query {} {}))]
              (test-case)))))

onetom04:02:16

which wouldn't work, even if with would have handled multiple bindings... so currently i have this instead:

(use-fixtures
  :each (fn [test-case]
          (sys/with [sys {:components (merge sys/datomic sys/graphql)}]
            (let [{:keys [graphql/schema-fn]} sys
                  schema (schema-fn)]
              (binding [q (fn [query] (gql/execute schema query {} {}))]
                (test-case))))))
which i think is not too bad... it raises the question though, how would u expose an api for tests, which are specialised for or tied to a specific system instance? it can help immensely to write concise tests, eg:
(deftest query-test
  (expect {:data {:txns [{:id "x" :tags ["tag-1"]}]}}
          (q "{ txns { id tags } }")))

onetom07:02:05

For the record, before I started using clip, I had a macro, like this:

(defmacro in-tmp-db [& body]
  `(let [db-uri# (str (gensym "datomic:-"))]
     (d/create-database db-uri#)
     (let [~'conn (d/connect db-uri#)
           ~'tx! (fn [& ~'args] (apply d/transact ~'conn ~'args))
           ~'db! (fn [] (d/db ~'conn))
           ~'entity (fn [& ~'args] (apply d/entity (~'db!) ~'args))
           ~'entid (fn [& ~'args] (apply d/entid (~'db!) ~'args))
           ~'pull (fn [& ~'args] (apply d/pull (~'db!) ~'args))]
       (try
         @(~'tx! (datomic/schema))
         ~@body
         (finally
           (d/release ~'conn)
           (d/delete-database db-uri#))))))
so my tests looked something like this:
(deftest some-test
  (expecting "something"
    (in-tmp-db
      (some.datomic/transaction! conn {:entity "map"})
      (expect #{"data-1" "data-2"} (some.datomic/query (db!) [:lookup "ref"])))))

dominicm08:02:56

I don't understand the question, sorry