如何在运行时配置Clojure库?

esp*_*eed 4 python dependency-injection clojure

作为一个Clojure学习练习,我正在移植Bulbs(http://bulbflow.com),这是我编写的图形数据库库,从Python到Clojure.

我仍然有点模糊的一件事是如何以Clojure惯用方式构建库.

为了支持多个数据库,Bulbs使用依赖注入.在实现接口的自定义Client类中抽象出不同的数据库后端,并在运行时配置客户端.

Graph对象及其各种代理对象包含低级Client对象的实例:

# bulbs/neo4jserver/graph.py

class Graph(object):

    default_uri = NEO4J_URI

    def __init__(self, config=None):
        self.config = config or Config(self.default_uri)
        self.client = Neo4jClient(self.config)

        self.vertices = VertexProxy(Vertex, self.client)
        self.edges = EdgeProxy(Edge, self.client)
Run Code Online (Sandbox Code Playgroud)

您可以通过为相应的图形数据库服务器创建Graph对象来使用Bulbs:

>>> from bulbs.neo4jserver import Graph
>>> g = Graph()
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过代理对象在数据库中创建顶点和边:

>>> james = g.vertices.create(name="James")
>>> julie = g.vertices.create(name="Julie")
>>> g.edges.create(james, "knows", julie)
Run Code Online (Sandbox Code Playgroud)

这种设计使得从REPL中使用Bulbs变得容易,因为您只需导入并实例化Graph对象(或者如果需要,可以传入自定义Config对象).

但我不确定如何在Clojure中使用此设计,因为Graph对象及其代理需要保存在运行时配置的Client对象.

Clojure的做法是什么?

更新:这就是我最终做的......

;; bulbs/neo4jserver/client.clj

(def ^:dynamic *config* default-config)

(defn set-config!
  [config]
  (alter-var-root #'*config* (fn [_] (merge default-config config))))

(defn neo4j-client
  [& [config]]
  (set-config! config))

(neo4j-client {:root_uri "http://localhost:7474/data/db/"})

(println *config*)
Run Code Online (Sandbox Code Playgroud)

更新2:

Andrew Cooke指出,使用全局变量会阻止您在程序中使用多个独立的图形"实例",而您可以在Python版本中使用.

所以我想出了这个:

(defn graph
  [& [config]]
  (let [config (get-config config)]
    (fn [func & args]
      (apply func config args))))

(defn create-vertex
  [config data]
  (let [path (build-path vertex-path)
        params (remove-null-values data)]
    (rest/post config path params)))

(defn gremlin
  [config script & [params]]
  (rest/post config gremlin-path {:script script :params params}))
Run Code Online (Sandbox Code Playgroud)

然后你可以调用这样的不同函数:

(def g (graph {:root_uri "http://localhost:7474/data/db/"}))

(g create-vertex {:name "James"})

(g gremlin "g.v(id)" {:id 178})
Run Code Online (Sandbox Code Playgroud)

现在我还没有深入研究宏,而且我不太确定这种方法的优点与其他方法相比,所以反馈很受欢迎.

Art*_*ldt 6

协议非常适合在Clojure中,您定义了一个协议(很像一个接口),它定义了与数据库接口所需的所有函数,然后在运行时调用构建在协议实例中的图协议的构造函数.连接到您选择的数据库.

除了使用Clojure协议之外,基本流程非常相似.