Repository: mathesar-foundation/mathesar

Issue:
Column dropping operation should use attnum
## Problem
<!-- Please provide a clear and concise description of the problem that this feature request is designed to solve.-->

Currently, the column dropping function uses the column index to identify columns.  This is brittle, and we've decided to change to using the `attnum` property of columns instead.

## Proposed solution
<!-- A clear and concise description of your proposed solution or feature. -->

The function in `db/columns/operations/drop.py` should use `attnum` instead of `column_index`, and should properly use the `table_oid, attnum` pair to identify columns for its logic.  Use the function `get_column_name_from_attnum` in the `db.columns.operations.select` module for this.

## Additional context
<!-- Add any other context or screenshots about the feature request here.-->

We'll need to modify any place where the function is called as well.


Discussion:

Resolving patch:
diff --git a/db/columns/operations/drop.py b/db/columns/operations/drop.py
--- a/db/columns/operations/drop.py
+++ b/db/columns/operations/drop.py
@@ -1,13 +1,14 @@
 from alembic.migration import MigrationContext
 from alembic.operations import Operations
 
+from db.columns.operations.select import get_column_name_from_attnum
 from db.tables.operations.select import reflect_table_from_oid
 
 
-def drop_column(table_oid, column_index, engine):
-    column_index = int(column_index)
+def drop_column(table_oid, column_attnum, engine):
     table = reflect_table_from_oid(table_oid, engine)
-    column = table.columns[column_index]
+    column_name = get_column_name_from_attnum(table_oid, column_attnum, engine)
+    column = table.columns[column_name]
     with engine.begin() as conn:
         ctx = MigrationContext.configure(conn)
         op = Operations(ctx)
diff --git a/mathesar/api/db/viewsets/columns.py b/mathesar/api/db/viewsets/columns.py
--- a/mathesar/api/db/viewsets/columns.py
+++ b/mathesar/api/db/viewsets/columns.py
@@ -166,7 +166,7 @@ def destroy(self, request, pk=None, table_pk=None):
         column_instance = self.get_object()
         table = column_instance.table
         try:
-            table.drop_column(column_instance.column_index)
+            table.drop_column(column_instance.attnum)
             column_instance.delete()
         except IndexError:
             raise NotFound
diff --git a/mathesar/models.py b/mathesar/models.py
--- a/mathesar/models.py
+++ b/mathesar/models.py
@@ -261,10 +261,10 @@ def alter_column(self, column_index, column_data):
             column_data,
         )
 
-    def drop_column(self, column_index):
+    def drop_column(self, column_attnum):
         drop_column(
             self.oid,
-            column_index,
+            column_attnum,
             self.schema._sa_engine,
         )
 


Test patch:
diff --git a/db/tests/columns/operations/test_drop.py b/db/tests/columns/operations/test_drop.py
--- a/db/tests/columns/operations/test_drop.py
+++ b/db/tests/columns/operations/test_drop.py
@@ -1,6 +1,7 @@
 from sqlalchemy import String, Integer, Column, Table, MetaData
 
 from db.columns.operations.drop import drop_column
+from db.columns.operations.select import get_column_attnum_from_name
 from db.tables.operations.select import get_oid_from_table, reflect_table_from_oid
 from db.tests.types import fixtures
 
@@ -23,7 +24,8 @@ def test_drop_column_correct_column(engine_with_schema):
     )
     table.create()
     table_oid = get_oid_from_table(table_name, schema, engine)
-    drop_column(table_oid, 0, engine)
+    column_attnum = get_column_attnum_from_name(table_oid, target_column_name, engine)
+    drop_column(table_oid, column_attnum, engine)
     altered_table = reflect_table_from_oid(table_oid, engine)
     assert len(altered_table.columns) == 1
     assert nontarget_column_name in altered_table.columns