# the following migration step alters the tmssapp_taskblueprint_compute_aggretates_for_schedulingunitblueprint trigger function from migration 0037_populate_subtask_allowed_state_transitions_on_hold.py
# the only difference is that the state for all-tasks-obsolete is now aggregated as well.
# yes, this is ugly/annoying that we have to replicate code, but that's how database migration steps/deltas/patches work...
migrations.RunSQL('''CREATE OR REPLACE FUNCTION tmssapp_taskblueprint_compute_aggretates_for_schedulingunitblueprint()
RETURNS trigger AS
$BODY$
DECLARE
agg_scheduled_start_time timestamp with time zone;
agg_scheduled_stop_time timestamp with time zone;
agg_actual_process_start_time timestamp with time zone;
agg_actual_process_stop_time timestamp with time zone;
agg_actual_on_sky_start_time timestamp with time zone;
agg_actual_on_sky_stop_time timestamp with time zone;
agg_process_start_time timestamp with time zone;
agg_process_stop_time timestamp with time zone;
agg_on_sky_start_time timestamp with time zone;
agg_on_sky_stop_time timestamp with time zone;
agg_observed_start_time timestamp with time zone;
agg_observed_stop_time timestamp with time zone;
agg_status character varying(128);
agg_obsolete_since timestamp with time zone;
agg_on_sky_duration interval;
agg_observed_duration interval;
agg_duration interval;
BEGIN
-- aggregate the various timestamps
-- consider all the tasks for this schedulingunitblueprint
-- use a WITH Common Table Expression followed by a SELECT INTO variables for speed
WITH task_agg AS (SELECT MIN(scheduled_start_time) as scheduled_start_time,
MAX(scheduled_stop_time) as scheduled_stop_time,
MIN(actual_process_start_time) as actual_process_start_time,
MAX(actual_process_stop_time) as actual_process_stop_time,
SUM(duration) as duration,
MIN(actual_on_sky_start_time) as actual_on_sky_start_time,
MAX(actual_on_sky_stop_time) as actual_on_sky_stop_time,
MIN(process_start_time) as process_start_time,
MAX(process_stop_time) as process_stop_time,
MIN(on_sky_start_time) as on_sky_start_time,
MAX(on_sky_stop_time) as on_sky_stop_time,
SUM(on_sky_duration) as on_sky_duration,
MIN(obsolete_since) as obsolete_since
FROM tmssapp_taskblueprint
WHERE tmssapp_taskblueprint.scheduling_unit_blueprint_id=NEW.scheduling_unit_blueprint_id
INTO agg_observed_start_time, agg_observed_stop_time, agg_observed_duration
FROM observed_task_agg;
-- aggregate the task statuses into one schedulingunit status
-- See design: https://support.astron.nl/confluence/display/TMSS/Specification+Flow/#SpecificationFlow-SchedulingUnitBlueprints
-- consider all the taskblueprints for this schedulingunitblueprint
-- use a WITH Common Table Expression followed by a SELECT INTO variables for speed
WITH task_statuses AS (SELECT tmssapp_taskblueprint.status_id, tmssapp_tasktemplate.type_id
FROM tmssapp_taskblueprint
INNER JOIN tmssapp_tasktemplate on tmssapp_tasktemplate.id=tmssapp_taskblueprint.specifications_template_id
WHERE tmssapp_taskblueprint.scheduling_unit_blueprint_id=NEW.scheduling_unit_blueprint_id
AND tmssapp_taskblueprint.obsolete_since IS NULL)
SELECT CASE
WHEN (SELECT COUNT(true) FROM task_statuses)=0 THEN 'defined'
WHEN EXISTS(SELECT true FROM task_statuses WHERE status_id='defined') THEN 'defined'
WHEN (SELECT COUNT(true) FROM task_statuses WHERE status_id in ('finished', 'observed'))=(SELECT COUNT(true) FROM task_statuses) THEN 'finished'
WHEN EXISTS(SELECT true FROM task_statuses WHERE status_id='cancelled') THEN 'cancelled'
WHEN EXISTS(SELECT true FROM task_statuses WHERE status_id='error') THEN 'error'
WHEN EXISTS(SELECT true FROM task_statuses WHERE status_id='unschedulable') THEN 'unschedulable'
WHEN EXISTS(SELECT true FROM task_statuses WHERE status_id IN ('queued', 'started', 'observed', 'finished', 'on hold')) THEN
CASE
WHEN (SELECT COUNT(true) FROM task_statuses WHERE type_id='observation' AND status_id IN ('observed', 'finished'))<(SELECT COUNT(true) FROM task_statuses WHERE type_id='observation') THEN 'observing'
WHEN NOT EXISTS(SELECT true FROM task_statuses WHERE type_id='pipeline' AND status_id IN ('queued', 'started', 'finished')) THEN 'observed'
WHEN EXISTS(SELECT true FROM task_statuses WHERE type_id='ingest' AND status_id IN ('queued', 'started', 'on hold')) THEN 'ingesting'
WHEN (SELECT COUNT(true) FROM task_statuses WHERE type_id='ingest' AND status_id='finished')=(SELECT COUNT(true) FROM task_statuses WHERE type_id='ingest') AND (SELECT COUNT(true) FROM task_statuses WHERE type_id='ingest')>0 THEN 'ingested'
WHEN (SELECT COUNT(true) FROM task_statuses WHERE type_id='pipeline' AND status_id='finished')=(SELECT COUNT(true) FROM task_statuses WHERE type_id='pipeline') AND (SELECT COUNT(true) FROM task_statuses WHERE type_id='pipeline')>0 THEN 'processed'
WHEN EXISTS(SELECT true FROM task_statuses WHERE type_id='pipeline' AND status_id IN ('queued', 'started', 'scheduled', 'finished')) THEN 'processing'
END
WHEN EXISTS(SELECT true FROM task_statuses WHERE status_id='scheduled') THEN 'scheduled'
END
INTO agg_status
FROM task_statuses;
-- when no non-obsolete tasks available
IF agg_status IS NULL THEN
-- when no tasks at all -> defined
IF (SELECT COUNT(tmssapp_taskblueprint.id) FROM tmssapp_taskblueprint WHERE tmssapp_taskblueprint.scheduling_unit_blueprint_id=NEW.scheduling_unit_blueprint_id) = 0 THEN
agg_status := 'defined';
ELSE
-- there are tasks.
-- if all obsolete -> cancelled
IF (SELECT COUNT(tmssapp_taskblueprint.id) FROM tmssapp_taskblueprint WHERE tmssapp_taskblueprint.scheduling_unit_blueprint_id=NEW.scheduling_unit_blueprint_id AND tmssapp_taskblueprint.obsolete_since IS NOT NULL)=(SELECT COUNT(tmssapp_taskblueprint.id) FROM tmssapp_taskblueprint WHERE tmssapp_taskblueprint.scheduling_unit_blueprint_id=NEW.scheduling_unit_blueprint_id) THEN
agg_status := 'cancelled';
ELSE
agg_status := 'schedulable';
END IF;
END IF;
END IF;
-- all aggregated timestamps and statuses were computed
-- now update the referred taskblueprint with these aggregated values
UPDATE tmssapp_schedulingunitblueprint
SET scheduled_start_time=agg_scheduled_start_time,