Fork me on GitHub
#clj-commons
<
2022-06-02
>
genRaiy08:06:26

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 ! )

delaguardo08:06:08

there is cljs implementation for ordered-map

1
genRaiy08:06:53

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

borkdude09:06:39

So you are looking for the ordered set?

borkdude09:06:15

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

genRaiy09:06:46

(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)))

genRaiy09:06:46

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

genRaiy09:06:06

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

borkdude09:06:48

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

genRaiy09:06:27

yes, that is a very decent opinion

genRaiy09:06:27

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

borkdude09:06:42

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

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

borkdude09:06:17

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

genRaiy09:06:03

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

genRaiy09:06:46

if you assoc first you cannot test for key existence

borkdude09:06:20

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

borkdude09:06:48

How big are these items? How many elements?

borkdude09:06:26

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

genRaiy09:06:59

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

genRaiy09:06:30

(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))))))

borkdude09:06:12

How often do you need to know the order?

genRaiy09:06:34

always ... you want to track history properly

borkdude09:06:52

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

genRaiy09:06:57

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

borkdude09:06:05

yes, that too ;)

genRaiy09:06:07

I'll get there

borkdude09:06:48

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

genRaiy09:06:09

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

borkdude09:06:21

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

borkdude09:06:43

Are you also preparing your ClojureD workshop now? ;)

😂 2
genRaiy09:06:05

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.

genRaiy09:06:00

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

delaguardo09:06:11

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

genRaiy10:06:57

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

genRaiy10:06:08

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

genRaiy08:06:06

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