feat(politics): update election scheduling logic to include all unoccupied positions and improve query efficiency
This commit is contained in:
@@ -80,60 +80,86 @@ private:
|
|||||||
)";
|
)";
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
// STEP 1: Erzeuge nur diejenigen Wahlen, bei denen noch keine Election
|
// STEP 1: Erzeuge Wahlen für *alle* unbesetzten Soll-Stellen.
|
||||||
// für denselben Termin (NOW()+2 Tage) existiert.
|
// Dabei zählen auch bereits angelegte Wahlen als Reservierung,
|
||||||
|
// damit der tägliche Lauf keine doppelten Ausschreibungen erzeugt.
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
static constexpr const char* QUERY_SELECT_NEEDED_ELECTIONS = R"(
|
static constexpr const char* QUERY_SELECT_NEEDED_ELECTIONS = R"(
|
||||||
WITH
|
WITH
|
||||||
-- 1) Definiere das heutige Datum einmal als Referenz
|
-- 1) Definiere den tatsächlichen Wahltermin einmal als Referenz.
|
||||||
|
-- Die Bewerbungsphase dauert drei Tage (vgl. process_elections()).
|
||||||
target_date AS (
|
target_date AS (
|
||||||
SELECT NOW()::date AS election_date
|
SELECT NOW() + INTERVAL '3 days' AS election_date
|
||||||
),
|
),
|
||||||
|
|
||||||
-- 2) Lösche nur diejenigen Ämter, deren Ablaufdatum heute erreicht ist,
|
-- 2) Abgelaufene Ämter entfernen. Ein <= statt = heilt auch Lücken,
|
||||||
-- und merke deren (office_type_id, region_id)
|
-- falls der Worker an einem Tag nicht gelaufen ist.
|
||||||
expired_today AS (
|
expired_offices AS (
|
||||||
DELETE FROM falukant_data.political_office AS po
|
DELETE FROM falukant_data.political_office AS po
|
||||||
USING falukant_type.political_office_type AS pot
|
USING falukant_type.political_office_type AS pot
|
||||||
WHERE po.office_type_id = pot.id
|
WHERE po.office_type_id = pot.id
|
||||||
AND (po.created_at + (pot.term_length * INTERVAL '1 day'))::date = (SELECT election_date FROM target_date)
|
AND po.created_at + (pot.term_length * INTERVAL '1 day') <= NOW()
|
||||||
RETURNING
|
RETURNING
|
||||||
pot.id AS office_type_id,
|
pot.id AS office_type_id,
|
||||||
po.region_id AS region_id
|
po.region_id AS region_id
|
||||||
),
|
),
|
||||||
|
|
||||||
-- 3) Gruppiere nach Typ+Region und zähle, wie viele Sitze heute frei geworden sind
|
-- 3) Alle Soll-Stellen pro politischem Amt und echter Spielregion.
|
||||||
gaps_per_region AS (
|
-- Bisher wurden nur gerade abgelaufene Ämter betrachtet. Deshalb
|
||||||
|
-- erhielten nie besetzte (z. B. neu hinzugefügte) Amtstypen nie eine
|
||||||
|
-- Ausschreibung.
|
||||||
|
required_seats AS (
|
||||||
SELECT
|
SELECT
|
||||||
office_type_id,
|
pot.id AS office_type_id,
|
||||||
region_id,
|
r.id AS region_id,
|
||||||
COUNT(*) AS gaps
|
pot.seats_per_region AS seats_total
|
||||||
FROM expired_today
|
FROM falukant_type.political_office_type AS pot
|
||||||
|
JOIN falukant_data.region AS r
|
||||||
|
ON TRUE
|
||||||
|
JOIN falukant_type.region AS rt
|
||||||
|
ON rt.id = r.region_type_id
|
||||||
|
AND rt.label_tr = pot.region_type
|
||||||
|
),
|
||||||
|
|
||||||
|
-- 4) Aktuell besetzte und durch laufende Wahlen bereits reservierte
|
||||||
|
-- Sitze zählen.
|
||||||
|
occupied_seats AS (
|
||||||
|
SELECT po.office_type_id, po.region_id, COUNT(*) AS seats_occupied
|
||||||
|
FROM falukant_data.political_office AS po
|
||||||
|
JOIN falukant_type.political_office_type AS pot
|
||||||
|
ON pot.id = po.office_type_id
|
||||||
|
-- Datenändernde CTEs teilen sich denselben Statement-Snapshot.
|
||||||
|
-- Deshalb abgelaufene Zeilen hier ausdrücklich nicht mitzählen.
|
||||||
|
WHERE po.created_at + (pot.term_length * INTERVAL '1 day') > NOW()
|
||||||
|
GROUP BY po.office_type_id, po.region_id
|
||||||
|
),
|
||||||
|
reserved_seats AS (
|
||||||
|
SELECT office_type_id, region_id, SUM(posts_to_fill) AS seats_reserved
|
||||||
|
FROM falukant_data.election
|
||||||
GROUP BY office_type_id, region_id
|
GROUP BY office_type_id, region_id
|
||||||
),
|
),
|
||||||
|
gaps_per_region AS (
|
||||||
-- 4) Filtere nur diejenigen Typ+Region‐Kombinationen, für die noch **keine** Election
|
|
||||||
-- mit genau demselben Datum angelegt wurde
|
|
||||||
to_schedule AS (
|
|
||||||
SELECT
|
SELECT
|
||||||
g.office_type_id,
|
rs.office_type_id,
|
||||||
g.region_id,
|
rs.region_id,
|
||||||
g.gaps,
|
rs.seats_total
|
||||||
|
- COALESCE(os.seats_occupied, 0)
|
||||||
|
- COALESCE(es.seats_reserved, 0) AS gaps,
|
||||||
td.election_date
|
td.election_date
|
||||||
FROM
|
FROM required_seats AS rs
|
||||||
gaps_per_region AS g
|
LEFT JOIN occupied_seats AS os
|
||||||
CROSS JOIN
|
ON os.office_type_id = rs.office_type_id
|
||||||
target_date AS td
|
AND os.region_id = rs.region_id
|
||||||
WHERE NOT EXISTS (
|
LEFT JOIN reserved_seats AS es
|
||||||
SELECT 1
|
ON es.office_type_id = rs.office_type_id
|
||||||
FROM falukant_data.election AS e
|
AND es.region_id = rs.region_id
|
||||||
WHERE e.office_type_id = g.office_type_id
|
CROSS JOIN target_date AS td
|
||||||
AND e.region_id = g.region_id
|
WHERE rs.seats_total
|
||||||
AND e."date"::date = td.election_date
|
- COALESCE(os.seats_occupied, 0)
|
||||||
)
|
- COALESCE(es.seats_reserved, 0) > 0
|
||||||
),
|
),
|
||||||
|
|
||||||
-- 5) Lege für jede so gefilterte Kombination genau eine Election an
|
-- 5) Lege für jede vakante Kombination genau eine Election an.
|
||||||
new_elections AS (
|
new_elections AS (
|
||||||
INSERT INTO falukant_data.election
|
INSERT INTO falukant_data.election
|
||||||
(office_type_id, "date", posts_to_fill, created_at, updated_at, region_id)
|
(office_type_id, "date", posts_to_fill, created_at, updated_at, region_id)
|
||||||
@@ -145,7 +171,7 @@ private:
|
|||||||
NOW() AS updated_at,
|
NOW() AS updated_at,
|
||||||
ts.region_id
|
ts.region_id
|
||||||
FROM
|
FROM
|
||||||
to_schedule AS ts
|
gaps_per_region AS ts
|
||||||
RETURNING
|
RETURNING
|
||||||
id AS election_id,
|
id AS election_id,
|
||||||
region_id,
|
region_id,
|
||||||
|
|||||||
Reference in New Issue
Block a user