Fork me on GitHub
#beginners
<
2017-03-25
>
mbcev01:03:04

Getting a no suitable driver exception when using clojure.java.jdbc and I'm not sure why. I added the mysql maven dependency to my project structure via maven (using intelliJ + cursive). Do I need to do something with my project.clj for Lein?

noisesmith01:03:47

what matters is that the mysql dep shows up in clojure's classpath

mbcev01:03:17

I required [clojure.java.jdbc :as j]

noisesmith01:03:37

mbcev the require only works if your classpath is right

noisesmith01:03:09

mbcev the point here is that you can use your IDE to add deps - as long as deps your project defines are visible to clojure in the classpath at runtime

noisesmith01:03:32

usually, I would use lein to declare deps, and I mostly use lein as a tool for setting my project classpath

noisesmith01:03:55

but what really matters is the classpath the java process running clojure.jar sees

mbcev01:03:16

I understand the words that you're saying but I don't understand how to achieve what you're saying. I added [org.clojure/java.jdbc "0.7.0-alpha3"] to my project.clj but that's just the wrapper for JDBC right? They're saying you also need the JDBC driver you intend to use but there isn't any instruction there regarding adding that to my classpath?

noisesmith01:03:51

mbcev it's pretty simple - [organization/project version-string]

noisesmith01:03:04

you can find the mvn coordinates on maven, or via the project usually

mbcev01:03:50

oh okay, so it should be the same as what I added via cursive via maven then I assume [mysql:mysql-connector-java 6.0.6]

noisesmith01:03:14

[mysql/mysql-connector-java "5.1.6"]

noisesmith01:03:28

