inou/.claude/worktrees/vibrant-nash/lib/stubs.go

594 lines
15 KiB
Go

package lib
// =============================================================================
// LEGACY STUBS — temporary bridges while callers are migrated to dbcore.go
//
// Each stub logs its call so we can find and replace callers.
// Delete this file when all callers use the new core.
// =============================================================================
import (
"database/sql"
"encoding/json"
"fmt"
"log"
"os"
)
// --- Legacy types ---
type EntryFilter struct {
DossierID string
Type string
Value string
SearchKey string
FromDate int64
ToDate int64
Limit int
}
type DossierFilter struct {
DateOfBirth string
Limit int
}
type AccessFilter struct {
AccessorID string
TargetID string
Status *int
}
type DossierQueryRow struct {
Dossier
Category int `db:"category"`
EntryCount int `db:"entry_count"`
}
type DossierAccess struct {
Access
}
// --- Entry stubs ---
func EntryAdd(e *Entry) error {
log.Printf("[STUB] EntryAdd(entry=%s, dossier=%s, cat=%d)", e.EntryID, e.DossierID, e.Category)
if e.EntryID == "" {
e.EntryID = NewID()
}
return entrySave(e)
}
func EntryAddBatch(entries []*Entry) error {
log.Printf("[STUB] EntryAddBatch(n=%d)", len(entries))
for _, e := range entries {
if e.EntryID == "" {
e.EntryID = NewID()
}
if err := entrySave(e); err != nil {
return err
}
}
return nil
}
func EntryAddBatchValues(entries []Entry) error {
log.Printf("[STUB] EntryAddBatchValues(n=%d)", len(entries))
for i := range entries {
if entries[i].EntryID == "" {
entries[i].EntryID = NewID()
}
if err := entrySave(&entries[i]); err != nil {
return err
}
}
return nil
}
func EntryGet(ctx *AccessContext, id string) (*Entry, error) {
accessorID := ""
if ctx != nil {
accessorID = ctx.AccessorID
}
return entryGetByID(accessorID, id)
}
func EntryQuery(ctx *AccessContext, dossierID string, category int, typ, parent string) ([]*Entry, error) {
accessorID := ""
if ctx != nil {
accessorID = ctx.AccessorID
}
f := &Filter{Category: category}
if typ != "" {
f.Type = typ
}
if parent != "" && parent != "*" {
f.ParentID = parent
}
return EntryRead(accessorID, dossierID, f)
}
func EntryList(accessorID string, parent string, category int, f *EntryFilter) ([]*Entry, error) {
dossierID := ""
filter := &Filter{Category: category, ParentID: parent}
if f != nil {
dossierID = f.DossierID
filter.Type = f.Type
filter.SearchKey = f.SearchKey
filter.FromDate = f.FromDate
filter.ToDate = f.ToDate
filter.Limit = f.Limit
}
return EntryRead(accessorID, dossierID, filter)
}
func EntryQueryOld(dossierID string, category int, typ string) ([]*Entry, error) {
return EntryRead("", dossierID, &Filter{Category: category, Type: typ})
}
func EntryCount(ctx *AccessContext, dossierID string, category int, typ string) (int, error) {
entries, err := EntryQuery(ctx, dossierID, category, typ, "*")
if err != nil {
return 0, err
}
return len(entries), nil
}
func EntryModify(e *Entry) error {
log.Printf("[STUB] EntryModify(entry=%s)", e.EntryID)
return entrySave(e)
}
func EntryDelete(entryID string) error {
log.Printf("[STUB] EntryDelete(id=%s)", entryID)
_, err := db.Exec("DELETE FROM entries WHERE EntryID = ?", entryID)
return err
}
func EntryDeleteTree(ctx *AccessContext, dossierID, entryID string) error {
log.Printf("[STUB] EntryDeleteTree(dossier=%s, entry=%s)", dossierID, entryID)
// Delete children first
children, _ := entryQuery(dossierID, &Filter{Category: -1, ParentID: entryID})
for _, c := range children {
db.Exec("DELETE FROM entries WHERE EntryID = ?", c.EntryID)
}
_, err := db.Exec("DELETE FROM entries WHERE EntryID = ?", entryID)
return err
}
func EntryDeleteByCategory(ctx *AccessContext, dossierID string, category int) error {
log.Printf("[STUB] EntryDeleteByCategory(dossier=%s, cat=%d)", dossierID, category)
_, err := db.Exec("DELETE FROM entries WHERE DossierID = ? AND Category = ?", dossierID, category)
return err
}
func EntryRemoveByDossier(ctx *AccessContext, dossierID string) error {
log.Printf("[STUB] EntryRemoveByDossier(dossier=%s)", dossierID)
_, err := db.Exec("DELETE FROM entries WHERE DossierID = ?", dossierID)
return err
}
func EntryChildren(dossierID, parentID string) ([]*Entry, error) {
return EntryRead("", dossierID, &Filter{Category: -1, ParentID: parentID})
}
func EntryChildrenByType(dossierID, parentID string, typ string) ([]*Entry, error) {
return EntryRead("", dossierID, &Filter{Category: -1, ParentID: parentID, Type: typ})
}
func EntryTypes(dossierID string, category int) ([]string, error) {
entries, err := EntryRead("", dossierID, &Filter{Category: category})
if err != nil {
return nil, err
}
seen := map[string]bool{}
var types []string
for _, e := range entries {
if !seen[e.Type] {
seen[e.Type] = true
types = append(types, e.Type)
}
}
return types, nil
}
// --- Dossier stubs ---
func DossierGet(ctx *AccessContext, id string) (*Dossier, error) {
accessorID := ""
if ctx != nil {
accessorID = ctx.AccessorID
}
entries, err := EntryRead(accessorID, id, &Filter{Category: 0})
if err != nil || len(entries) == 0 {
return nil, fmt.Errorf("dossier not found: %s", id)
}
e := entries[0]
d := &Dossier{DossierID: e.DossierID, Name: e.Summary, Email: e.SearchKey}
if e.Data != "" {
var data struct {
DOB string `json:"dob"`
Sex int `json:"sex"`
Lang string `json:"lang"`
}
if json.Unmarshal([]byte(e.Data), &data) == nil {
d.DateOfBirth = data.DOB
d.Sex = data.Sex
if data.Lang != "" {
d.Preferences.Language = data.Lang
}
}
}
return d, nil
}
func DossierGetFirst(ctx *AccessContext) (*Dossier, error) {
log.Printf("[STUB] DossierGetFirst")
return &Dossier{}, nil
}
func DossierGetByEmail(ctx *AccessContext, email string) (*Dossier, error) {
log.Printf("[STUB] DossierGetByEmail(email=%s)", email)
return nil, fmt.Errorf("stub: not implemented")
}
func DossierGetBySessionToken(token string) *Dossier {
log.Printf("[STUB] DossierGetBySessionToken")
return nil
}
func DossierWrite(ctx *AccessContext, dossiers ...*Dossier) error {
log.Printf("[STUB] DossierWrite(n=%d)", len(dossiers))
return nil
}
func DossierList(ctx *AccessContext, f *DossierFilter) ([]*Dossier, error) {
log.Printf("[STUB] DossierList")
return nil, nil
}
func DossierQuery(accessorID string) ([]*DossierQueryRow, error) {
// Get all accessible dossier profiles via RBAC
dossierEntries, err := EntryRead(accessorID, "", &Filter{Category: 0})
if err != nil {
return nil, err
}
var rows []*DossierQueryRow
for _, de := range dossierEntries {
d := Dossier{DossierID: de.DossierID, Name: de.Summary, Email: de.SearchKey}
if de.Data != "" {
var data struct {
DOB string `json:"dob"`
Sex int `json:"sex"`
Lang string `json:"lang"`
}
if json.Unmarshal([]byte(de.Data), &data) == nil {
d.DateOfBirth = data.DOB
d.Sex = data.Sex
if data.Lang != "" {
d.Preferences.Language = data.Lang
}
}
}
// Count entries by category for this dossier
allEntries, err := EntryRead(accessorID, de.DossierID, &Filter{Category: -1})
if err != nil {
continue
}
catCounts := map[int]int{}
for _, e := range allEntries {
if e.Category > 0 {
catCounts[e.Category]++
}
}
if len(catCounts) == 0 {
// Still include dossier even with no entries
rows = append(rows, &DossierQueryRow{Dossier: d})
} else {
for cat, count := range catCounts {
rows = append(rows, &DossierQueryRow{Dossier: d, Category: cat, EntryCount: count})
}
}
}
return rows, nil
}
func DossierSetAuthCode(dossierID string, code int, expiresAt int64) error {
log.Printf("[STUB] DossierSetAuthCode(dossier=%s)", dossierID)
return nil
}
func DossierClearAuthCode(dossierID string) error {
log.Printf("[STUB] DossierClearAuthCode(dossier=%s)", dossierID)
return nil
}
func DossierSetSessionToken(dossierID string, token string) error {
log.Printf("[STUB] DossierSetSessionToken(dossier=%s)", dossierID)
return nil
}
// --- Access stubs ---
func AccessGet(accessorID, targetID string) (*Access, error) {
log.Printf("[STUB] AccessGet(accessor=%s, target=%s)", accessorID, targetID)
return nil, nil
}
func AccessWrite(records ...*Access) error {
log.Printf("[STUB] AccessWrite(n=%d)", len(records))
return nil
}
func AccessRemove(accessorID, targetID string) error {
log.Printf("[STUB] AccessRemove(accessor=%s, target=%s)", accessorID, targetID)
return nil
}
func AccessList(f *AccessFilter) ([]*Access, error) {
if f == nil {
return nil, nil
}
var grants []*Access
if f.AccessorID != "" {
return grants, dbQuery(
"SELECT AccessID, DossierID, GranteeID, EntryID, Relation, Ops, CreatedAt FROM access WHERE GranteeID = ?",
[]any{f.AccessorID},
&grants,
)
}
if f.TargetID != "" {
return grants, dbQuery(
"SELECT AccessID, DossierID, GranteeID, EntryID, Relation, Ops, CreatedAt FROM access WHERE DossierID = ?",
[]any{f.TargetID},
&grants,
)
}
return nil, nil
}
func AccessListByAccessor(granteeID string) ([]*Access, error) {
log.Printf("[STUB] AccessListByAccessor(grantee=%s)", granteeID)
return nil, nil
}
func AccessListByTargetWithNames(targetID string) ([]map[string]interface{}, error) {
log.Printf("[STUB] AccessListByTargetWithNames(target=%s)", targetID)
return nil, nil
}
func AccessUpdateTimestamp(granteeID, dossierID string) error {
log.Printf("[STUB] AccessUpdateTimestamp(grantee=%s, dossier=%s)", granteeID, dossierID)
return nil
}
func AccessGrantRole(dossierID, granteeID, role string) error {
log.Printf("[STUB] AccessGrantRole(dossier=%s, grantee=%s, role=%s)", dossierID, granteeID, role)
return nil
}
// --- Audit stubs ---
func auditWrite(a *AuditEntry) {
if a.AuditID == "" {
a.AuditID = NewID()
}
if a.Timestamp == 0 {
a.Timestamp = nowUnix()
}
db.Exec(`INSERT INTO audit (AuditID, Actor1ID, Actor2ID, TargetID, Action, Details, RelationID, Timestamp)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
a.AuditID, a.Actor1ID, a.Actor2ID, a.TargetID,
Pack([]byte(a.Action)), Pack([]byte(a.Details)),
a.RelationID, a.Timestamp,
)
}
func AuditAdd(a *AuditEntry) error {
auditWrite(a)
return nil
}
func AuditLog(actor1ID string, action string, targetID string, details string) {
auditWrite(&AuditEntry{Actor1ID: actor1ID, Action: action, TargetID: targetID, Details: details})
}
func AuditLogFull(actor1ID, actor2ID, targetID string, action, details string, relationID int) {
auditWrite(&AuditEntry{Actor1ID: actor1ID, Actor2ID: actor2ID, TargetID: targetID, Action: action, Details: details, RelationID: relationID})
}
func AuditQueryByActor(actor1ID string, from, to int64) ([]*AuditEntry, error) {
log.Printf("[STUB] AuditQueryByActor(actor=%s)", actor1ID)
return nil, nil
}
func AuditQueryByTarget(targetID string, from, to int64) ([]*AuditEntry, error) {
log.Printf("[STUB] AuditQueryByTarget(target=%s)", targetID)
return nil, nil
}
// --- Object stubs ---
func ObjectWrite(ctx *AccessContext, dossierID, entryID string, data []byte) error {
log.Printf("[STUB] ObjectWrite(dossier=%s, entry=%s, size=%d)", dossierID, entryID, len(data))
path := ObjectPath(dossierID, entryID)
if err := os.MkdirAll(path[:len(path)-len(entryID)-1], 0750); err != nil {
return err
}
return os.WriteFile(path, Pack(data), 0640)
}
func ObjectRead(ctx *AccessContext, dossierID, entryID string) ([]byte, error) {
log.Printf("[STUB] ObjectRead(dossier=%s, entry=%s)", dossierID, entryID)
packed, err := os.ReadFile(ObjectPath(dossierID, entryID))
if err != nil {
return nil, err
}
return Unpack(packed), nil
}
func ObjectRemoveByDossier(ctx *AccessContext, dossierID string) error {
log.Printf("[STUB] ObjectRemoveByDossier(dossier=%s)", dossierID)
return os.RemoveAll(ObjectPath(dossierID, "")[:len(ObjectDir)+1+len(dossierID)])
}
// --- Lab stubs ---
func LabEntryListForIndex() ([]*Entry, error) {
log.Printf("[STUB] LabEntryListForIndex")
return nil, nil
}
func LabTestSave(t *LabTest) error {
log.Printf("[STUB] LabTestSave")
return nil
}
func LabRefSaveBatch(refs []LabReference) error {
log.Printf("[STUB] LabRefSaveBatch(n=%d)", len(refs))
return nil
}
func RefDelete(table, col, id string) error {
log.Printf("[STUB] RefDelete(table=%s, col=%s, id=%s)", table, col, id)
return nil
}
// --- Genome types and stubs ---
type GenomeMatch struct {
RSID string `json:"rsid"`
Genotype string `json:"genotype"`
Gene string `json:"gene,omitempty"`
Magnitude *float64 `json:"magnitude,omitempty"`
Repute string `json:"repute,omitempty"`
Summary string `json:"summary,omitempty"`
Categories []string `json:"categories,omitempty"`
}
type GenomeQueryResult struct {
Matches []GenomeMatch `json:"matches"`
Returned int `json:"returned"`
Total int `json:"total"`
}
type GenomeQueryOpts struct {
Category string
Search string
Gene string
RSIDs []string
MinMagnitude float64
Repute string
IncludeHidden bool
Sort string
Offset int
Limit int
AccessorID string
}
type ImageOpts struct {
WC, WW float64
Zoom float64
PanX, PanY float64
}
func GenomeQuery(ctx *AccessContext, dossierID string, opts GenomeQueryOpts) (*GenomeQueryResult, error) {
log.Printf("[STUB] GenomeQuery(dossier=%s)", dossierID)
return &GenomeQueryResult{}, nil
}
func ImageGet(ctx *AccessContext, id string, opts *ImageOpts) ([]byte, error) {
log.Printf("[STUB] ImageGet(id=%s)", id)
return ObjectRead(ctx, "", id)
}
func EntryCategoryCounts(ctx *AccessContext, dossierID string) (map[string]int, error) {
log.Printf("[STUB] EntryCategoryCounts(dossier=%s)", dossierID)
return map[string]int{}, nil
}
func EntryQueryByDate(dossierID string, from, to int64) ([]*Entry, error) {
return EntryRead("", dossierID, &Filter{Category: -1, FromDate: from, ToDate: to})
}
// --- Audit types and stubs ---
type AuditFilter struct {
ActorID string
TargetID string
Action string
FromDate int64
ToDate int64
Limit int
}
func AuditList(f *AuditFilter) ([]*AuditEntry, error) {
if f == nil {
return nil, nil
}
q := "SELECT AuditID, Actor1ID, Actor2ID, TargetID, Action, Details, RelationID, Timestamp FROM audit WHERE 1=1"
var args []any
if f.TargetID != "" {
q += " AND TargetID = ?"
args = append(args, f.TargetID)
}
if f.ActorID != "" {
q += " AND Actor1ID = ?"
args = append(args, f.ActorID)
}
if f.FromDate > 0 {
q += " AND Timestamp >= ?"
args = append(args, f.FromDate)
}
if f.ToDate > 0 {
q += " AND Timestamp < ?"
args = append(args, f.ToDate)
}
q += " ORDER BY Timestamp DESC"
if f.Limit > 0 {
q += fmt.Sprintf(" LIMIT %d", f.Limit)
}
var entries []*AuditEntry
err := dbQuery(q, args, &entries)
return entries, err
}
// --- Tracker types and stubs ---
type TrackerFilter struct {
DossierID string
Category string
Type string
ActiveOnly bool
Limit int
}
func TrackerList(f *TrackerFilter) ([]*Tracker, error) {
log.Printf("[STUB] TrackerList")
return nil, nil
}
// --- Misc stubs ---
func OpenReadOnly(path string) (*sql.DB, error) {
log.Printf("[STUB] OpenReadOnly(path=%s)", path)
return sql.Open("sqlite3", path+"?mode=ro")
}
func TrackerDistinctTypes(dossierID string) (map[string][]string, error) {
log.Printf("[STUB] TrackerDistinctTypes(dossier=%s)", dossierID)
return nil, nil
}
func MigrateCategory() error {
log.Printf("[STUB] MigrateCategory")
return nil
}
func MigrateDOB() error {
log.Printf("[STUB] MigrateDOB")
return nil
}