We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Implement adding a new empty table
## Problem
<!-- Please provide a clear and concise description of the problem that this feature request is designed to solve.-->
Users may want to create an empty table.

## Proposed solution
<!-- A clear and concise description of your proposed solution or feature. -->
The ["Basic Table Operations" design spec](https://wiki.mathesar.org/design/specs/table-operations) has a solution for this, which we need to implement on the frontend. We will be implementing a different design than the one in the spec, which will need to be improvised.

This issue involves the following portions of the spec:
- _User Experience_: 
  - User adds a new table
  - User edits a new table name
  - User adds an empty table
- _Interactions_: 
  - Sequential Table Names
 
Please note that we'll need to generate and display a default name of the table that the user can use. Following the logic in #449 is recommended.

## Additional context
<!-- Add any other context or screenshots about the feature request here.-->
- Backend work: #184 
- Design issue: #185
- #449 is related.

Logs of conversation on Matrix from @pavish:

> For adding an empty table, instead of showing Empty table option within the tab, I think it might be better to show it on the top.
> 
> The Add new table button can be changed to a dropdown with two options. 1. Empty table, 2. Import data.
> 
> On clicking empty table, it would just send a create table request and create the table. Then the user can rename it if they want.
> 
> This will have clean separation of concerns. Because Import data, involves importing from csv, remote file import and then copy/paste from spreadsheet..
> 
> Empty table, would just create a new empty table.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mathesar/api/viewsets/tables.py`
Content:
```
1 from django_filters import rest_framework as filters
2 from psycopg2.errors import CheckViolation, DuplicateTable, InvalidTextRepresentation
3 from rest_framework import status, viewsets
4 from rest_framework.decorators import action
5 from rest_framework.exceptions import ValidationError, APIException
6 from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
7 from rest_framework.response import Response
8 from sqlalchemy.exc import ProgrammingError, DataError, IntegrityError
9 
10 from db.types.alteration import UnsupportedTypeException
11 from mathesar.api.filters import TableFilter
12 from mathesar.api.pagination import DefaultLimitOffsetPagination
13 from mathesar.api.serializers.tables import TableSerializer, TablePreviewSerializer
14 from mathesar.models import Table
15 from mathesar.utils.tables import (
16     get_table_column_types, create_table_from_datafile, create_empty_table,
17     gen_table_name
18 )
19 
20 
21 class TableViewSet(viewsets.GenericViewSet, ListModelMixin, RetrieveModelMixin):
22     serializer_class = TableSerializer
23     pagination_class = DefaultLimitOffsetPagination
24     filter_backends = (filters.DjangoFilterBackend,)
25     filterset_class = TableFilter
26 
27     def get_queryset(self):
28         return Table.objects.all().order_by('-created_at')
29 
30     def create(self, request):
31         serializer = TableSerializer(data=request.data, context={'request': request})
32         serializer.is_valid(raise_exception=True)
33 
34         if not serializer.validated_data['name']:
35             name = gen_table_name(
36                 serializer.validated_data['schema'],
37                 serializer.validated_data['data_files'],
38             )
39         else:
40             name = serializer.validated_data['name']
41 
42         try:
43             if serializer.validated_data['data_files']:
44                 table = create_table_from_datafile(
45                     serializer.validated_data['data_files'],
46                     name,
47                     serializer.validated_data['schema'],
48                 )
49             else:
50                 table = create_empty_table(
51                     name,
52                     serializer.validated_data['schema']
53                 )
54         except ProgrammingError as e:
55             if type(e.orig) == DuplicateTable:
56                 raise ValidationError(
57                     f"Relation {request.data['name']} already exists in schema {request.data['schema']}"
58                 )
59             else:
60                 raise APIException(e)
61 
62         serializer = TableSerializer(table, context={'request': request})
63         return Response(serializer.data, status=status.HTTP_201_CREATED)
64 
65     def partial_update(self, request, pk=None):
66         serializer = TableSerializer(
67             data=request.data, context={'request': request}, partial=True
68         )
69         serializer.is_valid(raise_exception=True)
70         table = self.get_object()
71 
72         # Save the fields that are stored in the model.
73         present_model_fields = []
74         for model_field in table.MODEL_FIELDS:
75             if model_field in serializer.validated_data:
76                 setattr(table, model_field, serializer.validated_data[model_field])
77                 present_model_fields.append(model_field)
78         table.save(update_fields=present_model_fields)
79         for key in present_model_fields:
80             del serializer.validated_data[key]
81 
82         # Save the fields that are stored in the underlying DB.
83         try:
84             table.update_sa_table(serializer.validated_data)
85         except ValueError as e:
86             raise ValidationError(e)
87 
88         # Reload the table to avoid cached properties
89         table = self.get_object()
90         serializer = TableSerializer(table, context={'request': request})
91         return Response(serializer.data)
92 
93     def destroy(self, request, pk=None):
94         table = self.get_object()
95         table.delete_sa_table()
96         table.delete()
97         return Response(status=status.HTTP_204_NO_CONTENT)
98 
99     @action(methods=['get'], detail=True)
100     def type_suggestions(self, request, pk=None):
101         table = self.get_object()
102         col_types = get_table_column_types(table)
103         return Response(col_types)
104 
105     @action(methods=['post'], detail=True)
106     def previews(self, request, pk=None):
107         table = self.get_object()
108         serializer = TablePreviewSerializer(data=request.data)
109         serializer.is_valid(raise_exception=True)
110         columns = serializer.data["columns"]
111 
112         column_names = [col["name"] for col in columns]
113         if not len(column_names) == len(set(column_names)):
114             raise ValidationError("Column names must be distinct")
115         if not len(columns) == len(table.sa_columns):
116             raise ValidationError("Incorrect number of columns in request.")
117 
118         table_data = TableSerializer(table, context={"request": request}).data
119         try:
120             preview_records = table.get_preview(columns)
121         except (DataError, IntegrityError) as e:
122             if type(e.orig) == InvalidTextRepresentation or type(e.orig) == CheckViolation:
123                 raise ValidationError("Invalid type cast requested.")
124             else:
125                 raise APIException
126         except UnsupportedTypeException as e:
127             raise ValidationError(e)
128         except Exception as e:
129             raise APIException(e)
130 
131         table_data.update(
132             {
133                 # There's no way to reflect actual column data without
134                 # creating a view, so we just use the submission, assuming
135                 # no errors means we changed to the desired names and types
136                 "columns": columns,
137                 "records": preview_records
138             }
139         )
140 
141         return Response(table_data)
142
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mathesar/api/viewsets/tables.py b/mathesar/api/viewsets/tables.py
--- a/mathesar/api/viewsets/tables.py
+++ b/mathesar/api/viewsets/tables.py
@@ -31,26 +31,15 @@
         serializer = TableSerializer(data=request.data, context={'request': request})
         serializer.is_valid(raise_exception=True)
 
-        if not serializer.validated_data['name']:
-            name = gen_table_name(
-                serializer.validated_data['schema'],
-                serializer.validated_data['data_files'],
-            )
-        else:
-            name = serializer.validated_data['name']
+        schema = serializer.validated_data['schema']
+        data_files = serializer.validated_data.get('data_files')
+        name = serializer.validated_data.get('name') or gen_table_name(schema, data_files)
 
         try:
-            if serializer.validated_data['data_files']:
-                table = create_table_from_datafile(
-                    serializer.validated_data['data_files'],
-                    name,
-                    serializer.validated_data['schema'],
-                )
+            if data_files:
+                table = create_table_from_datafile(data_files, name, schema)
             else:
-                table = create_empty_table(
-                    name,
-                    serializer.validated_data['schema']
-                )
+                table = create_empty_table(name, schema)
         except ProgrammingError as e:
             if type(e.orig) == DuplicateTable:
                 raise ValidationError(

{"golden_diff": "diff --git a/mathesar/api/viewsets/tables.py b/mathesar/api/viewsets/tables.py\n--- a/mathesar/api/viewsets/tables.py\n+++ b/mathesar/api/viewsets/tables.py\n@@ -31,26 +31,15 @@\n         serializer = TableSerializer(data=request.data, context={'request': request})\n         serializer.is_valid(raise_exception=True)\n \n-        if not serializer.validated_data['name']:\n-            name = gen_table_name(\n-                serializer.validated_data['schema'],\n-                serializer.validated_data['data_files'],\n-            )\n-        else:\n-            name = serializer.validated_data['name']\n+        schema = serializer.validated_data['schema']\n+        data_files = serializer.validated_data.get('data_files')\n+        name = serializer.validated_data.get('name') or gen_table_name(schema, data_files)\n \n         try:\n-            if serializer.validated_data['data_files']:\n-                table = create_table_from_datafile(\n-                    serializer.validated_data['data_files'],\n-                    name,\n-                    serializer.validated_data['schema'],\n-                )\n+            if data_files:\n+                table = create_table_from_datafile(data_files, name, schema)\n             else:\n-                table = create_empty_table(\n-                    name,\n-                    serializer.validated_data['schema']\n-                )\n+                table = create_empty_table(name, schema)\n         except ProgrammingError as e:\n             if type(e.orig) == DuplicateTable:\n                 raise ValidationError(\n", "issue": "Implement adding a new empty table\n## Problem\r\n<!-- Please provide a clear and concise description of the problem that this feature request is designed to solve.-->\r\nUsers may want to create an empty table.\r\n\r\n## Proposed solution\r\n<!-- A clear and concise description of your proposed solution or feature. -->\r\nThe [\"Basic Table Operations\" design spec](https://wiki.mathesar.org/design/specs/table-operations) has a solution for this, which we need to implement on the frontend. We will be implementing a different design than the one in the spec, which will need to be improvised.\r\n\r\nThis issue involves the following portions of the spec:\r\n- _User Experience_: \r\n  - User adds a new table\r\n  - User edits a new table name\r\n  - User adds an empty table\r\n- _Interactions_: \r\n  - Sequential Table Names\r\n \r\nPlease note that we'll need to generate and display a default name of the table that the user can use. Following the logic in #449 is recommended.\r\n\r\n## Additional context\r\n<!-- Add any other context or screenshots about the feature request here.-->\r\n- Backend work: #184 \r\n- Design issue: #185\r\n- #449 is related.\r\n\r\nLogs of conversation on Matrix from @pavish:\r\n\r\n> For adding an empty table, instead of showing Empty table option within the tab, I think it might be better to show it on the top.\r\n> \r\n> The Add new table button can be changed to a dropdown with two options. 1. Empty table, 2. Import data.\r\n> \r\n> On clicking empty table, it would just send a create table request and create the table. Then the user can rename it if they want.\r\n> \r\n> This will have clean separation of concerns. Because Import data, involves importing from csv, remote file import and then copy/paste from spreadsheet..\r\n> \r\n> Empty table, would just create a new empty table.\n", "before_files": [{"content": "from django_filters import rest_framework as filters\nfrom psycopg2.errors import CheckViolation, DuplicateTable, InvalidTextRepresentation\nfrom rest_framework import status, viewsets\nfrom rest_framework.decorators import action\nfrom rest_framework.exceptions import ValidationError, APIException\nfrom rest_framework.mixins import ListModelMixin, RetrieveModelMixin\nfrom rest_framework.response import Response\nfrom sqlalchemy.exc import ProgrammingError, DataError, IntegrityError\n\nfrom db.types.alteration import UnsupportedTypeException\nfrom mathesar.api.filters import TableFilter\nfrom mathesar.api.pagination import DefaultLimitOffsetPagination\nfrom mathesar.api.serializers.tables import TableSerializer, TablePreviewSerializer\nfrom mathesar.models import Table\nfrom mathesar.utils.tables import (\n    get_table_column_types, create_table_from_datafile, create_empty_table,\n    gen_table_name\n)\n\n\nclass TableViewSet(viewsets.GenericViewSet, ListModelMixin, RetrieveModelMixin):\n    serializer_class = TableSerializer\n    pagination_class = DefaultLimitOffsetPagination\n    filter_backends = (filters.DjangoFilterBackend,)\n    filterset_class = TableFilter\n\n    def get_queryset(self):\n        return Table.objects.all().order_by('-created_at')\n\n    def create(self, request):\n        serializer = TableSerializer(data=request.data, context={'request': request})\n        serializer.is_valid(raise_exception=True)\n\n        if not serializer.validated_data['name']:\n            name = gen_table_name(\n                serializer.validated_data['schema'],\n                serializer.validated_data['data_files'],\n            )\n        else:\n            name = serializer.validated_data['name']\n\n        try:\n            if serializer.validated_data['data_files']:\n                table = create_table_from_datafile(\n                    serializer.validated_data['data_files'],\n                    name,\n                    serializer.validated_data['schema'],\n                )\n            else:\n                table = create_empty_table(\n                    name,\n                    serializer.validated_data['schema']\n                )\n        except ProgrammingError as e:\n            if type(e.orig) == DuplicateTable:\n                raise ValidationError(\n                    f\"Relation {request.data['name']} already exists in schema {request.data['schema']}\"\n                )\n            else:\n                raise APIException(e)\n\n        serializer = TableSerializer(table, context={'request': request})\n        return Response(serializer.data, status=status.HTTP_201_CREATED)\n\n    def partial_update(self, request, pk=None):\n        serializer = TableSerializer(\n            data=request.data, context={'request': request}, partial=True\n        )\n        serializer.is_valid(raise_exception=True)\n        table = self.get_object()\n\n        # Save the fields that are stored in the model.\n        present_model_fields = []\n        for model_field in table.MODEL_FIELDS:\n            if model_field in serializer.validated_data:\n                setattr(table, model_field, serializer.validated_data[model_field])\n                present_model_fields.append(model_field)\n        table.save(update_fields=present_model_fields)\n        for key in present_model_fields:\n            del serializer.validated_data[key]\n\n        # Save the fields that are stored in the underlying DB.\n        try:\n            table.update_sa_table(serializer.validated_data)\n        except ValueError as e:\n            raise ValidationError(e)\n\n        # Reload the table to avoid cached properties\n        table = self.get_object()\n        serializer = TableSerializer(table, context={'request': request})\n        return Response(serializer.data)\n\n    def destroy(self, request, pk=None):\n        table = self.get_object()\n        table.delete_sa_table()\n        table.delete()\n        return Response(status=status.HTTP_204_NO_CONTENT)\n\n    @action(methods=['get'], detail=True)\n    def type_suggestions(self, request, pk=None):\n        table = self.get_object()\n        col_types = get_table_column_types(table)\n        return Response(col_types)\n\n    @action(methods=['post'], detail=True)\n    def previews(self, request, pk=None):\n        table = self.get_object()\n        serializer = TablePreviewSerializer(data=request.data)\n        serializer.is_valid(raise_exception=True)\n        columns = serializer.data[\"columns\"]\n\n        column_names = [col[\"name\"] for col in columns]\n        if not len(column_names) == len(set(column_names)):\n            raise ValidationError(\"Column names must be distinct\")\n        if not len(columns) == len(table.sa_columns):\n            raise ValidationError(\"Incorrect number of columns in request.\")\n\n        table_data = TableSerializer(table, context={\"request\": request}).data\n        try:\n            preview_records = table.get_preview(columns)\n        except (DataError, IntegrityError) as e:\n            if type(e.orig) == InvalidTextRepresentation or type(e.orig) == CheckViolation:\n                raise ValidationError(\"Invalid type cast requested.\")\n            else:\n                raise APIException\n        except UnsupportedTypeException as e:\n            raise ValidationError(e)\n        except Exception as e:\n            raise APIException(e)\n\n        table_data.update(\n            {\n                # There's no way to reflect actual column data without\n                # creating a view, so we just use the submission, assuming\n                # no errors means we changed to the desired names and types\n                \"columns\": columns,\n                \"records\": preview_records\n            }\n        )\n\n        return Response(table_data)\n", "path": "mathesar/api/viewsets/tables.py"}], "after_files": [{"content": "from django_filters import rest_framework as filters\nfrom psycopg2.errors import CheckViolation, DuplicateTable, InvalidTextRepresentation\nfrom rest_framework import status, viewsets\nfrom rest_framework.decorators import action\nfrom rest_framework.exceptions import ValidationError, APIException\nfrom rest_framework.mixins import ListModelMixin, RetrieveModelMixin\nfrom rest_framework.response import Response\nfrom sqlalchemy.exc import ProgrammingError, DataError, IntegrityError\n\nfrom db.types.alteration import UnsupportedTypeException\nfrom mathesar.api.filters import TableFilter\nfrom mathesar.api.pagination import DefaultLimitOffsetPagination\nfrom mathesar.api.serializers.tables import TableSerializer, TablePreviewSerializer\nfrom mathesar.models import Table\nfrom mathesar.utils.tables import (\n    get_table_column_types, create_table_from_datafile, create_empty_table,\n    gen_table_name\n)\n\n\nclass TableViewSet(viewsets.GenericViewSet, ListModelMixin, RetrieveModelMixin):\n    serializer_class = TableSerializer\n    pagination_class = DefaultLimitOffsetPagination\n    filter_backends = (filters.DjangoFilterBackend,)\n    filterset_class = TableFilter\n\n    def get_queryset(self):\n        return Table.objects.all().order_by('-created_at')\n\n    def create(self, request):\n        serializer = TableSerializer(data=request.data, context={'request': request})\n        serializer.is_valid(raise_exception=True)\n\n        schema = serializer.validated_data['schema']\n        data_files = serializer.validated_data.get('data_files')\n        name = serializer.validated_data.get('name') or gen_table_name(schema, data_files)\n\n        try:\n            if data_files:\n                table = create_table_from_datafile(data_files, name, schema)\n            else:\n                table = create_empty_table(name, schema)\n        except ProgrammingError as e:\n            if type(e.orig) == DuplicateTable:\n                raise ValidationError(\n                    f\"Relation {request.data['name']} already exists in schema {request.data['schema']}\"\n                )\n            else:\n                raise APIException(e)\n\n        serializer = TableSerializer(table, context={'request': request})\n        return Response(serializer.data, status=status.HTTP_201_CREATED)\n\n    def partial_update(self, request, pk=None):\n        serializer = TableSerializer(\n            data=request.data, context={'request': request}, partial=True\n        )\n        serializer.is_valid(raise_exception=True)\n        table = self.get_object()\n\n        # Save the fields that are stored in the model.\n        present_model_fields = []\n        for model_field in table.MODEL_FIELDS:\n            if model_field in serializer.validated_data:\n                setattr(table, model_field, serializer.validated_data[model_field])\n                present_model_fields.append(model_field)\n        table.save(update_fields=present_model_fields)\n        for key in present_model_fields:\n            del serializer.validated_data[key]\n\n        # Save the fields that are stored in the underlying DB.\n        try:\n            table.update_sa_table(serializer.validated_data)\n        except ValueError as e:\n            raise ValidationError(e)\n\n        # Reload the table to avoid cached properties\n        table = self.get_object()\n        serializer = TableSerializer(table, context={'request': request})\n        return Response(serializer.data)\n\n    def destroy(self, request, pk=None):\n        table = self.get_object()\n        table.delete_sa_table()\n        table.delete()\n        return Response(status=status.HTTP_204_NO_CONTENT)\n\n    @action(methods=['get'], detail=True)\n    def type_suggestions(self, request, pk=None):\n        table = self.get_object()\n        col_types = get_table_column_types(table)\n        return Response(col_types)\n\n    @action(methods=['post'], detail=True)\n    def previews(self, request, pk=None):\n        table = self.get_object()\n        serializer = TablePreviewSerializer(data=request.data)\n        serializer.is_valid(raise_exception=True)\n        columns = serializer.data[\"columns\"]\n\n        column_names = [col[\"name\"] for col in columns]\n        if not len(column_names) == len(set(column_names)):\n            raise ValidationError(\"Column names must be distinct\")\n        if not len(columns) == len(table.sa_columns):\n            raise ValidationError(\"Incorrect number of columns in request.\")\n\n        table_data = TableSerializer(table, context={\"request\": request}).data\n        try:\n            preview_records = table.get_preview(columns)\n        except (DataError, IntegrityError) as e:\n            if type(e.orig) == InvalidTextRepresentation or type(e.orig) == CheckViolation:\n                raise ValidationError(\"Invalid type cast requested.\")\n            else:\n                raise APIException\n        except UnsupportedTypeException as e:\n            raise ValidationError(e)\n        except Exception as e:\n            raise APIException(e)\n\n        table_data.update(\n            {\n                # There's no way to reflect actual column data without\n                # creating a view, so we just use the submission, assuming\n                # no errors means we changed to the desired names and types\n                \"columns\": columns,\n                \"records\": preview_records\n            }\n        )\n\n        return Response(table_data)\n", "path": "mathesar/api/viewsets/tables.py"}]}