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
by
selected by
 
最佳答案

最适合的匹配项将被选择 - 给定 Keyword 和 Object 的实现,将选择 Keyword 实现。

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

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

"如果一个接口是从另一个接口继承的,则使用更继承的,否则未指定使用哪个"。


编辑
只是为了澄清。

我只想扩展一个  ToSql 协议,我想要扩展的协议 *覆盖* 实际在先前的扩展中已经扩展的类型。

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

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

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

谢谢!
就像我看到的,extend-protocol 转换成了扩展类型 Keyword 的 extend-type,且最后一个 extend-type 获胜。

(-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,但绝对在我的计划中。

我的任务是以下
我需要将具有相同元数据形状(表和列)的几个insert 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参数的向量,因此我想提交一个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]

也许你可以给我更好的建议。
...