Fork me on GitHub
#mount
<
2016-02-29
>
mostr19:02:12

hey, mount newbie here. Do you use partially applied functions as states in mount? E.g. I have (defn find-user [db id] …) function and turn it into state that depends on db state like (defstate user-finder :start (partial find-user db)).

mostr19:02:41

This works fine, but doesn’t obviously “react” properly when db state is stopped

mostr19:02:03

I mean it still keeps the “running” version of db state. Is there a way to combine those two: partial application to avoid dragging all the “deps” as well as having “live-link” to db state? Gist here: https://gist.github.com/mostr/372f65ece0ad6ea218d1

tolitius20:02:17

looks like you are missing a :stop

tolitius20:02:19

(defstate db :start users)

tolitius20:02:36

that's why it is not stopped when (mount/stop) is called

tolitius20:02:51

try (defstate db :start users :stop #{})

tolitius20:02:59

or whatever stop value makes more sense

tolitius20:02:12

in reality it will be a real db disconnect

mostr21:02:46

hm, so I did the following:

(defn stop []
  (prn "Stopping users db")
  #{})

(defstate db
          :start users
          :stop (stop))

mostr21:02:57

but still get

Loading src/clj_sandbox/ms/users_db.clj... done
(mount/stop)
=> {:stopped []}
(mount/start)
=>
{:started ["#'clj-sandbox.ms.users-db/db"
           "#'clj-sandbox.ms.user-finder/user-finder"
           "#'clj-sandbox.ms.user-finder/user-finder2"]}
(user-finder 2)
=> {:id 2, :name "bar"}
(mount/stop #'clj-sandbox.ms.users-db/db)
"Stopping users db"
=> {:stopped ["#'clj-sandbox.ms.users-db/db"]}
(user-finder 2)
=> {:id 2, :name "bar”}

mostr21:02:29

not sure if this is real-life case (stop db while running), but trying to understand how things work in mount

mostr21:02:16

Actually this works as expected as there is (partial…) in user-finder state definition which just probably takes “current” value/reference to db and doesn’t care about state changes. But I wonder whether there is a way to combine these two things: partial application + being aware of state changes

tolitius21:02:32

I'll check it out in a couple hours.. will let you know

mostr21:02:07

sure, no worries simple_smile

tolitius23:02:47

looking at it with less distractions... simple_smile yea, this is expected, here is just plain Clojure example:

boot.user=> (def db {:a 42})
#'boot.user/db
boot.user=> (def find-key (partial db))
#'boot.user/find-key
boot.user=> (find-key :a)
42
boot.user=> (def a {})
#'boot.user/a
boot.user=> (find-key :a)
42

tolitius23:02:55

in case you are ok with closing state over in function, you can simply (:require [users-db :refer [db]]) in user-finder and use it within a function.

tolitius23:02:34

you are of course have freedom of where to use defstate, but I found it is best used for resources, like db in this case

tolitius23:02:14

and API, such as user-finder could just use it as functions, rather than be defstates themselves

tolitius23:02:01

there you can choose whether to close over that db and pass it there directly

tolitius23:02:24

for example, say you have your db API that have access to db state live in app.db namespace. then you can do:

(:require [app.db :as db])

(GET "/find-user" [user]
  (db/find-user user))
or, if you'd like to use your pure find-user function, you can do that too:
(:require [app.db :refer [db]])

(GET "/find-user" [user]
  (find-user db user))
you could notice that in the second example, a route closes over the db state. which is ok, since this is the edge of your application (i.e. no impact or coupling with business logic).