-
Notifications
You must be signed in to change notification settings - Fork 0
ORM und Sync
sp5lib.orm ist der SQLAlchemy-2.0-Layer der Bibliothek: eine datenbankagnostische
Abbildung des Schichtplaner5-Datenbestands auf SQLite oder PostgreSQL, inklusive
DBF→SQL-Synchronisation. Der Layer ist rein additiv — er ersetzt den DBF-Pfad
nicht, sondern existiert parallel dazu:
- DBF bleibt Source of Truth für den Original-Client und den Standardbetrieb (Datenbankformat).
- Der ORM-Spiegel ist als Read-Mirror ausgelegt:
sync_all()überträgt die Daten per Upsert in die SQL-Datenbank; ein Rückschreiben SQL → DBF ist bewusst nicht implementiert.
.DBF-Dateien ──read_dbf──► sp5lib.orm.sync ──Upsert──► SQLite / PostgreSQL
│
Repositories / SP5PostgresDatabase
from sp5lib.orm import get_engine, init_db
from sp5lib.orm.base import session_scope
# Entwicklung: SQLite
engine = get_engine("sqlite:///sp5.db")
# Produktion: PostgreSQL (nur die URL ändert sich)
engine = get_engine("postgresql://user:pw@localhost:5432/sp5")
init_db(engine) # legt alle Tabellen an- Alle Abfragen laufen über die SQLAlchemy-ORM-API (kein Roh-SQL) — der Wechsel zwischen SQLite und PostgreSQL ist nur eine andere Verbindungs-URL.
- Die SQLite-Engine wird mit WAL-Modus und aktivierten Foreign-Key-Pragmas
konfiguriert, die PostgreSQL-Engine mit Connection-Pooling und
pool_pre_ping. -
session_scope(engine)liefert einen Kontextmanager mit Commit/Rollback;get_session(engine)eine einzelne Session.
Die kanonischen Modelle liegen in sp5lib.orm.models und sind direkt aus
sp5lib.orm importierbar. Jedes Modell hat ein to_dict(), das die echten
DBF-Feldnamen spiegelt (z. B. LEAVETYPID, ENTITLEMNT, DESCRIPT) — Konsumenten
erhalten also dieselben Schlüssel wie beim direkten DBF-Lesen.
| Modell | DBF-Quelle | Inhalt |
|---|---|---|
Employee |
5EMPL |
Mitarbeiter |
Group / GroupAssignment
|
5GROUP / 5GRASG
|
Gruppen (hierarchisch) und Zuordnungen |
Shift |
5SHIFT |
Schichtarten |
LeaveType |
5LEAVT |
Abwesenheitsarten |
Workplace |
5WOPL |
Arbeitsplätze |
ShiftAssignment |
5MASHI |
Dienstplan-Einträge |
SpecialShift |
5SPSHI |
Sonderschichten |
Absence |
5ABSEN |
Abwesenheiten |
Holiday / Period
|
5HOLID / 5PERIO
|
Feiertage, Perioden |
AccountBooking |
5BOOK |
Kontobuchungen |
OvertimeEntry |
5OVER |
Überstunden |
LeaveEntitlement |
5LEAEN |
Urlaubsansprüche |
ShiftDemand / SpecialDemand
|
5SHDEM / 5SPDEM
|
Besetzungsbedarf |
Cycle / CycleAssignment
|
5CYCLE / 5CYASS
|
Schichtmodelle und Zuweisungen |
Restriction |
5RESTR |
Restriktionen |
Company |
— | Mandanten-Vorgriff ohne DBF-Gegenstück (kein Sync) |
Für Bestandscode bleiben die früheren Namen als Aliase importierbar:
ScheduleEntry (= ShiftAssignment), Booking (= AccountBooking),
OvertimeRecord (= OvertimeEntry), StaffingRequirement (= ShiftDemand).
Zusätzlich definiert sp5lib.orm.models_pg PostgreSQL-Zusatzmodelle ohne
DBF-Sync — User, CycleEntry, Note, HolidayBan, ExtraCharge, Settings,
ChangelogEntry — und re-exportiert alle kanonischen Modelle.
Der Datenzugriff ist im Repository-Pattern gekapselt (sp5lib.orm.repository,
18 Repositories): saubere Trennung von Fachlogik und Datenzugriff, leicht testbar
mit In-Memory-SQLite. Alle Repositories bieten get(id) und ein list(…) mit
fachlichen Filtern (Datumsfenster, Mitarbeiter, Jahr, Gruppe, include_hidden, …).
EmployeeRepository und GroupRepository haben darüber hinaus Schreibmethoden
(create, update, soft_delete, search, Mitglieder-Verwaltung).
from sp5lib.orm import get_engine, init_db
from sp5lib.orm.base import session_scope
from sp5lib.orm.repository import EmployeeRepository, GroupRepository
engine = get_engine("sqlite:///sp5.db")
init_db(engine)
with session_scope(engine) as session:
emp_repo = EmployeeRepository(session)
grp_repo = GroupRepository(session)
emp = emp_repo.create(name="Müller", firstname="Hans", hrsweek=38.5)
grp = grp_repo.create(name="Frühschicht", shortname="FS")
grp_repo.add_member(grp.id, emp.id)
members = grp_repo.get_members(grp.id)
results = emp_repo.search("müll")sp5lib.orm.sync.sync_all(engine, daten_path) spiegelt 19 DBF-Tabellen per
Upsert (nach DBF-ID: vorhandene Zeilen werden aktualisiert, neue eingefügt) in
einer Transaktion und liefert ein Dictionary mit den Record-Zahlen je Tabelle:
from sp5lib.orm import get_engine, init_db
from sp5lib.orm.sync import sync_all
engine = get_engine("sqlite:///sp5.db")
init_db(engine)
stats = sync_all(engine, "/pfad/zu/SP5/Daten")
print(stats) # {"employees": …, "groups": …, …}Dasselbe leistet ohne Python-Code das Kommando sp5lib sync (CLI).
Der Sync ist darauf ausgelegt, mit gewachsenen Realdatenbeständen durchzulaufen:
-
Gruppen-Hierarchie zweiphasig: Eltern-Verweise werden erst nach dem Anlegen
aller Gruppen aufgelöst; hängende Verweise werden auf
NULLgesetzt und geloggt. -
Zuordnungstabellen (
5GRASG,5CYASS): die DBF-IDist dort kein globaler Schlüssel — der Sync verwendet einen eigenen Autoincrement-Schlüssel, dedupliziert auf(Mitarbeiter, Gruppe)bzw.(Mitarbeiter, Zyklus, Start)und überspringt Zeilen mit unbekannten Verweisen. -
Datumsbehaftete Tabellen: Zeilen mit leerem oder ungültigem
DATEwerden übersprungen und gezählt geloggt. - Referenzspalten (Mitarbeiter/Schicht/Abwesenheitsart/Arbeitsplatz) sind bewusst einfache Integer ohne Datenbank-Foreign-Key, damit auch inkonsistente Altdaten synchronisierbar bleiben.
SP5Database nutzt 30 DBF-Tabellen, der Sync spiegelt 19. Ohne SQL-Gegenstück
bleiben u. a. 5USER, 5NOTE, 5CYENT, 5CYEXC, 5USETT, 5XCHAR, 5HOBAN,
5EMACC, 5GRACC, 5DADEM und 5MAGRP — Benutzerkonten, Notizen und
Zyklus-Details müssen auf einem reinen SQL-Backend von der Anwendung selbst gepflegt
werden (die App tut das; siehe
PostgreSQL-Support im App-Wiki).
Für den Betrieb der REST-API auf PostgreSQL bietet sp5lib.pg_database die Klasse
SP5PostgresDatabase mit denselben Methodensignaturen wie SP5Database — als
Teilmenge (Stammdaten-CRUD, Dienstplan-Basis, Benutzer/2FA, Notizen, Statistik-
und Kontoauswertungen). Die Auswertungen rechnen über dieselbe Rechenschicht wie das
DBF-Backend (Berechnungen). Die Backend-Wahl zur Laufzeit übernimmt
sp5lib.db_factory.get_database() anhand der Umgebungsvariablen DB_BACKEND,
DATABASE_URL und SP5_DB_PATH (siehe API-Referenz).
Home — Startseite
- Installation — PyPI, Git, Docker
-
CLI — Das
sp5lib-Kommando
- Datenbankformat — DBF/CDX aus Nutzersicht
- Berechnungen — Soll/Ist, Konten, Zuschläge
-
ORM-und-Sync — SQLAlchemy-Spiegel &
sync_all
-
API-Referenz —
SP5Database& Module
- Entwicklung — Setup, Tests, Repo-Verbund