mirror of https://gitlab.com/pamhyr/pamhyr2
Model: Start export model into SQLite database.
* Study: Create table. * River: Create node and reach table. * Geometry: Create table only for profileXYZ and pointXYZ.results
parent
5566d87774
commit
2ed3254b46
|
|
@ -0,0 +1,148 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sqlite3
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from tools import SQL
|
||||
from Model.Except import NotImplementedMethodeError
|
||||
|
||||
# Top level model class
|
||||
class SQLModel(SQL):
|
||||
_sub_classes = []
|
||||
|
||||
def _init_db_file(self, db, is_new = True):
|
||||
exists = Path(db).exists()
|
||||
|
||||
if exists and is_new:
|
||||
os.remove(db)
|
||||
|
||||
self._db = sqlite3.connect(db)
|
||||
self._cur = self._db.cursor()
|
||||
|
||||
if is_new:
|
||||
self._create() # Create db
|
||||
self._save() # Save
|
||||
else:
|
||||
self._update() # Update db scheme if necessary
|
||||
self._load() # Load data
|
||||
|
||||
def _create_submodel(self):
|
||||
for cls in self._sub_classes:
|
||||
requests = cls._sql_create(
|
||||
lambda sql: self.execute(
|
||||
sql,
|
||||
fetch_one = False,
|
||||
commit = True
|
||||
)
|
||||
)
|
||||
|
||||
def _create(self):
|
||||
raise NotImplementedMethodeError(self, self._create)
|
||||
|
||||
def _update_submodel(self, version):
|
||||
for cls in self._sub_classes:
|
||||
requests = cls._sql_update(
|
||||
lambda sql: self.execute(
|
||||
sql,
|
||||
fetch_one = False,
|
||||
commit = True
|
||||
),
|
||||
version
|
||||
)
|
||||
|
||||
def _update(self):
|
||||
raise NotImplementedMethodeError(self, self._update)
|
||||
|
||||
def _save_submodel(self, objs):
|
||||
for obj in objs:
|
||||
requests = obj._sql_save(
|
||||
lambda sql: self.execute(
|
||||
sql,
|
||||
fetch_one = False,
|
||||
commit = True
|
||||
)
|
||||
)
|
||||
|
||||
def _save(self):
|
||||
raise NotImplementedMethodeError(self, self._save)
|
||||
|
||||
@classmethod
|
||||
def _load(cls, filename):
|
||||
raise NotImplementedMethodeError(cls, cls._load)
|
||||
|
||||
# Sub model class
|
||||
class SQLSubModel(object):
|
||||
_sub_classes = []
|
||||
|
||||
def _sql_format(self, value):
|
||||
# Replace ''' by ''' to preserve SQL injection
|
||||
if type(value) == str:
|
||||
value = value.replace("'", "'")
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def _create_submodel(cls, execute):
|
||||
for sc in cls._sub_classes:
|
||||
sc._sql_create(execute)
|
||||
|
||||
@classmethod
|
||||
def _sql_create(cls, execute):
|
||||
"""Create data base scheme
|
||||
|
||||
Args:
|
||||
execute: Function to exec SQL resquest
|
||||
|
||||
Returns:
|
||||
Return true, otherelse false if an issue appear
|
||||
"""
|
||||
raise NotImplementedMethodeError(cls, cls._sql_create)
|
||||
|
||||
@classmethod
|
||||
def _update_submodel(cls, execute, version):
|
||||
for sc in cls._sub_classes:
|
||||
sc._sql_update(execute, version)
|
||||
|
||||
@classmethod
|
||||
def _sql_update(cls, execute, version):
|
||||
"""Update data base scheme
|
||||
|
||||
Args:
|
||||
execute: Function to exec SQL resquest
|
||||
version: Current database version
|
||||
|
||||
Returns:
|
||||
Return true, otherelse false if an issue appear
|
||||
"""
|
||||
raise NotImplementedMethodeError(cls, cls._sql_update)
|
||||
|
||||
@classmethod
|
||||
def _sql_load(cls, execute, data = None):
|
||||
"""Load instance of this class from SQL data base
|
||||
|
||||
Args:
|
||||
execute: Function to exec SQL request
|
||||
data: Optional data for the class constructor
|
||||
|
||||
Returns:
|
||||
Return new instance of class
|
||||
"""
|
||||
raise NotImplementedMethodeError(cls, cls._sql_load)
|
||||
|
||||
def _save_submodel(self, execute):
|
||||
for sc in self._sub_classes:
|
||||
sc._sql_update(execute)
|
||||
|
||||
def _sql_save(self, execute, data = None):
|
||||
"""Save class data to data base
|
||||
|
||||
Args:
|
||||
execute: Function to exec SQL resquest
|
||||
data: Optional additional information for save
|
||||
|
||||
Returns:
|
||||
Return true, otherelse false if an issue appear during
|
||||
save
|
||||
"""
|
||||
raise NotImplementedMethodeError(self, self._sql_save)
|
||||
|
|
@ -70,7 +70,7 @@ class NotImplementedMethodeError(ExeceptionWithMessageBox):
|
|||
f" '{self.func.__name__}' " +
|
||||
_translate("Exception", "not implemented") +
|
||||
_translate("Exception", "for class") +
|
||||
f" '{self.obj.__class__}'"
|
||||
f" '{self.obj.__class__ if self.obj.__class__ != type else self.obj}'"
|
||||
)
|
||||
|
||||
def header(self):
|
||||
|
|
|
|||
|
|
@ -3,9 +3,12 @@
|
|||
from math import dist
|
||||
import numpy as np
|
||||
|
||||
from Model.DB import SQLSubModel
|
||||
from Model.Geometry.Point import Point
|
||||
|
||||
class PointXYZ(Point):
|
||||
class PointXYZ(Point, SQLSubModel):
|
||||
_sub_classes = []
|
||||
|
||||
def __init__(self, x:float = 0.0, y:float = 0.0, z:float = 0.0,
|
||||
name:str = "", status = None):
|
||||
super(PointXYZ, self).__init__(name=name, status=status)
|
||||
|
|
@ -14,6 +17,36 @@ class PointXYZ(Point):
|
|||
self._y = float(y)
|
||||
self._z = float(z)
|
||||
|
||||
@classmethod
|
||||
def _sql_create(cls, execute):
|
||||
execute("""
|
||||
CREATE TABLE geometry_pointXYZ(
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
name TEXT,
|
||||
x INTEGER NOT NULL,
|
||||
y INTEGER NOT NULL,
|
||||
z INTEGER NOT NULL,
|
||||
profile INTEGER NOT NULL,
|
||||
FOREIGN KEY(profile) REFERENCES profileXYZ(id)
|
||||
)
|
||||
""")
|
||||
|
||||
cls._create_submodel(execute)
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _sql_update(cls, execute, version):
|
||||
cls._update_submodel(execute, version)
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _sql_load(cls, execute, data = None):
|
||||
return None
|
||||
|
||||
def _sql_save(self, execute, data = None):
|
||||
return True
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_data(cls, header, data):
|
||||
point = None
|
||||
|
|
|
|||
|
|
@ -5,12 +5,17 @@ from typing import List
|
|||
|
||||
from tools import timer
|
||||
|
||||
from Model.DB import SQLSubModel
|
||||
from Model.Except import ClipboardFormatError
|
||||
from Model.Geometry.Profile import Profile
|
||||
from Model.Geometry.PointXYZ import PointXYZ
|
||||
from Model.Geometry.Vector_1d import Vector1d
|
||||
|
||||
class ProfileXYZ(Profile):
|
||||
class ProfileXYZ(Profile, SQLSubModel):
|
||||
_sub_classes = [
|
||||
PointXYZ,
|
||||
]
|
||||
|
||||
def __init__(self,
|
||||
name: str = "",
|
||||
kp: float = 0.,
|
||||
|
|
@ -41,6 +46,36 @@ class ProfileXYZ(Profile):
|
|||
status = status,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _sql_create(cls, execute):
|
||||
execute("""
|
||||
CREATE TABLE geometry_profileXYZ(
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
name TEXT,
|
||||
reach INTEGER NOT NULL,
|
||||
kp REAL NOT NULL,
|
||||
num INTEGER NOT NULL,
|
||||
code1 INTEGER NOT NULL,
|
||||
code2 INTEGER NOT NULL,
|
||||
FOREIGN KEY(reach) REFERENCES river_reach(id)
|
||||
)
|
||||
""")
|
||||
|
||||
cls._create_submodel(execute)
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _sql_update(cls, execute, version):
|
||||
cls._update_submodel(execute, version)
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _sql_load(cls, execute, data = None):
|
||||
return None
|
||||
|
||||
def _sql_save(self, execute, data = None):
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def from_data(cls, header, data):
|
||||
profile = None
|
||||
|
|
|
|||
|
|
@ -10,12 +10,18 @@ from functools import reduce
|
|||
|
||||
from tools import flatten, timer, trace
|
||||
|
||||
from Model.DB import SQLSubModel
|
||||
|
||||
from Model.Geometry.Profile import Profile
|
||||
from Model.Geometry.ProfileXYZ import ProfileXYZ
|
||||
|
||||
from Model.Except import FileFormatError, exception_message_box
|
||||
|
||||
class Reach:
|
||||
class Reach(SQLSubModel):
|
||||
_sub_classes = [
|
||||
ProfileXYZ,
|
||||
]
|
||||
|
||||
def __init__(self, status=None, parent=None):
|
||||
self._status = status
|
||||
self._parent = parent
|
||||
|
|
@ -24,6 +30,34 @@ class Reach:
|
|||
self._guidelines_is_valid = False
|
||||
self._guidelines = {}
|
||||
|
||||
@classmethod
|
||||
def _sql_create(cls, execute):
|
||||
cls._create_submodel(execute)
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _sql_update(cls, execute, version):
|
||||
cls._update_submodel(execute, version)
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def _sql_load(cls, execute, data = None):
|
||||
new = cls(status = data["status"], parent = data["parent"])
|
||||
|
||||
new._profiles = ProfileXYZ._sql_load(
|
||||
execute,
|
||||
data = {
|
||||
"status": data["status"],
|
||||
"reach": new,
|
||||
}
|
||||
)
|
||||
|
||||
return new
|
||||
|
||||
def _sql_save(self, execute, data = None):
|
||||
cls._save_submodel(execute, data)
|
||||
return True
|
||||
|
||||
def profile(self, i):
|
||||
"""Returns profile at index i
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,15 @@ class Node(object):
|
|||
def name(self):
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return self.pos.x
|
||||
|
||||
@property
|
||||
def y(self):
|
||||
return self.pos.y
|
||||
|
||||
|
||||
def setPos(self, x, y):
|
||||
self.pos.x = x
|
||||
self.pos.y = y
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from Model.DB import SQLSubModel
|
||||
|
||||
from Model.Network.Node import Node
|
||||
from Model.Network.Edge import Edge
|
||||
from Model.Network.Graph import Graph
|
||||
|
|
@ -16,7 +18,9 @@ from Model.SolverParameters.SolverParametersList import SolverParametersList
|
|||
|
||||
from Solver.Solvers import solver_type_list
|
||||
|
||||
class RiverNode(Node):
|
||||
class RiverNode(Node, SQLSubModel):
|
||||
_sub_classes = []
|
||||
|
||||
def __init__(self, id:str, name:str,
|
||||
x:float, y:float,
|
||||
status = None):
|
||||
|
|
@ -28,6 +32,31 @@ class RiverNode(Node):
|
|||
|
||||
self._locker = None
|
||||
|
||||
@classmethod
|
||||
def _sql_create(cls, execute):
|
||||
execute("""
|
||||
CREATE TABLE river_node(
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
x REAL NOT NULL,
|
||||
y REAL NOT NULL
|
||||
)
|
||||
""")
|
||||
|
||||
cls._create_submodel(execute)
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _sql_update(cls, execute, version):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def _sql_load(cls, execute, data = None):
|
||||
return True
|
||||
|
||||
def _sql_save(self, execute, data = None):
|
||||
return True
|
||||
|
||||
@property
|
||||
def locker(self):
|
||||
return self._locker
|
||||
|
|
@ -37,7 +66,12 @@ class RiverNode(Node):
|
|||
self._locker = locker
|
||||
|
||||
|
||||
class RiverReach(Edge):
|
||||
class RiverReach(Edge, SQLSubModel):
|
||||
_sub_classes = [
|
||||
Reach,
|
||||
# SectionList,
|
||||
]
|
||||
|
||||
def __init__(self, id:str, name:str,
|
||||
node1:RiverNode = None,
|
||||
node2:RiverNode = None,
|
||||
|
|
@ -51,6 +85,33 @@ class RiverReach(Edge):
|
|||
self._reach = Reach(status=self._status, parent=self)
|
||||
self._sections = SectionList(status=self._status)
|
||||
|
||||
@classmethod
|
||||
def _sql_create(cls, execute):
|
||||
execute("""
|
||||
CREATE TABLE river_reach(
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
node1 INTEGER,
|
||||
node2 INTEGER,
|
||||
FOREIGN KEY(node1) REFERENCES river_node(id),
|
||||
FOREIGN KEY(node2) REFERENCES river_node(id)
|
||||
)
|
||||
""")
|
||||
|
||||
cls._create_submodel(execute)
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _sql_update(cls, execute, version):
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _sql_load(cls, execute, data = None):
|
||||
return None
|
||||
|
||||
def _sql_save(self, execute, data = None):
|
||||
return True
|
||||
|
||||
@property
|
||||
def reach(self):
|
||||
return self._reach
|
||||
|
|
@ -59,7 +120,17 @@ class RiverReach(Edge):
|
|||
def sections(self):
|
||||
return self._sections
|
||||
|
||||
class River(Graph):
|
||||
class River(Graph, SQLSubModel):
|
||||
_sub_classes = [
|
||||
RiverNode,
|
||||
RiverReach,
|
||||
# BoundaryConditionList,
|
||||
# LateralContributionList,
|
||||
# InitialConditionsDict,
|
||||
# StricklersList,
|
||||
# SolverParametersList,
|
||||
]
|
||||
|
||||
def __init__(self, status=None):
|
||||
super(River, self).__init__(status=status)
|
||||
|
||||
|
|
@ -74,6 +145,31 @@ class River(Graph):
|
|||
self._stricklers = StricklersList(status=self._status)
|
||||
self._parameters = {}
|
||||
|
||||
@classmethod
|
||||
def _sql_create(cls, execute):
|
||||
cls._create_submodel(execute)
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _sql_update(cls, execute, version):
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def _sql_load(cls, execute, data = None):
|
||||
return None
|
||||
|
||||
def _sql_save(self, execute, data = None):
|
||||
return True
|
||||
|
||||
@property
|
||||
def reach(self):
|
||||
return self._reach
|
||||
|
||||
@property
|
||||
def sections(self):
|
||||
return self._sections
|
||||
|
||||
|
||||
@property
|
||||
def boundary_condition(self):
|
||||
return self._boundary_condition
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
import pickle
|
||||
|
||||
class Serializable():
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
def __init__(self):
|
||||
return
|
||||
|
||||
@classmethod
|
||||
def open(cls, filename):
|
||||
|
|
|
|||
|
|
@ -3,18 +3,28 @@
|
|||
import os
|
||||
from datetime import datetime
|
||||
|
||||
from Model.DB import SQLModel
|
||||
from Model.Saved import SavedStatus
|
||||
from Model.Serializable import Serializable
|
||||
|
||||
from Model.Except import NotImplementedMethodeError
|
||||
from Model.River import River
|
||||
|
||||
from Checker.Study import *
|
||||
|
||||
class Study(Serializable):
|
||||
def __init__(self):
|
||||
# Serialization information
|
||||
super(Study, self).__init__("")
|
||||
self.filename = ""
|
||||
class Study(SQLModel):
|
||||
_sub_classes = [
|
||||
River,
|
||||
]
|
||||
|
||||
def __init__(self, filename = None, init_new = True):
|
||||
# Metadata
|
||||
self._version = "0.0.0"
|
||||
self.creation_date = datetime.now()
|
||||
self.last_modification_date = datetime.now()
|
||||
self.last_save_date = datetime.now()
|
||||
|
||||
self._filename = filename
|
||||
super(Study, self).__init__(filename = filename)
|
||||
|
||||
self.status = SavedStatus()
|
||||
|
||||
|
|
@ -25,10 +35,7 @@ class Study(Serializable):
|
|||
self._time_system = "time"
|
||||
self._date = datetime.fromtimestamp(0)
|
||||
|
||||
self.creation_date = datetime.now()
|
||||
self.last_modification_date = datetime.now()
|
||||
self.last_save_date = datetime.now()
|
||||
|
||||
if init_new:
|
||||
# Study data
|
||||
self._river = River(status = self.status)
|
||||
|
||||
|
|
@ -66,6 +73,15 @@ class Study(Serializable):
|
|||
self._name = str(name)
|
||||
self.status.modified()
|
||||
|
||||
@property
|
||||
def filename(self):
|
||||
return self._filename
|
||||
|
||||
@filename.setter
|
||||
def filename(self, filename):
|
||||
self._filename = str(filename)
|
||||
self._init_db_file(filename, is_new = True)
|
||||
|
||||
@property
|
||||
def time_system(self):
|
||||
return self._time_system
|
||||
|
|
@ -88,9 +104,9 @@ class Study(Serializable):
|
|||
self._date = timestamp
|
||||
self.status.modified()
|
||||
|
||||
@classmethod
|
||||
def new(cls):
|
||||
return cls()
|
||||
# @classmethod
|
||||
# def new(cls):
|
||||
# return cls()
|
||||
|
||||
@classmethod
|
||||
def new(cls, name, description, date = None):
|
||||
|
|
@ -101,3 +117,46 @@ class Study(Serializable):
|
|||
me.use_date()
|
||||
me.date = date
|
||||
return me
|
||||
|
||||
@classmethod
|
||||
def open(cls, filename):
|
||||
me = cls._load(filename)
|
||||
return me
|
||||
|
||||
#######
|
||||
# SQL #
|
||||
#######
|
||||
|
||||
def _create(self):
|
||||
# Info (metadata)
|
||||
self.execute("CREATE TABLE info(key TEXT NOT NULL UNIQUE, value TEXT NOT NULL)")
|
||||
self.execute(
|
||||
f"INSERT INTO info VALUES ('version', '{self._sql_format(self._version)}')",
|
||||
commit = True
|
||||
)
|
||||
|
||||
self._create_submodel()
|
||||
self.commit()
|
||||
|
||||
def _update(self):
|
||||
version = self.execute(f"SELECT value FROM info WHERE key='version'")
|
||||
|
||||
print(f"{version} == {self._version}")
|
||||
if version == self._version:
|
||||
return True
|
||||
|
||||
print("TODO: update")
|
||||
raise NotImplementedMethodeError(self, self._update)
|
||||
|
||||
@classmethod
|
||||
def _load(cls, filename):
|
||||
new = cls(init_new = False)
|
||||
|
||||
# Load river data
|
||||
self._river = River.load()
|
||||
|
||||
return new
|
||||
|
||||
def _save(self):
|
||||
|
||||
self.commit()
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||
Returns:
|
||||
Nothing
|
||||
"""
|
||||
if self.model.filename == "":
|
||||
if self.model.filename is None or self.model.filename == "":
|
||||
file_name, _ = QFileDialog.getSaveFileName(
|
||||
self, "Save File",
|
||||
"", "Pamhyr(*.pkl)"
|
||||
|
|
@ -282,9 +282,9 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
|
|||
if self.model is None:
|
||||
dialog = QFileDialog(self)
|
||||
dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
|
||||
dialog.setDefaultSuffix(".pkl")
|
||||
dialog.setDefaultSuffix(".pamhyr")
|
||||
#dialog.setFilter(dialog.filter() | QtCore.QDir.Hidden)
|
||||
dialog.setNameFilters(['PamHyr (*.pkl)'])
|
||||
dialog.setNameFilters(['PamHyr (*.pamhyr)'])
|
||||
|
||||
if dialog.exec_():
|
||||
file_name = dialog.selectedFiles()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class Config(SQL):
|
|||
self.filename = Config.filename()
|
||||
self.set_default_value()
|
||||
|
||||
super(Config, self).__init__(db = self.filename)
|
||||
super(Config, self).__init__(filename = self.filename)
|
||||
|
||||
def _create(self):
|
||||
# Info (meta data)
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ def old_pamhyr_date_to_timestamp(date:str):
|
|||
# from sqlite3.
|
||||
|
||||
class SQL(object):
|
||||
def __init__(self, db = "db.sqlite3"):
|
||||
def _init_db_file(self, db):
|
||||
exists = Path(db).exists()
|
||||
|
||||
self._db = sqlite3.connect(db)
|
||||
|
|
@ -178,6 +178,13 @@ class SQL(object):
|
|||
self._update() # Update db scheme if necessary
|
||||
self._load() # Load data
|
||||
|
||||
|
||||
def __init__(self, filename = None):
|
||||
self._db = None
|
||||
|
||||
if filename is not None:
|
||||
self._init_db_file(filename)
|
||||
|
||||
def commit(self):
|
||||
self._db.commit()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue