Fork me on GitHub
#beginners
<
2021-12-06
>
mateus.henrique.brum01:12:55

Hi guys, I have a doubt here. I started to study next.jdbc awesome library (thanks @seancorfield). Unfortunately, I was not able to disable auto-commit, according to the manual, it is something like this.

(require '[next.jdbc :as jdbc])

(def mdb {:dbtype "mysql" :dbname "silly" :user "root" :password "root" :auto-commit false})

(def mds (jdbc/get-connection mdb))

(jdbc/with-transaction [tx mds]
                       (jdbc/execute-one! tx ["insert into address (name, email) values('Caoimhe','')"]))  
But the result is still there without any explicit commit (.commit tx) Thanks everyone …

seancorfield03:12:46

@mbrum FYI, there's a dedicated #sql channel for all SQL/JDBC stuff for the future. I'm not entirely sure what you're asking: a transaction is, by definition, auto-commit unless you explicitly say it should be :rollback-only true per the docs https://cljdoc.org/d/com.github.seancorfield/next.jdbc/1.2.753/api/next.jdbc#with-transaction

seancorfield03:12:32

You generally do not want to run with-transaction on a connection: you would normally run it on a datasource (and let it manage the connection for you) and use a connection-pooled datasource.

seancorfield03:12:03

Inside with-transaction, if you throw an exception, the TX will rollback, otherwise it will commit (per the docs). If you start with a connection that is set to :auto-commit false, it will be reset to :auto-commit false after the TX completes, but the whole point of with-transaction is to set up a committable TX on a connection (either the one you provided, or one it creates for you from a datasource).

mateus.henrique.brum10:12:20

Hello Sean, thank you so much for your reply, it is much clear now, I just started to study it and bumped into something that is not completely clear, as I told you, by the docs (as I have understood it) it should not have committed this transaction…. Thanks..

zackteo07:12:25

Hello, at the start of a file, at (ns ... is there a particular reason why one might use :use instead of :require ? Would there be a reason to (:use midje.sweet rather than :require it?

Benjamin08:12:13

it is bad style to use because it undermines some benefits of strong names. It can be helpful when exploring at the repl but frankly I like to just say (:require [midje.sweet :as ms]) and type ms/...

zackteo09:12:26

By undermine benefits, you mean cause it does the equivalent of refer? So the namespace is not reflected?

dorab17:12:20

Also, consider what happens if there is a function called foo that is in two namespaces that are both required using :use ?

zackteo02:12:02

Is use equivalent to refer all btw?

zackteo02:12:59

Am asking this question on use because I am working on a codebase with :use and was trying to make sure it makes sense to convert it to :require

dorab16:12:59

Not sure what you mean by "equivalent". Both :use and :require will require/load the namespace. In addition, :use will also bind the public vars of the loaded namespace into the namespace being loaded into. In general, you can "convert" (ns my.lib (:use sub.lib)) to (ns my.lib (:require [sub.lib :as sub])) and then replace all implicitly bound vars from sub.lib (say foo) by sub/foo.

👍 1
GGfpc12:12:30

Hey! In clojure spec, when I define a spec with an (spec/or ::spec-a ::spec-b), is the generator supposed to always generate the second type in the list? I would like it to be random

pavlosmelissinos12:12:35

That's not how s/or works. You need to define pairs of "path name" and spec. So e.g. when you conform some data, spec will tell you which path was followed Check out the docstring

pavlosmelissinos12:12:55

So you'd have to write something like (s/or :path1 ::spec-a :path2 ::spec-b) to get what you want

Sebastian14:12:14

I have a function that uses filter and returns a lazy sequence. I don't want a lazy sequence, so I've used filtervto return a vector instead. Now I've stumbled upon 'doall'. It solves the same problem, but i was wondering if one way is better than the other?

Sebastian14:12:30

I am mostly wondering if doall provides better performance, since it wont have to copy over all the elements, but just basically walk through the sequence retaining/returning the heads

alexmiller14:12:15

the best way is actually to use (into [] (filter f) coll)

alexmiller14:12:32

but as to your actual question, filterv will be better from a memory use pov and probably better for perf as vectors are more efficient than lazy seqs.

Sebastian14:12:00

Thank you! I thought that (into [] (filter f) coll) was basically how filterv behaved?

alexmiller15:12:19

similar result, totally different impl

jumar16:12:22

@U064X3EF3 do you mind expanding on why the transducer version is "the best way"?

alexmiller16:12:48

transducers are a general way to separate the input source from the transformation from the output collection. so they serve the same goal, but are much more general - you can compose multiple transducer transformations in the into and it will still be a single pass over the input to realize the result

👀 1
alexmiller16:12:05

if transducers had been invented first, filterv would never have been added

jumar16:12:28

Thanks, so I read this as it's not necessarily better in terms of performance but better for composition and reusability

alexmiller17:12:05

yep. performance wise for this particular thing, they are both essentially a reduce from vector to transient vector so perf should be essentially the same.

Ben List15:12:41

Is there a fn like iterate that works for any arbitrary (f x). I know I can use reductions over and infinate range and just toss the collection but wasnt sure if there was a builtin for that eg: (defn iterate* [f x] (reductions (fn [dx _] (f dx)) x (range)))

delaguardo16:12:33

(defn iterate [f x] (lazy-seq (let [res (f x)] (cons res (iterate f res)))))

👍 1
Ben List16:12:00

I think that only works with functions without arguments

Ben List16:12:12

I want to apply the result of each call to the next lazily and infinately

Cora (she/her)16:12:41

I don't know then 😞

pranav.g16:12:05

What is a good way to update the value of a vector at a specific index? I know update function can be used to make update to a specific index position of a vector as well. But update is defined for maps and using it for vector doesn't seem idiomatic. Wdyt?

tschady16:12:09

seems idiomatic to me

alexmiller16:12:22

you can assoc at the index

pranav.g17:12:43

Yes. I was just curious if it is somehow discouraged to use map specific functions on vectors. For my case update works well because I need to use the existing value to derive the new value.

pranav.g17:12:46

I guess as long as it works, it's not a big deal then. Thanks.

sheluchin17:12:02

Is there a way I can check what methods are available on a Java object instance in my REPL?

sheluchin17:12:46

Beauty. Thanks!

👍 1
Sean Sanker18:12:33

Hi Everyone! Does anyone know why I can't get the source for this function? I don't believe the token is invalid? repl usage:

user=> (repl/source-fn 'example.namespace/example-function)
Execution error at user/eval105226 (form-init17088966657071738526.clj:1).
Invalid token: ::feature/example-feature
function definition:
(defn example-function
  [{:keys [user]}]
  (-> (user/if-feature-available
        user
        ::feature/example-feature)
      (account/save!)))
Maybe relevant? https://clojure.atlassian.net/browse/CLJ-2359 https://groups.google.com/g/clojure/c/zNi79W95vWk Thank you!

ghadi18:12:53

correct, you're running into that issue the token is valid, it's just being read in a context that doesn't have access to the alias map to resolve feature

Sean Sanker18:12:06

Ah so would the workaround be to make feature available in the namespace that I'm calling source-fn from? Is there a way to get the function source raw without trying to parse it out (thus avoiding trying to read the token)?

ghadi18:12:41

the source reading stuff is dumb and just reads forms without code evaluation

ghadi18:12:08

you need to read and understand the ns of the file containing the source to be able to accurately resolve aliased keywords

❤️ 1
Sean Sanker18:12:26

Thank you so much! I'll look into it.

ghadi18:12:48

keep in mind an autoresolved keyword ::a/bcd has no programmatic representation (at least not in Clojure's reader)

❤️ 1
ghadi18:12:03

they are fully resolved by the time they leave the reader

❤️ 1
ghadi18:12:24

so if something has a code form with fully resolved keywords, what should the source fn print?

❤️ 1
rfisher23:12:57

Doing Advent of Code, I find a lot of my functions use loop/recur , and they feel like more work and more mental effort than they ought to. Is loop generally considered a "last resort"? Does idiomatic Clojure do a lot of looping? How about recursive functions? I get the feeling things like map and filter are more powerful than I currently realise, and I keep hearing mutterings about transducers. It's easy to look up the grammar and API of a language, but harder and IMO more important, to get a handle on idiomatic usage. Any pointers, or am I asking too broad a question?