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 投票

选中
 
最佳答案

将选择最具体的匹配项 - 如果给出了关键字和对象实现,将选择关键字实现。

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

来源于 https://clojure.org/reference/protocols

"如果一个接口是从另一个接口派生的,那么使用更派生的接口,否则使用哪个接口是不确定的"。


编辑
只是为了澄清。

我想要扩展 ToSql 协议的一个扩展,我想要扩展的协议类型已在之前的扩展中被扩展。

例如,我在 honey sql 库中有为 Keyword 类型提供的 ToSql 扩展,并且我在我的代码中也提供了 Keyword 类型的 ToSql 扩展。

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

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

谢谢!
根据我所见,extend-protocol 转换为为 ToSqlextend-type Keyword,最新的扩展类型获胜。

(-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被内联

jdb/execute! 等待SQL和一个SQL参数向量,所以我想要提交一个SQL语句和SQL参数向量
"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]

也许您可以提供更准确的方法。
...