2024 Clojure状态调查中分享您的想法!

欢迎!请参阅关于页面以获取更多关于此信息的工作原理。

0
协议

嗨!

以下是honeysql中的代码:

(extend-protocol ToSql
  #?(:clj clojure.lang.Keyword
     :cljs cljs.core/Keyword)
  (to-sql [x]
    (let [s (name x)]
      (case (.charAt s 0)
        \% (let [call-args (string/split (subs s 1) #"\." 2)]
             (to-sql (apply call (map keyword call-args))))
        \? (to-sql (param (keyword (subs s 1))))
        (quote-identifier x))))

  .... ;SKIPPED

  #?(:clj Object :cljs default)
  (to-sql [x]
    #?(:clj (add-anon-param x)
       :cljs (if (sequential? x)
               (seq->sql x)
               (add-anon-param x)))))

假设我正在调用

(to-sql :column-name)

调用方法的选择取决于查找的顺序,因为Keyword是Object的子类,而且:column-name是Keyword和Object。

我在clojure协议文档中没有找到有关定义方法查找顺序的信息。

我还调查了extend-protocol的实现,据我了解,:impls中有一个普通的HashMap,其中存储了所有方法,所以查找的顺序也没有任何保证。

换句话说,对于具有子类关系的类型扩展协议的规则是什么,或者这也许完全不正确,我应该只为没有任何类型关系的类型扩展协议。

谢谢!

1 答案

+2

selected
 
最佳答案

将选择最具体的匹配项——给定Keyword和Object实现,将选择Keyword实现。

如果最具体的匹配项不明确(两个扩展的接口都扩展了相同的具体类型),则选择的实现是任意的且未定义的(因此您可能应该避免这样做)。

内容来自 https://clojure.org/reference/protocols

"如果一个接口是由另一个接口派生的,则使用派生更多的那个;否则,使用哪个未指定"


编辑
只是为了澄清。

我有一个 `ToSql` 协议的扩展,我想扩展相同的协议,并 *覆盖* 之前扩展中已扩展的类型。

例如,我在 honey sql 库中对 Keyword 类型有 `ToSql` 扩展,并在我的代码中对 Keyword 类型进行了 `ToSql` 扩展。

这些扩展是如何组合的?我的扩展覆盖了库中定义的扩展吗?

或者这是“同一具体类型扩展了两个被扩展的接口”的情况,其中 Keyword 是一个被扩展的类型,ToSql 是一个被同一类型扩展了两次的接口。

谢谢!
据我所见,extend-protocol 转换成了 ToSql 的 extend-type Keyword,并且最新的 extend-type 获胜。

(-reset-methods (alter-var-root (:var proto) assoc-in [:impls atype] mmap))

请核实。

谢谢!
是的,在协议中,特定类型只有一个“槽”,所以你可以通过扩展来替换它。话虽如此,当你这样做时要小心(因为你正在替换别人安装的功能)。有关指南,请参阅https://clojure.org/reference/protocols#_guidelines_for_extension
by
作为HoneySQL的维护者,我担心你在这里可能试图覆盖内置的低级别类型转换之一——HoneySQL需要为你所需的以关键字不同处理的库如何处理?
by
嗨,Sean!
HoneySQL非常棒,紧凑且实用。阅读和调整它对我来说是一件非常愉悦的事情:)
另外,我没有玩过你的next.jdbc,但绝对在我的计划之内。

我的任务是 следующее
我需要将具有相同元数据形状(表和列)的多个honey sql插入命令批量插入到单个jdbc/execute!调用中。
示范
1. {:insert-into [:my-table]
    :values [{:col1 "str1"
               :col2 "str2"}]}
2. {:insert-into [:my-table]
    :values [{:col1 "str1"
              :col2 nil}]} <--------- 这里我们有nil值

honey sql给了我以下结果
1. "insert into "my-table" ("col1","col2") VALUES (?, ?)"  ["str1" "str2"]
2. "insert into "my-table" ("col1","col2") VALUES (?, NULL)"  ["str1"]   <----- NULL已经内联

jdbc/execute!期望sql和sql-params的向量,所以我 want to提交一个sql-statement和sql-params的向量
"insert into "my-table" ("col1","col2") VALUES (?, ?)" and [["str1" "str2"] ["str1"]],但是我应该有相同的params "layout"。

因此,我需要覆盖默认的honeysql行为,即内联'NULL'(和布尔值),以将它们提升到sql参数中。

结果

1. "insert into "my-table" ("col1","col2") VALUES (?, ?)"  ["str1" "str2"]
2. "insert into "my-table" ("col1","col2") VALUES (?, ?)"  ["str1" nil]

也许你可以提供更准确的方法来解决这个问题。
...