We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Automatic import of tables when new database is connected.
**Problem**
<!-- Please provide a clear and concise description of the problem that this feature request is designed to solve.-->
When a user sets up an existing database in Mathesar, they'll expect to see their tables. We don't currently do anything to sync existing databases with Mathesar.

**Proposed solution**
<!-- A clear and concise description of your proposed solution or feature. -->
We should create instances of the appropriate Django models for tables in existing databases.

**Additional context**
<!-- Add any other context or screenshots about the feature request here.-->
Blocked by #61

--- 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/models.py`
Content:
```
1 from django.contrib.auth.models import User
2 from django.core.cache import cache
3 from django.db import models
4 from django.utils.functional import cached_property
5 
6 from mathesar.database.base import create_mathesar_engine
7 from mathesar.utils import models as model_utils
8 from db import tables, records, schemas, columns
9 
10 NAME_CACHE_INTERVAL = 60 * 5
11 
12 
13 class BaseModel(models.Model):
14     created_at = models.DateTimeField(auto_now_add=True)
15     updated_at = models.DateTimeField(auto_now=True)
16 
17     class Meta:
18         abstract = True
19 
20 
21 class DatabaseObject(BaseModel):
22     oid = models.IntegerField()
23 
24     class Meta:
25         abstract = True
26 
27     def __str__(self):
28         return f"{self.__class__.__name__}: {self.oid}"
29 
30 
31 # TODO: Replace with a proper form of caching
32 # See: https://github.com/centerofci/mathesar/issues/280
33 _engine = None
34 
35 
36 class Schema(DatabaseObject):
37     database = models.CharField(max_length=128)
38 
39     @property
40     def _sa_engine(self):
41         global _engine
42         # We're caching this since the engine is used frequently.
43         if _engine is None:
44             _engine = create_mathesar_engine(self.database)
45         return _engine
46 
47     @cached_property
48     def name(self):
49         cache_key = f"{self.database}_schema_name_{self.oid}"
50         try:
51             schema_name = cache.get(cache_key)
52             if schema_name is None:
53                 schema_name = schemas.get_schema_name_from_oid(
54                     self.oid, self._sa_engine
55                 )
56                 cache.set(cache_key, schema_name, NAME_CACHE_INTERVAL)
57             return schema_name
58         # We catch this error, since it lets us decouple the cadence of
59         # overall DB reflection from the cadence of cache expiration for
60         # schema names.  Also, it makes it obvious when the DB layer has
61         # been altered, as opposed to other reasons for a 404 when
62         # requesting a schema.
63         except TypeError:
64             return 'MISSING'
65 
66 
67 class Table(DatabaseObject):
68     schema = models.ForeignKey('Schema', on_delete=models.CASCADE,
69                                related_name='tables')
70     import_verified = models.BooleanField(blank=True, null=True)
71 
72     @cached_property
73     def _sa_table(self):
74         try:
75             table = tables.reflect_table_from_oid(
76                 self.oid, self.schema._sa_engine,
77             )
78         # We catch this error, since it lets us decouple the cadence of
79         # overall DB reflection from the cadence of cache expiration for
80         # table names.  Also, it makes it obvious when the DB layer has
81         # been altered, as opposed to other reasons for a 404 when
82         # requesting a table.
83         except TypeError:
84             table = tables.create_empty_table("MISSING")
85         return table
86 
87     @cached_property
88     def name(self):
89         return self._sa_table.name
90 
91     @property
92     def sa_columns(self):
93         return self._sa_table.columns
94 
95     @property
96     def sa_column_names(self):
97         return self.sa_columns.keys()
98 
99     def add_column(self, column_data):
100         return columns.create_column(
101             self.schema._sa_engine,
102             self.oid,
103             column_data,
104         )
105 
106     def alter_column(self, column_index, column_data):
107         return columns.alter_column(
108             self.schema._sa_engine,
109             self.oid,
110             column_index,
111             column_data,
112         )
113 
114     def drop_column(self, column_index):
115         columns.drop_column(
116             self.schema._sa_engine,
117             self.oid,
118             column_index,
119         )
120 
121     @property
122     def sa_num_records(self):
123         return tables.get_count(self._sa_table, self.schema._sa_engine)
124 
125     @property
126     def sa_all_records(self):
127         return records.get_records(self._sa_table, self.schema._sa_engine)
128 
129     def get_record(self, id_value):
130         return records.get_record(self._sa_table, self.schema._sa_engine, id_value)
131 
132     def get_records(self, limit=None, offset=None, filters=[], order_by=[]):
133         return records.get_records(self._sa_table, self.schema._sa_engine, limit,
134                                    offset, filters=filters, order_by=order_by)
135 
136     def get_group_counts(
137         self, group_by, limit=None, offset=None, filters=[], order_by=[]
138     ):
139         return records.get_group_counts(self._sa_table, self.schema._sa_engine,
140                                         group_by, limit, offset, filters=filters,
141                                         order_by=order_by)
142 
143     def create_record_or_records(self, record_data):
144         return records.create_record_or_records(self._sa_table, self.schema._sa_engine, record_data)
145 
146     def update_record(self, id_value, record_data):
147         return records.update_record(self._sa_table, self.schema._sa_engine, id_value, record_data)
148 
149     def delete_record(self, id_value):
150         return records.delete_record(self._sa_table, self.schema._sa_engine, id_value)
151 
152 
153 class DataFile(BaseModel):
154     file = models.FileField(
155         upload_to=model_utils.user_directory_path,
156     )
157     user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
158     table_imported_to = models.ForeignKey(Table, related_name="data_files", blank=True,
159                                           null=True, on_delete=models.SET_NULL)
160     delimiter = models.CharField(max_length=1, default=',', blank=True)
161     escapechar = models.CharField(max_length=1, blank=True)
162     quotechar = models.CharField(max_length=1, default='"', blank=True)
163
```

Path: `mathesar/utils/schemas.py`
Content:
```
1 from rest_framework.exceptions import ValidationError
2 
3 from db.schemas import (
4     create_schema, get_schema_oid_from_name, get_mathesar_schemas,
5     get_mathesar_schemas_with_oids
6 )
7 from mathesar.database.base import create_mathesar_engine
8 from mathesar.models import Schema
9 
10 
11 def create_schema_and_object(name, database):
12     engine = create_mathesar_engine(database)
13 
14     all_schemas = get_mathesar_schemas(engine)
15     if name in all_schemas:
16         raise ValidationError({"name": "Schema name is not unique"})
17 
18     create_schema(name, engine)
19     schema_oid = get_schema_oid_from_name(name, engine)
20     schema = Schema.objects.create(oid=schema_oid, database=database)
21     return schema
22 
23 
24 def reflect_schemas_from_database(database):
25     engine = create_mathesar_engine(database)
26     db_schema_oids = {
27         schema["oid"] for schema in get_mathesar_schemas_with_oids(engine)
28     }
29     schemas = [
30         Schema.objects.get_or_create(oid=oid, database=database)
31         for oid in db_schema_oids
32     ]
33     for schema in Schema.objects.all():
34         if schema.oid not in db_schema_oids:
35             schema.delete()
36     return schemas
37
```
--- 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/models.py b/mathesar/models.py
--- a/mathesar/models.py
+++ b/mathesar/models.py
@@ -30,7 +30,7 @@
 
 # TODO: Replace with a proper form of caching
 # See: https://github.com/centerofci/mathesar/issues/280
-_engine = None
+_engines = {}
 
 
 class Schema(DatabaseObject):
@@ -38,11 +38,11 @@
 
     @property
     def _sa_engine(self):
-        global _engine
+        global _engines
         # We're caching this since the engine is used frequently.
-        if _engine is None:
-            _engine = create_mathesar_engine(self.database)
-        return _engine
+        if self.database not in _engines:
+            _engines[self.database] = create_mathesar_engine(self.database)
+        return _engines[self.database]
 
     @cached_property
     def name(self):
diff --git a/mathesar/utils/schemas.py b/mathesar/utils/schemas.py
--- a/mathesar/utils/schemas.py
+++ b/mathesar/utils/schemas.py
@@ -31,6 +31,6 @@
         for oid in db_schema_oids
     ]
     for schema in Schema.objects.all():
-        if schema.oid not in db_schema_oids:
+        if schema.database == database and schema.oid not in db_schema_oids:
             schema.delete()
     return schemas

{"golden_diff": "diff --git a/mathesar/models.py b/mathesar/models.py\n--- a/mathesar/models.py\n+++ b/mathesar/models.py\n@@ -30,7 +30,7 @@\n \n # TODO: Replace with a proper form of caching\n # See: https://github.com/centerofci/mathesar/issues/280\n-_engine = None\n+_engines = {}\n \n \n class Schema(DatabaseObject):\n@@ -38,11 +38,11 @@\n \n     @property\n     def _sa_engine(self):\n-        global _engine\n+        global _engines\n         # We're caching this since the engine is used frequently.\n-        if _engine is None:\n-            _engine = create_mathesar_engine(self.database)\n-        return _engine\n+        if self.database not in _engines:\n+            _engines[self.database] = create_mathesar_engine(self.database)\n+        return _engines[self.database]\n \n     @cached_property\n     def name(self):\ndiff --git a/mathesar/utils/schemas.py b/mathesar/utils/schemas.py\n--- a/mathesar/utils/schemas.py\n+++ b/mathesar/utils/schemas.py\n@@ -31,6 +31,6 @@\n         for oid in db_schema_oids\n     ]\n     for schema in Schema.objects.all():\n-        if schema.oid not in db_schema_oids:\n+        if schema.database == database and schema.oid not in db_schema_oids:\n             schema.delete()\n     return schemas\n", "issue": "Automatic import of tables when new database is connected.\n**Problem**\r\n<!-- Please provide a clear and concise description of the problem that this feature request is designed to solve.-->\r\nWhen a user sets up an existing database in Mathesar, they'll expect to see their tables. We don't currently do anything to sync existing databases with Mathesar.\r\n\r\n**Proposed solution**\r\n<!-- A clear and concise description of your proposed solution or feature. -->\r\nWe should create instances of the appropriate Django models for tables in existing databases.\r\n\r\n**Additional context**\r\n<!-- Add any other context or screenshots about the feature request here.-->\r\nBlocked by #61\n", "before_files": [{"content": "from django.contrib.auth.models import User\nfrom django.core.cache import cache\nfrom django.db import models\nfrom django.utils.functional import cached_property\n\nfrom mathesar.database.base import create_mathesar_engine\nfrom mathesar.utils import models as model_utils\nfrom db import tables, records, schemas, columns\n\nNAME_CACHE_INTERVAL = 60 * 5\n\n\nclass BaseModel(models.Model):\n    created_at = models.DateTimeField(auto_now_add=True)\n    updated_at = models.DateTimeField(auto_now=True)\n\n    class Meta:\n        abstract = True\n\n\nclass DatabaseObject(BaseModel):\n    oid = models.IntegerField()\n\n    class Meta:\n        abstract = True\n\n    def __str__(self):\n        return f\"{self.__class__.__name__}: {self.oid}\"\n\n\n# TODO: Replace with a proper form of caching\n# See: https://github.com/centerofci/mathesar/issues/280\n_engine = None\n\n\nclass Schema(DatabaseObject):\n    database = models.CharField(max_length=128)\n\n    @property\n    def _sa_engine(self):\n        global _engine\n        # We're caching this since the engine is used frequently.\n        if _engine is None:\n            _engine = create_mathesar_engine(self.database)\n        return _engine\n\n    @cached_property\n    def name(self):\n        cache_key = f\"{self.database}_schema_name_{self.oid}\"\n        try:\n            schema_name = cache.get(cache_key)\n            if schema_name is None:\n                schema_name = schemas.get_schema_name_from_oid(\n                    self.oid, self._sa_engine\n                )\n                cache.set(cache_key, schema_name, NAME_CACHE_INTERVAL)\n            return schema_name\n        # We catch this error, since it lets us decouple the cadence of\n        # overall DB reflection from the cadence of cache expiration for\n        # schema names.  Also, it makes it obvious when the DB layer has\n        # been altered, as opposed to other reasons for a 404 when\n        # requesting a schema.\n        except TypeError:\n            return 'MISSING'\n\n\nclass Table(DatabaseObject):\n    schema = models.ForeignKey('Schema', on_delete=models.CASCADE,\n                               related_name='tables')\n    import_verified = models.BooleanField(blank=True, null=True)\n\n    @cached_property\n    def _sa_table(self):\n        try:\n            table = tables.reflect_table_from_oid(\n                self.oid, self.schema._sa_engine,\n            )\n        # We catch this error, since it lets us decouple the cadence of\n        # overall DB reflection from the cadence of cache expiration for\n        # table names.  Also, it makes it obvious when the DB layer has\n        # been altered, as opposed to other reasons for a 404 when\n        # requesting a table.\n        except TypeError:\n            table = tables.create_empty_table(\"MISSING\")\n        return table\n\n    @cached_property\n    def name(self):\n        return self._sa_table.name\n\n    @property\n    def sa_columns(self):\n        return self._sa_table.columns\n\n    @property\n    def sa_column_names(self):\n        return self.sa_columns.keys()\n\n    def add_column(self, column_data):\n        return columns.create_column(\n            self.schema._sa_engine,\n            self.oid,\n            column_data,\n        )\n\n    def alter_column(self, column_index, column_data):\n        return columns.alter_column(\n            self.schema._sa_engine,\n            self.oid,\n            column_index,\n            column_data,\n        )\n\n    def drop_column(self, column_index):\n        columns.drop_column(\n            self.schema._sa_engine,\n            self.oid,\n            column_index,\n        )\n\n    @property\n    def sa_num_records(self):\n        return tables.get_count(self._sa_table, self.schema._sa_engine)\n\n    @property\n    def sa_all_records(self):\n        return records.get_records(self._sa_table, self.schema._sa_engine)\n\n    def get_record(self, id_value):\n        return records.get_record(self._sa_table, self.schema._sa_engine, id_value)\n\n    def get_records(self, limit=None, offset=None, filters=[], order_by=[]):\n        return records.get_records(self._sa_table, self.schema._sa_engine, limit,\n                                   offset, filters=filters, order_by=order_by)\n\n    def get_group_counts(\n        self, group_by, limit=None, offset=None, filters=[], order_by=[]\n    ):\n        return records.get_group_counts(self._sa_table, self.schema._sa_engine,\n                                        group_by, limit, offset, filters=filters,\n                                        order_by=order_by)\n\n    def create_record_or_records(self, record_data):\n        return records.create_record_or_records(self._sa_table, self.schema._sa_engine, record_data)\n\n    def update_record(self, id_value, record_data):\n        return records.update_record(self._sa_table, self.schema._sa_engine, id_value, record_data)\n\n    def delete_record(self, id_value):\n        return records.delete_record(self._sa_table, self.schema._sa_engine, id_value)\n\n\nclass DataFile(BaseModel):\n    file = models.FileField(\n        upload_to=model_utils.user_directory_path,\n    )\n    user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)\n    table_imported_to = models.ForeignKey(Table, related_name=\"data_files\", blank=True,\n                                          null=True, on_delete=models.SET_NULL)\n    delimiter = models.CharField(max_length=1, default=',', blank=True)\n    escapechar = models.CharField(max_length=1, blank=True)\n    quotechar = models.CharField(max_length=1, default='\"', blank=True)\n", "path": "mathesar/models.py"}, {"content": "from rest_framework.exceptions import ValidationError\n\nfrom db.schemas import (\n    create_schema, get_schema_oid_from_name, get_mathesar_schemas,\n    get_mathesar_schemas_with_oids\n)\nfrom mathesar.database.base import create_mathesar_engine\nfrom mathesar.models import Schema\n\n\ndef create_schema_and_object(name, database):\n    engine = create_mathesar_engine(database)\n\n    all_schemas = get_mathesar_schemas(engine)\n    if name in all_schemas:\n        raise ValidationError({\"name\": \"Schema name is not unique\"})\n\n    create_schema(name, engine)\n    schema_oid = get_schema_oid_from_name(name, engine)\n    schema = Schema.objects.create(oid=schema_oid, database=database)\n    return schema\n\n\ndef reflect_schemas_from_database(database):\n    engine = create_mathesar_engine(database)\n    db_schema_oids = {\n        schema[\"oid\"] for schema in get_mathesar_schemas_with_oids(engine)\n    }\n    schemas = [\n        Schema.objects.get_or_create(oid=oid, database=database)\n        for oid in db_schema_oids\n    ]\n    for schema in Schema.objects.all():\n        if schema.oid not in db_schema_oids:\n            schema.delete()\n    return schemas\n", "path": "mathesar/utils/schemas.py"}], "after_files": [{"content": "from django.contrib.auth.models import User\nfrom django.core.cache import cache\nfrom django.db import models\nfrom django.utils.functional import cached_property\n\nfrom mathesar.database.base import create_mathesar_engine\nfrom mathesar.utils import models as model_utils\nfrom db import tables, records, schemas, columns\n\nNAME_CACHE_INTERVAL = 60 * 5\n\n\nclass BaseModel(models.Model):\n    created_at = models.DateTimeField(auto_now_add=True)\n    updated_at = models.DateTimeField(auto_now=True)\n\n    class Meta:\n        abstract = True\n\n\nclass DatabaseObject(BaseModel):\n    oid = models.IntegerField()\n\n    class Meta:\n        abstract = True\n\n    def __str__(self):\n        return f\"{self.__class__.__name__}: {self.oid}\"\n\n\n# TODO: Replace with a proper form of caching\n# See: https://github.com/centerofci/mathesar/issues/280\n_engines = {}\n\n\nclass Schema(DatabaseObject):\n    database = models.CharField(max_length=128)\n\n    @property\n    def _sa_engine(self):\n        global _engines\n        # We're caching this since the engine is used frequently.\n        if self.database not in _engines:\n            _engines[self.database] = create_mathesar_engine(self.database)\n        return _engines[self.database]\n\n    @cached_property\n    def name(self):\n        cache_key = f\"{self.database}_schema_name_{self.oid}\"\n        try:\n            schema_name = cache.get(cache_key)\n            if schema_name is None:\n                schema_name = schemas.get_schema_name_from_oid(\n                    self.oid, self._sa_engine\n                )\n                cache.set(cache_key, schema_name, NAME_CACHE_INTERVAL)\n            return schema_name\n        # We catch this error, since it lets us decouple the cadence of\n        # overall DB reflection from the cadence of cache expiration for\n        # schema names.  Also, it makes it obvious when the DB layer has\n        # been altered, as opposed to other reasons for a 404 when\n        # requesting a schema.\n        except TypeError:\n            return 'MISSING'\n\n\nclass Table(DatabaseObject):\n    schema = models.ForeignKey('Schema', on_delete=models.CASCADE,\n                               related_name='tables')\n    import_verified = models.BooleanField(blank=True, null=True)\n\n    @cached_property\n    def _sa_table(self):\n        try:\n            table = tables.reflect_table_from_oid(\n                self.oid, self.schema._sa_engine,\n            )\n        # We catch this error, since it lets us decouple the cadence of\n        # overall DB reflection from the cadence of cache expiration for\n        # table names.  Also, it makes it obvious when the DB layer has\n        # been altered, as opposed to other reasons for a 404 when\n        # requesting a table.\n        except TypeError:\n            table = tables.create_empty_table(\"MISSING\")\n        return table\n\n    @cached_property\n    def name(self):\n        return self._sa_table.name\n\n    @property\n    def sa_columns(self):\n        return self._sa_table.columns\n\n    @property\n    def sa_column_names(self):\n        return self.sa_columns.keys()\n\n    def add_column(self, column_data):\n        return columns.create_column(\n            self.schema._sa_engine,\n            self.oid,\n            column_data,\n        )\n\n    def alter_column(self, column_index, column_data):\n        return columns.alter_column(\n            self.schema._sa_engine,\n            self.oid,\n            column_index,\n            column_data,\n        )\n\n    def drop_column(self, column_index):\n        columns.drop_column(\n            self.schema._sa_engine,\n            self.oid,\n            column_index,\n        )\n\n    @property\n    def sa_num_records(self):\n        return tables.get_count(self._sa_table, self.schema._sa_engine)\n\n    @property\n    def sa_all_records(self):\n        return records.get_records(self._sa_table, self.schema._sa_engine)\n\n    def get_record(self, id_value):\n        return records.get_record(self._sa_table, self.schema._sa_engine, id_value)\n\n    def get_records(self, limit=None, offset=None, filters=[], order_by=[]):\n        return records.get_records(self._sa_table, self.schema._sa_engine, limit,\n                                   offset, filters=filters, order_by=order_by)\n\n    def get_group_counts(\n        self, group_by, limit=None, offset=None, filters=[], order_by=[]\n    ):\n        return records.get_group_counts(self._sa_table, self.schema._sa_engine,\n                                        group_by, limit, offset, filters=filters,\n                                        order_by=order_by)\n\n    def create_record_or_records(self, record_data):\n        return records.create_record_or_records(self._sa_table, self.schema._sa_engine, record_data)\n\n    def update_record(self, id_value, record_data):\n        return records.update_record(self._sa_table, self.schema._sa_engine, id_value, record_data)\n\n    def delete_record(self, id_value):\n        return records.delete_record(self._sa_table, self.schema._sa_engine, id_value)\n\n\nclass DataFile(BaseModel):\n    file = models.FileField(\n        upload_to=model_utils.user_directory_path,\n    )\n    user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)\n    table_imported_to = models.ForeignKey(Table, related_name=\"data_files\", blank=True,\n                                          null=True, on_delete=models.SET_NULL)\n    delimiter = models.CharField(max_length=1, default=',', blank=True)\n    escapechar = models.CharField(max_length=1, blank=True)\n    quotechar = models.CharField(max_length=1, default='\"', blank=True)\n", "path": "mathesar/models.py"}, {"content": "from rest_framework.exceptions import ValidationError\n\nfrom db.schemas import (\n    create_schema, get_schema_oid_from_name, get_mathesar_schemas,\n    get_mathesar_schemas_with_oids\n)\nfrom mathesar.database.base import create_mathesar_engine\nfrom mathesar.models import Schema\n\n\ndef create_schema_and_object(name, database):\n    engine = create_mathesar_engine(database)\n\n    all_schemas = get_mathesar_schemas(engine)\n    if name in all_schemas:\n        raise ValidationError({\"name\": \"Schema name is not unique\"})\n\n    create_schema(name, engine)\n    schema_oid = get_schema_oid_from_name(name, engine)\n    schema = Schema.objects.create(oid=schema_oid, database=database)\n    return schema\n\n\ndef reflect_schemas_from_database(database):\n    engine = create_mathesar_engine(database)\n    db_schema_oids = {\n        schema[\"oid\"] for schema in get_mathesar_schemas_with_oids(engine)\n    }\n    schemas = [\n        Schema.objects.get_or_create(oid=oid, database=database)\n        for oid in db_schema_oids\n    ]\n    for schema in Schema.objects.all():\n        if schema.database == database and schema.oid not in db_schema_oids:\n            schema.delete()\n    return schemas\n", "path": "mathesar/utils/schemas.py"}]}