Accountant: Inventar, where, Checkmk, Abrechnung
This commit is contained in:
1 parent
9f16148cde
commit
dd93277750
59 files changed
+7522
-113
No files matched your search
+30
-7
@@ -111,6 +111,19 @@ type Store struct {
|
||||
// Open öffnet (bzw. erstellt) die Datenbank unter path und bringt das Schema
|
||||
// auf den aktuellen Stand.
|
||||
func Open(ctx context.Context, path string) (*Store, error) {
|
||||
db, err := OpenDB(ctx, path, migrations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Store{db: db, now: time.Now}, nil
|
||||
}
|
||||
|
||||
// OpenDB öffnet (bzw. erstellt) eine SQLite-Datenbank mit den Einstellungen
|
||||
// des Servers und wendet migrations an: migrations[i] hebt das Schema von
|
||||
// Version i auf i+1 (Version in PRAGMA user_version). Die Liste darf nur
|
||||
// wachsen; eine neuere Datenbank liefert ErrSchemaTooNew. Für weitere
|
||||
// Datenbanken wie accountant.db.
|
||||
func OpenDB(ctx context.Context, path string, migrations []string) (*sql.DB, error) {
|
||||
// foreign_keys: sonst greift ON DELETE CASCADE nicht (gilt pro Verbindung).
|
||||
// _txlock=immediate: Schreib-Transaktionen holen die Sperre sofort und
|
||||
// warten per busy_timeout, statt beim Upgrade mit SQLITE_BUSY abzubrechen.
|
||||
@@ -120,12 +133,11 @@ func Open(ctx context.Context, path string) (*Store, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := &Store{db: db, now: time.Now}
|
||||
if err := s.migrate(ctx); err != nil {
|
||||
if err := migrate(ctx, db, migrations); err != nil {
|
||||
db.Close()
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// Close schließt die Datenbank.
|
||||
@@ -133,13 +145,17 @@ func (s *Store) Close() error { return s.db.Close() }
|
||||
|
||||
// SchemaVersion liefert die aktuelle Schema-Version.
|
||||
func (s *Store) SchemaVersion(ctx context.Context) (int, error) {
|
||||
return schemaVersion(ctx, s.db)
|
||||
}
|
||||
|
||||
func schemaVersion(ctx context.Context, db *sql.DB) (int, error) {
|
||||
var v int
|
||||
err := s.db.QueryRowContext(ctx, "PRAGMA user_version").Scan(&v)
|
||||
err := db.QueryRowContext(ctx, "PRAGMA user_version").Scan(&v)
|
||||
return v, err
|
||||
}
|
||||
|
||||
func (s *Store) migrate(ctx context.Context) error {
|
||||
v, err := s.SchemaVersion(ctx)
|
||||
func migrate(ctx context.Context, db *sql.DB, migrations []string) error {
|
||||
v, err := schemaVersion(ctx, db)
|
||||
if err != nil {
|
||||
return fmt.Errorf("store: Schema-Version lesen: %w", err)
|
||||
}
|
||||
@@ -147,7 +163,7 @@ func (s *Store) migrate(ctx context.Context) error {
|
||||
return fmt.Errorf("%w (Datenbank v%d, bekannt bis v%d)", ErrSchemaTooNew, v, len(migrations))
|
||||
}
|
||||
for i := v; i < len(migrations); i++ {
|
||||
tx, err := s.db.BeginTx(ctx, nil)
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -172,6 +188,13 @@ const timeLayout = "2006-01-02T15:04:05.000000000Z"
|
||||
|
||||
func formatTime(t time.Time) string { return t.UTC().Format(timeLayout) }
|
||||
|
||||
// FormatTime formatiert t im Speicherformat (UTC, feste Breite) – für
|
||||
// Datenbanken, die OpenDB nutzen.
|
||||
func FormatTime(t time.Time) string { return formatTime(t) }
|
||||
|
||||
// ScanTime liest einen so gespeicherten Zeitstempel nach t (NULL = Nullzeit).
|
||||
func ScanTime(t *time.Time) sql.Scanner { return dbTime{t} }
|
||||
|
||||
// normTime entfernt Monotonic-Clock und Zeitzone, damit gespeicherte und
|
||||
// gelesene Werte identisch sind.
|
||||
func normTime(t time.Time) time.Time { return t.Round(0).UTC() }
|
||||
|
||||
Reference in new issue
Block a user