Repository: mathesar-foundation/mathesar

Issue:
Test all code brought in from the prototype
**Problem**
<!-- Please provide a clear and concise description of the problem that this feature request is designed to solve.-->
The code brought over from the prototype in PRs #57 , #60, #75, #79, #85 is not yet fully tested

**Proposed solution**
<!-- A clear and concise description of your proposed solution or feature. -->

Write tests covering all code from those PRs which is not yet covered.



Discussion:

Resolving patch:
diff --git a/db/tables.py b/db/tables.py
--- a/db/tables.py
+++ b/db/tables.py
@@ -132,7 +132,7 @@ def _create_split_insert_stmt(
         remainder_columns,
         remainder_fk_name,
 ):
-    SPLIT_ID = "f{constants.MATHESAR_PREFIX}_split_column_alias"
+    SPLIT_ID = f"{constants.MATHESAR_PREFIX}_split_column_alias"
     extracted_column_names = [col.name for col in extracted_columns]
     remainder_column_names = [col.name for col in remainder_columns]
     split_cte = select(
@@ -224,7 +224,7 @@ def merge_tables(
     return merged_table
 
 
-def move_column_between_related_tables(
+def move_columns_between_related_tables(
         source_table_name,
         target_table_name,
         column_names,
@@ -318,9 +318,9 @@ def _get_column_moving_extraction_args(
         extracted_table_name = source_table_name
         remainder_table_name = target_table_name
         extraction_columns = [
-            col for col in target_table.columns
+            col for col in source_table.columns
             if not columns.MathesarColumn.from_column(col).is_default
-            and col not in column_names
+            and col.name not in column_names
         ]
     return extracted_table_name, remainder_table_name, extraction_columns
 


Test patch:
diff --git a/db/tests/test_tables.py b/db/tests/test_tables.py
--- a/db/tests/test_tables.py
+++ b/db/tests/test_tables.py
@@ -1,6 +1,6 @@
 import os
 import pytest
-from sqlalchemy import text, MetaData
+from sqlalchemy import text, MetaData, select
 from db import tables, constants, columns
 
 FILE_DIR = os.path.abspath(os.path.dirname(__file__))
@@ -11,6 +11,8 @@
 ROSTER_NO_TEACHERS = "Roster without Teachers"
 APP_SCHEMA = "test_schema"
 EXTRACTED_COLS = ["Teacher", "Teacher Email"]
+REM_MOVE_COL = ["Subject"]
+REM_MOVE_COLS = ["Student Name", "Student Email"]
 FKEY_COL = f"{TEACHERS}_{constants.ID}"
 
 
@@ -145,7 +147,49 @@ def test_extract_columns_leaves_correct_columns(extracted_remainder_roster):
     assert expect_remainder_names == actual_remainder_names
 
 
-def test_merge_columns_undoes_extract_columns_ddl(extracted_remainder_roster):
+def test_extract_columns_extracts_correct_data(extracted_remainder_roster):
+    # This test is only valid in combination
+    # with test_extract_columns_extracts_columns, since we assume the
+    # extracted column list is correct
+    extracted, _, roster, engine = extracted_remainder_roster
+    expect_tuple_sel = (
+        select([roster.columns[name] for name in EXTRACTED_COLS])
+        .distinct()
+    )
+    actual_tuple_sel = select(
+        [extracted.columns[name] for name in EXTRACTED_COLS]
+    )
+    with engine.begin() as conn:
+        expect_tuples = conn.execute(expect_tuple_sel).fetchall()
+        actual_tuples = conn.execute(actual_tuple_sel).fetchall()
+    assert sorted(expect_tuples) == sorted(actual_tuples)
+
+
+def test_extract_columns_leaves_correct_data(extracted_remainder_roster):
+    # This test is only valid in combination
+    # with test_extract_columns_leaves_correct_columns, since we assume the
+    # remainder column list is correct
+    extracted, remainder, roster, engine = extracted_remainder_roster
+    remainder_column_names = [
+        col.name for col in roster.columns
+        if col.name not in columns.DEFAULT_COLUMNS
+        and col.name not in EXTRACTED_COLS
+    ]
+    expect_tuple_sel = select(
+        [roster.columns[name] for name in remainder_column_names]
+    )
+    actual_tuple_sel = select(
+        [remainder.columns[name] for name in remainder_column_names]
+    )
+    with engine.begin() as conn:
+        expect_tuples = conn.execute(expect_tuple_sel).fetchall()
+        actual_tuples = conn.execute(actual_tuple_sel).fetchall()
+    assert sorted(expect_tuples) == sorted(actual_tuples)
+
+
+def test_merge_columns_undoes_extract_columns_ddl_rem_ext(
+        extracted_remainder_roster
+):
     extracted, remainder, roster, engine = extracted_remainder_roster
     tables.merge_tables(
         remainder.name,
@@ -160,3 +204,154 @@ def test_merge_columns_undoes_extract_columns_ddl(extracted_remainder_roster):
     expect_merged_names = sorted([col.name for col in roster.columns])
     actual_merged_names = sorted([col.name for col in merged.columns])
     assert expect_merged_names == actual_merged_names
+
+
+def test_merge_columns_undoes_extract_columns_ddl_ext_rem(
+        extracted_remainder_roster
+):
+    extracted, remainder, roster, engine = extracted_remainder_roster
+    tables.merge_tables(
+        extracted.name,
+        remainder.name,
+        "Merged Roster",
+        APP_SCHEMA,
+        engine,
+    )
+    metadata = MetaData(bind=engine, schema=APP_SCHEMA)
+    metadata.reflect()
+    merged = metadata.tables[f"{APP_SCHEMA}.Merged Roster"]
+    expect_merged_names = sorted([col.name for col in roster.columns])
+    actual_merged_names = sorted([col.name for col in merged.columns])
+    assert expect_merged_names == actual_merged_names
+
+
+def test_merge_columns_returns_original_data_rem_ext(
+        extracted_remainder_roster
+):
+    extracted, remainder, roster, engine = extracted_remainder_roster
+    tables.merge_tables(
+        remainder.name,
+        extracted.name,
+        "Merged Roster",
+        APP_SCHEMA,
+        engine,
+    )
+    metadata = MetaData(bind=engine, schema=APP_SCHEMA)
+    metadata.reflect()
+    roster_columns = sorted(
+        [
+            col.name for col in roster.columns
+            if col.name not in columns.DEFAULT_COLUMNS
+        ]
+    )
+    merged = metadata.tables[f"{APP_SCHEMA}.Merged Roster"]
+    merged_columns = sorted(
+        [
+            col.name for col in merged.columns
+            if col.name not in columns.DEFAULT_COLUMNS
+        ]
+    )
+    expect_tuple_sel = select(
+        [roster.columns[name] for name in roster_columns]
+    )
+    actual_tuple_sel = select(
+        [merged.columns[name] for name in merged_columns]
+    )
+    with engine.begin() as conn:
+        expect_tuples = conn.execute(expect_tuple_sel).fetchall()
+        actual_tuples = conn.execute(actual_tuple_sel).fetchall()
+    assert sorted(expect_tuples) == sorted(actual_tuples)
+
+
+def test_merge_columns_returns_original_data_ext_rem(
+        extracted_remainder_roster
+):
+    extracted, remainder, roster, engine = extracted_remainder_roster
+    tables.merge_tables(
+        extracted.name,
+        remainder.name,
+        "Merged Roster",
+        APP_SCHEMA,
+        engine,
+    )
+    metadata = MetaData(bind=engine, schema=APP_SCHEMA)
+    metadata.reflect()
+    roster_columns = sorted(
+        [
+            col.name for col in roster.columns
+            if col.name not in columns.DEFAULT_COLUMNS
+        ]
+    )
+    merged = metadata.tables[f"{APP_SCHEMA}.Merged Roster"]
+    merged_columns = sorted(
+        [
+            col.name for col in merged.columns
+            if col.name not in columns.DEFAULT_COLUMNS
+        ]
+    )
+    expect_tuple_sel = select(
+        [roster.columns[name] for name in roster_columns]
+    )
+    actual_tuple_sel = select(
+        [merged.columns[name] for name in merged_columns]
+    )
+    with engine.begin() as conn:
+        expect_tuples = conn.execute(expect_tuple_sel).fetchall()
+        actual_tuples = conn.execute(actual_tuple_sel).fetchall()
+    assert sorted(expect_tuples) == sorted(actual_tuples)
+
+
+def test_move_columns_moves_column_from_ext_to_rem(extracted_remainder_roster):
+    extracted, remainder, _, engine = extracted_remainder_roster
+    moving_col = EXTRACTED_COLS[0]
+    extracted_cols = [col.name for col in extracted.columns]
+    remainder_cols = [col.name for col in remainder.columns]
+    expect_extracted_cols = [
+        name for name in extracted_cols if name != moving_col
+    ]
+    expect_remainder_cols = remainder_cols + [moving_col]
+    extracted_name = extracted.name
+    remainder_name = remainder.name
+    tables.move_columns_between_related_tables(
+        extracted_name,
+        remainder_name,
+        [moving_col],
+        APP_SCHEMA,
+        engine,
+    )
+    metadata = MetaData(bind=engine, schema=APP_SCHEMA)
+    metadata.reflect()
+    new_extracted = metadata.tables[f"{APP_SCHEMA}.{extracted_name}"]
+    new_remainder = metadata.tables[f"{APP_SCHEMA}.{remainder_name}"]
+    actual_extracted_cols = [col.name for col in new_extracted.columns]
+    actual_remainder_cols = [col.name for col in new_remainder.columns]
+    assert sorted(actual_extracted_cols) == sorted(expect_extracted_cols)
+    assert sorted(actual_remainder_cols) == sorted(expect_remainder_cols)
+
+
+def test_move_columns_moves_column_from_rem_to_ext(extracted_remainder_roster):
+    extracted, remainder, _, engine = extracted_remainder_roster
+    extracted_cols = [col.name for col in extracted.columns]
+    remainder_cols = [col.name for col in remainder.columns]
+    moving_col = "Grade"
+    expect_remainder_cols = [
+        name for name in remainder_cols if name != moving_col
+    ]
+    expect_extracted_cols = extracted_cols + [moving_col]
+    extracted_name = extracted.name
+    remainder_name = remainder.name
+    tables.move_columns_between_related_tables(
+        remainder_name,
+        extracted_name,
+        [moving_col],
+        APP_SCHEMA,
+        engine,
+    )
+    metadata = MetaData(bind=engine, schema=APP_SCHEMA)
+    metadata.reflect()
+    new_extracted = metadata.tables[f"{APP_SCHEMA}.{extracted_name}"]
+    new_remainder = metadata.tables[f"{APP_SCHEMA}.{remainder_name}"]
+    actual_extracted_cols = [col.name for col in new_extracted.columns]
+    actual_remainder_cols = [col.name for col in new_remainder.columns]
+    assert sorted(actual_extracted_cols) == sorted(expect_extracted_cols)
+    assert sorted(actual_remainder_cols) == sorted(expect_remainder_cols)