Repository: mathesar-foundation/mathesar

Issue:
Implement filters for schema list API
**Problem**
<!-- Please provide a clear and concise description of the problem that this feature request is designed to solve.-->
Users should be able to:
- get schemas associated with a given database key from the schema list API.
- filter schemas by name.

**Proposed solution**
<!-- A clear and concise description of your proposed solution or feature. -->
Schema list API should take name and database filter parameters.

**Additional context**
<!-- Add any other context or screenshots about the feature request here.-->
We should use `django-filter` for this.


Discussion:

Resolving patch:
diff --git a/mathesar/filters.py b/mathesar/filters.py
--- a/mathesar/filters.py
+++ b/mathesar/filters.py
@@ -1,12 +1,21 @@
 from django_filters import rest_framework as filters
 
-from mathesar.models import Table
+from mathesar.models import Schema, Table
 
 
 class CharInFilter(filters.BaseInFilter, filters.CharFilter):
     pass
 
 
+class SchemaFilter(filters.FilterSet):
+    name = CharInFilter(field_name='name', lookup_expr='in')
+    database = CharInFilter(field_name='database', lookup_expr='in')
+
+    class Meta:
+        model = Schema
+        fields = ['name', 'database']
+
+
 class TableFilter(filters.FilterSet):
     name = CharInFilter(field_name='name', lookup_expr='in')
 
diff --git a/mathesar/views/api.py b/mathesar/views/api.py
--- a/mathesar/views/api.py
+++ b/mathesar/views/api.py
@@ -10,13 +10,15 @@
 from mathesar.serializers import TableSerializer, SchemaSerializer, RecordSerializer, DataFileSerializer
 from mathesar.utils.schemas import create_schema_and_object
 from mathesar.utils.api import create_table_from_datafile
-from mathesar.filters import TableFilter
+from mathesar.filters import SchemaFilter, TableFilter
 
 
 class SchemaViewSet(viewsets.GenericViewSet, ListModelMixin, RetrieveModelMixin):
     queryset = Schema.objects.all().order_by('-created_at')
     serializer_class = SchemaSerializer
     pagination_class = DefaultLimitOffsetPagination
+    filter_backends = (filters.DjangoFilterBackend,)
+    filterset_class = SchemaFilter
 
     def create(self, request):
         schema = create_schema_and_object(request.data['name'], request.data['database'])


Test patch:
diff --git a/mathesar/tests/views/api/test_schema_api.py b/mathesar/tests/views/api/test_schema_api.py
--- a/mathesar/tests/views/api/test_schema_api.py
+++ b/mathesar/tests/views/api/test_schema_api.py
@@ -4,7 +4,8 @@
 from mathesar.utils.schemas import create_schema_and_object
 
 
-def check_schema_response(response_schema, schema, schema_name, test_db_name, len_tables=1):
+def check_schema_response(response_schema, schema, schema_name, test_db_name,
+                          len_tables=1, check_schema_objects=True):
     assert response_schema['id'] == schema.id
     assert response_schema['name'] == schema_name
     assert response_schema['database'] == test_db_name
@@ -16,7 +17,8 @@ def check_schema_response(response_schema, schema, schema_name, test_db_name, le
         assert 'name' in response_table
         assert response_table['url'].startswith('http')
         assert response_table['url'].endswith(f'/api/v0/tables/{response_table_id}/')
-    assert schema_name in get_mathesar_schemas(create_mathesar_engine(test_db_name))
+    if check_schema_objects:
+        assert schema_name in get_mathesar_schemas(create_mathesar_engine(test_db_name))
 
 
 def test_schema_list(create_table, client, test_db_name):
@@ -53,6 +55,39 @@ def test_schema_list(create_table, client, test_db_name):
     check_schema_response(response_schema, schema, 'Patents', test_db_name)
 
 
+def test_schema_list_filter(client):
+    schema_params = [("schema_1", "database_1"), ("schema_2", "database_2"),
+                     ("schema_3", "database_3"), ("schema_1", "database_3")]
+    schemas = {(name, database): Schema.objects.create(name=name, database=database)
+               for name, database in schema_params}
+
+    names = ["schema_1", "schema_3"]
+    names_query = ",".join(names)
+    databases = ["database_2", "database_3"]
+    database_query = ",".join(databases)
+    query = f"name={names_query}&database={database_query}"
+
+    response = client.get(f'/api/v0/schemas/?{query}')
+    response_data = response.json()
+    response_schemas = response_data['results']
+
+    assert response.status_code == 200
+    assert response_data['count'] == 2
+    assert len(response_data['results']) == 2
+
+    response_schemas = {(schema["name"], schema["database"]): schema
+                        for schema in response_schemas}
+    for name in names:
+        for database in databases:
+            query_tuple = (name, database)
+            if query_tuple not in schemas:
+                continue
+            schema = schemas[query_tuple]
+            response_schema = response_schemas[query_tuple]
+            check_schema_response(response_schema, schema, schema.name, schema.database,
+                                  len_tables=0, check_schema_objects=False)
+
+
 def test_schema_detail(create_table, client, test_db_name):
     """
     Desired format: