text: # -*- coding: utf-8 -*-
  # Generated by Django 1.11.24 on 2019-10-25 21:43
  from __future__ import unicode_literals
  
  from datetime import timedelta
  from operator import itemgetter
  
  from django.db import migrations, models
  from django.db.migrations import RunPython
  
  from river.models import APPROVED
  
  
  def approval_key(approval):
      return "%s-%s-%s" % (approval.priority, approval.source_state.pk, approval.destination_state.pk)
  
  
  sql = """
  SELECT
      ta.id,
      ta.source_state_id,
      ta.destination_state_id,
      ta.transaction_date,
      ta.status,
      (
          select
              count(*)
          from river_transitionapproval ta_inner
          where ta_inner.workflow_id=ta.workflow_id AND
              ta_inner.object_id = ta.object_id AND
              ta_inner.source_state_id=ta.source_state_id AND
              ta_inner.destination_state_id=ta.destination_state_id AND
              ta_inner.priority=ta.priority AND
              ta_inner.date_created < ta.date_created
      ) as rw_number
  FROM river_transitionapproval ta
  WHERE rw_number=%d AND ta.workflow_id='%s' and ta.object_id='%s';
  """
  
  
  def migrate_iteration(apps, schema_editor):
      def _iterate(workflow, initial_state, workflow_object, last_approved_iteration=-1, generation=0):
          with schema_editor.connection.cursor() as cursor:
              output = cursor.execute(sql % (generation, workflow.pk, workflow_obj.pk)).fetchall()
              if output:
                  output = [
                      {
                          "pk": row[0],
                          "source_state_pk": row[1],
                          "destination_state_pk": row[2],
                          "approved_at": row[3],
                          "status": row[4]
                      }
                      for row in output
                  ]
  
                  last_approved = None
                  approvals = list([approval for approval in output if approval["source_state_pk"] == initial_state.pk])
                  iteration = last_approved_iteration + 1
                  processed_source_states = set()
                  while approvals:
                      workflow.transition_approvals.filter(pk__in=[approval['pk'] for approval in approvals]).update(iteration=iteration)
                      destination_state_pks = [approval['destination_state_pk'] for approval in approvals]
                      last_approved = next(reversed(sorted(filter(lambda a: a['status'] == APPROVED, approvals), key=itemgetter("approved_at"))), None)
                      processed_source_states.update([approval['source_state_pk'] for approval in approvals])
                      approvals = list([approval for approval in output if approval["source_state_pk"] in destination_state_pks and approval["source_state_pk"] not in processed_source_states])
                      iteration += 1
  
                  if last_approved:
                      last_approved_object = workflow.transition_approvals.get(pk=last_approved["pk"])
                      _iterate(workflow, last_approved_object.destination_state, workflow_object, last_approved_object.iteration, generation + 1)
  
      Workflow = apps.get_model('river', 'Workflow')
      for workflow in Workflow.objects.all():
          model_class = apps.get_model(workflow.content_type.app_label, workflow.content_type.model)
          for workflow_obj in model_class.objects.all():
              _iterate(workflow, workflow.initial_state, workflow_obj)
  
  
  class Migration(migrations.Migration):
      dependencies = [
          ('river', '0006_auto_20191020_1121'),
      ]
  
      operations = [
          migrations.AddField(
              model_name='transitionapproval',
              name='iteration',
              field=models.IntegerField(default=0, verbose_name='Priority'),
          ),
          migrations.RunPython(migrate_iteration, reverse_code=RunPython.noop),
      ]
  