簡體   English   中英

如何使用 next.jdbc 將 SQLite 中的 bool 列讀入 bool Clojure 值? SQLite 將布爾值存儲為 0/1

[英]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_activetruefalse 我不希望我的應用程序代碼必須跟蹤哪些列是 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM