Files
nexarch/internal/migrationverify/postgres.go
patrickandClaude Sonnet 5 628be89c9a
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) Canceled after 0s
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (pull_request) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
Core-Schnittstellen-Vertragstests / contract-tests (pull_request) Canceled after 0s
Core-Pflichttest-Gate / pflichttest-gate (pull_request) Canceled after 0s
RBAC-Rollenhierarchie-Pflichtgate / rbac-policy-invariant (pull_request) Canceled after 0s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
Supply-Chain-Scan (Go) / govulncheck (push) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (pull_request) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (pull_request) Canceled after 0s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (pull_request) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (pull_request) Canceled after 0s
CI / Web (dms-browser) (pull_request) Canceled after 0s
CI / Web (pdf-viewer) (pull_request) Canceled after 0s
CI / Web (shl) (pull_request) Canceled after 0s
Supply-Chain-Scan (Go) / govulncheck (pull_request) Canceled after 0s
Supply-Chain-Scan (npm) / npm-audit (pull_request) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (pull_request) Canceled after 0s
VAL-01: zeilenzahl-abgleich-kerntabelle
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-14 20:07:29 +00: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/migrationuser) 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/migrationuser.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
}