Commits

Anonymous committed 36b1150

Franziska now understand queries. Added doctests for query-system.

Comments (0)

Files changed (6)

franziska/api/base.py

 
         return val
 
-
+#TODO: refactor to metaclasses, add datamodels and handler definitions
 version_map = Method("version", allowed = ["Get"],
         childs = [Method("date", allowed = ["GET"])],
         doc = '''return version of connected database''')
         #self._io_loop.start()
         self._command_map = self.build_command_map(self, self.url, method_map)
         self.version.read()
+        if not self.version.data and\
+            self.version.data[0].has_key("error"):
+            #if connection hasnt success print error message
+            return False, self.version.data[0]['error']
         return True
 
     def close(self):
         self.read()
         return val
 
+    def execute(self, query):
+        '''executes given query'''
+        kwargs = self.__add_auth()
+        result = None
+        results = self._read(url = self.get_url(),
+            headers = query.build_headers(), body = query.to_json(), **kwargs)
+        return results
+
+    def run(self, script):
+        '''executes database script'''
+        raise NotImplementedError, "run() isnt implemented yet"
+
     def __getitem__(self, item):
         """add dict interface to Dispatcher object """
+        if self.data is None:
+            self.read() #if data is uninitialized, try to read from db
+
         exists = [True for x in self.data if x['id'] == item]
         if exists[0] == True:
             new_obj = self.init_new(item)

franziska/api/client.py

 from tornado.ioloop import IOLoop
 import tornado.web
 import tornado.httpclient
+import urllib
 
 import simplejson
 import functools
                 self.responses.append({"error": response.error,
                                         "url":  response.request.url,
                                         "header": response.request.headers,
-                                        "auth": response.request.auth_username})
+                                        "auth": response.request.auth_username,
+                                        "body":  response.request.body})
             else:
                 if response.headers['Content-Type'].find("json") > 0:
                     #if returned values are in json, then parse it
             self._io_loop.stop()
 
         client = tornado.httpclient.AsyncHTTPClient(io_loop = self._io_loop)
+        #TODO: move to tornado_client
+        #TODO: control or add  method that exports body as dict to json
+        if request.method == 'GET' and request.body is not None:
+            #export body to url params
+            params, request.body = simplejson.loads(request.body), None
+            request.url += "?%s" % (urllib.urlencode(params))
+            print request
+
         client.fetch(request, callback or handle_request)
         self._io_loop.start()
 

franziska/api/query.py

