diff options
-rw-r--r-- | patchwork/migrations/0039_unique_series_references.py | 110 |
1 files changed, 46 insertions, 64 deletions
diff --git a/patchwork/migrations/0039_unique_series_references.py b/patchwork/migrations/0039_unique_series_references.py index 99b10fc..3a10172 100644 --- a/patchwork/migrations/0039_unique_series_references.py +++ b/patchwork/migrations/0039_unique_series_references.py @@ -3,62 +3,6 @@ from django.db.models import Count import django.db.models.deletion -def merge_duplicate_series(apps, schema_editor): - SeriesReference = apps.get_model('patchwork', 'SeriesReference') - Patch = apps.get_model('patchwork', 'Patch') - - msgid_seriesrefs = {} - - # find all SeriesReference that share a msgid but point to different series - # and decide which of the series is going to be the authoritative one - msgid_counts = ( - SeriesReference.objects.values('msgid') - .annotate(count=Count('msgid')) - .filter(count__gt=1) - ) - for msgid_count in msgid_counts: - msgid = msgid_count['msgid'] - chosen_ref = None - for series_ref in SeriesReference.objects.filter(msgid=msgid): - if series_ref.series.cover_letter: - if chosen_ref: - # I don't think this can happen, but explode if it does - raise Exception( - "Looks like you've got two or more series that share " - "some patches but do not share a cover letter. Unable " - "to auto-resolve." - ) - - # if a series has a cover letter, that's the one we'll group - # everything under - chosen_ref = series_ref - - if not chosen_ref: - # if none of the series have cover letters, simply use the last - # one (hint: this relies on Python's weird scoping for for loops - # where 'series_ref' is still accessible outside the loop) - chosen_ref = series_ref - - msgid_seriesrefs[msgid] = chosen_ref - - # reassign any patches referring to non-authoritative series to point to - # the authoritative one, and delete the other series; we do this separately - # to allow us a chance to raise the exception above if necessary - for msgid, chosen_ref in msgid_seriesrefs.items(): - for series_ref in SeriesReference.objects.filter(msgid=msgid): - if series_ref == chosen_ref: - continue - - # update the patches to point to our chosen series instead, on the - # assumption that all other metadata is correct - for patch in Patch.objects.filter(series=series_ref.series): - patch.series = chosen_ref.series - patch.save() - - # delete the other series (which will delete the series ref) - series_ref.series.delete() - - def copy_project_field(apps, schema_editor): if connection.vendor == 'postgresql': schema_editor.execute( @@ -67,7 +11,7 @@ def copy_project_field(apps, schema_editor): SET project_id = patchwork_series.project_id FROM patchwork_series WHERE patchwork_seriesreference.series_id = patchwork_series.id - """ + """ ) elif connection.vendor == 'mysql': schema_editor.execute( @@ -75,7 +19,7 @@ def copy_project_field(apps, schema_editor): UPDATE patchwork_seriesreference, patchwork_series SET patchwork_seriesreference.project_id = patchwork_series.project_id WHERE patchwork_seriesreference.series_id = patchwork_series.id - """ # noqa + """ # noqa ) else: SeriesReference = apps.get_model('patchwork', 'SeriesReference') @@ -87,14 +31,49 @@ def copy_project_field(apps, schema_editor): series_ref.save() +def delete_duplicate_series(apps, schema_editor): + if connection.vendor == 'postgresql': + schema_editor.execute( + """ + DELETE + FROM + patchwork_seriesreference a + USING patchwork_seriesreference b + WHERE + a.id < b.id + AND a.project_id = b.project_id + AND a.msgid = b.msgid + """ + ) + elif connection.vendor == 'mysql': + schema_editor.execute( + """ + DELETE a FROM patchwork_seriesreference a + INNER JOIN patchwork_seriesreference b + WHERE + a.id < b.id + AND a.project_id = b.project_id + AND a.msgid = b.msgid + """ + ) + else: + Project = apps.get_model('patchwork', 'Project') + SeriesReference = apps.get_model('patchwork', 'SeriesReference') + + for project in Project.objects.all(): + ( + SeriesReference.objects.filter(project=project) + .annotate(count=Count('msgid')) + .filter(count__gt=1) + .delete() + ) + + class Migration(migrations.Migration): dependencies = [('patchwork', '0038_state_slug')] operations = [ - migrations.RunPython( - merge_duplicate_series, migrations.RunPython.noop, atomic=False - ), migrations.AddField( model_name='seriesreference', name='project', @@ -104,12 +83,12 @@ class Migration(migrations.Migration): to='patchwork.Project', ), ), - migrations.AlterUniqueTogether( - name='seriesreference', unique_together={('project', 'msgid')} - ), migrations.RunPython( copy_project_field, migrations.RunPython.noop, atomic=False ), + migrations.RunPython( + delete_duplicate_series, migrations.RunPython.noop, atomic=False + ), migrations.AlterField( model_name='seriesreference', name='project', @@ -118,4 +97,7 @@ class Migration(migrations.Migration): to='patchwork.Project', ), ), + migrations.AlterUniqueTogether( + name='seriesreference', unique_together={('project', 'msgid')} + ), ] |