作为一个Culjule学习练习,我移植了Bulbs(http://bulbflow.com),这是我从Python到Culjule的一个图形数据库库。
我还有些不清楚的一件事是如何用clojure惯用的方式构造库。
为了支持多个数据库,bulls使用依赖注入。在一个实现接口的自定义客户机类中抽象不同的数据库子查询,并在运行时配置客户机。
Graph对象及其各种代理对象包含低级客户端对象的实例:
# 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)
通过为相应的图形数据库服务器创建图形对象,可以使用bulls:
>>> from bulbs.neo4jserver import Graph
>>> g = Graph()
然后可以通过代理对象在数据库中创建顶点和边:
>>> james = g.vertices.create(name="James")
>>> julie = g.vertices.create(name="Julie")
>>> g.edges.create(james, "knows", julie)
这种设计使得使用repl中的bulls变得很容易,因为您所要做的就是导入和实例化graph对象(或者在需要时传入一个自定义配置对象)。
但我不知道如何在Culjue中实现这个设计,因为图形对象及其代理需要保存在运行时配置的客户端对象。
克洛尤尔是怎么做的?
更新:这就是我最后做的…
;; 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*)
更新2:
andrew cooke指出,使用全局var将使您无法在程序中使用多个独立的图形“实例”,而在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}))
然后可以调用不同的函数,如下所示:
(def g (graph {:root_uri "http://localhost:7474/data/db/"}))
(g create-vertex {:name "James"})
(g gremlin "g.v(id)" {:id 178})
现在我还没有深入研究宏,而且我不太确定这种方法与其他方法相比的优点,所以欢迎反馈。
最佳答案
Protocols非常适合于Culjule,您定义了一个协议(很像一个接口),它定义了与数据库接口所需的所有功能,然后在运行时调用图形协议的构建器,该协议在连接到您选择的DB的协议的实例中生成。
基本的流程非常相似,除了使用Culjule协议。