+'''
+Query.py includes all type of queries, which AllegroGraph accepts
+
+'''
+
+import simplejson
+from mimetypes import mimetypes
+
+class Query(object):
+	"""
+	base-class for Query-objects
+	"""
+	def __init__(self):
+		self._response_type = 'json'
+		self._content_type = 'json'
+		self._field_map = {}
+
+	def build_headers(self):
+		'''helps to build HTTP headers for query object'''
+
+		headers = {"Accept":  mimetypes[self._response_type],
+					"Content-type": mimetypes[self._response_type]
+					}
+		return headers
+
+	def to_dict(self,
+				ignore_none = True,
+				ignore_priv = True,
+				ignore_callable = True):
+		'''exports class as dict,
+			by default skips items with None, and __privvar__
+		'''
+		def ignored(key, val, ignore_none, ignore_priv, ignore_callable):
+			'''closure, that helps to filter out class members'''
+			if ignore_priv and key.startswith("_"):
+				return True
+			elif ignore_none and val is None:
+				return  True
+			elif ignore_callable and\
+				(hasattr(val, "__call__")):
+				return True
+			else:
+				return False
+		items = {}	
+		for key,val in self.__dict__.items():
+			if not ignored(key, val, ignore_none, ignore_priv, ignore_callable):
+				if self._field_map.has_key(key):
+					#map query fieldname with database's one
+					key = self._field_map[key]
+				items[str(key)] = str(val)
+
+		return items
+
+	def to_json(self, ignore_none = True):
+		return simplejson.dumps(self.to_dict(ignore_none))
+			
+
+
+class QueryResponse(object):
+	"""
+	"""
+	def __init__(self):
+		pass
+
+class RepoQuery(Query):
+	'''
+		Base class for all queries
+	'''
+	def __init__(self, query, query_lng,
+				response_type,
+				content_type = None,
+				infer = False,
+				context = None, named_context = None,
+				default_graph_uri =  None,
+				named_graph_uri = None,
+				limit = None, 
+				offset = None,
+				variables = None, check_variables = False,
+				default_graph_name = None,
+				planner = None,
+				save = None
+				):
+		'''
+		query - The query to be executed. The query may use the namespace 
+			prefixes defined for the user. 
+		queryLn - The language of the query. Can be sparql or prolog. 
+			Defaults to sparql. 
+		infer - A string that determines what kind of reasoning is used when 
+			executing the query. Default is false, no reasoning. Other options
+			are rdfs++ (same as true), and restriction for 
+			hasValue as well as rdf++ reasoning. 
+		context - Can be passed zero or more times. Sets the graph name, or 
+			list of graph names, that will be used by this query (as in FROM).
+			When no context is given, all graphs are used. The string null 
+			can be used to refer to the default graph of the store. 
+		namedContext - Also can be given multiple times. Behaves like context,
+			except that the named graphs retain their names (as in FROM NAMED). 
+		default-graph-uri - Can be passed any number of times. Works like 
+			context except that plain-URI values should be given, without
+			wrapping < and > characters. 
+		named-graph-uri - Works like default-graph-uri,
+			except that this specifies the named graphs to be used. 
+		limit -  An integer. Can be used to limit the amount of results 
+			returned by the query. 
+		offset - An integer. Can be used to skip a number of results at 
+			the start of the query. 
+		$[varname] - Parameters starting with a $ character can be used to
+			bind query variables to fixed value (an N-Triples term) 
+			when executing a SPARQL query. 
+		checkVariables - A boolean that defaults to false, indicating whether
+			an error should be raised when a SPARQL query selects variables 
+			that are not mentioned in the query body. 
+		defaultGraphName -  Can be used to provide a resource (URL) name for 
+			the default graph. Any references to that resource will 
+			reference the default graph, and in the output the resource 
+			will be substituted for any references to the default graph. 
+			Can be given multiple times to have multiple names refer to this 
+			graph, but only the first one will appear in the output. 
+		planner  Can be used to control the way the query is planned .
+		save -  When given, will cause the server to (as well as executing
+			the query normally) save the query as a prepared query under the 
+			name passed as the value for this parameter. 
+			See preparing queries . 
+		'''
+		super(RepoQuery, self).__init__()
+		self.query = query
+		self.query_lng = query_lng
+		self._response_type = response_type
+		self._content_type = content_type
+		self.infer = str(infer).lower()
+		self.context = context
+		self.named_context = named_context
+		self.default_graph_uri = default_graph_uri
+		self.named_graph_uri = named_graph_uri
+		self.limit = limit
+		self.offset = offset
+		self.variables = variables
+		self.check_variables = str(check_variables).lower()
+		self.default_graph_name = default_graph_name
+		self.planner = planner
+		self.save = save #str(save).lower()
+		self._field_map = {
+			"query_lng": "queryLn",
+			"named_context": "namedContext",
+			"default_graph_uri": "default-graph-uri",
+			"named_graph_uri": "named-graph-uri",
+			"check_variables": "checkVariables",
+			"default_graph_name": "default-graph-name"
+		}
+
+
+
+class SparqlQuery(RepoQuery):
+	'''wrapper function around RepoQuery to simplfy managing SparqlQueries'''
+	def __init__(self, query, response_type = None, **kwargs):
+		self.query_lng = "sparql"
+		self._response_type = response_type or "sparql+json"
+		super(SparqlQuery, self).__init__(
+			query =  query, 
+			query_lng = self.query_lng,
+			response_type = self._response_type,
+			**kwargs)
+
+class PrologQuery(RepoQuery):
+	''' '''
+	def __init__(self, query, response_type = None, **kwargs):
+		self.query_lng = 'prolog'
+		self._response_type = response_type or 'json'
+		super(PrologQuery, self).__init__(
+			query = query,
+			query_lng = self.query_lng,
+			response_type = self._response_type,
+			**kwargs)
+
+
+class StatementQuery(Query):
+	''' '''
+	def __init__(self, format = "ntriple",
+				subj = None, subj_end = None,
+				pred = None, pred_end = None,
+				obj =  None, obj_end = None,
+				context = None,
+				limit = None,
+				offset = None,
+				infer = False
+				):
+		'''
+		subj (GET, DELETE)- Match a specific subject. When given, 
+			should be a term in N-triples format. Can be given multiple times
+			to mean 'the subject must be one of these resources'. 
+		subjEnd (GET) - can only be given if exactly one subj parameter is given.
+			Matches a range of subjects. 
+		pred (GET, DELETE)- Match a specific predicate. 
+			Can be passed multiple times, like subj, to match a set. 
+		predEnd (GET)- Perform a range query on the predicate.
+		obj (GET, DELETE)- Match a specific object. Pass multiple values to 
+			match a set.
+		objEnd (GET)- Range query on objects.
+		context (GET/PUT/POST/DELETE)- Used to set the named graph into which
+			the new data is stored. Can be given multiple times. 
+			Restricts the query to the	given list of named graphs. 
+			When not specified, all graphs in the store are used. 
+		contextEnd - Range query on contexts / graph names.
+		baseURI (PUT/POST)- When loading RDF/XML data, the value of 
+			this parameter is used as the base URI of the document. 
+		commit - (PUT/POST) A positive integer. Will cause a commit to happen after 
+			every N added statements. Can be used to work around the fact that
+			importing a huge amount of statements in a single transaction will
+			require excessive amounts of memory. 
+		continueOnError -(PUT/POST) A boolean (default is false) that indicates
+			whether the load should continue when malformed data is encountered. 
+			Currently only works for N-Triples and N-Quads data. 
+		limit (GET)- An integer indicating the maximum amount of results to return.
+		offset (GET)- An integer. Tell the server to skip a number of results 
+			before it starts returning. 
+		infer (GET)- Used to turn on reasoning for this query.
+			Valid values are false, rdfs++, and hasvalue. 
+			Default is false - no reasoning. 
+		format - default ntriple, Possible format - look into mimetypes.
+		'''
+		self.format  = format
+		self.subj = subj
+		self.subj_end = subj_end
+		self.pred = pred
+		self.pred_end = pred_end
+		self.obj =  obj
+		self.obj_end = obj_end
+		self.context = context
+		self.limit = limit
+		self.offset = offset
+		self.infer = str(infer).lower()
+
+class GeoQuery(Query):
+	pass

