Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modifying the state backend-side #42

Open
jacomyal opened this issue Mar 13, 2019 · 1 comment
Open

Modifying the state backend-side #42

jacomyal opened this issue Mar 13, 2019 · 1 comment

Comments

@jacomyal
Copy link

jacomyal commented Mar 13, 2019

In my current project, I am trying to implement a no-JS fallback to the most basic state controllers (ie. the ones that only emit :state). It would work like this:

  1. The user clicks on a button, which is actually the submit of a hidden form
  2. The browser calls the current URL as a POST call, with the controller name, the event name and the serialized params in the payload
  3. The backend instanciates the reconciler, applies the related state controller (that would modify the related state branch), then renders the HTML page and sends it back

But I have two issues:

  • First, I cannot actually manage to modify the state backend-side
  • Also, I am not sure how useful the resolvers are

Why I cannot modify the state backend side

The current implementation of the Resolver is written such that it will always resolve the state branch with the initially given resolver function:

;; ...
clojure.lang.IDeref
(deref [_]
  (let [[key & path] path
        resolve (get resolver key)
        data (resolve)]
    (when state
      (swap! state assoc key data))
    (if reducer
      (reducer (get-in data path))
      (get-in data path))))
;; ...

By the way, this is also clearly stated in the doc.

There is no way to bypass that, except by instanciating a new Reconciler, with resolvers that return the modified state branches - which looks definitely smelly.

Can you see any other way to do that, with the current implementation of Citrus?

Also, a solution would be to first check if the related state branch is already in the state, before calling the resolver:

;; ...
clojure.lang.IDeref
(deref [_]
  (let [[key & path] path
        resolve (get resolver key)
        data (if (contains? state key)
               (get state key)
               (resolve))]
    (when state
      (swap! state assoc key data))
    (if reducer
      (reducer (get-in data path))
      (get-in data path))))
;; ...

Which by the way would deal with caching issue at the same time, and allow me to transform the state by just reset!ing the state atom.


Why using resolvers at all

I understand that the purpose of resolvers is to only load data that will actually be used in the UI. But the way I see it, I think it's not the best design:

  • I have to deal with cache by myself
  • I cannot concurrently load different data branches

So the code can become quite verbose, to have something that is not necessarily done the best possible way.

Meanwhile, if Citrus would simply skip this feature:

  • I'd have to only load the data I want (which looks less good on paper, I admit)
  • I could load my data the way I want (we already do this here, by the way)
  • I would simply give the new reconciler the initial state or a fed atom

The state would no more be lazy, which would make manipulating it way easier. What do you think about it?

@jacomyal
Copy link
Author

Quick follow-up, I finally use this code (which still seems a bit verbose, just to update a bit of data):

(defn reduce-reconciler
  [reconciler {:keys [controller-name event-name params]}]
  (let [resolver   (-> reconciler :resolvers controller-name)
        data       (if (fn? resolver) (resolver))
        controller (get controllers-map controller-name)
        result     (if controller
                     (controller event-name params data))]
    (if (contains? result :state)
      (citrus/reconciler {:state     (:state reconciler)
                          :resolvers (assoc (:resolvers reconciler) controller-name (constantly (:state result)))})
      reconciler)))

@martinklepsch martinklepsch changed the title Modityfing the state backend-side Modifying the state backend-side Apr 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant