This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-10-07
Channels
- # announcements (2)
- # babashka (34)
- # beginners (114)
- # biff (7)
- # calva (16)
- # cider (2)
- # clj-kondo (46)
- # clj-on-windows (14)
- # clojars (13)
- # clojure (33)
- # clojure-europe (17)
- # clojure-nl (2)
- # clojure-norway (8)
- # clojure-spec (3)
- # clojure-uk (3)
- # clojurescript (25)
- # community-development (1)
- # datalevin (1)
- # emacs (53)
- # fulcro (31)
- # gratitude (2)
- # jobs (1)
- # lambdaisland (12)
- # lsp (57)
- # malli (3)
- # nbb (1)
- # off-topic (92)
- # pathom (2)
- # pedestal (2)
- # releases (5)
- # shadow-cljs (25)
- # sql (3)
- # squint (1)
- # testing (6)
- # vim (11)
Hi Clojurians - I am writing a small test to post a record with Postgres, using ring.mock.request, something like this- (deftest test-post-group-targets (testing "test post group targets” (let [response (app (-> (request :put (str "/api/target-id”)) (header “header-key “90909090”) (json-body {:targetval_ 110 :targetdate "_2019-09-09" })))] (is (= 201 (:status response)))))) However, it's not able to serialize the date field I am passing and throwing exception by middleware - "message":"{:cause Don't know how to write JSON of class java.sql.Date, :via [{:type java.lang.Exception, :message Don't know how to write JSON of class java.sql.Date, :at [clojure.data.json$write_generic invokeStatic json.clj 100]}], :trace [[clojure.data.json$write_generic invokeStatic json.clj 110] [clojure.data.json$write_generic invoke json.clj 382] [clojure.data.json$fn__506$G__501__513 invoke json.clj 286] [clojure.data.json$write_object invokeStatic json.clj 335] [clojure.data.json$write_object invoke json.clj 319] [clojure.data.json$fn__506$G__501__513 invoke json.clj 286] [clojure.data.json$write invokeStatic json.clj 475] [clojure.data.json$write doInvoke json.clj 424] [clojure.lang.RestFn invoke RestFn.java 425] [clojure.lang.AFn applyToHelper AFn.java 156] [clojure.lang.RestFn applyTo RestFn.java 132] I am not sure if I need to write a custom write to handle this?
First off, when you're posting code or output, it makes it a lot more readable to use triple backticks around it, so it looks like this:
(some code here)
;; and some output
Second, you show code that calls json-body
which is in ring-mock but that uses Chesire to serialize data to JSON -- but your stacktrace shows clojure.data.json
as failing so you're not showing us the code that is actually failing.
I'm not sure why you're getting that message since clojure.data.json
knows how to serialize java.sql.Date
:
user=> (require '[clojure.data.json :as json])
nil
user=> (json/write-str {:date (java.sql.Date. 10000)})
"{\"date\":\"1969-12-31T08:00:00Z\"}"
user=>
So I wonder if you are using a old version of org.clojure/data.json
that dates back to before java.sql.Date
support was added? The enhanced date support was added in version 2.2.0 which was released six and a half years ago.yes, the version was old (0.2.6), I finally had to use below macro to expand the call and it worked -
(extend-type java.sql.Date
json/JSONWriter
(-write [date out]
(json/-write (str date) out)))
thanks for your help.I am struggling to find prettier for clojure or an alternative to use with VSCode. What you you boys and girls use?
If you are using VS-Code with Clojure, you probably use Calva, which includes cljfmt
I guess I need to figure out how to activate cljfmt on save
thanks
It should work out-of-the-box when you activate VS-Code's Format on Save
option. Calva will provide a Clojure Formatter to VS-Code
Try the Format Document
command from the command palette - it should format your file
My personal preference is to not use automatic code formatting tools. I've never met one that didn't do a bad job in one edge case or another and prefer to treat the indentation as a tool to help you understand the code, like commit messages, tests, comments and documentation. I realise this is an unpopular opinion, but I'm always confused when I see these sorts of requests, like it's normal to ask for a tool that deletes all the documentation from your code ...
I've been like you, Ed. But in teams, especially larger teams, it is almost impossible to agree on a certain style.
It is far easier to agree on some documented style, and use an automated tool to keep the code formatted according to this style. Most languages do have a very small number of "idiomatic" styles, and Clojure is one of them.
Of course, tools should not "delete all the documentation". Which tools does something like that? Definitely not cljfmt
I think that education is a better long term approach - esp. for large teams. Formatting tools often take things that are intentionally laid out, for example as a table, and strip out the whitespace to remove that visual cue. In something like Clojure, where the code is data, these sorts of visual queues can be useful with getting a point across quickly. I tend to use things like emacs' align-regex
to tidy up small sections of the file where needed. Yes, I agree that it's nice to have some coding conventions followed for consistency, but that's all part of your definition of done - "is it readable?" should be one of the questions your ask yourself before saying that the task is done, and indentation is part of that.
"readable" is subjective though. If your team agrees to lay out code in a table, wouldn't it be better to configure your formatter to apply this agreed-upon style?
I agree that too aggressive formatters can be a pain. I've encountered that in Java a lot, where formatters often broke my manual layout, and forced me to write "suppression" comments.
Have not had this issue in Clojure though, as cljfmt
is not super strict.
With default settijngs cljfmt
will not de-align tables like that. It is quite friendly with the existing formatting and mostly does indentation. Calva has a separate command for vertically aligning maps and binding vectors. And it's formatter (which is using cljfmt
) will leave these alone.
Also, formatting the current enclosing form in Calva is as easy as pressing tab
. So most often Format on Save is not necessary. At least not to me.
Yeah I have seen now that I can press tab to make the whole form pretty. It’s a small thing but when I press enter after a conditional, the cursor jumps the the start of the line instead of behind the paren.
I think you might be using the VIM extension? It’s moving the cursor there for unknown reasons. Some people get away with using Calva’s old indentation engine, which is a tad slower and thus can undo VIMs move. Ymmv.
Yeah correct. I use the vim extension. I find the emacs experience to be better but emacs is just…. too much haha.
Hello! I'm looking into storing logic as data in some dynamic store (db?) so that I can configure and select the logic being used at run time. I just want to survey the solution space for now so I don't want to impose any more constraints. If anyone has any ideas or suggestions please join the brainstorming 🙏 P.S If there's a better channel for this question, please point me there Thank you! 🙏 😊
But how do I store logic in edn? Is there a tool for serializing, let's say, functions, to edn and back?
a rules engine like odoyle will allow you to separate logic into a db-ish entity that is serializable, as well as dynamically modifiable. https://github.com/oakes/odoyle-rules
Thank you very much! This is a great lead, do you have any experience/ examples I could follow?
You can also look at #C08TC9JCS . Clara has examples in its repo, odoyle is used as a rule engine for some example games
For example https://github.com/oakes/play-cljc-examples/tree/master/dungeon-crawler
At odoyle is mentioned that since the rule engine uses macros you can't load them at run time, there's also a regular function option but it seems to revert to use functions instead of data. 😕
Clara seem to have the same issue (macros)
In the case of Clara, the macros are optional. You can generate rules with data and load them in working space. An even more interesting idea is to store the working memory with rules preloaded and since is immutable (yay) yo can use it to fire rules and generate new facts. Disclaimer: all this is theoretical, I haven't really used, but I intend to.
Thanks I'll take a second look and see how it can be used
Is there a way to declare a var for public consumption of a namespace without clobbering clojure core names internally?
;; The defining namespace use separate
;; names for * and star
(ns foo)
(defn star [x] (foobar x))
(star (* 1 2))
;; But in another namespace rely on
;; ns qualifier to avoid clobbering.
(require [foo])
(foo/* bar)
not sure i understood corectly: https://clojuredocs.org/clojure.core/refer-clojure
I want to provide foo/*
as a public var for use outside the namespace foo
.
But inside the namespace foo
, I want to not clobber clojure/*
, such that a bare *
works as expected in all cases.
i don't think that's possible you'll have to use the fully qualified version clojure.core/ inside foo, but you can also rename it so it's less verbose (:refer-clojure :rename { .*})
(you could also use a second namespace)
(ns foo-impl)
(defn star [x y] (* x y 2)
(ns foo (:require [foo-impl] :refer-clojure :exclude [*]))
(def * foo-impl/star)
Hey I have a quick question: What would be the best way to go about providing a reference to something that should be immutable. Simple example, given some data X, I want to make a separate map {:x X}, but I don't want to copy X into the map, I just want the map to reference X. I want it to be a reference for performance/memory reasons. The data will never be changed, so theres no need to copy. Should I just use (ref X)? Or an atom? But then they would be potentially mutable? Not sure of the convention here. Thank you
Isn’t this what def
/ ordinary vars accomplish?
I think you're over/early optimizing - I believe what you want is already the default (but an implementation detail), via clojure's persistent immutable data structures - but if you really wanted to ensure it was always the same place in memory, probably like you suggest, ref/atom, something you would deref to take the value of, but you'd always reference by place instead of value
Hm yeah it may be an over optimization, I will type more about the specific use
> I want to make a separate map {:x X}, but I don't want to copy X into the map making a separate map with X in it doesn't make a copy of X.
You could explore and create yourself a simple scenario to alleviate your concerns - make something like a string that is just filled with a bunch of vals until its 1G in size in your initial map - then make a derived map with conj - is your program now taking 2G of mem? Do it 10 more times - did your machine lock up due to lack of ram yet? 😄
@U7RJTCH6J O huh yeah I guess it won't really. I was thinking it needed to copy to guarantee immutibility, like if you mutate {:x X} then the original X wouldn't change, but because things are truly immutable anyways then it doesn't matter. Under the hood, (:x {:x X}) and X are just references to the underlying data of X.
So i was just misunderstanding clojure's variables I think
Thanks y'all
it's a pretty core thing that allows immutability in clojure to be nearly as fast as mutable stuff in other languages, because as you noted, copying would be that guarantee in other langs (trying to do full immutability in some non-clojure)
yet another mind blowing moment of realization while learning about clojure lol. I'm coming from functional-style javascript - so copying was the norm there
Yea, I remember it taking a while to fully grok the immutable data structures when I was first learning clojure.
Hi there, I have a update db function, as follows:
(defn update-client-global-target [client_id arguments]
(update table_name
(set-fields {:target_enroll (:target_usa arguments)
:target_lpi (str-to-date (:target_date arguments))})
(where {:client_id client_id})))
How can I dynamically set fields based on fields that are not nil and in a specific format.Yes, DB (Postgres in my case), supports this, I mean I want to set the field only if it's available otherwise not update it
do you want to do something, where the context of the DB and DB interface is not important?
these are the macros from Korma.core
I think I would need a closure.spec for validating these fields
you never need clojure.spec, unless that's what you want to use. i don't see how it would help in this context unless the db interface also wants you to use that
if you could extract your problem from the DB code, then it'll be a lot easier to solve
I am not having issues with either, I am very new to clojure and not sure how to set fields dynamically
I have to use the same update function, whether there are 2 fields to update or only one
(set-fields {:target_enroll (:target_usa arguments)
:target_lpi (str-to-date (:target_date arguments))})
DB fields
"How can I dynamically set fields based on fields that are not nil and in a specific format." in that sentence, you use field 2 times, does it mean the same thing both times, or do they mean different things?
sorry by set fields I mean set-fields (Macro)
from what i'm reading, it looks like a clojure map that is build up to describe what should be done to the db
how about you pretty print that object, and put it in here, and then we can talk about that object without talking about the DB at all
here is what arguments map looks like - {:targetenroll_ 680 :targetlpi_ "2020-08-21"}
{:type :update
:fields {}
:where []
:post-queries [first]}
the korma/update function makes something like thisfrom your {_:target_enroll_ 680 _:target_lpi_ "2020-08-21"}
object, what do you want to do that is "dynamic" with respect to the data in it?
I want to only set the field that is not nil and if its a date its in proper format
IF I pass something like this - {_:target_enroll_ 680 _:target_lpi nil_}
then update call should onl update target_enroll and be done with it
same behavior for {_:target_enroll_ 680}
the example arguments object doesn't work with the function you gave, it's missing 2 keys
(let [arguments {:target_enroll 680 :target_lpi "2020-08-21" :target_usa "whatever" :target_date #inst "2000"}
{:keys [target_enroll target_id target_usa target_date]}]
(cond-> query
(and target_enroll target_usa) (set-fields {:target_enroll target_usa})
(and target_id target_date) (set-fields {:target_lpi (str-to-date target_date)})
))
sorry my bad, it should be {_:target_usa_ 680 _:target_lpi nil_}
{_:target_enroll_ 680 _:target_date nil_}
you can do the same thing with if statements, i don't see clojure being a barrier in this case, other than if statements returning something (some languages don't do that)
I Tried When and it was returning nil, I will try with if
so should I try with if or try the clojure-spec route
i think if you are having trouble with basic control flow, do not approach a validation library
okay, I will go with if control flow
any validation library is going to give you a few extra layers of stuff to debug, and they are usually very unfriendly for troubleshooting
thanks much Paul, it was a good discussion for me
i think i wrote expands into this
(let [G__93269 query
G__93269 (if (and target_enroll target_usa)
(-> G__93269 (set-fields {:target_enroll target_usa}))
G__93269)]
(if (and target_id target_date)
(-> G__93269 (set-fields {:target_lpi (str-to-date target_date)}))
G__93269))
only 2 if statementscond
and cond-> cond->>
are usually a lot better to use than if or when because they are a bit more self documenting
whatever editor you are using, learn how to do macro expand, and also use the documentation lookup function. they are very useful
sure thing
clojure functions/macros have some name issues and i find myself looking at the docs a lot, even after ~10 years of programming in clojure
https://clojuredocs.org/ this is a useful resource as well
I just started Clojure last month
the examples on clojuredocs are really good. https://practical.li/clojure/ is a more tutorial focused site.
great