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?You should be able to, definitely. Lemme refresh my memory, one sec :)
The code for this is in the post start function
Oh, is it because you're using backtick? And you're getting a namespaced this?
ok, so how should this situation look like then?
In the exact example above, you could use a single quote instead.
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/ref
ered.
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 tooI'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.
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...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?
for now i think i will just make something like this with-system
:
http://pedestal.io/guides/pedestal-with-component#_testing
Isn't the PersistentHashMap and object already?
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
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.
I don't own PersistentHashMap, so I shouldn't extend it to an interface I don't own, Closeable
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..
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)))))
I don't know of any way to do that unfortunately. I'm not sure we should even if we could.
That macro looks good! If you wanted multiple bindings to be possible, maybe you could make it recursive?
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)))))
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 } }")))
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:<mem://test>-"))]
(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"])))))
I don't understand the question, sorry