{"action":"created","issue":{"url":"https://api.github.com/repos/roman01la/scrum/issues/9","repository_url":"https://api.github.com/repos/roman01la/scrum","labels_url":"https://api.github.com/repos/roman01la/scrum/issues/9/labels{/name}","comments_url":"https://api.github.com/repos/roman01la/scrum/issues/9/comments","events_url":"https://api.github.com/repos/roman01la/scrum/issues/9/events","html_url":"https://github.com/roman01la/scrum/issues/9","id":226055465,"number":9,"title":"Bug ? Subscription path must originally exist in server-side's resolver initial state","user":{"login":"DjebbZ","id":77278,"avatar_url":"https://avatars1.githubusercontent.com/u/77278?v=3","gravatar_id":"","url":"https://api.github.com/users/DjebbZ","html_url":"https://github.com/DjebbZ","followers_url":"https://api.github.com/users/DjebbZ/followers","following_url":"https://api.github.com/users/DjebbZ/following{/other_user}","gists_url":"https://api.github.com/users/DjebbZ/gists{/gist_id}","starred_url":"https://api.github.com/users/DjebbZ/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DjebbZ/subscriptions","organizations_url":"https://api.github.com/users/DjebbZ/orgs","repos_url":"https://api.github.com/users/DjebbZ/repos","events_url":"https://api.github.com/users/DjebbZ/events{/privacy}","received_events_url":"https://api.github.com/users/DjebbZ/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":14,"created_at":"2017-05-03T17:15:33Z","updated_at":"2017-06-05T17:00:52Z","closed_at":null,"body":"Ouch, I just stumbled upon what I think is a bug. Not sure.\r\n\r\nSay you have this reconciler server-side :\r\n\r\n``` clojure\r\n(scrum/reconciler {:state (atom {})\r\n                              :resolvers {[:a] (constantly {:b \"b\"})\r\n                                                [:a :b] (constantly \"b\")}}) ;; the weird thing !\r\n```\r\n\r\nand the following subscriptions :\r\n\r\n``` clojure\r\n(defn a [reconciler]\r\n  (scrum/subscription reconciler [:a]))\r\n\r\n(defn b [reconciler]\r\n  (scrum/subscription reconciler [:a :b] #(some-function %)))\r\n```\r\n\r\nAs it is the code works. But if I remove the \"weird\" resolver (the line with the comment) I get a NullPointerException when loading the page : (relevant stacktrace)\r\n\r\n```\r\nCaused by: java.lang.NullPointerException: null\r\n        at scrum.resolver.Resolver.deref(resolver.clj:8)\r\n        at clojure.core$deref.invokeStatic(core.clj:2310)\r\n        at clojure.core$deref.invoke(core.clj:2296)\r\n        at my.ns.my-component$fn__41563.invokeStatic(my-component.cljc:116)\r\n```\r\n\r\nI can't just remove the first resolver, it's really used somewhere else in my app.\r\n\r\nMy understanding of the code in `resolver.clj` is that when there's a subscription, at the moment you `rum/react` it (which is just `clojure.core/deref` server-side), it does a simple `(get resolvers path)`. In my case `path` is `[:a :b]`. So this path **must** exist in the resolvers map, even if it means duplicating part of the initial state across several paths.\r\n\r\nI know that by design, only `rum/react`ed subscription hence paths will have their corresponding resolving functions called. But it means that deep subscriptions must either have a top-level subscription executed before to get the child path values *or* have child path values duplicated in proper deep path in resolvers map.\r\n\r\nI hope I was clear.\r\n\r\nEdit : after some thinking, I realized I could just have this subscription instead and call it a day :\r\n\r\n``` clojure\r\n(defn b [reconciler]\r\n  (scrum/subscription reconciler [:a] #(some-function (:b %)))\r\n```\r\n\r\nThat is, reading the nested value in my aggregate function. But I think this make subscriptions mostly useless. Reading your subscriptions examples in the readme, I don't see how using paths like `[:users 0 :fname]` could work without the corresponding resolving function at this exact path in the reconciler.\r\n\r\nMaybe the solution is not to do a simple `get` in resolver.clj but a smart reduce :\r\n\r\n``` clojure\r\n(deftype Resolver [state resolvers path reducer]\r\n\r\n  clojure.lang.IDeref\r\n  (deref [_]\r\n    (let [resolve (get resolvers path) ;; use reduce instead\r\n          data (resolve)]\r\n      (when state\r\n        (swap! state assoc-in path data))\r\n      (if reducer\r\n        (reducer data)\r\n        data))))\r\n```\r\n\r\nThat is, the reducing code should check for each fragment of path if there's a corresponding resolving function and call if it exists. When no resolving function are found, it should `get` at this point (or maybe `get-in` ?).\r\n\r\nLong issue. End of work day gotta go. I hope this issue is helpful."},"comment":{"url":"https://api.github.com/repos/roman01la/scrum/issues/comments/306243710","html_url":"https://github.com/roman01la/scrum/issues/9#issuecomment-306243710","issue_url":"https://api.github.com/repos/roman01la/scrum/issues/9","id":306243710,"user":{"login":"roman01la","id":1355501,"avatar_url":"https://avatars3.githubusercontent.com/u/1355501?v=3","gravatar_id":"","url":"https://api.github.com/users/roman01la","html_url":"https://github.com/roman01la","followers_url":"https://api.github.com/users/roman01la/followers","following_url":"https://api.github.com/users/roman01la/following{/other_user}","gists_url":"https://api.github.com/users/roman01la/gists{/gist_id}","starred_url":"https://api.github.com/users/roman01la/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/roman01la/subscriptions","organizations_url":"https://api.github.com/users/roman01la/orgs","repos_url":"https://api.github.com/users/roman01la/repos","events_url":"https://api.github.com/users/roman01la/events{/privacy}","received_events_url":"https://api.github.com/users/roman01la/received_events","type":"User","site_admin":false},"created_at":"2017-06-05T17:00:52Z","updated_at":"2017-06-05T17:00:52Z","body":"Is my understanding correct that from UI point of view `products` is the same thing and the server is calling different resolvers for examples based on user role or something else that decides how to fetch data? "}}
{"actor":{"display_login":"roman01la"}}