diff --git a/backend/app/base/utils.py b/backend/app/base/utils.py new file mode 100644 index 0000000..867072e --- /dev/null +++ b/backend/app/base/utils.py @@ -0,0 +1,38 @@ +from typing import TypedDict, Tuple + +from flask_sqlalchemy import BaseQuery +from sqlalchemy import desc + + +class PaginationResponse(TypedDict): + items: list + max_pages: int + + +def order_by_column_name(query: BaseQuery, model_field: str, order_by_col_name: str) -> BaseQuery: + if order_by_col_name is not None: + if order_by_col_name == 'asc': + query = query.order_by(model_field) + elif order_by_col_name == 'desc': + query = query.order_by(desc(model_field)) + + return query + + +def paginate_models(page: str, query: BaseQuery) -> PaginationResponse or Tuple[dict, int]: + per_page = 10 + default_page = 1 + + if page is not None: + try: + page = int(page) + except ValueError: + return {"error": f"Invalid page! Page must be integer!"}, 400 + query = query.paginate(page=page, per_page=per_page, error_out=False) + else: + query = query.paginate(page=default_page, per_page=per_page, error_out=False) + + return { + 'items': query.items, + 'max_pages': query.pages + } diff --git a/backend/app/coordinator/routes/students.py b/backend/app/coordinator/routes/students.py index 2b4597e..c5a90b7 100644 --- a/backend/app/coordinator/routes/students.py +++ b/backend/app/coordinator/routes/students.py @@ -1,14 +1,16 @@ from typing import Tuple from random import randint -from flask import Blueprint, request, make_response, jsonify, Response +from flask import Blueprint, request, Response from marshmallow import ValidationError +from flask_sqlalchemy import get_debug_queries from ...students.models import Student from ..schemas import StudentSchema, StudentEditSchema, StudentCreateSchema from ...dependencies import db from ..utils import parse_csv from ..exceptions import InvalidNameOrTypeHeaderException +from ...base.utils import paginate_models bp = Blueprint("students", __name__, url_prefix="/students") @@ -16,8 +18,20 @@ bp = Blueprint("students", __name__, url_prefix="/students") @bp.route("/", methods=["GET"]) def list_students() -> Tuple[dict, int]: students_schema = StudentSchema(many=True) - students = Student.query.all() - return {"students": students_schema.dump(students)}, 200 + + fullname = request.args.get('fullname') + order_by_first_name = request.args.get('order_by_first_name') + order_by_last_name = request.args.get('order_by_last_name') + page = request.args.get('page') + + student_query = Student.search_by_fullname_and_order_by_first_name_or_last_name(fullname, order_by_first_name, + order_by_last_name) + + response = paginate_models(page, student_query) + if isinstance(response, tuple): + return response + print(get_debug_queries()[0]) + return {"students": students_schema.dump(response['items']), "max_pages": response['max_pages']}, 200 @bp.route("//", methods=["GET"]) diff --git a/backend/app/students/models.py b/backend/app/students/models.py index 6512db3..cc8d6c9 100644 --- a/backend/app/students/models.py +++ b/backend/app/students/models.py @@ -1,5 +1,9 @@ +from sqlalchemy.sql import text +from flask_sqlalchemy import BaseQuery + from ..dependencies import db from ..base.models import Person, Base +from ..base.utils import order_by_column_name class ProjectSupervisor(Base, Person): @@ -26,3 +30,21 @@ class Student(Person): group_id = db.Column(db.Integer, db.ForeignKey('groups.id')) group = db.relationship('Group', backref='students', lazy=True) mode = db.Column(db.Boolean, default=True, nullable=False) # True - stationary, False - non-stationary + + @classmethod + def search_by_fullname_and_order_by_first_name_or_last_name(cls, fullname: str = None, + order_by_first_name: str = None, + order_by_last_name: str = None) -> BaseQuery: + student_query = cls.query + + if fullname is not None: + """This works only for sqlite3 database - concat function doesn't exist so i used builtin concat + operator specific only for sqlite db - || """ + student_query = student_query.filter( + text("students_first_name || ' ' || students_last_name LIKE :fullname ") + ).params(fullname=f'{fullname}%') + + student_query = order_by_column_name(student_query, Student.first_name, order_by_first_name) + student_query = order_by_column_name(student_query, Student.last_name, order_by_last_name) + + return student_query