From 56692a3f295eae9912dcb1ad404c7b703ce3d44d Mon Sep 17 00:00:00 2001
From: Tim Repke <repke@mcc-berlin.net>
Date: Thu, 10 Aug 2023 19:18:00 +0200
Subject: [PATCH] add nql route

---
 requirements.txt            |  4 ++--
 server/api/routes/search.py | 31 ++++++++++++++++++++++++++++++-
 2 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/requirements.txt b/requirements.txt
index cffe8a7..020121f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-fastapi==0.100.1
+fastapi==0.101.0
 hypercorn==0.14.4
 toml==0.10.2
 email-validator==2.0.0.post2
@@ -8,4 +8,4 @@ httpx[http2]==0.24.1
 pymitter==0.4.0
 uvicorn==0.23.2
 python-multipart==0.0.6
-nacsos_data[scripts,server] @ git+ssh://git@gitlab.pik-potsdam.de/mcc-apsis/nacsos/nacsos-data.git@v0.9.0
+nacsos_data[scripts,server] @ git+ssh://git@gitlab.pik-potsdam.de/mcc-apsis/nacsos/nacsos-data.git@v0.9.1
diff --git a/server/api/routes/search.py b/server/api/routes/search.py
index db9d57b..a643575 100644
--- a/server/api/routes/search.py
+++ b/server/api/routes/search.py
@@ -1,16 +1,24 @@
 import httpx
 from pydantic import BaseModel
 from fastapi import APIRouter, Depends
+import sqlalchemy.sql.functions as func
+from typing import TYPE_CHECKING
 
 from nacsos_data.util.academic.openalex import query_async, SearchResult, SearchField, DefType, OpType
+from nacsos_data.db.crud.items import Query
+from nacsos_data.models.items import AcademicItemModel
 
 from server.util.security import UserPermissionChecker, UserPermissions
 from server.util.logging import get_logger
 from server.util.config import settings
+from server.data import db_engine
+
+if TYPE_CHECKING:
+    from sqlalchemy.ext.asyncio import AsyncSession  # noqa F401
 
-logger = get_logger('nacsos.api.route.search')
 router = APIRouter()
 
+logger = get_logger('nacsos.api.route.search')
 logger.info('Setting up academic search route')
 
 
@@ -69,3 +77,24 @@ async def term_expansion(term_prefix: str,
                       ttf=terms[i + 1]['ttf'])
             for i in range(0, len(terms), 2)
         ]
+
+
+class QueryResult(BaseModel):
+    n_docs: int
+    docs: list[AcademicItemModel]
+
+
+@router.get('/nql/query', response_model=QueryResult)
+async def nql_query(query: str,
+                    limit: int = 20,
+                    permissions: UserPermissions = Depends(UserPermissionChecker('dataset_read'))) -> QueryResult:
+    q = Query(query, project_id=permissions.permissions.project_id)
+
+    async with db_engine.session() as session:  # type: AsyncSession
+        stmt = q.stmt.subquery()
+        cnt_stmt = func.count(stmt.c.item_id)
+        return QueryResult(
+            n_docs=(await session.execute(cnt_stmt)).scalar(),  # type: ignore[arg-type]
+            docs=[AcademicItemModel.model_validate(item.__dict__)
+                  for item in (await session.execute(q.stmt.limit(limit))).scalars().all()]
+        )
-- 
GitLab