Fork me on GitHub
#clojure-norway
<
2023-12-15
>
slipset07:12:32

I går kveld skrev jeg et ganske så giftig update statement i sql. Det er utrolig så mye mer digg det er å ha en database enn mongo.

slipset07:12:47

Og, ja. Jeg vil heller skrive det i SQL enn i Clojure.

cjohansen07:12:56

Jøss. Hvorfor?

slipset07:12:35

Det er enda litt mer deklarativt enn det jeg får til i Clojure.

select f.model, b.value as "typeId" from field f, jsonb_array_elements_text(f."componentType") as b where (f.model, b.value) not in (select model, "typeId" from component_type_view);

slipset07:12:22

(dette er ikke den giftige greia jeg skrev igår, men dette er nærmest en direkte oversettelse fra problemet (gi meg alle modelid’er og type id’er i felter som er slik at disse ikke finnes blandt komponent-typene).

slipset07:12:29

En kollega skrev denne i Clojure og det var minst 20 linjer. Jeg har ikke prøvd å skrive det i clojure. Men, hvis du vil: Et felt i denne sammenhengen ser ut som:

{:_id 1 :model 2 :componentTypes [t1, t2, t3]}
Så utfordring nummer en er å få dette til å bli:
[{:_id 1, :model 2, :type t1}, {:_id 1 :model 2 :type t2} {:_id 1 :model 2 :type t3}]
og så fjerne alle av disse som _finnes i listen av komponent-typer, på formen:
[{:model 2 :typeId t2}]

slipset07:12:35

Det siste er vel egentlig ganske greit:

(remove (comp (set/project component-types [:model :typeId]) #(select-keys % [:model :type])) flattened-types )

slipset07:12:49

Så det er egentlig utfordring nummer en som jeg ikke finner noen nice løsning på sånn off the top of my head.

slipset08:12:03

Damn! chat-gtp to the rescue!

😁 1
Ivar Refsdal08:12:45

eg skulle nett til å svara med:

(comment
  (let [data [{:_id 1 :model 2 :componentTypes ['t1 't2 't3]}]]
    (vec
      (for [{:keys [model] :as d} data
            componentType (get d :componentTypes)]
        {:model model :typeId componentType}))))

Ivar Refsdal08:12:25

for er digg for å "eksplodere"/utvide ting

🎯 1
slipset08:12:38

for er så ikke en del av verktøykassa mi.

Ivar Refsdal08:12:46

evt:

(for [{:keys [model componentTypes]} data
      componentType componentTypes]
  {:model model :typeId componentType})
edit: formatering

slipset08:12:46

Jeg tror jeg ville gått for typ:

(defn explode [k kk data] (for [explosion (k data)] (assoc data kk explosion)))

(mapcat (partial explode :componentTypes :type) all-my-datas)

💥 2
leifericf08:12:50

k kk er en dristig signatur 😜

slipset08:12:56

Du tenker kkk 🙂 Jeg var litt usikker på hva jeg skulle kalle dem. kunne også vært k og k'

leifericf09:12:56

Hehe, ja, det var mest en dårlig joke i morgenørska 😅

leifericf08:12:47

Den siste uka har jeg skrivet om et digert Shell script til Babashka. Det ble skrevet av min sjefs sjef (mest Copilot). I går kom han innom pulten min for å slå av en prat (fordi jeg slutter), så benyttet jeg anledningen til å vise ham koden i VS Code/REPL. Han ble ganske tent! Senere på kvelden fikk jeg en melding: > Om du jobber neste uke også kan du ikke booke meg til en gjennomgang av clojure koden som du viste? Lettere å komme i gang med litt hjelp tenker jeg.

🔥 4
💯 1
terjesb08:12:14

Enig i at for kanskje er best her. En annen map-variant:

(comment
  (let [fs [{:_id 1 :model 2 :componentTypes ['t1, 't2, 't3]}]]
    (mapcat (fn [f]
              (map (fn [ct]
                     (merge (select-keys f [:_id :model]) {:type ct})) (:componentTypes f))) fs)))

({:_id 1, :model 2, :type t1}
 {:_id 1, :model 2, :type t2}
 {:_id 1, :model 2, :type t3})

terjesb08:12:07

Du hadde allerede pre-refactored denne;)

slipset08:12:56

Jeg foretrekker nok også å ha select-keys på utsiden, sånn at jeg kan gjøre projeksjonen tilslutt.

💯 1
slipset08:12:52

(og for projeksjoner har man jo set/project som bare er (map #(select-keys % ks) xs) men som gjør at man slipper å lese sistnvente.)

terjesb08:12:10

Men ja, denne er nærmere din for:

(let [fs [{:_id 1 :model 2 :componentTypes ['t1, 't2, 't3]} {:_id 2 :model 3 :componentTypes ['t4 't5, 't6]}]]
    (mapcat (fn [f] (map (fn [ct] (assoc f :type ct)) (:componentTypes f))) fs)))
dvs.
(defn explode [k kk data] (map #(assoc data kk %) (k data)))

  (let [fs [{:_id 1 :model 2 :componentTypes ['t1, 't2, 't3]} {:_id 2 :model 3 :componentTypes ['t4 't5, 't6]}]]
    (mapcat (partial explode :componentTypes :type) fs))
Så da kan du velge mellom:
(defn explode [k kk data] (for [explosion (k data)] (assoc data kk explosion)))

(defn explode [k kk data] (map #(assoc data kk %) (k data)))

slipset08:12:54

Takk @christian767 for at du sa “Jøss”, nå fikk jeg jo lært meg noe nytt.

2
cjohansen08:12:30

hehe, moro å kunne hjelpe

cjohansen08:12:13

Jeg er mest forbauset over at dette startet med "jeg vil heller gjøre update med sql" og endte opp i en diskusjon om datatransformasjon 😅

cjohansen08:12:54

Jeg har levd så lenge i datomic-land at det falt meg ikke engang inn at det var selecten det handlet om

slipset08:12:30

update’n var litt det samme:

update foo f
set bar = b.whatever
from baz b
where f.id = b.id and (b.whatever, b.whatnot) in (select whatever, whatnot from something_else...)
så basically litt sånn halvkompliserte greier som er ganske greit å uttrykke i sql, men som blir litt mer kode i clojure.

cjohansen09:12:53

Skjønner det nå, det var bare uvant med side-effecting data-transformasjon 😅

cjohansen09:12:08

for er Clojure's sql 😄

slipset09:12:08

https://ericnormand.me/mini-guide/clojure-set er jo en klassiker (til glede for nye lesere) Jeg mener det er en til som er enda litt bedre, men jeg klarer ikke å finne den akkurat nå.

👍 2
augustl09:12:35

det er en som heter clojure.math.combinatorics som har snacks som permutations og subsets

slipset09:12:42

BTW. jeg er skikkelig dårlig på å holde orden på alle join typene i sql. Jeg lærte sql en gang da vi skrev:

select a.foo, b.bar from aaas a, bbbbs b where a.id = b.id;
Som vel gir en inner join. Men siden vi er på sql kjøret idag, så fant jeg https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-joins/ som presenterte disse join’ene som venn-diagrammer, og da gir jo faktisk navnene mening også.

cjohansen14:12:35

Litt tynt med docs osv enn så lenge, men nå har @magnars og jeg sørget for at staten har minst ett API som leverer EDN 😄 https://www.matvaretabellen.no/api/

😻 3
👏 2
terjesb15:12:13

Grattis! En mini-jøss for extension istedenfor Accept:) Så ser jeg at det for nutrients isf kanskje også måtte vært med en Accept-Language. En av dagens mange trade-offs, sikkert:)

cjohansen16:12:44

Dette gir seg selv siden løsningen er en statisk site, så det er filer generert til disk. Da utgår headere 😊

magnars17:12:28

Tør jeg spørre hva du tenker er problematisk med filendelser, @U0523NZUF ?

terjesb08:12:20

Kun en mini-jøss. Jeg har også ting som leverer ut f.eks. .xml eller .csv i url-en når jeg skal serve en ‘fil’, og da returneres det som text/xml eller text/csv. Jeg har muligens en preferanse for content negotiation når den samme ressursen kan serves i ulike representasjoner, men ingen biggie og såvidt jeg vet er det ingen regler på dette. Dermed nysgjerrig på hvordan dere hadde tenkt her. Uansett glemte jeg helt at dette var statisk generert. Da må dette være en ok måte å gjøre det på, det funker jo i praksis. Avhengig av config på webserver/CDN kan det imidlertid gi en mindre presis content-type i response. At den kanskje server alle XML-filer som text/xml, selv om noen egentlig er application/atom+xml. F.eks. server Google Frontend .edn her som application/octet-stream og ikke application/edn. Vil jeg ha ut edn på klienten, gjør jeg det typisk eksplisitt eller manuelt. Eksplisitt med :as :auto forutsetter korrekt content-type og returnerer edn både for en JSON- og edn-ressurs, mens :as :clojure prøver å returnere edn uansett om det kommer som application/json, application/octet-stream, application/edn eller application/vnd.adobe.edn:)

cjohansen08:12:55

Ah, bra catch med content-type. Kan nok ikke skylde på google, det er vi som har konfigurert nginx 🙈 Skal fikse det!

👌 1
cjohansen14:12:25

For ikke å snakke om åpen kildekode i Clojure! https://github.com/mattilsynet/matvaretabellen-deux

augustl15:12:23

skal man vurdere en liten refactoring-runde her da kanskje?

augustl17:12:25

aaah, mye bedre