Anonymous avatar Anonymous committed cbfe6c1

tidier get/create

Comments (0)

Files changed (2)

scripts/borneo.py

 
 import json
 import tsv
+import random
+import threading
+import re
+import os
 
 from urlparse import urlparse, parse_qsl
 
-from bottle import post, request, run
+from bottle import put, post, request, response, run, abort
 
 from java.util import ArrayList, HashMap
 
 factory.setCacheProviders(cache_providers)
 #factory.setIndexProviders(index_providers_iter)
 
-databases = {
-    "foo": factory.newEmbeddedDatabase(data_dir + "/foo"),
-}
 
-engines = {
-    "foo": ExecutionEngine(databases["foo"]),
-}
+ALPHA_NUM = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+
+random_word = lambda x: "".join(random.choice(ALPHA_NUM) for i in range(x))
+
+DB_CACHE = {}
+DB_CACHE_LOCK = threading.Lock()
+DB_NAME_PATTERN = re.compile("[0-9A-Za-z_]+")
+DB_ROOT_DIR = "/home/elgin/git/borneo/graph"
+
+class Graph(object):
+
+    cache = {}
+    lock = threading.Lock()
+    name_pattern = re.compile("[0-9A-Za-z_]+")
+    root_dir = "/home/elgin/git/borneo/graph"
+
+    @classmethod
+    def _assert_valid_name(cls, graph_name):
+        if not Graph.name_pattern.match(graph_name):
+            raise ValueError("Illegal database name")
+
+    @classmethod
+    def get(cls, graph_name):
+        Graph._assert_valid_name(graph_name)
+        Graph.lock.acquire(True)
+        try:
+            if Graph.exists_on_disk(graph_name):
+                if not Graph.exists_in_cache(graph_name):
+                    Graph.cache[graph_name] = Graph(graph_name)
+                return 200, Graph.cache[graph_name]
+            else:
+                return 404, None
+        finally:
+            Graph.lock.release()
+
+    @classmethod
+    def create(cls, graph_name):
+        Graph._assert_valid_name(graph_name)
+        Graph.lock.acquire(True)
+        try:
+            if Graph.exists_on_disk(graph_name):
+                return 409, None
+            else:
+                Graph.cache[graph_name] = Graph(graph_name)
+                return 201, Graph.cache[graph_name]
+        finally:
+            Graph.lock.release()
+
+    @classmethod
+    def get_or_create(cls, graph_name):
+        Graph._assert_valid_name(graph_name)
+        Graph.lock.acquire(True)
+        try:
+            if Graph.exists_on_disk(graph_name):
+                if not Graph.exists_in_cache(graph_name):
+                    Graph.cache[graph_name] = Graph(graph_name)
+                return 200, Graph.cache[graph_name]
+            else:
+                Graph.cache[graph_name] = Graph(graph_name)
+                return 201, Graph.cache[graph_name]
+        finally:
+            Graph.lock.release()
+
+    @classmethod
+    def exists_on_disk(cls, graph_name):
+        path = os.path.join(DB_ROOT_DIR, graph_name)
+        return os.path.exists(path)
+
+    @classmethod
+    def exists_in_cache(cls, graph_name):
+        return graph_name in Graph.cache
+
+    def __init__(self, name):
+        self.name = name
+        self.path = os.path.join(Graph.root_dir, name)
+        self.is_new = not os.path.exists(self.path)
+        self.database = factory.newEmbeddedDatabase(self.path)
+        self.cypher = ExecutionEngine(self.database)
 
 def properties(entity):
     props = {}
 class JSONEncoder(json.JSONEncoder):
 
     def default(self, o):
-        if isinstance(o, Node):
+        if isinstance(o, Graph):
+            obj = {"__class__": "Graph", "__name__": o.name}
+            return obj
+        elif isinstance(o, Node):
             obj = properties(o)
             obj.update({"__class__": "Node", "__id__": o.id})
             return obj
         else:
             return json.JSONEncoder.default(self, o)
