clj-commons

ray 2022-06-02T08:52:26.152389Z

am looking for a CLJC suite of ordered collections but it seems like https://github.com/clj-commons/ordered is just for the JVM. Is that right? Do any of the crew know of a CLJS equivalent (cos my search fu is letting me down today ! )

Kirill Chernyshov 2022-06-02T08:57:08.186189Z

there is cljs implementation for ordered-map

👍🏼 1
ray 2022-06-02T08:57:53.745199Z

yes, ha ... just noticed that and mentioned it in the channel

borkdude 2022-06-02T09:06:39.482529Z

So you are looking for the ordered set?

borkdude 2022-06-02T09:07:15.356909Z

You can also solve this by keeping a vector and set around with the same data.

ray 2022-06-02T09:22:46.880989Z

(defn record-state-change
  "Add updated-item to the current state under the change-id key.
  If the change-id does not exist, add it to a FIFO list of changes."
  [{:keys [changelog] :as state} updated-item change-id]
  (cond-> state
          (not (get state change-id)) (assoc state :changelog
                                             (vec (conj changelog change-id)))
          :always (assoc change-id updated-item)))

ray 2022-06-02T09:23:46.419489Z

I could drop the cond-> if I had an ordered set cos the assoc is always idempotent

ray 2022-06-02T09:24:06.122099Z

So yeah, you can code around it but just would be nice

borkdude 2022-06-02T09:24:48.047399Z

A small price to pay for not using another dependency I'd say

ray 2022-06-02T09:25:27.669729Z

yes, that is a very decent opinion

ray 2022-06-02T09:28:27.528299Z

Maybe I am more optimistic about the quality of libs from the Clojure community than I am about JS but still, fewer deps are better indeed

borkdude 2022-06-02T09:28:42.562499Z

Instead of (cond-> state ...) I'd write here

(cond-> (assoc change-id updated-item) (not (get state change-id)) ...)

borkdude 2022-06-02T09:36:17.404779Z

@raymcdermott but wait, how is your example an ordered set? It's an ordered map, essentially?

ray 2022-06-02T09:43:03.750759Z

the map is unordered, as usual but the changelog list is ordered by insertion and avoids duplicate insertion.

ray 2022-06-02T09:43:46.421219Z

if you assoc first you cannot test for key existence

borkdude 2022-06-02T09:44:20.176549Z

So you have to update items, but you want to keep the order of first insertion

ray 2022-06-02T09:44:29.450509Z

yes

borkdude 2022-06-02T09:44:48.527169Z

How big are these items? How many elements?

borkdude 2022-06-02T09:45:26.747119Z

Another way to do this is to have an extra key: inserted-at ... with some timestamp or incrementing value so you can sort the map entries based on that

ray 2022-06-02T09:45:59.182409Z

the change-id is of the form id/digest and the digest is based on some input text. If that changes we will get a new digest and a new compound ID

ray 2022-06-02T09:46:30.879919Z

(ns replacement.protocol.state
  (:require [replacement.protocol.hashing :as hashing]
            #?(:cljs [promesa.core :as p])))

(defn record-state-change
  "Add updated-item to the current state under the change-id key.
  If the change-id does not exist, add it to a LIFO list of changes."
  [{:keys [changelog] :as state} updated-item change-id]
  (cond-> state
          (not (get state change-id)) (assoc :changelog (vec (cons change-id changelog)))
          :always (assoc change-id updated-item)))

(defn update-state
  [state updated-item distinction-key form-id]
  (let [digest-input (get updated-item distinction-key)]
    #?(:clj  (let [digest (hashing/digest digest-input)]
               (record-state-change state updated-item (keyword form-id digest)))
       :cljs (p/let [digest (hashing/digest digest-input)]
               (record-state-change state updated-item (keyword form-id digest))))))

borkdude 2022-06-02T09:47:12.751569Z

How often do you need to know the order?

ray 2022-06-02T09:47:34.844549Z

always ... you want to track history properly

borkdude 2022-06-02T09:47:52.821719Z

I mean, how often do you want to query the order

ray 2022-06-02T09:47:57.773319Z

oh and I know I should be using a database for this 🙂

borkdude 2022-06-02T09:48:05.164849Z

yes, that too ;)

ray 2022-06-02T09:48:07.654059Z

I'll get there

borkdude 2022-06-02T09:48:48.331669Z

In this stage I'd just use the extra key on the map to keep the insert order around

ray 2022-06-02T09:49:09.350569Z

I don't know how often the order will be queried ... maybe never but at least once when I demo it 😉

borkdude 2022-06-02T09:49:21.706499Z

unless performance becomes an issue, but you haven't proven that to yourself yet

borkdude 2022-06-02T09:49:43.390749Z

Are you also preparing your ClojureD workshop now? ;)

😂 2
ray 2022-06-02T09:50:00.332129Z

🤫

ray 2022-06-02T09:54:05.798319Z

the thing I'm trying to leverage is that s/conform will produce data that only changes if there is a meangingful change in the code text. Then I can keep a history of those changes and perform structural diffs.

ray 2022-06-02T09:55:00.620729Z

I'm not getting into all the edge cases around that but I think it will be interesting to see how far we can go with that data

Kirill Chernyshov 2022-06-02T09:56:11.455759Z

btw. for LIFO I usually use seq + conj for insertions + peek/pop for takes. That way allows you to not convert data from seq to vector and back on each insertion

ray 2022-06-02T09:57:33.751919Z

noted

ray 2022-06-02T10:02:57.669549Z

FYI this is how I'm currently calling it (update-state state var-data :conformed form-id)

ray 2022-06-02T10:04:08.436879Z

It's not terribly elegant but for the moment at least, it works

ray 2022-06-02T08:57:06.080759Z

actually, there is a map.cljs but not a set.cljs which, of course, is what I am looking for.