Skip to content

Instantly share code, notes, and snippets.

@not-in-stock
Last active August 10, 2021 14:26
Show Gist options
  • Select an option

  • Save not-in-stock/ec2bf0c74a270bb531c0f5f2dc45ec9a to your computer and use it in GitHub Desktop.

Select an option

Save not-in-stock/ec2bf0c74a270bb531c0f5f2dc45ec9a to your computer and use it in GitHub Desktop.
(ns not-in-stock.macro.subs
(:require [clojure.spec.alpha :as s]
[re-frame.core :as re-frame]
#?(:cljs reagent.ratom)))
(defn- signal-sub-form [signal]
`(re-frame/subscribe ~signal))
(defn- signal-fn-form [sub-bindings signals]
`(fn [~sub-bindings]
~(if (= 1 (count signals))
(signal-sub-form (first signals))
(mapv signal-sub-form signals))))
(defn- namespaced-keyword [sub-name]
(keyword (str *ns*) (name sub-name)))
(defmacro defsub [sub-name bindings & signals-and-input-fn]
(let [sub-kw (namespaced-keyword sub-name)
sub-bindings (into ['_] bindings)
input-sym (gensym "input__")
input-fn (last signals-and-input-fn)
signals (->> signals-and-input-fn
rest
(take-nth 2))]
(with-meta
`(do
(re-frame/reg-sub
~sub-kw
~@(when-not (empty? signals)
[(signal-fn-form sub-bindings signals)])
(fn [~input-sym ~sub-bindings]
(~input-fn ~input-sym)))
(defn ~sub-name ~bindings
[~sub-kw ~@bindings]))
{:input-sym input-sym})))
(s/fdef defsub
:args (s/cat :name simple-symbol?
:bindings (s/coll-of simple-symbol? :kind vector?)
:signals (s/* (s/cat :signal-sugar-kw #(= :<- %)
:signal any?))
:input-fn any?))
(defmacro defsub-raw [sub-name bindings f]
(let [sub-kw (namespaced-keyword sub-name)
sub-bindings (into ['_] bindings)
db-sym (gensym "*app-db__")]
(with-meta
`(do
(re-frame/reg-sub-raw
~sub-kw
(fn [~db-sym ~sub-bindings]
(reagent.ratom/reaction
(~f ~db-sym))))
(defn ~sub-name ~bindings
[~sub-kw ~@bindings]))
{:db-sym db-sym})))
(s/fdef defsub-raw
:args (s/cat :name simple-symbol?
:bindings (s/coll-of simple-symbol? :kind vector?)
:f any?))
@not-in-stock
Copy link
Author

not-in-stock commented Jul 15, 2020

Before

(rf/reg-sub ::full-data
  (fn [[_ user-id]]
    [(rf/subscribe [::subs.user/by-id user-id])
     (rf/subscribe [::form-data user-id])])
  (fn [[user form-data] _]
    (merge (select-keys user editable-attribute-keys)
           form-data)))

After

(defsub full-data [user-id]
  :<- (subs.user/by-id user-id)
  :<- [::form-data user-id]
  (fn [[user form-data]]
    (merge (select-keys user editable-attribute-keys)
     form-data)))

Usage

(<sub (form-subs/full-data user-id))

@not-in-stock
Copy link
Author

not-in-stock commented Jul 15, 2020

Before

(reg-sub-raw ::datetime
   (fn [_ [_ form-path]]
      (let [history-point-id (<sub (latest-history-point-id form-path))]
        (r/reaction (<sub (user-history-detail-datetime form-path waypoint-id)))))

After

(defsub-raw datetime [form-path]
  (fn [_]
    (let [history-point-id (<sub (latest-history-point-id form-path))]
      (<sub (user-history-detail-datetime form-path waypoint-id)))))

Usage

(<sub (datetime form-path)

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