[英]How do I read bool columns from SQLite into bool Clojure values with next.jdbc? SQLite stores booleans as 0/1
这是查看问题的最小代码。
(require '[next.jdbc :as jdbc])
(def db-spec {:dbtype "sqlite" :dbname "example-db"})
(jdbc/execute!
db-spec
["create table if not exists users (name text, is_active bool)"])
(jdbc/execute!
db-spec
["insert into users (name, is_active) values (?, ?)" "alice" true])
(jdbc/execute!
db-spec
["select * from users"])
;; => [#:users{:name "alice", :is_active 1}]
我希望最后一行的is_active
为true
或false
。 我不希望我的应用程序代码必须跟踪哪些列是 bool 并在获得结果集后进行转换。
next.jdbc
为您提供了几种方法来插入它如何从数据库值创建 Clojure 对象。 其中最通用的是通过:builder-fn
选项传递一个从builder-adapter
创建的值,并传递您自己的(或现有的)构建器和自定义的“read-column-by-index”
(require '[next.jdbc.result-set :as rs])
(defn sqlite-column-by-index-fn [builder ^ResultSet rs ^Integer i]
(let [rsm ^ResultSetMetaData (:rsmeta builder)]
(rs/read-column-by-index
(if (re-find #"(?i)(bool|bit)" (.getColumnTypeName rsm i))
(.getBoolean rs i)
(.getObject rs i))
rsm
i)))
(def sqlite-builder (rs/builder-adapter rs/as-maps sqlite-column-by-index-fn))
(jdbc/execute!
db/db-spec
["select id, \"email-confirmed?\" from user;"]
{:builder-fn sqlite-builder})
;; => [#:user{:id 1, :email-confirmed? true} #:user{:id 2, :email-confirmed? false}]
注意:如果您使用plan
,这并不总是有效。 对于绩效, plan
不能实现价值。 在您减少计划时,访问结果集的值将跳过上面自定义的按索引读取列的内容。 减少工作由您决定。
More info, from the author of next.jdbc
, can be found at https://github.com/seancorfield/next-jdbc/blob/develop/doc/tips-and-tricks.md#sqlite and https://github .com/seancorfield/next-jdbc/issues/134
这个答案的 rest 是 lagniappe。 这是我一路走来的“几乎就在那里”和错误的转弯。 对于可能提供的任何价值,我将其作为答案的一部分。
next.jdbc
允许您使用自定义功能扩展ReadableColumn
协议以转换值。
https://github.com/seancorfield/next-jdbc/blob/develop/doc/result-set-builders.md#readablecolumn
(extend-protocol result-set/ReadableColumn
Integer
(read-column-by-index [x mrs i]
(if (re-find #"(?i)bool" (.getColumnTypeName mrs i))
(if (= 1 x) true false)
x)))
它可能并不完美。 还有另一个 function, read-column-by-label
,它不接收ResultSetMetaData
object,我们可以调用getColumnTypeName
来测试列类型是否为布尔值。 read-column-by-label
只接收值和列名。 我不确定不覆盖 function 的后果是什么。 事情似乎只适用于read-column-by-index
。
编辑以说明这不是一个完整的修复。
例如, plan
返回一个可约数。 减少 function 获得了“映射”结果集。 一些接口的一些实现调用read-column-by-label
。 我认为这样做是出于性能原因? 因此,您可以在不“构建”整个 map 的情况下执行select-keys
之类的操作。 所以如果你想用减速器做下面的事情,那么上面的修复是不够的。
(def plan (jdbc/plan db-spec ["select * from users;"]))
(defn reduce-fn [a b]
(conj a (select-keys b [:users/name :users/is_active])))
(r/reduce reduce-fn [] plan)
;; => [#:users{:name "alice", :is_active 1}
;; #:users{:name "bob", :is_active 0}]
(jdbc/execute! db-spec ["select * from users;"])
;; => [#:users{:name "alice", :is_active true, :age 1}
;; #:users{:name "bob", :is_active false, :age 0}]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.