franziska/api/test/query_doc.py

+"""
+#print "Doctesting Franziska queries \n"
+>>> from base import *
+>>> import query
+>>> db = Franziska( auth = ('root', 'baas471'))
+>>> db.connect()
+True
+>>> repo = db.repositories['test']
+>>> repo.size() #doctest: +ELLIPSIS
+[...]
+
+>>> query = query.SparqlQuery( query = r'select ?s where {?s ?age "33"}', limit = 1)
+>>> repo.execute(query)
+>>> db.close()
+"""

franziska/api/test/query_doc.pyc

Binary file added.

franziska/api/util.py

+'''
+
+utils
+'''
+
+datatypes = {
+    #Integers
+        'int8'	: '<http://www.w3.org/2001/XMLSchema#byte>',
+        'int16'	: '<http://www.w3.org/2001/XMLSchema#short>',
+        'int32'	: '<http://www.w3.org/2001/XMLSchema#int>',
+        'int64'	: '<http://www.w3.org/2001/XMLSchema#long>',
+    #Unsigned Integers
+        'uint8'	: '<http://www.w3.org/2001/XMLSchema#unsignedByte>',
+        'uint16': '<http://www.w3.org/2001/XMLSchema#unsignedShort>',
+        'uint32': '<http://www.w3.org/2001/XMLSchema#unsignedInt>',
+        'uint64': '<http://www.w3.org/2001/XMLSchema#unsignedLong>',
+    #Floating point
+        'float'	: '<http://www.w3.org/2001/XMLSchema#float>',
+        'double': '<http://www.w3.org/2001/XMLSchema#double>',
+    #Times and Dates
+        'time'	: '<http://www.w3.org/2001/XMLSchema#time>',
+        'date'	: '<http://www.w3.org/2001/XMLSchema#date>',
+        'datetime': '<http://www.w3.org/2001/XMLSchema#dateTime>'
+}