Fork me on GitHub
#clojure
<
2015-12-23
>
trancehime03:12:19

i regret not building this app with cljs include, but I was new to clj when i started...

trancehime04:12:50

I have a question for yesql

trancehime05:12:47

How can I write a NULL value to the database using yesql?

jethroksy05:12:03

would that not be a database problem rather than a yesql problem?

trancehime05:12:10

@jethroksy: I have a form to submit some data which can have fields that don't always have known values

trancehime05:12:36

MySQL can have nullable integer values

trancehime06:12:04

The problem is I'm not sure how to pass a mysql "null" to the database write of yesql, which I believe uses nil

rhansen09:12:26

I used postgres with yesql, but it always worked just passing clojure nil

jethroksy10:12:12

@trancehime: sorry missed this. I also use postgres, but passing nil should work the same for mysql.

trancehime10:12:32

The problem is I get this error: java.sql.SQLException: Incorrect integer value: '' for column 'winner_id' at row 1

solicode11:12:53

@trancehime: Hmm, the error message makes it seem like empty string is being passed rather than nil

trancehime11:12:11

@solicode: Well, that's the crux of my problem. I have an input field in a form that might be left blank because the data that's supposed to go into that form might not necessarily be known at the time

trancehime11:12:48

I still would like to write the rest of the data into the database in spite of this blank form. But how do I change '' or even detect '' so I can handle it properly?

jethroksy12:12:09

@trancehime: looks like you could do some pre-parsing before you do the sql query

trancehime12:12:42

Ahhh crap. I should do the handling in the POST route, before doing the query... of course

spacepluk12:12:48

is there anything like clojurescript's js->clj for java maps?

jethroksy12:12:12

the issue here is the forms there, so you can't possibly have nil passed in... right? simple_smile

trancehime12:12:51

It's an [:input], so if it is blank, it must be an empty string

trancehime12:12:07

Well, anyway, even if I had changed the method of input to something like [:select] to force a default value, I would still need to do the pre-parsing in the POST route instead of directly in the function where I run the query. welp

solicode12:12:21

@spacepluk: You mean converting a Java map to a Clojure persistent map? Maybe into is what you're looking for? Like (into {} your-java-hash-map).

solicode12:12:49

But if you just want to call get or whatever, you can call that on Java maps and it'll work fine (stuff like assoc won't work on plain Java maps though).

spacepluk12:12:56

@solicode I need it to work on nested maps

spacepluk12:12:50

I think I'll take a look at js->clj's implementation

solicode12:12:38

Ah, I see. In that case, I’m not sure if there’s anything in the standard library

spacepluk12:12:13

it would be nice

spacepluk12:12:53

I guess nested java maps aren't that common

bronsa12:12:31

@spacepluk: if all your values are valid read-time clojure literals, you could just pr-str the java collection and read-string it back

spacepluk12:12:43

oh that might work, thanks!

trancehime12:12:40

Oh no, when I see doto I'm going to think of something entirely different from what it's supposed to be

spacepluk12:12:55

@bronsa reading would be slower than something like js->clj, right?

spacepluk12:12:49

I think I'll make a java->clj for this, but that's a very cool trick simple_smile

solicode12:12:04

@spacepluk: I think you want instance? rather than isa?

spacepluk12:12:56

@solicode thanks! I'm learning as I go simple_smile

solicode12:12:05

Also (java->clj x {:keywordize-keys false}) should probably be (java->clj x :keywordize-keys false)

solicode12:12:25

Since you use & opts

spacepluk13:12:06

I just updated the gist to something that works

solicode13:12:56

The part that iterates through the map looks strange to me. I think I would write it like this:

(into {} (for [[k v] x] 
           [(keyfn k) (thisfn v)]))

solicode13:12:36

Also, I wonder if the coll? check should go after the map check.

solicode13:12:02

A clojure map would return true for coll?

rcanepa13:12:33

Hi everyone. Is there an easy way to test a library without having to incorporate it to my project dependencies. I am only aware of leiningen based projects, so, when I want to evaluate a library, most of the times I end up creating a new project and adding all the libraries I want to evaluate as dependencies. Is there a better way to do this?

rcanepa13:12:49

Great!… thanks @stuartsierra !

spacepluk15:12:35

@solicode cool, that's better

magomimmo15:12:08

@spacepluk: or you could use #C053K90BR build tool, which allows even to add one or more deps at the REPL: boot.user=> (set-env! :dependencies #(conj % ‘[groupid/artifactid “X.Y.Z”]))

jaen16:12:01

lein has something similar as well, I think

jaen16:12:31

But it's certainly nicer to handle in boot.

rcanepa19:12:37

