from django_filters import rest_framework as filters
from rest_access_policy import AccessViewSetMixin
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
from rest_framework.response import Response

from mathesar.api.db.permissions.schema import SchemaAccessPolicy
from mathesar.api.dj_filters import SchemaFilter
from mathesar.api.pagination import DefaultLimitOffsetPagination
from mathesar.api.serializers.dependents import DependentSerializer, DependentFilterSerializer
from mathesar.api.serializers.schemas import SchemaSerializer
from mathesar.models.base import Schema
from mathesar.utils.schemas import create_schema_and_object


class SchemaViewSet(AccessViewSetMixin, viewsets.GenericViewSet, ListModelMixin, RetrieveModelMixin):
    serializer_class = SchemaSerializer
    pagination_class = DefaultLimitOffsetPagination
    filter_backends = (filters.DjangoFilterBackend,)
    filterset_class = SchemaFilter
    access_policy = SchemaAccessPolicy

    def get_queryset(self):
        qs = Schema.objects.all().order_by('-created_at')
        return self.access_policy.scope_viewset_queryset(self.request, qs)

    def create(self, request):
        serializer = SchemaSerializer(data=request.data, context={'request': request})
        serializer.is_valid(raise_exception=True)
        database_name = serializer.validated_data['database'].name
        schema = create_schema_and_object(
            serializer.validated_data['name'],
            database_name,
            comment=serializer.validated_data.get('description')
        )
        serializer = SchemaSerializer(schema)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def partial_update(self, request, pk=None):
        serializer = SchemaSerializer(
            data=request.data, context={'request': request}, partial=True
        )
        serializer.is_valid(raise_exception=True)

        schema = self.get_object()
        schema.update_sa_schema(serializer.validated_data)

        # Reload the schema to avoid cached properties
        schema = self.get_object()
        schema.clear_name_cache()
        serializer = SchemaSerializer(schema, context={'request': request})
        return Response(serializer.data)

    def destroy(self, request, pk=None):
        schema = self.get_object()
        schema.delete_sa_schema()
        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(methods=['get'], detail=True)
    def dependents(self, request, pk=None):
        serializer = DependentFilterSerializer(data=request.GET)
        serializer.is_valid(raise_exception=True)
        types_exclude = serializer.validated_data['exclude']

        schema = self.get_object()
        serializer = DependentSerializer(schema.get_dependents(types_exclude), many=True, context={'request': request})
        return Response(serializer.data)

mathesar/api/db/viewsets/schemas.py
from django_filters import rest_framework as filters
from rest_access_policy import AccessViewSetMixin
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
from rest_framework.response import Response

from mathesar.api.db.permissions.schema import SchemaAccessPolicy
from mathesar.api.dj_filters import SchemaFilter
from mathesar.api.pagination import DefaultLimitOffsetPagination
from mathesar.api.serializers.dependents import DependentSerializer, DependentFilterSerializer
from mathesar.api.serializers.schemas import SchemaSerializer
from mathesar.models.base import Schema
from mathesar.utils.schemas import create_schema_and_object


class SchemaViewSet(AccessViewSetMixin, viewsets.GenericViewSet, ListModelMixin, RetrieveModelMixin):
    serializer_class = SchemaSerializer
    pagination_class = DefaultLimitOffsetPagination
    filter_backends = (filters.DjangoFilterBackend,)
    filterset_class = SchemaFilter
    access_policy = SchemaAccessPolicy

    def get_queryset(self):
        qs = Schema.objects.all().order_by('name')
        return self.access_policy.scope_viewset_queryset(self.request, qs)

    def create(self, request):
        serializer = SchemaSerializer(data=request.data, context={'request': request})
        serializer.is_valid(raise_exception=True)
        database_name = serializer.validated_data['database'].name
        schema = create_schema_and_object(
            serializer.validated_data['name'],
            database_name,
            comment=serializer.validated_data.get('description')
        )
        serializer = SchemaSerializer(schema)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def partial_update(self, request, pk=None):
        serializer = SchemaSerializer(
            data=request.data, context={'request': request}, partial=True
        )
        serializer.is_valid(raise_exception=True)

        schema = self.get_object()
        schema.update_sa_schema(serializer.validated_data)

        # Reload the schema to avoid cached properties
        schema = self.get_object()
        schema.clear_name_cache()
        serializer = SchemaSerializer(schema, context={'request': request})
        return Response(serializer.data)

    def destroy(self, request, pk=None):
        schema = self.get_object()
        schema.delete_sa_schema()
        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(methods=['get'], detail=True)
    def dependents(self, request, pk=None):
        serializer = DependentFilterSerializer(data=request.GET)
        serializer.is_valid(raise_exception=True)
        types_exclude = serializer.validated_data['exclude']

        schema = self.get_object()
        serializer = DependentSerializer(schema.get_dependents(types_exclude), many=True, context={'request': request})
        return Response(serializer.data)

mathesar/api/db/viewsets/schemas.py
diff --git a/mathesar/api/db/viewsets/schemas.py b/mathesar/api/db/viewsets/schemas.py
index 1f2687dd5e..7126e1a419 100644
--- a/mathesar/api/db/viewsets/schemas.py
+++ b/mathesar/api/db/viewsets/schemas.py
@@ -22,7 +22,7 @@ class SchemaViewSet(AccessViewSetMixin, viewsets.GenericViewSet, ListModelMixin,
     access_policy = SchemaAccessPolicy
 
     def get_queryset(self):
-        qs = Schema.objects.all().order_by('-created_at')
+        qs = Schema.objects.all().order_by('name')
         return self.access_policy.scope_viewset_queryset(self.request, qs)
 
     def create(self, request):

Sort list of schemas
On the Database Page, the schemas appear in random order.

![image](https://user-images.githubusercontent.com/42411/199863005-2cc007c5-3224-489b-86de-80d924010833.png)

I think they should be listed alphabetically, perhaps with `public` first.

I'm not sure whether it would be better to handle this on the back end or the front end.

Any thoughts @mathemancer @rajatvijay?


Update:
* This issue is supposed to be handled on the backend.
* Part of this issue is solved in https://github.com/centerofci/mathesar/pull/2062
* Refer https://github.com/centerofci/mathesar/issues/1897#issuecomment-1470542703 for the current state of the issue.
