diff --git a/backend/api/search.py b/backend/api/search.py new file mode 100644 index 0000000..22a3cda --- /dev/null +++ b/backend/api/search.py @@ -0,0 +1,18 @@ +from fastapi import APIRouter, Depends + +from ..services import SearchService +from ..models.resource_model import Resource +from ..models.service_model import Service + + +api = APIRouter(prefix="/api/search") + +openapi_tags = { + "name": "Search", + "description": "Search through all resources and services for a string.", +} + +@api.post("", tags=["Search"]) +def search(query: str, search_svc: SearchService = Depends()) -> list[Resource | Service]: + return search_svc.search(query) + \ No newline at end of file diff --git a/backend/main.py b/backend/main.py index 12ecaad..9f1973f 100644 --- a/backend/main.py +++ b/backend/main.py @@ -3,7 +3,7 @@ from fastapi.responses import JSONResponse from fastapi.middleware.gzip import GZipMiddleware -from .api import user, health, service, resource, tag +from .api import user, health, service, resource, tag, search description = """ Welcome to the **COMPASS** RESTful Application Programming Interface. @@ -24,7 +24,7 @@ app = FastAPI( app.add_middleware(GZipMiddleware) -feature_apis = [user, health, service, resource, tag] +feature_apis = [user, health, service, resource, tag, search] for feature_api in feature_apis: app.include_router(feature_api.api) diff --git a/backend/services/__init__.py b/backend/services/__init__.py index 4067973..aac7718 100644 --- a/backend/services/__init__.py +++ b/backend/services/__init__.py @@ -1,4 +1,5 @@ from .user import UserService from .resource import ResourceService from .tag import TagService -from .service import ServiceService \ No newline at end of file +from .service import ServiceService +from .search import SearchService \ No newline at end of file diff --git a/backend/services/search.py b/backend/services/search.py new file mode 100644 index 0000000..0acc3c2 --- /dev/null +++ b/backend/services/search.py @@ -0,0 +1,37 @@ +from fastapi import Depends +from ..database import db_session +from sqlalchemy.orm import Session +from sqlalchemy import or_, select +from ..models.resource_model import Resource +from ..models.service_model import Service +from ..entities.resource_entity import ResourceEntity +from backend.entities.service_entity import ServiceEntity +from ..models.user_model import User, UserTypeEnum + + +class SearchService: + def __init__(self, session: Session = Depends(db_session)): + self._session = session + + def search(self, query_str: str) -> list[Resource | Service]: + results = [] + models = [ + ResourceEntity, + ServiceEntity, + ] + + for model in models: + columns = [column for column in model.__table__.columns] + + filters = [ + column.ilike(f"%{query_str}%") + for column in columns + if column.type.__class__.__name__ in ["String", "Text"] + ] + + if filters: + query = self._session.query(model).filter(or_(*filters)) + results.extend(query.all()) + + return results +