Fork me on GitHub
#pathom
<
2023-02-11
>
Jakub Holý (HolyJak)16:02:56

Hello! What are the best practices from invoking the parser from inside a mutation? Context: I have a safe-delete-entity mutation that first checks if the entity is referenced by any other entities and if it is, does not delete it and instead returns a list of those entities - e.g. [[:product/id 123] [:order/id 456]]. Now I want to make the list display-friendly and thus fetch also a nice label for each entity and return instead something nice and uniform, like [{:ident [:product/id 123] , :label "Product X"},{:ident [:order/id 456], :label "Order ABC"}] where the label comes actually from the :order/name or :product:name attribute. Now the complication is that in the case of order, the name is not stored in the db but computed by Pathom from other order attributes. So inside my mutation I want to do something like:

(->> deps-list ; list of idents
     (mapv (fn [idt] {:ident idt, 
                      :label (cond (order? idt) 
                                   (-> (parser env [{idt [:order/name]}]) first val :order/name) 
...)})))
Is that ok? But now I have circular dependency, as the parser depends on the mutation and the mutation on the parser. Can I somehow stick the parser inside env , or what do people do? Thank you!

Jakub Holý (HolyJak)17:02:45

Ok, so I solved it differently: the mutations returns {:deps [ident1 ident 2 ...]} and I have for each entity registered resolvers like these two:

(pbir/single-attr-resolver :order/id :ident (partial vector :order/id))
(pbir/alias-resolver :order/name :label)
which seems to work fine enough.

caleb.macdonaldblack19:02:15

@U0522TWDA Did you end up querying on the result of the mutation instead of querying within it?

Jakub Holý (HolyJak)19:02:53

No, I modified the query Fulcro send for the mutation to include the join so Pathom does all the work for me. Essentially (m/returning (rc/nc [:dependencies/id {:dependencies/dependants [:ident :label]}])) in the mutation def. The key part is {:dependencies/dependants [:ident :label]} where I had before only :dependencies/dependants . The tx sent is thus

[{(me/safe-delete-entity
   {:ident [:product/id 123]})
  [:dependencies/id
   {:dependencies/dependants [:ident :label]} 
   :tempids]}]

caleb.macdonaldblack20:02:10

Nice one. That’s how I would’ve done it.

❤️ 2
Jakub Holý (HolyJak)23:02:07

Thank you for the confirmation!

Eric Dvorsak06:02:25

for future reference I use 4 different solutions depending on when I have the data and when I need it. If I already know what I need to query before the mutation then it can be part of the same query as the mutation. I I only know after the mutation then the mutation can return some identifiers then it can be in the attributes of the mutation in my query Those are the easy ones. Then there's when I need the data IN the mutation. There's a plugin that can resolve mutation inputs but I find it awkward, not sure it works for anything more complex than a few attributes when you pass an ident. finally, and that's what you initially wanted to do, I do a query with the parser in the mutation. For that you simply assoc the parser in the env For instance mine looks like this:

(defstate parser
  :start
  (let [process (p.eql/boundary-interface base-env)]
    (fn [env tx]
      (let [ast (pa/auth-query auth-attributes tx)
            {user-id :user/id}  (get-in env [:ring/request :session])
            user-id (or user-id (get env :current-user/id))
            env      (-> env
                         (assoc
                           :parser process
                           :com.wsscode.pathom3.error/lenient-mode? true
                           ;; legacy param support
                           :current-user/id  user-id
                           :now (timestamp/now)
                           :query-params (rpc/combined-query-params ast))
                         (authorization))
            response (process env {:pathom/ast ast})]
        (if (-> response :com.wsscode.pathom3.error/error-data :unauthorized)
          "Unauthorized"
          response)))))

❤️ 2