If I have two database tables with some content such as ProductLines and Products (a product line may contain multiple products), how can I transform a flat representation of a join to something like a JSON nested structure?. I would like to provide an API point in which a user can ask for a specific product line (e.g.: api/v1/product-line/100) and fetch its information along with all its children.

rcanepa19:12:19

Should I reduce the result from the database query?

rcanepa19:12:22

Or there is a better way to deal with this?… in the past, I worked with web frameworks that provided that functionality under the hood, so this is new ground for me.

rcanepa19:12:46

Oh… I am working with a relational database (PostgreSQL).

rcanepa19:12:25

Also, I am using schemas to shape my data, so I know very well the final structure I want.

eyelidlessness19:12:31

is there a way to attach metadata to a var which will print a warning when referenced?

stuartsierra20:12:28

@eyelidlessness: not in Clojure itself. A linting tool could maybe do it

tolitius20:12:09

@rcanepa: there is also https://github.com/pallet/alembic in case you want to try libs from within the running REPL (to get to similar #C053K90BR flexibility as @magomimmo mentioned)

pesterhazy20:12:44

@rcanepa: yes, use reduce, into etc. to transform the db rows returned into the shape you want

pesterhazy20:12:22

it's surprisingly easy once you wrap your mind around it

pesterhazy20:12:35

it's fun to work with relational databases from clojure

pesterhazy20:12:17

you may want to transform the columns to keywords for easier handling

kopasetik20:12:54

I’ve read that clojure/lisp in general is so simple in terms of its set of native functions that you can fit such a set onto a napkin. Have you experienced that?

rcanepa20:12:26

@pesterhazy: Cool, I will take that route then

rcanepa20:12:47

@tolitius: I wasn’t aware of that library, I will check it too. Thanks!

pesterhazy21:12:35

@kopasetik: yup. It takes a while to grok it (especially when to use reduce), but after it clicks any transformation is pretty simple

pesterhazy21:12:03

transforming sequences and maps is an area where clojure shines, especially given its arrow macros

jarredlhumphrey21:12:11

has anyone had issues when logging with timbre across threads? I’m using the default println appender, but I’m seeing some successive logs being conflated into one line rather than two when called within the same millisecond across threads. I was under the impression println was thread-safe?

kopasetik21:12:38

OK, how do I use the index of a value that I’m mapping across a vector?

pesterhazy21:12:39

@jarredlhumphrey: it's thread-safe in that it won't crash, but I don't see how it could guarantee that lines don't get mixed up

stuartsierra21:12:47

println is not thread-safe

pesterhazy21:12:46

I think you'll see the same problem when using .write directly from java (or printf in C programs)

kopasetik21:12:50

Basically, I want to do [1, 2, 3].map(function(element, index){ return index;}) but in Clojure

jarredlhumphrey21:12:16

@stuartsierra @pesterhazy any suggestions on an appender or method thats thread-safe?

stuartsierra21:12:44

Use a real logging framework instead of println.

solicode21:12:13

Ah, but you’re using Timbre.

solicode21:12:38

You can customize the fn though, right? If so, this should still work

kopasetik21:12:58

And…now I have to write a power function from scratch. Yay?

jarredlhumphrey21:12:59

@solicode: I tried that with a custom appender as such:

jarredlhumphrey21:12:00

:appenders
   {:standard-out
    {:doc "Prints to *out*/*err*. Enabled by default."
     :min-level nil
     :enabled? true
     :async? false
     :rate-limit nil
     :fn (fn [{:keys [error? output]}] ; Use any appender args
           (binding [*out* (if error? *err* *out*)]
             (.write *out* (str output "\n"))))}}

jarredlhumphrey21:12:41

but still no luck.. still the same conflation

kopasetik21:12:09

Not sure whether I can use the Math library for this code challenge

kopasetik21:12:44

OK, had to coerce it to be an integer

pesterhazy21:12:03

you're welcome simple_smile

jaen21:12:52

@kopasetik: Power function is pretty easy to write, though. For example you could do

(defn pow [x y]
  (reduce * (take y (repeat x))))

jaen21:12:22

This has the advantage it works with arbitrary precision numbers Clojure has as well.

jaen21:12:28

Java maths function won't.

kopasetik22:12:07

OK, trying to figure out how take works… it seems like a loop and i thought that was counter to functional programming?

pesterhazy22:12:21

@solicode: you'll eventually need to use a Java library that logs to slf4j or logback or whatever, so this might be a good time to add logback (it too can log to stdout/stderr)

jaen22:12:19

@kopasetik: it's pretty easy, look

jaen22:12:33

(reapeat 2) will create an infinite sequence of 2s

jaen22:12:40

so, (2 2 2 2 2 2 2 2 2 ...)

jaen22:12:48

If you wanted to display that in your REPL

