From 42a9e342ef57a9ffa5016f4f57da633a811d2c0f Mon Sep 17 00:00:00 2001
From: stvn <stvn@mit.edu>
Date: Wed, 24 Feb 2021 12:00:34 -0800
Subject: [PATCH] fix: Manually backfill config_id UUIDs again

The previous backfills handled NULL entries;
this handles empty strings.

The difficulty here was that since the empty string in an invalid UUID
(as opposed to None/NULL which is just "blank"), attempts to instantiate
models would fail, given the invalid data. This meant we couldn't use
the Django ORM to handle the migration entirely; we need to craft some
raw SQL to work-around these checks and limitations.
---
 .../0009_backfill-empty-string-config-id.py   | 72 +++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100644 lti_consumer/migrations/0009_backfill-empty-string-config-id.py

diff --git a/lti_consumer/migrations/0009_backfill-empty-string-config-id.py b/lti_consumer/migrations/0009_backfill-empty-string-config-id.py
new file mode 100644
index 0000000..30f6a9e
--- /dev/null
+++ b/lti_consumer/migrations/0009_backfill-empty-string-config-id.py
@@ -0,0 +1,72 @@
+"""
+Backfill empty config_id records
+
+We need to do this with raw SQL,
+otherwise the model fails upon instantiation,
+as the empty string is an invalid UUID.
+"""
+import uuid
+
+from django.db import connection
+from django.db import migrations
+
+
+sql_forward = """\
+UPDATE
+    lti_consumer_lticonfiguration
+SET
+    config_id = %s
+WHERE
+    id = %s
+;\
+"""
+
+sql_select_empty = """\
+SELECT
+    id
+FROM
+    lti_consumer_lticonfiguration
+WHERE
+    config_id = ""
+;\
+"""
+
+
+def _get_ids_with_empty_uuid():
+    """
+    Retrieve the list of primary keys for each entry with a blank config_id
+    """
+    with connection.cursor() as cursor:
+        cursor.execute(sql_select_empty)
+        for row in cursor.fetchall():
+            yield row[0]
+
+
+def _create_config_ids(apps, schema_editor):
+    """
+    Generate a UUID for rows missing one
+
+    Note: The model stores these without hyphens.
+    """
+    for _id in _get_ids_with_empty_uuid():
+        config_id = uuid.uuid4()
+        config_id = str(config_id)
+        config_id = config_id.replace('-', '')
+        schema_editor.execute(sql_forward, [
+            config_id,
+            _id,
+        ])
+
+
+class Migration(migrations.Migration):
+    """
+    Backfill empty config_id records
+    """
+
+    dependencies = [
+        ('lti_consumer', '0008_fix_uuid_backfill'),
+    ]
+
+    operations = [
+        migrations.RunPython(_create_config_ids, atomic=False),
+    ]
-- 
GitLab