Strange behavior in carmine (clojure-redis client) - clojure

Consider this snippet in carmine
(wcar* (car/set "counter" 1) ;; expect to be number counter=1
(let [id (car/get "counter")] ;; expect to have id=1
(println id))) ;; [nil [[SET counter 1] [GET counter]]]
What I am doing wrong here? Is there a way to use let inside wcar* macro?

You can nest wcar forms which gives you access to the return values inside wcar:
(wcar*
(car/set "counter" 1)
(let [id (wcar*
(car/get "counter"))]
(println id)
id))

Related

Ways of accessing nested map values in Clojure?

I am currently using the two following blocks of code to access nested values in ClojureScript:
(def response (re-frame/subscribe [::subs/quote]))
(def body (:body #response))
(def value (:value body))
(println value)
(def result (-> #(re-frame/subscribe [::subs/quote]) :body :value))
(println result)
(def lol (get-in #(re-frame/subscribe [::subs/quote]) [:body :value]))
(println lol)
Are there any better / more succinct ways of doing this?
Keys can be used as operators to retrieve its value like so:
(def lol (:value (:body #(re-frame/subscribe [::subs/quote]))))
(println lol)
However, I prefer the verbose way using a function as get-in

Clojure if ( X and Y )?

The following code does not run as I am expecting. I want to be able to identify if foo and bar are empty and respond with an err accordingly else output "hello". However response only occurs when both foo and bar are present.
I'm new to Clojure and so probably missing something.
(defn create-entry [doc]
(let [id (str (java.util.UUID/randomUUID)) timestamp (quot (System/currentTimeMillis) 1000)]
(let [entry (assoc doc "id" id "timestamp" timestamp)]
(if (and (empty? [(get entry "foo") (empty? (get entry "bar")) ])
(response {:err "either foo or bar is required"})
) (prn "hello!")))))
You have some weird bracing issues going on. You stick both calls to get inside a vector, then check if that hard coded vector is empty.
I think you meant for your condition to be something more like:
(and (empty? (get entry "foo"))
(empty? (get entry "bar")))
I know this has been answered, but I thought I would add something here too. This could be better by splitting this up into two functions, one predicate, and call that from your create-entry function.
(defn entry? [entry]
(let [foo (get entry "foo")
bar (get entry "bar")]
(and (some? foo)
(some? bar))))
(defn create-entry [doc]
(let [id (str (UUID/randomUUID)) timestamp (quot (System/currentTimeMillis) 1000)]
(let [entry (assoc doc "id" id "timestamp" timestamp)]
(if (entry? entry)
(prn "hello!")
(response {:err "either foo or bar is required"})))))

how to avoid nesting in clojure

when my write a function to check a user can delete a post by clojure,I get this
(defn delete!
{:arglists}
[^String id]
(if (valid-number? id)
(let [result {:code 200 :status "error" :messag "delete success"}]
(if-let [user (session/get :userid)]
(if-let [post (pdb/id id)]
(if (= user (post :user_id))
(do
(pdb/delete! (Long/valueOf id))
(assoc result :status "ok"))
(assoc result :message (emsg :not-own)))
(assoc result :message (emsg :post-id-error))))
(assoc result :message (emsg :not-login)))))
so i want to fix it,i get this
https://github.com/4clojure/4clojure/blob/develop/src/foreclojure/register.clj#L27
https://github.com/4clojure/4clojure/blob/develop/src/foreclojure/utils.clj#L32
but it is line,but not a nest.
the delete! function is nest ugly and it is very hard to understand it,how to write a macro to avoid the nesting a lot.or other way to avoid it.
This doesn't need a macro. I guess cond is a macro, but it is the only one we need to make this code readable.
(defn delete!
;; {:arglists} ; this line will not compile
[^String id]
(let [result {:code 200 :status "error" :message "delete success"}
user (session/get :userid)
post (and user (valid-number? id) (pbd/id id))]
(cond
(not user)
(assoc result :message (emsg :not-login))
(not post)
(assoc result :message (emsg :post-id-error))
(not= user (:user_id post))
(assoc result :message (emsg :not-own))
:else
(do
(pdb/delete! (Long/valueOf id))
(assoc result :status "ok")))))
This is something a lot of people run into, so don't feel bad.
Check out this blog by Christophe Grand, which I think is a pretty nice (and concise!) solution.
Edit: you only need something fancy like this (or alternatively the version using delay in this other post) if you need to short-circuit execution like the original - otherwise noisesmith's answer is the way to go.
Here's how you could do this sort of thing with the Either monad -- I'm sure there are libraries for it already but I'll implement it here for completeness. (Note: this code hasn't been validated.)
(defn success? [v]
(contains? v :success))
(defn inject [v]
{:success v})
(defn bind [v f]
(if (success? v)
(apply f (:success v))
v))
(defmacro >>= [v & body]
(let [binds (map #(list 'bind %) body)]
`(-> ~v ~#binds)))
(defn delete!
{:arglists}
[^String id]
(if (valid-number? id)
(let [result {:code 200 :status "error" :message "delete success"}
check
(>>= (inject {:id id})
#(if-let [user (session/get :userid)]
{:success (assoc % :user user)}
(:failure (assoc result :message (emsg :not-login))))
#(if-let [post (pdb/id (:id %))]
{:success (assoc % :post post)}
{:failure (assoc result :message (emsg :post-id-error))})
#(if (= (:user %) ((:post %) :user_id))
{:success %}
{:failure (assoc result :message (emsg :not-own))}))]
(if (success? check)
(do
(pdb/delete! (Long/valueOf id))
(assoc result :status "ok"))
(:failure check)))))
The >>= macro works like the -> macro (obviously, since it uses it), but if any of the functions return a {:failure ...} then the chain short-circuits (thanks to bind) and the failure value of the function that failed becomes the value returned by >>=.
Edit
I should note that the function I have named inject is actually called return, but I decided to name it inject here since that's more along the lines of what it does in this monad.

clojure: dynamically compose query with korma

I am trying to create a very simple API with korma
Users can query a database like so:
localhost:8080/my_postgres_db/users.json?where[age]=50&limit=1
Currently I am getting an error when trying to apply a where clause to an existing, composable, query.
clojure.lang.ArityException: Wrong number of args (2) passed to: core$where
The code in question:
(defn- comp-query [q [func arg]]
(let [sql-fn (ns-resolve 'korma.core (-> func name symbol))]
(sql-fn q arg)))
(defn compose-query [table col]
(reduce comp-query (select* table) col))
Usage:
(def clauses {:where {:column1 10} :fields "a,b" :limit 10 :offset 500})
(-> (compose-query table clauses) select)
Everything behaves as expected, except for where clauses. I can combine limit, offset and fields in any way I choose and I get the expected results. Only when I have a :where key in my map do I run into the error.
Am I attempting something I shouldn't? Is this bad clojure? Any help would be appreciated.
Note: I have read this SO question
Edit: from lein repl I can manually compose a query in the same fashion and it works
(where (select* "my_table") {:a 5})
Edit:
If I modify my compose-query function to this:
(defn compose-query [table col]
; remove where clause to process seperately
(let [base (reduce comp-query (select* table) (dissoc col :where))]
(if-let [where-clause (:where col)]
(-> base (where where-clause))
base)))
Everything works as expected.
The problem here is that korma.core/where is not a function and needs to be handled specially. Where can't be implemented as a function and still correctly handle things like (where query (or (= :hits 1) (> :hits 5)))
You can use where* function as you are using select*.
Just make your clause map like:
(def clauses {:where* {:column1 10} :fields "a,b" :limit 10 :offset 500})
Just a hunch; expanding some of the threading macros makes it a little hard to see if they are correct:
core> (macroexpand-1 '(-> (compose-query table clauses) select))
(select (compose-query table clauses))
core> (macroexpand-1 '(-> func name symbol))
(clojure.core/-> (clojure.core/-> func name) symbol)
core> (macroexpand-1 '(clojure.core/-> func name))
(name func)
Passing func to name looks suspicious.

URL Checker in Clojure?

I have a URL checker that I use in Perl. I was wondering how something like this would be done in Clojure. I have a file with thousands of URLs and I'd like the output file to contain the URL (minus http://, https://) and a simple :1 for valid and :0 for false. Ideally, I could check each site concurrently, considering that this is one of Clojure's strengths.
Input
http://www.google.com
http://www.cnn.com
http://www.msnbc.com
http://www.abadurlisnotgood.com
Output
www.google.com:1
www.cnn.com:1
www.msnbc.com:1
www.abadurlisnotgood.com:0
I assume by "valid URL" you mean HTTP response 200. This might work. It requires clojure-contrib. Change map to pmap to attempt to make it parallel, like Arthur Ulfeldt mentioned.
(use '(clojure.contrib duck-streams
java-utils
str-utils))
(import '(java.net URL
URLConnection
HttpURLConnection
UnknownHostException))
(defn check-url [url]
(str (re-sub #"^(?i)http:/+" "" url)
":"
(try
(let [c (cast HttpURLConnection
(.openConnection (URL. url)))]
(if (= 200 (.getResponseCode c))
1
0))
(catch UnknownHostException _
0))))
(defn check-urls-from-file [filename]
(doseq [line (map check-url
(read-lines (as-file filename)))]
(println line)))
Given your example as input:
user> (check-urls-from-file "urls.txt")
www.google.com:1
www.cnn.com:1
www.msnbc.com:1
www.abadurlisnotgood.com:0
Write a small function that appends a ":1" or ":0" to a url and then use pmap to apply it in parallel to all the urls.
(defn check-a-url [url] .... )
(pmap #(if (check-a-url %) (str url ":1") (str url ":0")))
Clojure now has a as-url function in clojure.java.io:
(as-url "http://google.com") ;;=> #object[java.net.URL 0x5dedf9bd "http://google.com"]
(str (as-url "http://google.com")) ;;=> "http://google.com"
(as-url "notanurl") ;; java.net.MalformedURLException
Based on that we could write a function like so:
(defn check-url
"checks if the url is well formed"
[url]
(str (clojure.string/replace-first url #"(http://|https://)" "")
":"
(try (as-url url) ;; built-in, does not perform an actual request, and does very little validation
1
(catch Exception e 0))))
(defn check-urls-from-file
"from Brian Carper answer"
[filename]
(doseq [line (map check-url (read-lines (as-file filename)))]
(println line)))
Instead of pmap, I used agents with send-off in conjunction with the above solution. I think this is better when there is blocking I/O. I believe pmap has limited concurrency too. Here's what I have so far. I wonder how this will scale with thousands of URLs.
(use '(clojure.contrib duck-streams
java-utils
str-utils))
(import '(java.net URL
URLConnection
HttpURLConnection
UnknownHostException))
(defn check-url [url]
(str (re-sub #"^(?i)http:/+" "" url)
":"
(try
(let [c (cast HttpURLConnection
(.openConnection (URL. url)))]
(if (= 200 (.getResponseCode c))
1
0))
(catch UnknownHostException _
0))))
(def urls (read-lines "urls.txt"))
(def agents (for [url urls] (agent url)))
(doseq [agent agents]
(send-off agent check-url))
(apply await agents)
(def x '())
(doseq [url (filter deref agents)]
(def x (cons #url x)))
(prn x)
(shutdown-agents)