Skip to content

Instantly share code, notes, and snippets.

@mpenet
Created May 12, 2014 16:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mpenet/23fd53aabc853eb7e565 to your computer and use it in GitHub Desktop.
Save mpenet/23fd53aabc853eb7e565 to your computer and use it in GitHub Desktop.
(ns qbits.alia.codec
(:require [clojure.core.typed :as T])
(:import
(java.nio ByteBuffer)
(com.datastax.driver.core
DataType
DataType$Name
ResultSet
Row)))
(defmacro make-decoders [row idx col-type & specs]
(reduce (fn [m [decoder-type# form#]]
(assoc m
decoder-type#
`(fn [~(vary-meta row assoc :tag "com.datastax.driver.core.Row")
~(vary-meta idx assoc :tag "java.lang.Integer")
~(vary-meta col-type assoc :tag "com.datastax.driver.core.DataType")]
~form#)))
{}
(partition 2 specs)))
(defn ^Class types-args->type
[^"[Lcom.datastax.driver.core.DataType;" type-args pred]
(.asJavaClass ^DataType (pred type-args)))
(def decoders
(make-decoders row idx col-type
DataType$Name/ASCII (.getString row idx)
DataType$Name/BIGINT (.getLong row idx)
DataType$Name/BLOB (.getBytes row idx)
DataType$Name/BOOLEAN (.getBool row idx)
DataType$Name/COUNTER (.getLong row idx)
DataType$Name/CUSTOM (.getBytesUnsafe row idx)
DataType$Name/DECIMAL (.getDecimal row idx)
DataType$Name/DOUBLE (.getDouble row idx)
DataType$Name/FLOAT (.getFloat row idx)
DataType$Name/INET (.getInet row idx)
DataType$Name/INT (.getInt row idx)
DataType$Name/TEXT (.getString row idx)
DataType$Name/TIMESTAMP (.getDate row idx)
DataType$Name/TIMEUUID (.getUUID row idx)
DataType$Name/UUID (.getUUID row idx)
DataType$Name/VARCHAR (.getString row idx)
DataType$Name/VARINT (.getVarint row idx)
DataType$Name/LIST (seq (.getList row idx (types-args->type (.getTypeArguments col-type) first)))
DataType$Name/SET (into #{} (.getSet row idx (types-args->type (.getTypeArguments col-type) first)))
DataType$Name/MAP (let [t (.getTypeArguments col-type)]
(into {} (.getMap row idx
(types-args->type t first)
(types-args->type t second))))))
(defn decode
[^Row row ^Integer idx ^DataType col-type]
((decoders (.getName col-type)) row idx col-type))
(T/ann encode [Any -> Any])
;; only used for prepared statements
(T/defprotocol> PCodec
(encode [x]
"Encodes clj value into a valid cassandra value for prepared
statements (usefull for external libs such as joda time)"))
(T/tc-ignore
(extend-protocol PCodec
(Class/forName "[B")
(encode [x] (ByteBuffer/wrap x))
Object
(encode [x] x)
nil
(encode [x] x)))
(defn result-set->maps
[^ResultSet result-set string-keys?]
(let [key-fn (if string-keys? identity keyword)]
(-> (map (fn [^Row row]
(let [cdef (.getColumnDefinitions row)
len (.size cdef)]
(loop [idx (int 0)
row-map (transient {})]
(if (= idx len)
(persistent! row-map)
(recur (unchecked-inc-int idx)
(assoc! row-map
(key-fn (.getName cdef idx))
(decode row idx (.getType cdef idx))))))))
result-set)
(vary-meta assoc :execution-info (.getExecutionInfo result-set)))))
@mpenet
Copy link
Author

mpenet commented May 12, 2014

user=> (clojure.repl/pst)
ExceptionInfo Class not found: (Class/forName "[B") {:file "qbits/alia/codec.clj", :column 13, :line 68, :class (Class/forName "[B"), :ast {:name x__#0, :op :binding, :env {:line 68, :column 13, :internal-name "fn__3329", :file "qbits/alia/codec.clj", :once false, :context :expr, :ns qbits.alia.codec}, :o-tag (Class/forName "[B"), :variadic? false, :arg-id 0, :form x, :tag (Class/forName "[B"), :local :arg}}
clojure.core/ex-info (core.clj:4403)
clojure.tools.analyzer.passes.jvm.validate/validate (validate.clj:236)
clojure.tools.analyzer.jvm/run-passes/analyze--13492/fn--13493 (jvm.clj:416)
clojure.tools.analyzer.ast/walk (ast.clj:68)
clojure.tools.analyzer.ast/walk/walk--12055 (ast.clj:67)
clojure.core/mapv/fn--6311 (core.clj:6353)
clojure.lang.ArrayChunk.reduce (ArrayChunk.java:58)
clojure.core.protocols/fn--6093 (protocols.clj:98)
clojure.core.protocols/fn--6057/G--6052--6066 (protocols.clj:19)
clojure.core.protocols/seq-reduce (protocols.clj:31)
clojure.core.protocols/fn--6076 (protocols.clj:60)
clojure.core.protocols/fn--6031/G--6026--6044 (protocols.clj:13)
nil
user=>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment