From 22e47e75cd66cb6af6ab8e3d73c7752d841bb042 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ji=C5=99=C3=AD=20Setni=C4=8Dka?= <setnicka@seznam.cz>
Date: Thu, 4 Mar 2021 01:41:57 +0100
Subject: [PATCH] =?UTF-8?q?DB:=20Zaveden=C3=AD=20=C4=8D=C3=A1sti=20kola=20?=
 =?UTF-8?q?a=20p=C5=99id=C3=A1n=C3=AD=20master=5Fround=5Fid=20a=20master?=
 =?UTF-8?q?=5Fcontest=5Fid?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Budou použity pro vícedílná kola. Všechny kola/soutěže ve skupině se
budou odkazovat na stejné hlavní kolo/soutěž, operace s účastníky budou
prováděny na hlavním kole/soutěži.

Část kola je číslo 1, 2, ... a pokud je nastaveno, tak se projevuje do
kódu kola jako přilepené písmeno (70-A-3a, 70-A-3b)

Issue #178
---
 db/db.ddl                | 15 +++++++++++----
 db/upgrade-20210307b.sql | 18 ++++++++++++++++++
 mo/db.py                 |  8 +++++++-
 3 files changed, 36 insertions(+), 5 deletions(-)
 create mode 100644 db/upgrade-20210307b.sql

diff --git a/db/db.ddl b/db/db.ddl
index ae71eae7..ccccdee6 100644
--- a/db/db.ddl
+++ b/db/db.ddl
@@ -90,9 +90,11 @@ CREATE TYPE score_mode AS ENUM (
 
 CREATE TABLE rounds (
 	round_id	serial		PRIMARY KEY,
+	master_round_id	int		DEFAULT NULL REFERENCES rounds(round_id),
 	year		int		NOT NULL,			-- ročník MO
 	category	varchar(2)	NOT NULL,			-- "A", "Z5" apod.
 	seq		int		NOT NULL,			-- 1=domácí kolo atd.
+	part		int		NOT NULL DEFAULT 0,		-- část kola (u dělených kol)
 	level		int		NOT NULL,			-- úroveň hierarchie míst
 	name		varchar(255)	NOT NULL,			-- zobrazované jméno ("Krajské kolo" apod.)
 	state		round_state	NOT NULL DEFAULT 'preparing',	-- stav kola
@@ -104,17 +106,22 @@ CREATE TABLE rounds (
 	score_mode	score_mode	NOT NULL DEFAULT 'basic',	-- mód výsledkovky
 	score_winner_limit	int	DEFAULT NULL,			-- bodový limit na označení za vítěze
 	score_successful_limit	int	DEFAULT NULL,			-- bodový limit na označení za úspěšného řešitele
-	UNIQUE (year, category, seq)
+	UNIQUE (year, category, seq, part)
 );
 
+CREATE INDEX rounds_master_round_id_index ON rounds (master_round_id);
+
 -- Soutěže (instance kola v konkrétním místě)
 CREATE TABLE contests (
-	contest_id	serial		PRIMARY KEY,
-	round_id	int		NOT NULL REFERENCES rounds(round_id),
-	place_id	int		NOT NULL REFERENCES places(place_id),
+	contest_id		serial		PRIMARY KEY,
+	master_contest_id	int		DEFAULT NULL REFERENCES contests(contest_id),
+	round_id		int		NOT NULL REFERENCES rounds(round_id),
+	place_id		int		NOT NULL REFERENCES places(place_id),
 	UNIQUE (round_id, place_id)
 );
 
+CREATE INDEX contests_master_contest_id_index ON contests (master_contest_id);
+
 -- Detaily účastníka
 CREATE TABLE participants (
 	user_id		int		NOT NULL REFERENCES users(user_id),
diff --git a/db/upgrade-20210307b.sql b/db/upgrade-20210307b.sql
new file mode 100644
index 00000000..4c1fc444
--- /dev/null
+++ b/db/upgrade-20210307b.sql
@@ -0,0 +1,18 @@
+SET ROLE 'mo_osmo';
+
+ALTER TABLE rounds
+	ADD COLUMN	master_round_id		int	DEFAULT NULL REFERENCES rounds(round_id),
+	ADD COLUMN	part			int	NOT NULL DEFAULT 0;				-- část kola (u dělených kol)
+
+ALTER TABLE contests
+	ADD COLUMN	master_contest_id	int	DEFAULT NULL REFERENCES contests(contest_id);
+
+ALTER TABLE rounds
+	DROP CONSTRAINT "rounds_year_category_seq_key",
+	ADD CONSTRAINT "rounds_year_category_seq_part_key" UNIQUE (year, category, seq, part);
+
+CREATE INDEX rounds_master_round_id_index ON rounds (master_round_id);
+CREATE INDEX contests_master_contest_id_index ON contests (master_contest_id);
+
+UPDATE rounds SET master_round_id=round_id;
+UPDATE contests SET master_contest_id=contest_id;
diff --git a/mo/db.py b/mo/db.py
index f24e55c8..0082b288 100644
--- a/mo/db.py
+++ b/mo/db.py
@@ -187,13 +187,15 @@ round_score_mode_names = {
 class Round(Base):
     __tablename__ = 'rounds'
     __table_args__ = (
-        UniqueConstraint('year', 'category', 'seq'),
+        UniqueConstraint('year', 'category', 'seq', 'part'),
     )
 
     round_id = Column(Integer, primary_key=True, server_default=text("nextval('rounds_round_id_seq'::regclass)"))
+    master_round_id = Column(Integer, ForeignKey('rounds.round_id'))
     year = Column(Integer, nullable=False)
     category = Column(String(2), nullable=False)
     seq = Column(Integer, nullable=False)
+    part = Column(Integer, nullable=False)
     level = Column(Integer, nullable=False)
     name = Column(String(255), nullable=False)
     state = Column(Enum(RoundState, name='round_state'), nullable=False, server_default=text("'preparing'::round_state"))
@@ -206,6 +208,8 @@ class Round(Base):
     score_winner_limit = Column(Integer)
     score_successful_limit = Column(Integer)
 
+    master = relationship('Round', primaryjoin='Round.master_round_id == Round.round_id', remote_side='Round.round_id', post_update=True)
+
     def round_code(self):
         return f"{self.year}-{self.category}-{self.seq}"
 
@@ -275,9 +279,11 @@ class Contest(Base):
     )
 
     contest_id = Column(Integer, primary_key=True, server_default=text("nextval('contests_contest_id_seq'::regclass)"))
+    master_contest_id = Column(Integer, ForeignKey('contests.contest_id'))
     round_id = Column(Integer, ForeignKey('rounds.round_id'), nullable=False)
     place_id = Column(Integer, ForeignKey('places.place_id'), nullable=False)
 
+    master = relationship('Contest', primaryjoin='Contest.master_contest_id == Contest.contest_id', remote_side='Contest.contest_id', post_update=True)
     place = relationship('Place')
     round = relationship('Round')
 
-- 
GitLab