Added a Database Generator

This commit is contained in:
Philipp Horstenkamp 2023-12-29 01:29:31 +01:00
parent a833439ba7
commit 81d5abbf24

View File

@ -7,12 +7,56 @@ Auch wenn es seit einiger Zeit SQLAlchemy2 gibt haben wir uns entschieden mit Ve
SQLAlchemy ist ein sehr mächtiges und beliebtes Werkzeug, leider ist die Projektdokumentation sehr undurchsichtig. SQLAlchemy ist ein sehr mächtiges und beliebtes Werkzeug, leider ist die Projektdokumentation sehr undurchsichtig.
Da aber SQLAlchemy1.4 zurzeit noch gewartet wird, ist dies für dieses Projekt kein Problem. Da aber SQLAlchemy1.4 zurzeit noch gewartet wird, ist dies für dieses Projekt kein Problem.
Hier ein kurzes Beipiel einer SQL-defintion via SQLAlchemy. Hier ein kurzes Beispiel einer SQL-Defintion via SQLAlchemy.
Dynamicly generated
```python ```python
import sqlalchemy as sa
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class DistrictCourt(Base):
"""DistrictCourt."""
__tablename__ = "district_court"
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
city = sa.Column(sa.String(100), nullable=False)
name = sa.Column(sa.String(100), nullable=False, unique=True)
class Company(Base):
"""Company."""
__tablename__ = "company"
__table_args__ = (
sa.UniqueConstraint("hr", "court_id"),
sa.UniqueConstraint("name"),
)
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
hr = sa.Column(sa.String, nullable=False)
court_id = sa.Column(
sa.Integer,
sa.ForeignKey("district_court.id"),
nullable=False,
)
name = sa.Column(sa.String(150), nullable=False)
founding_date = sa.Column(sa.Date, nullable=True)
```
Natürlich ist es manchmal sinnvoll SQL-Tabellen dynamischer und mit wenig Code-Duplication zu generieren.
Eine Möglichkeit dazu ist die folgende Definition in der die Union einiger Teildefinitionen als Dictionary.
So kann zum Beispiel eine Tabelle generiert werden,
in der ein Enumerationswert die Column angibt ohne das die Datenbank durch den Enum als Foreign Key aufgeblasen/verlangsamt wird.
```python
from aki_prj23_transparenzregister.utils.enum_types import (
FinancialKPIEnum,
)
AnnualFinanceStatement = type( AnnualFinanceStatement = type(
"AnnualFinanceStatement", "AnnualFinanceStatement",
(Base,), (Base,),
@ -26,129 +70,19 @@ AnnualFinanceStatement = type(
) )
``` ```
Das Anlegen der Klassen alleine reicht nicht aus, um diese in einer SQL Datenbank anzulegen.
Diese müssen über das `Base`-Objekt wie folgt Initialisiert werden.
```python
Base.metadata.create_all(db.bind)
```
Dabei ist `db` eine `sqlalchemy.orm.Session` welche über eine SQL-Engine mit einer Datenbank verbindet.
Das resultierende SQL-Schema sieht dan wie folgt aus:
```{eval-rst} ```{eval-rst}
.. drawio-figure:: test-db.drawio .. drawio-figure:: test-db.drawio
:format: png :format: png
:page-index: 1 :page-index: 1
``` ```
```{mermaid}
classDiagram
direction BT
class annual_finance_statement {
integer company_id
date date
float revenue
float net_income
float ebit
float ebitda
float gross_profit
float operating_profit
float assets
float liabilities
float equity
float current_assets
float current_liabilities
float long_term_debt
float short_term_debt
float cash_and_cash_equivalents
float dividends
float cash_flow
integer id
}
class company {
varchar hr
integer court_id
varchar(150) name
varchar(26) company_type
date founding_date
varchar business_purpose
varchar(100) street
varchar(30) house_number
varchar(5) zip_code
varchar(100) city
float longitude
float latitude
float pos_accuracy
float capital_value
varchar(13) original_currency
varchar(12) capital_type
date last_update
varchar(100) sector
integer id
}
class district_court {
varchar(100) city
varchar(100) name
integer id
}
class news {
varchar(150) title
datetime timestamp
varchar text
varchar source_url
varchar source_domain
varchar(8) overall_sentiment_label
float overall_sentiment_certainty
integer number_of_companies
integer sum_of_times_named
integer id
}
class person {
varchar(100) firstname
varchar(100) lastname
date date_of_birth
varchar(100) works_for
varchar(100) street
varchar(10) house_number
varchar(5) zip_code
varchar(100) city
float longitude
float latitude
float pos_accuracy
integer id
}
class relation {
integer company_id
date date_from
date date_to
varchar(24) relation
integer id
}
class company_relation {
integer company2_id
integer id
}
class person_relation {
integer person_id
integer id
}
class sentiment {
integer company_id
integer article_id
integer times_named
varchar(8) specific_sentiment_label
float specific_sentiment_score
integer id
}
class missing_company {
varchar(5) zip_code
varchar(100) city
integer number_of_links
boolean searched_for
varchar(150) name
}
annual_finance_statement --> company : company_id->id
company --> district_court : court_id->id
company_relation --> company : company2_id->id
company_relation --> relation : id
person_relation --> person : person_id -> id
person_relation --> relation : id
relation --> company : company_id -> id
sentiment --> company : company_id -> id
sentiment --> news : article_id -> id
```