Skip to content

Instantly share code, notes, and snippets.

@awkay
Last active January 29, 2025 20:46
Show Gist options
  • Select an option

  • Save awkay/f70d3c872ed40a94e2fcd923eb4436f3 to your computer and use it in GitHub Desktop.

Select an option

Save awkay/f70d3c872ed40a94e2fcd923eb4436f3 to your computer and use it in GitHub Desktop.
Macros for making Pathom resolvers/mutations that can be eval'd in the repl to update them without needing a restart.
(ns pathom.connect-macros
(:require
[com.fulcrologic.rad.database-adapters.datomic-options :as do]
[clojure.spec.alpha :as s]
[com.fulcrologic.fulcro.algorithms.do-not-use :as futil]
[com.wsscode.pathom.connect :as pc]))
;; Use @registry as your resolvers in pathom parser def...just make sure you require all nses that define resolvers/mutations in that ns
;; so they all get into the registry first.
(defonce registry (atom []))
(defn register! [resolver] (swap! registry conj resolver))
(defn update-database-atoms! [env]
(doseq [dbk (keys (get env do/databases))
:let [dbatom (get-in env [do/databases dbk])
conn (get-in env [do/connections dbk])]]
(reset! dbatom (d/db conn))))
(s/def ::check (s/or :sym symbol? :expr list?))
(s/def ::mutation-args (s/cat
:sym simple-symbol?
:doc (s/? string?)
:arglist vector?
:config map?
:body (s/* any?)))
(defn defpathom-backend-endpoint* [endpoint args update-database?]
(let [{:keys [sym arglist doc config body]} (futil/conform! ::mutation-args args)
internal-fn-sym (symbol (str (name sym) "__internal-fn__"))
nspc (if (namespace sym) sym (name (ns-name *ns*)))
fqsym (symbol nspc (name sym))
env-arg (first arglist)
params-arg (second arglist)
update-dbatom (when (or update-database? (= endpoint `pc/defmutation))
`(update-database-atoms! ~env-arg))]
`(do
;; Use this internal function so we can dynamically update a resolver in
;; dev without having to restart the whole pathom parser.
(defn ~internal-fn-sym [env# params#]
(let [~env-arg env#
~params-arg params#
result# (do ~@body)]
~update-dbatom
;; Pathom doesn't expect nils
(cond
(sequential? result#) (vec (remove nil? result#))
(nil? result#) {}
:else result#)))
(~endpoint ~(cond-> sym
doc (with-meta {:doc doc})) [env# params#]
~config
(~internal-fn-sym env# params#))
(register! ~sym) ; side effect the resolver into a shared atom that I can defer into pathom config
::done)))
(defmacro defmutation [& args] (defpathom-backend-endpoint* `pc/defmutation args true))
(defmacro defresolver [& args] (defpathom-backend-endpoint* `pc/defresolver args false))
@yoodame
Copy link

yoodame commented Jan 29, 2025

@awkay this works. It is missing the [datomic.client.api :as d] require.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment