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

“如果一个接口由另一个接口继承而来,那么使用更深入的接口,否则使用哪个接口是不确定的。”

by
编辑 by
只是为了澄清。

我想扩展一个  ToSql 协议,我想扩展相同的协议 *重写* 类型,该类型在之前的扩展中已经扩展。

例如,我在 honey sql 库中为 Keyword 类型实现了 ToSql 扩展,并在我的代码中为 Keyword 类型实现了 ToSql 扩展。

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

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

谢谢!
by
据我所见,extend-protocol 将转换为 extend-type Keyword 的 ToSql,最后的 extend-type 获胜。

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

请确认。

谢谢!
by
是的,在协议中特定的类型只有一个“槽数”,所以你可以通过扩展来替换它。话虽如此,当你这样做时应该小心(因为你正在替换某人安装的功能)。有关指南请参阅 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被内联

jdbcreader execution! 函数等待SQL和SQL参数向量,所以我想要提交一个SQL语句和一个SQL参数向量
"insert into "my-table" ("col1","col2") VALUES (?, ?)" and [["str1" "str2"] ["str1"]],但为了做到这一点,我需要相同的参数"布局"。

因此,我需要覆盖Honey SQL默认行为,即将'NULL'(及布尔值)内联,以便提升它们进入SQL参数。

结果:

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

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