Java方法作为带有嵌套方法调用的函数中的参数(更新)
我有一个通过clojure sql获取JDBC元数据的函数Java方法作为带有嵌套方法调用的函数中的参数(更新),java,sql,jdbc,clojure,Java,Sql,Jdbc,Clojure,我有一个通过clojure sql获取JDBC元数据的函数 (ns relink (:require [clojure.contrib.sql :as sql] [clojure.string :as str] )) (let [db-host "localhost" db-port 1433 db-name "databasename"] (def db {:classname "com.microsoft.sqlser
(ns relink
(:require
[clojure.contrib.sql :as sql]
[clojure.string :as str]
))
(let [db-host "localhost"
db-port 1433
db-name "databasename"]
(def db {:classname "com.microsoft.sqlserver.jdbc.SQLServerDriver"
:subprotocol "sqlserver"
:subname (str "//" db-host ":" db-port)
:databasename db-name
:user "user"
:password "password"}))
(defn get-table-metadata
"Take database spec, return all table names from the database metadata"
[db]
(sql/with-connection db
(doall
(resultset-seq
(.getTables
(.getMetaData (sql/connection))
nil nil "%" (into-array '("TABLE")))))))
(get-table-metadata db)
现在,我想通过将java方法调用包装在clojure函数中作为参数,扩展该函数以使用其他SQL元数据,如下所示:
(get-sql-metadata db .getTables nil nil "%" (into-array '("TABLE")))
如果不将(.getMetaData(sql/connection))也放在函数参数中,似乎无法完成此操作
(get-sql-metadata db #(.getTables (.getMetaData (sql/connection)) nil nil "%" (into-array '("TABLE"))))
但是,我想在get sql metadata函数中抽象出这一点,因为它对于所有元数据方法调用都是相同的
我曾尝试用doto、…、>和(.notation)重写resultset seq中的部分,但都无法正常工作
我错过了什么
更新:
下面的解决方案是可行的,但是需要一些黑客攻击。我不相信str invoke中的反射应该是必要的,所以我不会把它作为一个答案发布
(defn str-invoke [instance method-str & args]
(clojure.lang.Reflector/invokeInstanceMethod
instance
method-str
(to-array args)))
(defn get-sql-metadata
"Take database spec, metadata method (as string) and method parameters"
[db method & args]
(sql/with-connection db
(doall
(resultset-seq
(apply str-invoke
(.getMetaData (sql/connection))
method args)))))
(get-sql-metadata db "getTables" nil nil "%" (into-array '("TABLE")))
问题似乎是需要apply,但不能在.form上使用。问题是您试图在对象“nil”上调用.getTables。当您删除(.getMetaData(sql/connection))时您删除了.getTables消息的接收者。您需要元数据对象,以便可以对其调用.getTables方法。您可以将其包装在let中:
(let [metadata (.getMetaData (sql/connection))]
(get-sql-metadata db #(.getTables metatdata nil nil "%" (into-array '("TABLE")))))
更新:
这个怎么样:
(get-sql-metadata db (fn [meta] (.getTables meta nil nil "%" (into-array '("TABLE")))))
然后“获取表元数据”变为:
(defn get-table-metadata
"Take database spec, return all table names from the database metadata"
[db metafunction]
(sql/with-connection db
(doall
(resultset-seq
(metafunction (.getMetaData (sql/connection)))))))
在生成get sql元数据时,函数将导致clojure在应用函数之前对参数求值,因此无法向函数传递无法求值的“.unknown”符号,如.getTables 另一方面,在宏中,在应用宏之前不会计算参数。 因此,将函数设置为宏将允许您执行此操作 比如:
当然也有可能通过使用宏memfn将方法调用转换为clojure函数,但我认为这不是您想要的那样我仍然可以传递(.getMetaData(sql/connection))在函数参数中,只是以不同的形式。也许我应该重写这个问题,但我正在寻找一种方法,如何在get sql metadata函数中抽象它(在resultset seq中),只将db&the.getTables方法及其参数放在函数参数中。解决方案可行,但函数参数很难变得更清晰或更简洁。我自己找到了一个解决方案,我将在更新中发布,但我不相信它使用的反射步骤是必要的。
(defmacro get-sql-metadata [db method & args]
`(with-connection
~db
(doall
(resultset-seq
(~method
(.getMetaData (connection))
~@args)))))