Browse Source

Serialize query results early and stream out.

Stefano Cossu 6 years ago
parent
commit
d756458d9d
2 changed files with 28 additions and 23 deletions
  1. 14 3
      lakesuperior/api/query.py
  2. 14 20
      lakesuperior/endpoints/query.py

+ 14 - 3
lakesuperior/api/query.py

@@ -1,21 +1,32 @@
 import logging
 
+from io import BytesIO
+
 from lakesuperior.dictionaries.namespaces import ns_collection as nsc
 from lakesuperior.dictionaries.namespaces import ns_mgr as nsm
 from lakesuperior.env import env
+from lakesuperior.store.ldp_rs.lmdb_store import LmdbStore, TxnManager
 
 
 logger = logging.getLogger(__name__)
 rdfly = env.app_globals.rdfly
+rdf_store = env.app_globals.rdf_store
 
 
-def sparql_query(qry_str):
+def sparql_query(qry_str, fmt):
     '''
     Send a SPARQL query to the triplestore.
 
     @param qry_str (str) SPARQL query string. SPARQL 1.1 Query Language
     (https://www.w3.org/TR/sparql11-query/) is supported.
+    @param fmt(string) Serialization format. This varies depending on the
+    query type (SELECT, ASK, CONSTRUCT, etc.). [@TODO Add reference to RDFLib
+    serialization formats]
 
-    @return rdflib.query.QueryResult
+    @return BytesIO
     '''
-    return rdfly.raw_query(qry_str)
+    with TxnManager(rdf_store) as txn:
+        qres = rdfly.raw_query(qry_str)
+        out_stream = BytesIO(qres.serialize(format=fmt))
+
+    return out_stream

+ 14 - 20
lakesuperior/endpoints/query.py

@@ -1,12 +1,11 @@
 import logging
 
-from flask import Blueprint, current_app, request, render_template
+from flask import Blueprint, current_app, request, render_template, send_file
 from rdflib.plugin import PluginException
 
 from lakesuperior.env import env
 from lakesuperior.dictionaries.namespaces import ns_mgr as nsm
 from lakesuperior.api import query as query_api
-from lakesuperior.store.ldp_rs.lmdb_store import LmdbStore, TxnManager
 
 # Query endpoint. raw SPARQL queries exposing the underlying layout can be made
 # available. Also convenience methods that allow simple lookups based on simple
@@ -14,7 +13,6 @@ from lakesuperior.store.ldp_rs.lmdb_store import LmdbStore, TxnManager
 # N.B All data sources are read-only for this endpoint.
 
 logger = logging.getLogger(__name__)
-rdf_store = env.app_globals.rdf_store
 rdfly = env.app_globals.rdfly
 
 query = Blueprint('query', __name__)
@@ -55,25 +53,21 @@ def sparql():
     if request.method == 'GET':
         return render_template('sparql_query.html', nsm=nsm)
     else:
-        if request.mimetype == 'multipart/form-data':
-            qstr = request.form['query']
+        if request.mimetype == 'application/sparql-query':
+            qstr = request.stream.read()
         else:
-            qstr = stream.read()
+            qstr = request.form['query']
         logger.debug('Query: {}'.format(qstr))
-        with TxnManager(rdf_store) as txn:
-            qres = query_api.sparql_query(qstr)
 
-            match = request.accept_mimetypes.best_match(accept_mimetypes.keys())
-            if match:
-                enc = accept_mimetypes[match]
-            else:
-                enc = request.accept_mimetypes.best
+        match = request.accept_mimetypes.best_match(accept_mimetypes.keys())
+        fmt = (
+                accept_mimetypes[match] if match
+                else request.accept_mimetypes.best)
 
-            try:
-                out = qres.serialize(format=enc)
-            except PluginException:
-                return (
-                    'Unable to serialize results into format {}'.format(enc),
-                    406)
+        try:
+            out_stream = query_api.sparql_query(qstr, fmt)
+        except PluginException:
+            return (
+                'Unable to serialize results into format {}'.format(fmt), 406)
 
-    return out, 200
+    return send_file(out_stream, mimetype=fmt), 200