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 的实现,据我了解,其中有一个普通的 HashMap 的 :impls,其中存储了所有方法,因此再次没有关于查找顺序的任何保证。

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

谢谢!

1 答案

+2

被选中
 
最佳答案

将选择最具体的匹配项 - 给定关键字和对象实现,关键字实现将被选择。

如果最具体的匹配项是模糊的(同一具体类型扩展了两个被扩展的接口),则所选实现是任意的且未定义的(因此你可能会避免这么做)。

查看更多信息:https://clojure.org/reference/protocols

"如果一个接口是由另一个接口派生出来的,则使用更派生的接口,否则哪个接口被使用是不确定的"。

只是为了澄清。

我有一个扩展ToSql协议的扩展,我想扩展相同协议中的相同类型,即已经在前一个扩展中扩展的类型。

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

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

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

谢谢!
正如我所见,extend-protocol转换为ToSql的extend-type Keyword,最后扩展类型获胜。

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

请确认。

谢谢!
是的,在一个协议中只有一个特定类型的“槽位”,所以你可以通过扩展来替换它。话虽如此,当你这样做时应该小心(因为你正在替换别人安装的功能)。有关指南,请参阅 https://clojure.org/reference/protocols#_guidelines_for_extension
作为HoneySQL的维护者,我会担心您在这里试图覆盖内置的低级类型转换之一——对于与库默认处理不同的关键字,HoneySQL需要做什么呢?
嗨,Sean!
HoneySQL非常好用、紧凑且功能最全。阅读和调试它对我来说是一件非常愉快的物理活动 :)
此外,我没有玩你的next.jdbc,但它肯定在我的计划之中。

我的任务是:
我需要将具有相同元数据的(表和列)的几个插入HoneySQL命令批量插入到单个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参数的向量,所以我想提交一个sql语句和sql参数的向量
"insert into "my-table" ("col1","col2") VALUES (?, ?)" 和 [["str1" "str2"] ["str1"]],但为了做到这一点,我需要相同的参数"布局"。

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

结果:

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

你可以提供更准确的做法吗。
...