Changelog
Version: v0.3-alpha
Datum: 2025-08-12
Hinweis: Baseline war v0.2-alpha (ganz am Anfang dieses Chats). Diese Version (v0.3-alpha) fasst alle Änderungen, Erweiterungen und Verbesserungen zusammen, die seit v0.2-alpha implementiert wurden.
Übersicht (Kurz)
v0.3-alpha erweitert das Mini‑ORM erheblich: Connection‑Management & Pooling, robustere Transaktionen mit Savepoints, persistente Migrations‑Historie, Audit‑Trigger, umfangreiche DDL- und Batch‑Methoden, Soft‑Delete‑Integration in Queries, Hooks erweitert, Schema‑Caching, Typ‑Inference, Streaming für große Abfragen, Logging und viele Convenience‑Methoden (get_by, get_or_create, paginate_with_count, usw.).
Neu (Added)
-
Connection / Pooling
- connect_pool(minconn, maxconn, **db_params)
- close() / close_pool()
-
Logging & Observability
- set_logger(fn) zum Registrieren eines Query‑Loggers
- healthcheck() für einfache DB‑Erreichbarkeitsprüfung
- explain(query, analyze=True) zur Abfrageoptimierung
-
Transaktionen & Savepoints
- transaction() Contextmanager mit Verschachtelung (innere Ebenen verwenden Savepoints)
- savepoint(name=None) separater Savepoint‑Context
-
Migrations‑Framework (persistente Historie)
- schema_migrations Tabelle wird angelegt
- run_migrations() protokolliert ausgeführte Migrationen
- add_migration(name, fn) zur Registrierung
-
Audit‑Trail
- enable_audit_trail(table, audit_table="audit_log") legt Trigger und Audit‑Tabelle an
-
Hooks
- Global und tabellenspezifische BEFORE/AFTER Hooks (register_before_insert, register_after_insert)
- BEFORE‑Hooks können Daten mutieren; AFTER‑Hooks werden exceptionsicher ausgeführt
-
Soft‑Delete
- soft_delete(), restore_soft_deleted(), purge_soft_deleted_older_than()
- automatische Berücksichtigung von deleted-Spalte in Abfragen (exclude_deleted flag)
-
CRUD / Convenience
- get_by(), first(), last(), get_or_create()
- paginate_with_count()
- list_all_ids()
- exists_by_id()
- to_dict(), refresh(), clone_row(), copy_row_to_table()
-
Upsert / Bulk / Batch
- upsert(table, conflict_cols, values, update_cols=None) (RETURNING id)
- bulk_create(rows) (execute_values)
- bulk_update(rows, key="id") via VALUES/... FROM‑Konstrukt
- execute_batch(query, params, page_size) (psycopg2.extras.execute_batch)
-
Streaming & große Datenmengen
- stream_query(query, params=(), fetch_size=1000) mit serverseitigem Cursor
-
Schema / DDL
- inspect_schema(table) mit TTL‑Cache (set_schema_cache_ttl)
- ensure_columns(table, columns: Dict[col, SQLType]) für Mehrfach‑ALTER
- create_table, drop_table, add_index, add_unique, add_foreign_key, drop_constraint, rename_column, drop_column
- add_timestamps(table) + Trigger für updated_at
- ensure_version_column(table, version_col="version") für Optimistic Locking
- vacuum_analyze(table=None)
-
Optimistic Locking
- save_with_version(version_col="version") mit vorherigem ensure_version_column
-
Aggregates
- aggregate(table, func, column, **conditions) (SUM/MIN/MAX/AVG/COUNT etc.)
-
Schema‑Caching und Typ‑Inference
- automatisches Anlegen neuer Spalten mit inferiertem SQL‑Typ (TEXT, BOOLEAN, BIGINT, JSONB, TIMESTAMP, ...)
- Cache default TTL = 300s, konfigurierbar via set_schema_cache_ttl
Verbesserungen (Changed)
-
_get_cursor() / Connection-Handling
- Unterstützung für Pooling vs. Einzelverbindung, Cursor‑Commit/Rollback jetzt korrekt mit/ohne outer transaction
- Cursor wird immer geschlossen; Pool‑Verbindung wird nur zurückgegeben, wenn nicht in globaler transaction()
-
transaction()
- Verschachtelung mittels Savepoints (innere Scope → SAVEPOINT / RELEASE / ROLLBACK TO)
- threadlocal Speicherung der Verbindung/Depth (Thread‑sicherer Kontext)
-
Hooks
- Unterstützung globaler ("*") Hooks neben tabellenspezifischen Hooks
- BEFORE‑Hooks werfen Fehler (abbruch); AFTER‑Hooks werden log‑sicher ausgeführt (Fehler werden unterdrückt)
-
Schema‑Inspektion/Cache
- TTL‑Cache zur Verminderung von information_schema‑Abfragen, Cache‑Invalidierung nach DDL‑Operationen
-
Soft‑Delete
- Automatische Filterung (exclude_deleted=True) in find_ids/get_all/paginate/count/exists
-
create(), bulk_create(), upsert()
- Optional: Spaltentypen explizit per column_types oder infer_types=True
- Fehlende Spalten werden automatisch mit sinnvoller Typwahl angelegt
-
Fehlerbehandlung
- Logging des SQL (wenn Logger gesetzt) ohne das Ausführen zu beeinflussen
- Hooks und Logger dürfen nicht die DB‑Operationen destabilisieren
Fehlerbehebungen (Fixed)
- Resource‑Leaks beim Pooling verhindert (Cursor schließen, putconn sicherstellen)
- Transaktionslogik: commit/rollback wird korrekt nur am Outermost‑Level durchgeführt
- Bulk‑Inserts: execute_values korrekt eingesetzt und RETURNING id gelesen
- Schema‑Änderungen invalidieren nun Cache korrekt
Entfernt / Deprecated
- Keine Methoden wurden absichtlich entfernt; einige Signaturen wurden erweitert (kompatibel, aber erweiterte Parameter vorhanden):
- create(...) Signature erweitert um column_types & infer_types
- register_before_insert/register_after_insert nehmen jetzt Optional table (None/"*" = global)
Breaking Changes / Migration Notes
- Wenn du externe Code hast, der register_before_insert(table, fn) mit table None benutzt hat, das Verhalten ist jetzt konsistent: verwende "*" oder None für globale Hooks.
- create() akzeptiert jetzt zusätzliche optionale Parameter (column_types, infer_types) — bestehende Aufrufe bleiben kompatibel.
- transaction(): vorherige Implementierung kann in seltenen Fällen ein anderes Verhalten beim nested transaction handling gehabt haben; überprüfe komplexe Migrationsskripts, die sich auf implicit commits verlassen.
- run_migrations() legt nun persistente Tabelle schema_migrations an. Falls du bereits eine Tabelle mit anderem Schema namens schema_migrations hast, müssten Konflikte überprüft werden.
- add_timestamps() und enable_audit_trail() legen PL/pgSQL‑Funktionen/Trigger an — falls Namen kollidieren, passe Namen an.
Empfehlung vor Upgrade:
- Backup der DB / Schema.
- Prüfe vorhandene Tabellen
schema_migrations/audit_logauf Namenskonflikte. - Führe run_migrations() in Testumgebung aus.
- Falls du save_with_version einsetzen willst: zuerst ensure_version_column(table).
Upgrade‑/Migrations‑Beispiel
-
Verbindung herstellen (Test):
- DM.connect_pool(...)
-
Logging einschalten (optional):
- DM.set_logger(lambda q,p: print(q, p))
-
Migrationen ausführen:
- DM.add_migration("001_add_index_users_email", lambda: DM.add_index("users","email", unique=True))
- DM.run_migrations()
-
Audit aktivieren (optional):
- DM.enable_audit_trail("users")
-
Versionierung (optional):
- DM.ensure_version_column("users")
Beispiele (neues Verhalten)
- get_or_create:
obj, created = DM.get_or_create("users", defaults={"name":"X"}, email="a@b.c")- Upsert:
uid = DM.upsert("users", conflict_cols=["email"], values={"email":"a@b.c","name":"Ada"})- Transaction mit Savepoint:
with DM.transaction():
a = DM.create("t", x=1)
with DM.savepoint():
b = DM.create("t", x=2)
# Fehler -> nur Savepoint rollback- Streaming:
for row in DM.stream_query("SELECT * FROM big_table"):
process(row)Sonstiges / Hinweise
- Default Schema‑Cache TTL = 300 Sekunden (konfigurierbar)
- Typ‑Inference ist heuristisch; bei Bedarf explizit column_types übergeben
- Alle neu hinzugefügten Features sind auf SQL‑Injection geschützt (sql.Identifier, Parameterbindung). Achte dennoch bei dynamischen SQL‑Fragments (z. B. aggregate func) auf Validierung.