(that's from the last mysql project I ever set up)

noisesmith01:03:39

use the newer version string, but it needs to be a string

noisesmith01:03:46

and use / instead of :

mbcev01:03:28

wow I feel stupid; thanks...

noisesmith01:03:01

no need to feel stupid - I don't know if I ever found that documented anywhere, I just figured it out trial and error based on other project.clj entries

noisesmith01:03:31

there's probably a utility somewhere that takes a maven pom and outputs a vector for project.clj

mbcev01:03:07

Let me ask you one more question. Any preference between HoneySQL, SQLingvo and Korma?

noisesmith02:03:01

that's a personal thing, but I like hugsql https://github.com/layerware/hugsql - get input from other people though since there's a big bit of opinion in that

seancorfield02:03:35

@mbcev Just catching up on the JDBC discussion. Happy to field any further questions you have — I’m the maintainer of org.clojure/java.jdbc.

seancorfield02:03:36

We use MySQL very heavily at World Singles with java.jdbc and the HoneySQL library. We like HoneySQL when we have complex queries that are built up programmatically — because we can build query fragments and then compose them together.

seancorfield02:03:04

But a lot of people like YeSQL and HugSQL so there are several good options.

mbcev02:03:33

Thanks @seancorfield . I'm not sure if I have any obvious questions right now. Just kind of playing around right now I guess. Just trying to query my local db to see what makes sense I guess. I'm sure there are several great options but they're all the same to me since I haven't used any of them hah.

seancorfield02:03:43

My impression is that Korma is no longer maintained (since you mentioned that) but some people still like its “ORM” style approach.

mbcev02:03:09

Okay wait, so Honey outputs vectors that I can pass into jdbc/query ? Am I understanding that correctly?

seancorfield02:03:13

It builds data structures and then turns those into SQL and parameters in a vector.

seancorfield02:03:34

So you can do stuff like this:

(jdbc/query (-> application :database :pooled-db)
                (-> (cond-> (-> (select    :u.*)
                                (cross-equivalence? site)
                                (platinum?)
                                (from      [:user :u])
                                (with-primary-photo)
                                (where     [:in :u.id ids])
                                (order-by  [(apply sql/call :field :u.id ids)]))
                      (and self (site/has-covalence? site))
                      (with-covalence self))
                    (sql/format :quoting :mysql)))
and platinum? is like this
(defn platinum?
  "Given a query map over user u, add in platinum, along with the
  left join on userGroup needed for that."
  [query]
  (-> query
      (merge-select    [(sql/call :<> :ug.id nil) :platinum])
      (merge-left-join [:userGroup :ug]
                       [:and
                        [:= :ug.userid :u.id]
                        [:= :ug.groupid 2]])))

seancorfield02:03:07

with-primary-photo and with-covalence are two more query-building functions.

seancorfield02:03:16

The nice thing is that each function can contribute parts to the select, the joins, the where clause etc.

seancorfield02:03:43

(we have some really complex reporting queries that are built up from tables of metadata)

seancorfield02:03:28

One of my colleagues gave a talk at Clojure/West 2015 about how we use HoneySQL https://www.youtube.com/watch?v=alkcjyhesjI

mbcev02:03:31

Right, right. Yeah I'm thinking I'm understanding how Honey works. What's tripping me up a little right now is http://clojure.github.io/java.jdbc/ functions but I'm assuming that this is just a wrapper for Java JDBC so I need to go look up something like http://docs.oracle.com/javase/tutorial/jdbc/basics/ to better understand how and when to use what?

seancorfield02:03:11

You shouldn’t need to worry about the underlying JDBC.

seancorfield02:03:48

Clojure’s java.jdbc library provides fairly straightforward functions to insert!, delete!, and update! rows, to run querys, with [”some sql string” param1 param2] etc.

seancorfield02:03:41

You’ll probably find the community docs for java.jdbc will be helpful http://clojure-doc.org/articles/ecosystem/java_jdbc/home.html

mbcev02:03:11

ahh okay perfect, yeah this is what I needed

seancorfield02:03:19

I need to update that page (and the README) to no longer reference Korma 🙂

seancorfield02:03:43

Hopefully this example in the README will get you started with MySQL https://github.com/clojure/java.jdbc/#example-usage

seancorfield02:03:55

(I need to go help my wife with dinner)

mbcev02:03:24

No worries; I appreciate the help @seancorfield . I think I've got it from here. At least enough to get myself into trouble.

seancorfield02:03:26

I’ll be around later if you have questions. I’m a night owl!

seancorfield03:03:20

(I'm back around now, in case there are JDBC questions)

mbcev04:03:28

will I run into trouble using (= "string" "string") over (= 0 (compare "str" "str")) to evaluate two strings being equal like I would in Java?

noisesmith05:03:50

what kind of trouble is that exactly?

mbcev05:03:07

I'm referring to how in pure Java the == operator on strings is comparing by object reference not object value like .equal or .compareTo would.

noisesmith05:03:12

= in clojure is value

Alex Miller (Clojure team)12:03:06

= on strings will turn into using .equals()

Alex Miller (Clojure team)12:03:43

You can use identical? to get the equivalent of = in Java

Alex Miller (Clojure team)12:03:48

So to answer your original question - no, you won't get in trouble and you should use = in Clojure

redeu17:03:27

I've got a function to move ants randomly in a grid and I iterate over all ants to move them using this function

(defn loop-ant
  [ant-ref]
  (move-ant! ant-ref (random-direction)))
When I iterate over them with the following functions, it works as expected and all ants walk randomly every loop iteration
(defn loop-ants
  []
  (loop [ant (first ants)
         left-ants (rest ants)]
    (if (nil? ant)
      nil
      (do
        (loop-ant ant)
        (recur (first left-ants) (rest left-ants))))))
But if I call it using a map function like in the following code, the ants do nothing and I cry internally
(defn loop-ants
  []
  (map loop-ant ants))
If I use pmap instead, only some of the ants move

redeu17:03:45

Each grid cell (defining if an ant and what is present in that tile) and each ant struct are wrapped in ref if that changes anything. Anyone has an idea on what's going on?

noisesmith17:03:02

@redeu map and pmap are lazy, and do nothing if nothing consumes their results

noisesmith17:03:43

you can use run! instead of map if you don't need the value from each loop-ant call

redeu17:03:57

@noisesmith Omg I can't believe I didn't notice that. That's exactly what I needed, thank you!

noisesmith17:03:29

also, if you need to do other collection operations for side effects, two common options are to wrap in dorun (if you don't need the values) or doall (if you need them but not right away) or to use doseq (if you have a lazy operation to make the values, but want to operate on each one imperatively

redeu17:03:17

That's pretty useful to know, I haven't seen any of those functions yet

seancorfield19:03:25

It's funny... I used run! for the very first time on Thursday... to show a friend the equivalent Clojure to his JavaScript. It was very non-idiomatic for Clojure (using side-effects). Another friend had already shown him the idiomatic way without side-effects but he said that "wasn't close enough" to his original code.