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

被选中
 
最佳答案

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

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

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

"如果一个接口派生自另一个接口,则使用派生较多的,否则未指定使用哪个接口"


编辑
仅为了澄清。

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

例如,我在honey sql库中为Keyword类型扩展了ToSql扩展,并在我自己的代码中为Keyword类型创建了一个ToSql扩展。

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

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

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

(-reset-methods(使用(alter-var-root(:var proto)(关联-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向量,所以我想要提交一个sql语句和sql-params向量
"insert into "my-table" ("col1","col2") VALUES (?, ?)" 和 [["str1" "str2"] ["str1"]],但是这样做我需要相同的params "布局"。

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

结果

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

你有什么更准确的建议吗?
...