// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com) // All rights reserved. // RDD (Replaceable Database Driver) interface definitions for Five. // // Design: Harbour's 101-method RDDFUNCS vtable → Go interface composition. // Each interface is small and focused (Go philosophy). // Drivers implement only what they need; BaseArea provides defaults. // // Inheritance via Go embedding: // BaseArea (WAAREA) → DBFArea → NTXArea / CDXArea // // Reference: // /mnt/d/harbour-core/include/hbapirdd.h (lines 640-816) // docs/rdd-architecture-spec.md package hbrdd import ( "five/hbrt" "fmt" "strings" "sync" ) // --- Driver registry --- var ( driversMu sync.RWMutex drivers = map[string]Driver{} ) // RegisterDriver registers an RDD driver by name. func RegisterDriver(d Driver) { driversMu.Lock() drivers[strings.ToUpper(d.Name())] = d driversMu.Unlock() } // GetDriver returns a registered driver by name. func GetDriver(name string) (Driver, error) { driversMu.RLock() d, ok := drivers[strings.ToUpper(name)] driversMu.RUnlock() if !ok { return nil, fmt.Errorf("unknown RDD driver: %s", name) } return d, nil } // --- Core interfaces --- // Driver creates and opens work areas. // Harbour: RDD node with RDDFUNCS table. type Driver interface { Name() string Open(params OpenParams) (Area, error) Create(params CreateParams) (Area, error) } // OpenParams for opening an existing table. type OpenParams struct { Path string // file path (without extension) Alias string // workarea alias Shared bool // shared access mode ReadOnly bool // read-only mode CodePage string // code page name } // CreateParams for creating a new table. type CreateParams struct { Path string Alias string Fields []FieldInfo CodePage string } // FieldInfo describes a database field. // Harbour: DBFFIELD (32 bytes in file, this is the runtime representation) type FieldInfo struct { Name string // up to 10 chars (Harbour limit) Type byte // 'C', 'N', 'L', 'D', 'M', 'I', 'B', '@', '+', '=', '^', 'Y', etc. Len int // field length Dec int // decimal places Flags byte // 0x01=system, 0x02=nullable, 0x04=binary } // --- Area interface (WAAREA + DBF core) --- // Area is the primary interface for accessing a database table. // Harbour: AREAP with SELF_* macro dispatch. type Area interface { // Identity Driver() Driver Alias() string SetAlias(string) // Lifecycle Close() error Flush() error // Movement — Harbour: hb_waBof, hb_waEof, hb_waFound, hb_waGoTo, etc. BOF() bool EOF() bool Found() bool GoTo(recNo uint32) error GoTop() error GoBottom() error Skip(count int64) error // Record info RecNo() uint32 RecCount() (uint32, error) Deleted() bool // Field access — Harbour: SELF_FIELDCOUNT, SELF_GETVALUE, SELF_PUTVALUE FieldCount() int GetFieldInfo(index int) FieldInfo GetValue(fieldIndex int) (hbrt.Value, error) PutValue(fieldIndex int, val hbrt.Value) error // Record operations — Harbour: SELF_APPEND, SELF_DELETE, SELF_RECALL Append() error Delete() error Recall() error // Bulk operations Pack() error Zap() error // State — Harbour: hb_waSetFound, locate support SetFound(b bool) SetLocate(expr string, block func(*hbrt.Thread) bool) LocateBlock() func(*hbrt.Thread) bool // Filter SetFilter(expr string, block func(*hbrt.Thread) bool) error ClearFilter() error HasFilter() bool } // --- Optional interfaces (drivers implement as needed) --- // Indexer provides index management and key-based seeking. // Harbour: order* methods in RDDFUNCS (9 methods). // Only DBFNTX and DBFCDX implement this. type Indexer interface { // Order management OrderCreate(params OrderCreateParams) error OrderListAdd(path string) error OrderListClear() error OrderListFocus(tagName string) error OrderListRebuild() error OrderDestroy(tagName string) error OrderInfo(ordNo int) (*OrderInfo, error) // Key-based seeking — Harbour: SELF_SEEK Seek(key hbrt.Value, softSeek bool, findLast bool) (bool, error) } // OrderCreateParams for INDEX ON. type OrderCreateParams struct { TagName string // index tag name KeyExpr string // key expression (e.g., "UPPER(lastname+firstname)") ForExpr string // FOR condition (e.g., "active = .T.") FilePath string // index file path Unique bool Descending bool // KeyFunc is an optional compiled key evaluator. When non-nil, the // indexer calls it directly instead of going through MacroEval on the // KeyExpr string. gengo emits this as an inline Go closure that // mirrors the AST of the key expression — zero string parsing at // runtime, symbol lookups hoisted out of the loop. // // Contract: caller must position the workarea (GoTo) before calling. // Returns the key value for the current record. KeyFunc func() hbrt.Value // ForFunc is the compiled counterpart of KeyFunc for the optional // FOR expression. When non-nil the indexer calls it instead of // parsing ForExpr as a string and running it through the macro // evaluator — eliminates strings.Index/ToUpper/splitArgs per record // in filtered-index builds and rebuilds. Returns true when the // current record should be included. // // Contract: caller must position the workarea (GoTo) before calling. ForFunc func() bool } // OrderInfo holds information about an index order. type OrderInfo struct { Name string KeyExpr string ForExpr string Unique bool Descending bool KeyCount uint32 Custom bool } // Locker provides record and file locking. // Harbour: SELF_LOCK, SELF_UNLOCK, SELF_RAWLOCK type Locker interface { LockRecord(recNo uint32) (bool, error) UnlockRecord(recNo uint32) error LockFile() (bool, error) UnlockFile() error IsLocked(recNo uint32) bool } // Relater provides SET RELATION support. // Harbour: SELF_SETREL, SELF_CLEARREL, SELF_FORCEREL type Relater interface { SetRelation(child Area, keyExpr func(*hbrt.Thread) hbrt.Value, scoped bool) error ClearRelation() error ForceRel() error SyncChildren() error } // MemoHandler provides memo field read/write. // Harbour: SELF_OPENMEMFILE, SELF_CLOSEMEMFILE, SELF_GETVALUEFILE, SELF_PUTVALUEFILE type MemoHandler interface { OpenMemo(path string) error CloseMemo() error ReadMemo(blockNo uint32) ([]byte, error) WriteMemo(data []byte) (uint32, error) } // Scoper provides SET SCOPE support for index-based range queries. type Scoper interface { SetScope(top, bottom hbrt.Value) error ClearScope() error }