jaen22:12:01

it will loop infinitely, because you can't really display an infinite list

jaen22:12:21

Takes a number of elements from a sequence

jaen22:12:23

So for example

jaen22:12:45

(take 2 [1 2 3 4]) results in (1 2)

jaen22:12:07

(take 4 [5 6 7 8 9 10 11]) will result in (5 6 7 8) and so on.

jaen22:12:16

so we basically infinitely repeat our base

jaen22:12:47

then take as many elements of that sequence as our exponent signifies.

jaen22:12:58

So for (pow 2 4)

jaen22:12:04

we have an infinite sequence of 2s

jaen22:12:09

And we take 4 elements from that

jaen22:12:20

we have (2 2 2 2)

jaen22:12:40

And with reduce we just multiply those numbers by themselves in sequence.

jaen22:12:48

Which implements the definition of exponentiation.

jaen22:12:53

Does it make any sense?

sveri22:12:08

I have an atom containing a seq. Now, what I want to do is update every element in the seq inside the atom like this [1 2 3 4] -> [2 3 4 5]. So, I need a function that gives me the whole seq inside the atom, maps over it and updates the atom. All this should happen as one transaction. So first getting the vec, than updating and resetting the atom is not an option. I need swap!. But which function combines with swap gives me the whole seq and replaces it then?

kopasetik22:12:52

@jaen: Yes, it makes sense simple_smile

sveri22:12:15

Ah, I think my question is nonsense, I can write my own function, right?

kopasetik22:12:26

Just wondering why take returns a list instead of a vector

jaen22:12:38

@kopasetik: it doesn't return a list, exactly.

jaen22:12:42

It returns a sequence

jaen22:12:46

Which so it happens

sveri22:12:50

ok, everyone forget my question -.-

jaen22:12:55

Is printed as a list in the repl

jaen22:12:23

@kopasetik:

boot.user=> (class (take 2 [1 2 3 4]))
clojure.lang.LazySeq

pesterhazy22:12:28

@kopasetik: for most purposes, you don't need to care if a function's result is a sequence, a list or a vector

jaen22:12:58

You can think of sequences as hmm... if you're familiar with generators it could be an analogy.

jaen22:12:09

It's something that produces a sequence of elements when iterated.

jaen22:12:32

And so it happens like other languages have iterators, Clojure has sequences as the ubiquitous iteration protocol.

solicode22:12:53

@jarredlhumphrey: Sorry, back to your issue. I just tried this (followed the example on Timbre's project page) and it worked for me:

:appenders {:example-println-appender
             {:enabled?   true
              :async?     false
              :min-level  nil
              :rate-limit nil
              :output-fn  :inherit
              :fn         (fn [data]
                            (let [{:keys [output-fn]} data
                                  formatted-output-str (output-fn data)]
                              (print (str formatted-output-str "\n"))))}}

jaen22:12:25

@kopasetik: So in general Clojure likes dealing with sequences - map returns a sequence transformed by a function, reduce reduces a sequence to one value, filter returns a sequence only with elements that match a given predicate, take returns n-first elements of a sequence and so on. If you decide to pick up "Programming Clojure" it's all rather very nicely introduced there.

jaen22:12:19

So basically if you decide to transform something you'll get a sequence out of that, in general it won't preserve the type of sequence (as an implementation detail different types of collection have different underlying sequences, I think, but like I said - implementation detail). If you for some reason need a specific type of a collection there's into - (into {} [[:a 1] [:b 2]]) will return {:a 1 :b 2} and (into [] (map #(* % 2) [1 2 3])) will give you [2 4 6].

jaen22:12:43

(in general into takes a sequence and constructs a collection out of it's elements).

kopasetik22:12:58

@jaen: Really informative. Thanks! 😄

jaen22:12:03

No problem

anmonteiro23:12:41

I can't believe I haven't run in this doubt before, but: is it possible to reference a key in a map at definition time? e.g. (def x {:a 1 :b (inc (:a x))})

anmonteiro23:12:33

I mean, the above example doesn't work, but I was wondering if it would be possible to make it work without defining x first and then merging :b or something like that

jr23:12:11

if you know the value of a then (def x (let [a 1] {:a a :b (inc a)}))

anmonteiro23:12:35

@jr: that will obviously work, thx, will use that for now, but was looking for a less verbose alternative

kopasetik23:12:16

But I get an error here...

jaen23:12:22

Try using Big Integers then, maybe?

jaen23:12:31

1N is a big integer.

jaen23:12:55

There's also a (bigint 1) function

kopasetik23:12:05

Yes! That made it work! Thanks simple_smile

kopasetik23:12:15

It took me half a day to solve that in Clojure… 😮

mheld23:12:41

how do y’all feel about boot vs lein?