From 5c4948bd6d9c6f5abe3674b8b8c57062b8b74f34 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rouby Date: Tue, 23 Jul 2024 13:38:05 +0200 Subject: [PATCH] Pamhyr: Database: Update data dictionary and some change to prepare db 0.1.0. --- src/Model/AdditionalFile/AddFile.py | 8 +- .../BoundaryCondition/BoundaryCondition.py | 64 +++-- src/Model/Friction/Friction.py | 2 +- src/Model/Friction/FrictionList.py | 4 +- src/Model/Geometry/PointXYZ.py | 7 +- src/Model/Geometry/ProfileXYZ.py | 4 +- src/Model/Geometry/Reach.py | 4 +- .../Basic/HydraulicStructures.py | 4 +- src/Model/HydraulicStructures/Basic/Value.py | 2 +- .../HydraulicStructures.py | 4 +- .../InitialConditions/InitialConditions.py | 8 +- .../LateralContribution.py | 244 +++++++++++++----- src/Model/REPLine/REPLine.py | 2 +- src/Model/Reservoir/Reservoir.py | 4 +- src/Model/River.py | 152 ++++++++--- src/Model/Scenario.py | 2 +- src/Model/SedimentLayer/SedimentLayer.py | 6 +- .../SolverParameters/SolverParametersList.py | 4 +- src/Model/Stricklers/Stricklers.py | 4 +- src/Model/Stricklers/StricklersList.py | 4 +- src/Model/Study.py | 18 +- src/Model/Tools/PamhyrDB.py | 13 +- src/Model/Tools/PamhyrDict.py | 4 +- src/Model/Tools/PamhyrID.py | 26 +- src/Model/Tools/PamhyrList.py | 14 +- 25 files changed, 426 insertions(+), 182 deletions(-) diff --git a/src/Model/AdditionalFile/AddFile.py b/src/Model/AdditionalFile/AddFile.py index f87abc69..afde5d59 100644 --- a/src/Model/AdditionalFile/AddFile.py +++ b/src/Model/AdditionalFile/AddFile.py @@ -123,7 +123,7 @@ class AddFile(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": release = int(release) @@ -132,15 +132,15 @@ class AddFile(SQLSubModel): cls._db_create(execute) if 8 < release < 13: - cls._db_update_to_0_0_13(execute) + cls._db_update_to_0_0_13(execute, data) return True @classmethod - def _db_update_to_0_0_13(cls, execute): + def _db_update_to_0_0_13(cls, execute, data): table = "additional_files" - cls.update_db_add_pamhyr_id(execute, table) + cls.update_db_add_pamhyr_id(execute, table, data) Scenario.update_db_add_scenario(execute, table) cls._db_create(execute, ext="_tmp") diff --git a/src/Model/BoundaryCondition/BoundaryCondition.py b/src/Model/BoundaryCondition/BoundaryCondition.py index 986a9219..ef1433a1 100644 --- a/src/Model/BoundaryCondition/BoundaryCondition.py +++ b/src/Model/BoundaryCondition/BoundaryCondition.py @@ -32,7 +32,7 @@ from Model.Scenario import Scenario logger = logging.getLogger() -class Data(SQLSubMode): +class Data(SQLSubModel): _sub_classes = [] def __init__(self, id: int = -1, @@ -52,10 +52,10 @@ class Data(SQLSubMode): ind INTEGER NOT NULL, data0 TEXT NOT NULL, data1 TEXT NOT NULL, - bc INTEGER, + lc INTEGER, {Scenario.create_db_add_scenario()}, {Scenario.create_db_add_scenario_fk()}, - FOREIGN KEY(bc) REFERENCES boundary_condition(pamhyr_id), + FOREIGN KEY(lc) REFERENCES boundary_condition(pamhyr_id), PRIMARY KEY(pamhyr_id, scenario) ) """) @@ -63,13 +63,13 @@ class Data(SQLSubMode): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == "0" and int(minor) < 1: cls._db_update_to_0_1_0(execute) - return True + return cls._update_submodel(execute, version, data) @classmethod def _db_update_to_0_1_0(cls, execute): @@ -81,8 +81,8 @@ class Data(SQLSubMode): cls._db_create(execute, ext="_tmp") execute( f"INSERT INTO {table} " + - "(pamhyr_id, ind, data0, data1, bc, scenario) " + - "SELECT pamhyr_id, ind, data0, data1, bc, scenario " + + "(pamhyr_id, ind, data0, data1, lc, scenario) " + + "SELECT pamhyr_id, ind, data0, data1, lc, scenario " + f"FROM {table}" ) @@ -92,12 +92,12 @@ class Data(SQLSubMode): @classmethod def _db_load(cls, execute, data=None): new = [] - bc = data["bc"] + lc = data["lc"] values = execute( "SELECT pamhyr_id, ind, data0, data1 " + "FROM boundary_condition_data " + - f"WHERE bc = {bc._pamhyr_id} " + + f"WHERE lc = {lc._pamhyr_id} " + "ORDER BY ind ASC" ) @@ -111,7 +111,7 @@ class Data(SQLSubMode): nd = cls( id=pid, - types=bc._types, + types=lc._types, status=data['status'] ) nd._data = [data0, data1] @@ -125,12 +125,12 @@ class Data(SQLSubMode): ind = data["ind"] data0 = self._db_format(str(self[0])) data1 = self._db_format(str(self[1])) - bc = data["bc"] + lc = data["lc"] sql = ( "INSERT INTO " + "boundary_condition_data(pamhyr_id, ind, data0, data1, bc) " + - f"VALUES ({pid}, {ind}, '{data0}', {data1}, {bc._pamhyr_id})" + f"VALUES ({pid}, {ind}, '{data0}', {data1}, {lc._pamhyr_id})" ) execute(sql) @@ -174,26 +174,29 @@ class BoundaryCondition(SQLSubModel): """) return cls._create_submodel(execute) + @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") - if major == "0" and int(minor) < 1: - cls._db_update_to_0_1_0(execute) + if major == minor == "0": + cls._db_update_to_0_1_0(execute, data) - return cls._update_submodel(execute, version) + return cls._update_submodel(execute, version, data) @classmethod - def _db_update_to_0_1_0(cls, execute): + def _db_update_to_0_1_0(cls, execute, data): table = "boundary_condition" - cls.update_db_add_pamhyr_id(execute, table) + cls.update_db_add_pamhyr_id(execute, table, data) Scenario.update_db_add_scenario(execute, table) cls._db_create(execute, ext="_tmp") + + # Copy table execute( - f"INSERT INTO {table} " + - "(pamhyr_id, name, type, tab, node, scenario) " + + f"INSERT INTO {table}_tmp " + + f"(pamhyr_id, name, type, tab, node, scenario) " + "SELECT pamhyr_id, name, type, tab, node, scenario " + f"FROM {table}" ) @@ -201,6 +204,24 @@ class BoundaryCondition(SQLSubModel): execute(f"DROP TABLE {table}") execute(f"ALTER TABLE {table}_tmp RENAME TO {table}") + cls._db_update_to_0_1_0_set_node_pid(execute, nodes) + + @classmethod + def _db_update_to_0_1_0_set_node_pid(cls, execute, nodes): + bcs = execute( + "SELECT pamhyr_id, node FROM boundary_condition" + ) + + for row in bcs: + pid = row[0] + node_id = row[1] + + execute( + "UPDATE boundary_condition " + + f"SET node = {nodes[node_id]} " + + f"WHERE pamhyr_id = {pid}" + ) + @classmethod def _get_ctor_from_type(cls, t): from Model.BoundaryCondition.BoundaryConditionTypes import ( @@ -267,7 +288,7 @@ class BoundaryCondition(SQLSubModel): if self._node is not None: node = self._node.id - sql = ( + execute( "INSERT INTO " + "boundary_condition(pamhyr_id, name, type, tab, node) " + "VALUES (" + @@ -275,7 +296,6 @@ class BoundaryCondition(SQLSubModel): f"'{self._db_format(self._type)}', '{tab}', {node}" + ")" ) - execute(sql) data["bc"] = self diff --git a/src/Model/Friction/Friction.py b/src/Model/Friction/Friction.py index 2ddbe9c6..9c6c368b 100644 --- a/src/Model/Friction/Friction.py +++ b/src/Model/Friction/Friction.py @@ -70,7 +70,7 @@ class Friction(SQLSubModel): return True @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": if int(release) < 11: diff --git a/src/Model/Friction/FrictionList.py b/src/Model/Friction/FrictionList.py index 0158d9a4..d67db3fd 100644 --- a/src/Model/Friction/FrictionList.py +++ b/src/Model/Friction/FrictionList.py @@ -39,12 +39,12 @@ class FrictionList(PamhyrModelList): execute("ALTER TABLE `section` RENAME TO `friction`") @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): if version == "0.0.0": logger.info(f"Update friction TABLE from {version}") cls._db_update_0_0_1(execute, version) - return cls._update_submodel(execute, version) + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): diff --git a/src/Model/Geometry/PointXYZ.py b/src/Model/Geometry/PointXYZ.py index 9ba79e66..c9f2866a 100644 --- a/src/Model/Geometry/PointXYZ.py +++ b/src/Model/Geometry/PointXYZ.py @@ -55,9 +55,7 @@ class PointXYZ(Point, SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): - cls._update_submodel(execute, version) - + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": if int(release) < 2: @@ -68,7 +66,8 @@ class PointXYZ(Point, SQLSubModel): REFERENCES sedimentary_layer(id) """ ) - return True + + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): diff --git a/src/Model/Geometry/ProfileXYZ.py b/src/Model/Geometry/ProfileXYZ.py index 9d31a97d..833f5a49 100644 --- a/src/Model/Geometry/ProfileXYZ.py +++ b/src/Model/Geometry/ProfileXYZ.py @@ -91,7 +91,7 @@ class ProfileXYZ(Profile, SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": rl = int(release) @@ -112,7 +112,7 @@ class ProfileXYZ(Profile, SQLSubModel): """ ) - return cls._update_submodel(execute, version) + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): diff --git a/src/Model/Geometry/Reach.py b/src/Model/Geometry/Reach.py index f33eb5de..bed6838a 100644 --- a/src/Model/Geometry/Reach.py +++ b/src/Model/Geometry/Reach.py @@ -58,8 +58,8 @@ class Reach(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): - return cls._update_submodel(execute, version) + def _db_update(cls, execute, version, data=None): + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): diff --git a/src/Model/HydraulicStructures/Basic/HydraulicStructures.py b/src/Model/HydraulicStructures/Basic/HydraulicStructures.py index bbb10c2c..20bffa5c 100644 --- a/src/Model/HydraulicStructures/Basic/HydraulicStructures.py +++ b/src/Model/HydraulicStructures/Basic/HydraulicStructures.py @@ -70,13 +70,13 @@ class BasicHS(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": if int(release) < 6: cls._db_create(execute) - return True + return cls._update_submodel(execute, version, data) @classmethod def _get_ctor_from_type(cls, t): diff --git a/src/Model/HydraulicStructures/Basic/Value.py b/src/Model/HydraulicStructures/Basic/Value.py index e39c0c41..effb3ece 100644 --- a/src/Model/HydraulicStructures/Basic/Value.py +++ b/src/Model/HydraulicStructures/Basic/Value.py @@ -49,7 +49,7 @@ class BHSValue(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": if int(release) < 6: diff --git a/src/Model/HydraulicStructures/HydraulicStructures.py b/src/Model/HydraulicStructures/HydraulicStructures.py index f7cf4097..2262af0a 100644 --- a/src/Model/HydraulicStructures/HydraulicStructures.py +++ b/src/Model/HydraulicStructures/HydraulicStructures.py @@ -81,7 +81,7 @@ class HydraulicStructure(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": rl = int(release) @@ -103,7 +103,7 @@ class HydraulicStructure(SQLSubModel): """ ) - return True + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): diff --git a/src/Model/InitialConditions/InitialConditions.py b/src/Model/InitialConditions/InitialConditions.py index 1b923cda..047dd4de 100644 --- a/src/Model/InitialConditions/InitialConditions.py +++ b/src/Model/InitialConditions/InitialConditions.py @@ -74,7 +74,7 @@ class Data(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": if int(release) < 11: @@ -82,7 +82,7 @@ class Data(SQLSubModel): "ALTER TABLE initial_conditions RENAME COLUMN kp TO rk" ) - return cls._update_submodel(execute, version) + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): @@ -240,8 +240,8 @@ class InitialConditions(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): - return cls._update_submodel(execute, version) + def _db_update(cls, execute, version, data=None): + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): diff --git a/src/Model/LateralContribution/LateralContribution.py b/src/Model/LateralContribution/LateralContribution.py index bfed1d14..350e4cd4 100644 --- a/src/Model/LateralContribution/LateralContribution.py +++ b/src/Model/LateralContribution/LateralContribution.py @@ -27,66 +27,162 @@ from tools import ( from Model.Tools.PamhyrDB import SQLSubModel from Model.Except import NotImplementedMethodeError +from Model.Scenario import Scenario logger = logging.getLogger() +class Data(SQLSubModel): + _sub_classes = [] + + def __init__(self, id: int = -1, + types=[float, float], + status=None): + super(Data, self).__init__(id) + self._status = status + + self._types = types + self._data = [] + + @classmethod + def _db_create(cls, execute, ext=""): + execute(f""" + CREATE TABLE lateral_contribution_data{ext}( + {cls.create_db_add_pamhyr_id()}, + ind INTEGER NOT NULL, + data0 TEXT NOT NULL, + data1 TEXT NOT NULL, + lc INTEGER, + {Scenario.create_db_add_scenario()}, + {Scenario.create_db_add_scenario_fk()}, + FOREIGN KEY(lc) REFERENCES lateral_contribution(pamhyr_id), + PRIMARY KEY(pamhyr_id, scenario) + ) + """) + + return cls._create_submodel(execute) + + @classmethod + def _db_update(cls, execute, version, data=None): + major, minor, release = version.strip().split(".") + + if major == "0" and int(minor) < 1: + cls._db_update_to_0_1_0(execute) + + return cls._update_submodel(execute, version, data) + + @classmethod + def _db_update_to_0_1_0(cls, execute): + table = "lateral_contribution_data" + + cls.update_db_add_pamhyr_id(execute, table) + Scenario.update_db_add_scenario(execute, table) + + cls._db_create(execute, ext="_tmp") + execute( + f"INSERT INTO {table} " + + "(pamhyr_id, ind, data0, data1, lc, scenario) " + + "SELECT pamhyr_id, ind, data0, data1, lc, scenario " + + f"FROM {table}" + ) + + execute(f"DROP TABLE {table}") + execute(f"ALTER TABLE {table}_tmp RENAME TO {table}") + + @classmethod + def _db_load(cls, execute, data=None): + new = [] + lc = data["lc"] + + values = execute( + "SELECT pamhyr_id, ind, data0, data1 " + + "FROM lateral_contribution_data " + + f"WHERE lc = {lc._pamhyr_id} " + + "ORDER BY ind ASC" + ) + + for v in values: + it = iter(v) + + pid = next(it) + ind = next(it) + data0 = bc._types[0](next(it)) + data1 = bc._types[1](next(it)) + + nd = cls( + id=pid, + types=lc._types, + status=data['status'] + ) + nd._data = [data0, data1] + + new.append((ind, nd)) + + return new + + def _db_save(self, execute, data=None): + pid = self._pamhyr_id + ind = data["ind"] + data0 = self._db_format(str(self[0])) + data1 = self._db_format(str(self[1])) + lc = data["lc"] + + sql = ( + "INSERT INTO " + + "lateral_contribution_data (pamhyr_id, ind, data0, data1, bc) " + + f"VALUES ({pid}, {ind}, '{data0}', {data1}, {lc._pamhyr_id})" + ) + execute(sql) + + def __getitem__(self, key): + return self._types[key](self._data[key]) + + def __setitem__(self, key, value): + self._data[key] = self._types[key](value) + + class LateralContribution(SQLSubModel): _sub_classes = [] _id_cnt = 0 def __init__(self, id: int = -1, name: str = "", status=None): - super(LateralContribution, self).__init__() - + super(LateralContribution, self).__init__(id) self._status = status - if id == -1: - self.id = LateralContribution._id_cnt - else: - self.id = id - self._name = name self._type = "" self._edge = None - self._begin_rk = 0.0 - self._end_rk = 0.0 + self._begin_rk = None + self._end_rk = None self._data = [] self._header = [] self._types = [float, float] - LateralContribution._id_cnt = max( - LateralContribution._id_cnt + 1, self.id) - @classmethod - def _db_create(cls, execute): - execute(""" - CREATE TABLE lateral_contribution( - id INTEGER NOT NULL PRIMARY KEY, + def _db_create(cls, execute, ext=""): + execute(f""" + CREATE TABLE lateral_contribution{ext}( + {cls.create_db_add_pamhyr_id()}, name TEXT NOT NULL, type TEXT NOT NULL, tab TEXT NOT NULL, - edge INTEGER, - begin_rk REAL NOT NULL, - end_rk REAL NOT NULL, - FOREIGN KEY(edge) REFERENCES river_reach(id) - ) - """) - - execute(""" - CREATE TABLE lateral_contribution_data( - id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - ind INTEGER NOT NULL, - data0 TEXT NOT NULL, - data1 TEXT NOT NULL, - lc INTEGER, - FOREIGN KEY(lc) REFERENCES lateral_contribution(id) + reach INTEGER, + begin_section INTEGER, + end_section INTEGER, + {Scenario.create_db_add_scenario()}, + {Scenario.create_db_add_scenario_fk()}, + FOREIGN KEY(reach) REFERENCES river_reach(pamhyr_id), + FOREIGN KEY(begin_section) + REFERENCES geometry_profileXYZ(pamhyr_id), + FOREIGN KEY(end_section) + REFERENCES geometry_profileXYZ(pamhyr_id) ) """) return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": if int(release) < 11: @@ -103,7 +199,35 @@ class LateralContribution(SQLSubModel): """ ) - return True + execute( + """ + ALTER TABLE lateral_contribution + RENAME COLUMN edge TO reach + """ + ) + + cls._db_update_to_0_1_0(execute) + + return cls._update_submodel(execute, version, data) + + @classmethod + def _db_update_to_0_1_0(cls, execute): + table = "lateral_contribution" + + cls.update_db_add_pamhyr_id(execute, table) + Scenario.update_db_add_scenario(execute, table) + + cls._db_create(execute, ext="_tmp") + + execute( + f"INSERT INTO {table} " + + "(pamhyr_id, name, type, tab, reach, scenario) " + + "SELECT pamhyr_id, name, type, tab, reach, scenario " + + f"FROM {table}" + ) + + execute(f"DROP TABLE {table}") + execute(f"ALTER TABLE {table}_tmp RENAME TO {table}") @classmethod def _get_ctor_from_type(cls, t): @@ -126,7 +250,7 @@ class LateralContribution(SQLSubModel): tab = data["tab"] table = execute( - "SELECT id, name, type, edge, begin_rk, end_rk " + + "SELECT pamhyr_id, name, type, reach, begin_section, end_section " + f"FROM lateral_contribution WHERE tab = '{tab}'" ) @@ -138,45 +262,45 @@ class LateralContribution(SQLSubModel): name=row[1], status=data['status'] ) - lc.edge = None + lc.reach = None + lc._begin_section = None + lc._end_section = None + if row[3] != -1: - lc.edge = next(filter(lambda e: e.id == row[3], data["edges"])) - lc._begin_rk = row[4] - lc._end_rk = row[5] + lc.reach = next(filter(lambda e: e.id == row[3], data["edges"])) + lc._begin_section = lc.reach.profile(row[4]) + lc._end_section = lc.reach.profile(row[5]) - values = execute( - "SELECT ind, data0, data1 FROM lateral_contribution_data " + - f"WHERE lc = '{lc.id}'" - ) - # Create dummy data list - for _ in values: - lc.add(0) - # Write data - for v in values: - ind = v[0] - data0 = lc._types[0](v[1]) - data1 = lc._types[1](v[2]) - # Replace data at pos ind - lc._data[ind] = (data0, data1) - - new.append(lc) + data["lc"] = lc + lc._data = Data._db_load(execute, data=data) return new def _db_save(self, execute, data=None): tab = data["tab"] - execute(f"DELETE FROM lateral_contribution WHERE id = {self.id}") - execute(f"DELETE FROM lateral_contribution_data WHERE lc = {self.id}") + execute( + "DELETE FROM lateral_contribution " + + f"WHERE pamhyr_id = {self._pamhyr_id}" + ) + execute( + "DELETE FROM lateral_contribution_data " + + f"WHERE lc = {self._pamhyr_id}" + ) - edge = -1 - if self._edge is not None: - edge = self._edge.id + reach = -1 + begin_section = -1 + end_section = -1 + + if self._reach is not None: + reach = self._reach._pamhyr_id + begin_section = self._begin_section._pamhyr_id + end_section = self._end_section._pamhyr_id sql = ( "INSERT INTO " + "lateral_contribution(id, name, type, tab, " + - "edge, begin_rk, end_rk) " + + "reach, begin_section, end_section) " + "VALUES (" + f"{self.id}, '{self._db_format(self._name)}', " + f"'{self._db_format(self._type)}', '{tab}', {edge}, " + diff --git a/src/Model/REPLine/REPLine.py b/src/Model/REPLine/REPLine.py index a803e8db..86538deb 100644 --- a/src/Model/REPLine/REPLine.py +++ b/src/Model/REPLine/REPLine.py @@ -123,7 +123,7 @@ class REPLine(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": if int(release) < 9: diff --git a/src/Model/Reservoir/Reservoir.py b/src/Model/Reservoir/Reservoir.py index 1d719348..c93e0faa 100644 --- a/src/Model/Reservoir/Reservoir.py +++ b/src/Model/Reservoir/Reservoir.py @@ -69,13 +69,13 @@ class Reservoir(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": if int(release) < 5: cls._db_create(execute) - return True + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): diff --git a/src/Model/River.py b/src/Model/River.py index 55c17c63..b3f98099 100644 --- a/src/Model/River.py +++ b/src/Model/River.py @@ -19,6 +19,7 @@ from tools import flatten, logger_exception from Model.Tools.PamhyrDB import SQLSubModel +from Model.Scenario import Scenario from Model.Network.Node import Node from Model.Network.Edge import Edge @@ -49,9 +50,11 @@ from Solver.Solvers import solver_type_list class RiverNode(Node, SQLSubModel): _sub_classes = [] - def __init__(self, id: str, name: str, + def __init__(self, id: int, name: str, x: float, y: float, status=None): + self._pamhyr_id = self.get_new_pamhyr_id(id) + super(RiverNode, self).__init__( id, name, x, y, @@ -61,13 +64,16 @@ class RiverNode(Node, SQLSubModel): self._locker = None @classmethod - def _db_create(cls, execute): - execute(""" + def _db_create(cls, execute, ext=""): + execute(f""" CREATE TABLE river_node( - id INTEGER NOT NULL PRIMARY KEY, + {cls.create_db_add_pamhyr_id()}, name TEXT NOT NULL, x REAL NOT NULL, - y REAL NOT NULL + y REAL NOT NULL, + {Scenario.create_db_add_scenario()}, + {Scenario.create_db_add_scenario_fk()}, + PRIMARY KEY(pamhyr_id, scenario) ) """) @@ -75,30 +81,54 @@ class RiverNode(Node, SQLSubModel): return True @classmethod - def _db_update(cls, execute, version): - return True + def _db_update(cls, execute, version, data=None): + major, minor, release = version.strip().split(".") + + if major == minor == "0": + cls._db_update_to_0_1_0(execute) + + return cls._update_submodel(execute, version, data) + + @classmethod + def _db_update_to_0_1_0(cls, execute): + table = "river_node" + + cls.update_db_add_pamhyr_id(execute, table) + Scenario.update_db_add_scenario(execute, table) + + cls._db_create(execute, ext="_tmp") + + # Copy table + execute( + f"INSERT INTO {table}_tmp " + + f"(pamhyr_id, name, x, y, scenario) " + + "SELECT pamhyr_id, name, x, y, scenario " + + f"FROM {table}" + ) + + execute(f"DROP TABLE {table}") + execute(f"ALTER TABLE {table}_tmp RENAME TO {table}") @classmethod def _db_load(cls, execute, data=None): nodes = [] - table = execute("SELECT id, name, x, y FROM river_node") + table = execute("SELECT pamhyr_id, name, x, y FROM river_node") for row in table: - # Update id counter - cls._id_cnt = max(cls._id_cnt, row[0]) - # Create new node - nodes.append(cls(*row, status=data["status"])) + nodes.append( + cls(*row, status=data["status"]) + ) return nodes def _db_save(self, execute, data=None): - sql = ( - "INSERT OR REPLACE INTO river_node(id, name, x, y) VALUES (" + - f"{self.id}, '{self._db_format(self.name)}', " + + execute( + "INSERT OR REPLACE INTO river_node(pamhyr_id, name, x, y) VALUES (" + + f"{self._pamhyr_id}, " + + f"'{self._db_format(self.name)}', " + f"{self.x}, {self.y}" + ")" ) - execute(sql) return True @@ -121,6 +151,8 @@ class RiverReach(Edge, SQLSubModel): node1: RiverNode = None, node2: RiverNode = None, status=None): + self._pamhyr_id = self.get_new_pamhyr_id(id) + super(RiverReach, self).__init__( id, name, node1, node2, @@ -132,15 +164,18 @@ class RiverReach(Edge, SQLSubModel): @classmethod def _db_create(cls, execute): - execute(""" + execute(f""" CREATE TABLE river_reach( - id INTEGER NOT NULL PRIMARY KEY, + {cls.create_db_add_pamhyr_id()}, name TEXT NOT NULL, - enable BOOLEAN NOT NULL, + enabled BOOLEAN NOT NULL, node1 INTEGER, node2 INTEGER, - FOREIGN KEY(node1) REFERENCES river_node(id), - FOREIGN KEY(node2) REFERENCES river_node(id) + {Scenario.create_db_add_scenario()}, + {Scenario.create_db_add_scenario_fk()}, + FOREIGN KEY(node1) REFERENCES river_node(pamhyr_id), + FOREIGN KEY(node2) REFERENCES river_node(pamhyr_id), + PRIMARY KEY(pamhyr_id, scenario) ) """) @@ -148,8 +183,33 @@ class RiverReach(Edge, SQLSubModel): return True @classmethod - def _db_update(cls, execute, version): - return cls._update_submodel(execute, version) + def _db_update(cls, execute, version, data=None): + major, minor, release = version.strip().split(".") + + if major == minor == "0": + cls._db_update_to_0_1_0(execute) + + return cls._update_submodel(execute, version, data) + + @classmethod + def _db_update_to_0_1_0(cls, execute): + table = "river_reach" + + cls.update_db_add_pamhyr_id(execute, table) + Scenario.update_db_add_scenario(execute, table) + + cls._db_create(execute, ext="_tmp") + + # Copy table + execute( + f"INSERT INTO {table}_tmp " + + f"(pamhyr_id, name, enabled, node1, node2, scenario) " + + "SELECT pamhyr_id, name, enable, node1, node2, scenario " + + f"FROM {table}" + ) + + execute(f"DROP TABLE {table}") + execute(f"ALTER TABLE {table}_tmp RENAME TO {table}") @classmethod def _db_load(cls, execute, data=None): @@ -159,22 +219,30 @@ class RiverReach(Edge, SQLSubModel): data = {} table = execute( - "SELECT id, name, enable, node1, node2 FROM river_reach" + "SELECT pamhyr_id, name, enabled, node1, node2 FROM river_reach" ) for row in table: - # Update id counter - cls._id_cnt = max(cls._id_cnt, row[0]) - # Create new reach - id = row[0] - name = row[1] - enable = (row[2] == 1) - # Get nodes corresponding to db foreign key id - node1 = next(filter(lambda n: n.id == row[3], data["nodes"])) - node2 = next(filter(lambda n: n.id == row[4], data["nodes"])) + it = iter(row) - new = cls(id, name, node1, node2, status=data["status"]) - new.enable(enable=enable) + # Create new reach + pid = next(it) + name = next(it) + enabled = (next(it) == 1) + # Get nodes corresponding to db foreign key id + node1 = next( + filter( + lambda n: n.pamhyr_id == next(it), data["nodes"] + ) + ) + node2 = next( + filter( + lambda n: n.pamhyr_id == next(it), data["nodes"] + ) + ) + + new = cls(pid, name, node1, node2, status=data["status"]) + new.enable(enable=enabled) data["reach"] = new @@ -186,16 +254,15 @@ class RiverReach(Edge, SQLSubModel): return reachs def _db_save(self, execute, data=None): - sql = ( + execute( "INSERT OR REPLACE INTO " + - "river_reach(id, name, enable, node1, node2) " + + "river_reach(pamhyr_id, name, enable, node1, node2) " + "VALUES (" + - f"{self.id}, '{self._db_format(self._name)}', " + + f"{self.pamhyr_id}, '{self._db_format(self._name)}', " + f"{self._db_format(self.is_enable())}," - f"{self.node1.id}, {self.node2.id}" + + f"{self.node1.pamhyr_id}, {self.node2.pamhyr_id}" + ")" ) - execute(sql) if data is None: data = {} @@ -258,9 +325,8 @@ class River(Graph, SQLSubModel): return True @classmethod - def _db_update(cls, execute, version): - cls._update_submodel(execute, version) - return True + def _db_update(cls, execute, version, data=None): + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): diff --git a/src/Model/Scenario.py b/src/Model/Scenario.py index 1f06f333..dcbb4e82 100644 --- a/src/Model/Scenario.py +++ b/src/Model/Scenario.py @@ -87,7 +87,7 @@ class Scenario(SQLSubModel): return "FOREIGN KEY(scenario) REFERENCES scenario(id)" @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": if int(release) < 12: diff --git a/src/Model/SedimentLayer/SedimentLayer.py b/src/Model/SedimentLayer/SedimentLayer.py index b31238cd..90c9fd8d 100644 --- a/src/Model/SedimentLayer/SedimentLayer.py +++ b/src/Model/SedimentLayer/SedimentLayer.py @@ -124,7 +124,7 @@ class Layer(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": if int(release) < 2: @@ -260,13 +260,13 @@ class SedimentLayer(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": if int(release) < 2: cls._db_create(execute) - return True + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): diff --git a/src/Model/SolverParameters/SolverParametersList.py b/src/Model/SolverParameters/SolverParametersList.py index 3b6a1dd1..5837d552 100644 --- a/src/Model/SolverParameters/SolverParametersList.py +++ b/src/Model/SolverParameters/SolverParametersList.py @@ -96,7 +96,7 @@ class SolverParametersList(PamhyrModelList): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): major, minor, release = version.strip().split(".") if major == minor == "0": @@ -132,7 +132,7 @@ class SolverParametersList(PamhyrModelList): if release < 14: cls._db_update_to_0_0_14(execute) - return cls._update_submodel(execute, version) + return cls._update_submodel(execute, version, data) @classmethod def _db_update_to_0_0_4(cls, execute, insert): diff --git a/src/Model/Stricklers/Stricklers.py b/src/Model/Stricklers/Stricklers.py index 45272f7d..94b18b87 100644 --- a/src/Model/Stricklers/Stricklers.py +++ b/src/Model/Stricklers/Stricklers.py @@ -62,8 +62,8 @@ class Stricklers(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): - return cls._update_submodel(execute, version) + def _db_update(cls, execute, version, data=None): + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): diff --git a/src/Model/Stricklers/StricklersList.py b/src/Model/Stricklers/StricklersList.py index 305040fb..37d82033 100644 --- a/src/Model/Stricklers/StricklersList.py +++ b/src/Model/Stricklers/StricklersList.py @@ -33,8 +33,8 @@ class StricklersList(PamhyrModelList): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): - return cls._update_submodel(execute, version) + def _db_update(cls, execute, version, data=None): + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): diff --git a/src/Model/Study.py b/src/Model/Study.py index 8267470e..152773e4 100644 --- a/src/Model/Study.py +++ b/src/Model/Study.py @@ -272,7 +272,23 @@ class Study(SQLModel): "INSERT INTO info VALUES ('study_release', '0')" ) - if self._update_submodel(version[0]): + if int(minor) < 1: + # Need to temporary disable the sqlite foreign keys + # checking to update db dans change the table id fk to + # table pamhyr_id fk + self.execute( + "PRAGMA foreign_keys = OFF;" + ) + + ok = self._update_submodel(version[0], data={}) + + if int(minor) < 1: + # Reactivate foreign keys checking + self.execute( + "PRAGMA foreign_keys = ON;" + ) + + if ok: self.execute( f"UPDATE info SET value='{self._version}' WHERE key='version'" ) diff --git a/src/Model/Tools/PamhyrDB.py b/src/Model/Tools/PamhyrDB.py index 901af6da..ec177e5c 100644 --- a/src/Model/Tools/PamhyrDB.py +++ b/src/Model/Tools/PamhyrDB.py @@ -75,16 +75,19 @@ class SQLModel(SQL): raise NotImplementedMethodeError(self, self._create) - def _update_submodel(self, version): + def _update_submodel(self, version, data=None): def fn(sql): return self.execute( sql, fetch_one=False, commit=False ) + if data is None: + data = {} + ok = True for cls in self._sub_classes: - ok &= cls._db_update(fn, version) + ok &= cls._db_update(fn, version, data) self.commit() return ok @@ -184,12 +187,12 @@ class SQLSubModel(PamhyrID): raise NotImplementedMethodeError(cls, cls._db_create) @classmethod - def _update_submodel(cls, execute, version): + def _update_submodel(cls, execute, version, data=None): for sc in cls._sub_classes: - sc._db_update(execute, version) + sc._db_update(execute, version, data) @classmethod - def _db_update(cls, execute, version): + def _db_update(cls, execute, version, data=None): """Update data base scheme Args: diff --git a/src/Model/Tools/PamhyrDict.py b/src/Model/Tools/PamhyrDict.py index 93e563eb..2885d364 100644 --- a/src/Model/Tools/PamhyrDict.py +++ b/src/Model/Tools/PamhyrDict.py @@ -43,8 +43,8 @@ class PamhyrModelDict(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): - return cls._update_submodel(execute, version) + def _db_update(cls, execute, version, data=None): + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): diff --git a/src/Model/Tools/PamhyrID.py b/src/Model/Tools/PamhyrID.py index 0527329a..7f99d404 100644 --- a/src/Model/Tools/PamhyrID.py +++ b/src/Model/Tools/PamhyrID.py @@ -47,26 +47,44 @@ class PamhyrID(object): @classmethod def update_db_add_pamhyr_id(cls, execute, table, - autoset=True): + autoset=True, + data={}): execute( f"ALTER TABLE {table} " + f"ADD COLUMN pamhyr_id INTEGER NOT NULL DEFAULT -1" ) if autoset: - table = execute(f"SELECT id FROM {table}") + rows = execute(f"SELECT id FROM {table}") + id2pid = cls.update_db_add_pamhyr_id_init_id2pid(table, data) - for row in table: + for row in rows: + id = row[0] pid = cls.get_new_pamhyr_id(-1) + id2pid[table][id] = pid + execute( f"UPDATE {table} " + f"SET pamhyr_id = {pid} " + - f"WHERE id = {row[0]}" + f"WHERE id = {id}" ) return True + @classmethod + def update_db_add_pamhyr_id_init_id2pid(cls, table, data): + id2pid = {} + if "id2pid" in data: + id2pid = data["id2pid"] + else: + data["id2pid"] = id2pid + + if table not in id2pid: + id2pid[table] = {} + + return id2pid + @classmethod def create_db_add_pamhyr_id(cls): return "pamhyr_id INTEGER NOT NULL" diff --git a/src/Model/Tools/PamhyrList.py b/src/Model/Tools/PamhyrList.py index b0cc282d..0d5cb9d2 100644 --- a/src/Model/Tools/PamhyrList.py +++ b/src/Model/Tools/PamhyrList.py @@ -28,8 +28,7 @@ logger = logging.getLogger() class PamhyrModelList(SQLSubModel): - _sub_classes = [ - ] + _sub_classes = [] def __init__(self, status=None): super(PamhyrModelList, self).__init__() @@ -46,8 +45,8 @@ class PamhyrModelList(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): - return cls._update_submodel(execute, version) + def _db_update(cls, execute, version, data=None): + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None): @@ -167,8 +166,7 @@ class PamhyrModelList(SQLSubModel): class PamhyrModelListWithTab(SQLSubModel): _tabs_list = [] - _sub_classes = [ - ] + _sub_classes = [] def __init__(self, status=None): super(PamhyrModelListWithTab, self).__init__() @@ -187,8 +185,8 @@ class PamhyrModelListWithTab(SQLSubModel): return cls._create_submodel(execute) @classmethod - def _db_update(cls, execute, version): - return cls._update_submodel(execute, version) + def _db_update(cls, execute, version, data=None): + return cls._update_submodel(execute, version, data) @classmethod def _db_load(cls, execute, data=None):