+#
+#def _get_or_create_graph(graph_name):
+#    if not DB_NAME_PATTERN.match(graph_name):
+#        raise ValueError("Illegal database name")
+#    DB_CACHE_LOCK.acquire(True)
+#    try:
+#        if graph_name not in DB_CACHE:
+#            DB_CACHE[graph_name] = Graph(graph_name)
+#    finally:
+#        DB_CACHE_LOCK.release()
+#    return DB_CACHE[graph_name]
+#
+#def _create_graph():
+#    name = None
+#    DB_CACHE_LOCK.acquire(True)
+#    try:
+#        while True:
+#            name = "_" + random_word(11)
+#            path = os.path.join(DB_ROOT_DIR, name)
+#            if not Graph.exists(path):
+#                DB_CACHE[name] = Graph(name)
+#                break
+#    finally:
+#        DB_CACHE_LOCK.release()
+#    return DB_CACHE[name]
+#
+#def _destroy_graph(graph_name):
+#    pass
 
-@post("/graph/:graph/cypher")
-def execute_cypher(graph):
-    query = str(request.body.read())
-    params = HashMap()
-    for key, value in request.query.items():
-        value = json.loads(value)   # might raise ValueError
-        params.put(key, value)
-    engine = engines[graph]
-    result = engine.execute(query, params)  # might raise org.neo4j.cypher.ParameterNotFoundException
+def _execute_cypher(graph_name, query, params):
+    response.status, graph = Graph.get(graph_name)
+    result = graph.cypher.execute(query, params)  # might raise org.neo4j.cypher.ParameterNotFoundException
     columns = result.columns()
     data = []
     for row in result.iterator():
         data.append([row[column] for column in columns])
+    return data
+
+@post("/graph/")
+def create_graph():
+    graph = None
+    while True:
+        graph_name = "_" + random_word(11)
+        if not Graph.exists_on_disk(graph_name):
+            response.status, graph = Graph.create(graph_name)
+            break
+    if response.status_code == 201:
+        response.set_header("Location", "/graph/" + graph.name)
+    return None
+
+@put("/graph/:graph_name")
+def get_or_create_graph(graph_name):
+    response.status, graph = Graph.get_or_create(graph_name)
+    if response.status_code == 201:
+        response.set_header("Location", "/graph/" + graph.name)
+    return None
+
+@post("/graph/:graph_name/cypher")
+def execute_cypher(graph_name):
+    query = request.body.read()
+    params = HashMap()
+    for key, value in request.query.items():
+        value = json.loads(value)   # might raise ValueError
+        params.put(key, value)
+    data = _execute_cypher(graph_name, query, params)
     return tsv.dumps(data, json_encoder=JSONEncoder)
 
 if __name__ == '__main__':

scripts/graph.py

-#!/usr/bin/env jython
-# -*- encoding=utf8 -*-
-
-# Borneo - Alternative Database Server for Neo4j
-# Copyright (C) 2012  Nigel Small <borneo@nigelsmall.org>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-from java.util import ArrayList
-
-from org.neo4j.graphdb import *
-from org.neo4j.graphdb.factory import *
-from org.neo4j.index.lucene import *
-from org.neo4j.kernel import *
-from org.neo4j.kernel.impl.cache import *
-
-data_dir = "/home/elgin/git/borneo/graph"
-
-cache_providers = ArrayList()
-cache_providers.add(SoftCacheProvider())
-
-#lucene = LuceneIndexProvider()
-#index_providers = ArrayList()
-#index_providers.add(lucene)
-#index_providers_iter = ListIndexIterable()
-#index_providers_iter.setIndexProviders(index_providers)
-
-factory = GraphDatabaseFactory()
-factory.setCacheProviders(cache_providers)
-#factory.setIndexProviders(index_providers_iter)
-
-databases = {
-    "foo": factory.newEmbeddedDatabase(data_dir + "/foo"),
-}
-
-class CollectionHandler(object):
-
-    def do_GET(self, request, params):
-        """ fetch list of all graphs
-        """
-        pass
-
-    def do_PUT(self, request, params):
-        raise NotImplementedError
-
-    def do_POST(self, request, params):
-        """ create unnamed graph
-        """
-        pass
-
-    def do_DELETE(self, request, params):
-        raise NotImplementedError
-
-
-class ResourceHandler(object):
-
-    def do_GET(self, request, graph_name, params):
-        """ fetch named graph
-        """
-        pass
-
-    def do_PUT(self, request, graph_name, params):
-        """ create/update named graph
-        """
-        pass
-
-    def do_POST(self, request, graph_name, params):
-        raise NotImplementedError
-
-    def do_DELETE(self, request, graph_name, params):
-        """ destroy graph
-        """
-        pass
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.