Files
nexarch/internal/migration/verify/postgres.go
T
patrickandClaude Sonnet 5.5 5b8c20777d refactor: Pruefgate-Pakete nach Funktion benannt, migration* gruppiert
- dms/ai/workflow: qa0x-Pakete nach internal/gates/<thema> verschoben, Paketname = Thema
- internal/migration{acl,audit,...} -> internal/migration/{acl,audit,...}
- Importpfade, Gate-Skripte und zwei relative Migrationspfade angepasst
- keine Logikaenderung; mail-Gates bewusst unveraendert (pfadabhaengig)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 12:44:21 +01:00

64 lines
2.6 KiB
Go

package migrationverify
import (
"context"
"fmt"
"github.com/jackc/pgx/v5/pgxpool"
)
// TenantPoolResolver liefert den Pool der physischen Tenant-Datenbank
// (Modell C, siehe internal/tenant) zu einem Tenant-Slug.
type TenantPoolResolver func(ctx context.Context, tenantSlug string) (*pgxpool.Pool, error)
// PostgresTenantCountProvider zaehlt users und documents direkt in der
// Tenant-Datenbank, in die COR-02 (internal/migration/user) bzw. DOK-01
// (dms/internal/migrationdocument) schreiben. Die Nachrichten-Zieltabelle
// existiert nicht in Postgres (siehe mail/internal/messagemigration,
// Metadaten liegen ausschliesslich im Manticore-Suchindex) — das
// Messages-Feld bleibt hier 0 und muss ueber einen eigenen CountProvider
// eingespeist werden (siehe CombineUsers-Muster).
type PostgresTenantCountProvider struct {
Resolver TenantPoolResolver
}
func (p PostgresTenantCountProvider) Counts(ctx context.Context, tenantSlug string) (TenantCounts, error) {
pool, err := p.Resolver(ctx, tenantSlug)
if err != nil {
return TenantCounts{}, fmt.Errorf("migrationverify: tenant-pool fuer %q: %w", tenantSlug, err)
}
var users, documents int64
if err := pool.QueryRow(ctx, `SELECT COUNT(*) FROM users`).Scan(&users); err != nil {
return TenantCounts{}, fmt.Errorf("migrationverify: users zaehlen (%q): %w", tenantSlug, err)
}
if err := pool.QueryRow(ctx, `SELECT COUNT(*) FROM documents`).Scan(&documents); err != nil {
return TenantCounts{}, fmt.Errorf("migrationverify: documents zaehlen (%q): %w", tenantSlug, err)
}
return TenantCounts{TenantSlug: tenantSlug, Users: users, Documents: documents}, nil
}
// RegistryApprovedUserCountProvider zaehlt freigegebene
// user_migration_map-Eintraege je Tenant (siehe
// internal/migration/user.MapStore.Approved) als Quellzahl der
// Benutzer-Kerntabelle.
type RegistryApprovedUserCountProvider struct {
RegistryPool *pgxpool.Pool
TenantIDBySlug map[string]string
}
func (p RegistryApprovedUserCountProvider) Counts(ctx context.Context, tenantSlug string) (TenantCounts, error) {
tenantID, ok := p.TenantIDBySlug[tenantSlug]
if !ok {
return TenantCounts{}, fmt.Errorf("migrationverify: kein nexarch_tenant_id fuer slug %q", tenantSlug)
}
var users int64
if err := p.RegistryPool.QueryRow(ctx, `
SELECT COUNT(*) FROM user_migration_map WHERE approved_at IS NOT NULL AND nexarch_tenant_id = $1
`, tenantID).Scan(&users); err != nil {
return TenantCounts{}, fmt.Errorf("migrationverify: freigegebene user-map-eintraege zaehlen (%q): %w", tenantSlug, err)
}
return TenantCounts{TenantSlug: tenantSlug, Users: users}, nil
}