package db import ( "context" "github.com/jackc/pgx/v5" ) func (db *DB) GetTenantBySubdomain(ctx context.Context, subdomain string) (*Tenant, error) { var t Tenant var ownerID, customDomain *string err := db.pool.QueryRow(ctx, `SELECT id, owner_id, subdomain, custom_domain, premium, members_enabled, donations_enabled, created_at FROM tenants WHERE subdomain = $1`, subdomain).Scan(&t.ID, &ownerID, &t.Subdomain, &customDomain, &t.Premium, &t.MembersEnabled, &t.DonationsEnabled, &t.CreatedAt) if err == pgx.ErrNoRows { return nil, nil } if ownerID != nil { t.OwnerID = *ownerID } if customDomain != nil { t.CustomDomain = *customDomain } return &t, err } func (db *DB) GetTenantByOwner(ctx context.Context, ownerID string) (*Tenant, error) { var t Tenant var owner, customDomain *string err := db.pool.QueryRow(ctx, `SELECT id, owner_id, subdomain, custom_domain, premium, members_enabled, donations_enabled, created_at FROM tenants WHERE owner_id = $1`, ownerID).Scan(&t.ID, &owner, &t.Subdomain, &customDomain, &t.Premium, &t.MembersEnabled, &t.DonationsEnabled, &t.CreatedAt) if err == pgx.ErrNoRows { return nil, nil } if owner != nil { t.OwnerID = *owner } if customDomain != nil { t.CustomDomain = *customDomain } return &t, err } func (db *DB) CreateTenant(ctx context.Context, ownerID, subdomain string) (*Tenant, error) { var t Tenant err := db.pool.QueryRow(ctx, `INSERT INTO tenants (owner_id, subdomain) VALUES ($1, $2) RETURNING id, owner_id, subdomain, custom_domain, premium, members_enabled, donations_enabled, created_at`, ownerID, subdomain).Scan(&t.ID, &t.OwnerID, &t.Subdomain, &t.CustomDomain, &t.Premium, &t.MembersEnabled, &t.DonationsEnabled, &t.CreatedAt) return &t, err } func (db *DB) GetTenantByID(ctx context.Context, id string) (*Tenant, error) { var t Tenant var ownerID, customDomain *string err := db.pool.QueryRow(ctx, `SELECT id, owner_id, subdomain, custom_domain, premium, members_enabled, donations_enabled, created_at FROM tenants WHERE id = $1`, id).Scan(&t.ID, &ownerID, &t.Subdomain, &customDomain, &t.Premium, &t.MembersEnabled, &t.DonationsEnabled, &t.CreatedAt) if err == pgx.ErrNoRows { return nil, nil } if ownerID != nil { t.OwnerID = *ownerID } if customDomain != nil { t.CustomDomain = *customDomain } return &t, err } func (db *DB) IsUserTenantOwner(ctx context.Context, userID, tenantID string) (bool, error) { var exists bool err := db.pool.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM tenants WHERE id = $1 AND owner_id = $2)`, tenantID, userID).Scan(&exists) return exists, err } func (db *DB) IsSubdomainAvailable(ctx context.Context, subdomain string) (bool, error) { var exists bool err := db.pool.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM reserved_subdomains WHERE subdomain = $1)`, subdomain).Scan(&exists) if err != nil { return false, err } if exists { return false, nil } err = db.pool.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM demos WHERE subdomain = $1 AND expires_at > NOW())`, subdomain).Scan(&exists) if err != nil { return false, err } if exists { return false, nil } err = db.pool.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM tenants WHERE subdomain = $1)`, subdomain).Scan(&exists) if err != nil { return false, err } return !exists, nil } func (db *DB) ListTenants(ctx context.Context) ([]Tenant, error) { rows, err := db.pool.Query(ctx, `SELECT id, owner_id, subdomain, custom_domain, premium, members_enabled, donations_enabled, created_at FROM tenants`) if err != nil { return nil, err } defer rows.Close() var tenants []Tenant for rows.Next() { var t Tenant var ownerID, customDomain *string if err := rows.Scan(&t.ID, &ownerID, &t.Subdomain, &customDomain, &t.Premium, &t.MembersEnabled, &t.DonationsEnabled, &t.CreatedAt); err != nil { return nil, err } if ownerID != nil { t.OwnerID = *ownerID } if customDomain != nil { t.CustomDomain = *customDomain } tenants = append(tenants, t) } return tenants, rows.Err() }