<reponame>code-review-doctor/orchestra<gh_stars>100-1000
# Generated by Django 2.2.13 on 2020-09-04 14:49


from django.db import migrations
from django.db.models import OuterRef
from django.db.models import Subquery


def fill_project_and_step_fields(apps, schema_editor):
    Step = apps.get_model('orchestra', 'Step')
    Project = apps.get_model('orchestra', 'Project')
    Todo = apps.get_model('orchestra', 'Todo')
    # This is the outer query field the querysets in the subqueries need to refer to
    o = OuterRef('id')
    # Select a step which has a task which has a todo which has an identical ID
    step_outerref_filter_qs = Step.objects.filter(tasks__todos__id=o)
    # Select a project which has a task which has a todo which has an identical ID
    project_outterref_filter_qs = Project.objects.filter(tasks__todos__id=o)
    # We need id value only. These will go as subqueries
    subq_step = step_outerref_filter_qs.values('id')[:1]
    subq_proj = project_outterref_filter_qs.values('id')[:1]
    # Update all todos
    Todo.objects.update(project=Subquery(subq_proj), step=Subquery(subq_step))
    """
    The query above generates the following SQL-query:

    UPDATE "orchestra_todo"
    SET "project_id" = (
          SELECT     u0."id"
          FROM       "orchestra_project" U0
          INNER JOIN "orchestra_task" U1
          ON         (u0."id" = u1."project_id")
          INNER JOIN "orchestra_todo" U2
          ON         (u1."id" = u2."task_id")
          WHERE      u2."id" = ("orchestra_todo"."id") limit 1),
       "step_id" = (
          SELECT     u0."id"
          FROM       "orchestra_step" u0
          INNER JOIN "orchestra_task" u1
          ON         (u0."id" = u1."step_id")
          INNER JOIN "orchestra_todo" u2
          ON         (u1."id" = u2."task_id")
          WHERE      u2."id" = ("orchestra_todo"."id") limit 1)
    WHERE  "orchestra_todo"."is_deleted" = false;args=(false,)
    """

class Migration(migrations.Migration):

    dependencies = [
        ('orchestra', '0086_add_fields_to_todo'),
    ]

    operations = [
        migrations.RunPython(fill_project_and_step_fields,  # manually-reviewed
                             reverse_code=migrations.RunPython.noop),  # manually-reviewed
    ]
