<commit_before>(ns taoensso.carmine "Clojure Redis client & message queue."
  {:author "<NAME>"}
  (:refer-clojure :exclude [time get set key keys type sync sort eval])
  (:require [clojure.string :as str]
            [taoensso.encore      :as encore]
            [taoensso.timbre      :as timbre]
            [taoensso.nippy.tools :as nippy-tools]
            [taoensso.carmine
             (protocol    :as protocol)
             (connections :as conns)
             (commands    :as commands)]))

;;;; Connections

(encore/defalias with-replies protocol/with-replies)

(defmacro wcar
  "Evaluates body in the context of a thread-bound pooled connection to Redis
  server. Sends Redis commands to server as pipeline and returns the server's
  response. Releases connection back to pool when done.

  `conn-opts` arg is a map with connection pool and spec options:
    {:pool {} :spec {:host \"127.0.0.1\" :port 6379}} ; Default
    {:pool {} :spec {:uri \"redis://redistogo:pass@panga.redistogo.com:9475/\"}}
    {:pool {} :spec {:host \"127.0.0.1\" :port 6379
                     :password \"<PASSWORD>\"
                     :timeout-ms 6000
                     :db 3}}

  A `nil` or `{}` `conn-opts` will use defaults. A `:none` pool can be used
  to skip connection pooling. For other pool options, Ref. http://goo.gl/EiTbn."
  {:arglists '([conn-opts :as-pipeline & body] [conn-opts & body])}
  [conn-opts & [s1 & sn :as sigs]]
  `(let [[pool# conn#] (conns/pooled-conn ~conn-opts)

         ;; To support `wcar` nesting with req planning, we mimmick
         ;; `with-replies` stashing logic here to simulate immediate writes:
         ?stashed-replies#
         (when protocol/*context*
           (protocol/execute-requests :get-replies :as-pipeline))]

     (try
       (let [response# (protocol/with-context conn#
                         (protocol/with-replies* ~@sigs))]
         (conns/release-conn pool# conn#)
         response#)

       (catch Exception e#
         (conns/release-conn pool# conn# e#) (throw e#))

       ;; Restore any stashed replies to preexisting context:
       (finally
         (when ?stashed-replies#
           (parse nil ; Already parsed on stashing
             (mapv return ?stashed-replies#)))))))

(comment
  (wcar {} (ping) "not-a-Redis-command" (ping))
  (with-open [p (conns/conn-pool {})] (wcar {:pool p} (ping) (ping)))
  (wcar {} (ping))
  (wcar {} :as-pipeline (ping))

  (wcar {} (echo 1) (println (with-replies (ping))) (echo 2))
  (wcar {} (echo 1) (println (with-replies :as-pipeline (ping))) (echo 2)))

;;;; Misc

;;; Similar to encore/as-<x> but throw on non-nil unparseables:
(defn as-int   [x] (when x (if (number? x) (long   x) (Long/parseLong     x))))
(defn as-float [x] (when x (if (number? x) (double x) (Double/parseDouble x))))
(defn as-bool  [x] (when x
                     (cond (or (true? x) (false? x))            x
                           (or (= x "false") (= x "0") (= x 0)) false
                           (or (= x "true")  (= x "1") (= x 1)) true
                           :else (throw (Exception.
                                         (format "Couldn't coerce as bool: %s" x))))))

(encore/defalias parse       protocol/parse)
(encore/defalias parser-comp protocol/parser-comp)

(defmacro parse-int     [& body] `(parse as-int    ~@body))
(defmacro parse-float   [& body] `(parse as-float  ~@body))
(defmacro parse-bool    [& body] `(parse as-bool   ~@body))
(defmacro parse-keyword [& body] `(parse keyword   ~@body))

(encore/defalias parse-raw   protocol/parse-raw)
(encore/defalias parse-nippy protocol/parse-nippy)
(encore/defalias as-map      encore/as-map)

(defmacro parse-map [form & [kf vf]] `(parse #(encore/as-map % ~kf ~vf) ~form))

(defn key
  "Joins parts to form an idiomatic compound Redis key name. Suggested style:
    * \"category:subcategory:id:field\" basic form.
    * Singular category names (\"account\" rather than \"accounts\").
    * Plural _field_ names when appropriate (\"account:friends\").
    * Dashes for long names (\"email-address\" rather than \"emailAddress\", etc.)."
  [& parts] (str/join ":" (mapv #(if (keyword? %) (encore/fq-name %) (str %))
                                parts)))

(comment (key :foo/bar :baz "qux" nil 10))

(encore/defalias raw            protocol/raw)
(encore/defalias with-thaw-opts nippy-tools/with-thaw-opts)
(encore/defalias freeze         nippy-tools/wrap-for-freezing
  "Forces argument of any type (incl. keywords, simple numbers, and binary types)
  to be subject to automatic de/serialization with Nippy.")

(encore/defalias return protocol/return)<commit_msg>Migrate `as-<x>` fns to Encore utils<commit_after>(ns taoensso.carmine "Clojure Redis client & message queue."
  {:author "<NAME>"}
  (:refer-clojure :exclude [time get set key keys type sync sort eval])
  (:require [clojure.string :as str]
            [taoensso.encore      :as encore]
            [taoensso.timbre      :as timbre]
            [taoensso.nippy.tools :as nippy-tools]
            [taoensso.carmine
             (protocol    :as protocol)
             (connections :as conns)
             (commands    :as commands)]))

;;;; Connections

(encore/defalias with-replies protocol/with-replies)

(defmacro wcar
  "Evaluates body in the context of a thread-bound pooled connection to Redis
  server. Sends Redis commands to server as pipeline and returns the server's
  response. Releases connection back to pool when done.

  `conn-opts` arg is a map with connection pool and spec options:
    {:pool {} :spec {:host \"127.0.0.1\" :port 6379}} ; Default
    {:pool {} :spec {:uri \"redis://redistogo:pass@panga.redistogo.com:9475/\"}}
    {:pool {} :spec {:host \"127.0.0.1\" :port 6379
                     :password \"<PASSWORD>\"
                     :timeout-ms 6000
                     :db 3}}

  A `nil` or `{}` `conn-opts` will use defaults. A `:none` pool can be used
  to skip connection pooling. For other pool options, Ref. http://goo.gl/EiTbn."
  {:arglists '([conn-opts :as-pipeline & body] [conn-opts & body])}
  [conn-opts & [s1 & sn :as sigs]]
  `(let [[pool# conn#] (conns/pooled-conn ~conn-opts)

         ;; To support `wcar` nesting with req planning, we mimmick
         ;; `with-replies` stashing logic here to simulate immediate writes:
         ?stashed-replies#
         (when protocol/*context*
           (protocol/execute-requests :get-replies :as-pipeline))]

     (try
       (let [response# (protocol/with-context conn#
                         (protocol/with-replies* ~@sigs))]
         (conns/release-conn pool# conn#)
         response#)

       (catch Exception e#
         (conns/release-conn pool# conn# e#) (throw e#))

       ;; Restore any stashed replies to preexisting context:
       (finally
         (when ?stashed-replies#
           (parse nil ; Already parsed on stashing
             (mapv return ?stashed-replies#)))))))

(comment
  (wcar {} (ping) "not-a-Redis-command" (ping))
  (with-open [p (conns/conn-pool {})] (wcar {:pool p} (ping) (ping)))
  (wcar {} (ping))
  (wcar {} :as-pipeline (ping))

  (wcar {} (echo 1) (println (with-replies (ping))) (echo 2))
  (wcar {} (echo 1) (println (with-replies :as-pipeline (ping))) (echo 2)))

;;;; Misc

(encore/defalias as-bool     encore/as-bool  "Returns x as bool, or nil.")
(encore/defalias as-int      encore/as-int   "Returns x as integer, or nil.")
(encore/defalias as-float    encore/as-float "Returns x as float, or nil.")
(encore/defalias as-map      encore/as-map)
(encore/defalias parse       protocol/parse)
(encore/defalias parser-comp protocol/parser-comp)

;;; Note that 'parse' has different meanings in Carmine/Encore context:
(defmacro parse-int     [& body] `(parse as-int    ~@body))
(defmacro parse-float   [& body] `(parse as-float  ~@body))
(defmacro parse-bool    [& body] `(parse as-bool   ~@body))
(defmacro parse-keyword [& body] `(parse keyword   ~@body))

(encore/defalias parse-raw   protocol/parse-raw)
(encore/defalias parse-nippy protocol/parse-nippy)

(defmacro parse-map [form & [kf vf]] `(parse #(encore/as-map % ~kf ~vf) ~form))

(defn key
  "Joins parts to form an idiomatic compound Redis key name. Suggested style:
    * \"category:subcategory:id:field\" basic form.
    * Singular category names (\"account\" rather than \"accounts\").
    * Plural _field_ names when appropriate (\"account:friends\").
    * Dashes for long names (\"email-address\" rather than \"emailAddress\", etc.)."
  [& parts] (str/join ":" (mapv #(if (keyword? %) (encore/fq-name %) (str %))
                                parts)))

(comment (key :foo/bar :baz "qux" nil 10))

(encore/defalias raw            protocol/raw)
(encore/defalias with-thaw-opts nippy-tools/with-thaw-opts)
(encore/defalias freeze         nippy-tools/wrap-for-freezing
  "Forces argument of any type (incl. keywords, simple numbers, and binary types)
  to be subject to automatic de/serialization with Nippy.")

(encore/defalias return protocol/return)
{'fraction_non_alphanumeric': 0.1477399242930305, 'fraction_numerical': 0.008461367178802049, 'mean_word_length': 2.61634460547504, 'pattern_counts': {'":': 2, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 6, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4771732', 'n_tokens_mistral': 3095, 'n_tokens_neox': 2967, 'n_words': 884}