Documentation
¶
Overview ¶
Package db provides SQLite access using modernc.org/sqlite (no CGO). Goals: performance, concurrency and predictability with minimal dependencies. - Separate pools: one writer (RW) and many readers (RO). - WAL + synchronous=NORMAL + busy_timeout. - Short transactions; no per-operation context timeouts in this layer. - WAL checkpoint on Close() for hygiene.
Index ¶
- Variables
- func IsValidUsername(username string) error
- func RunMigration() error
- func RunMigrationOn(s *SQLite) error
- func SetAppMigrationsFS(fsys fs.FS)
- type DescendantItem
- type EAVAttribute
- type EAVEntityType
- type EAVRecord
- type EAVRecordValues
- func ExecutePosLoadScript(entityType *EAVEntityType, values EAVRecordValues) (modifiedValues EAVRecordValues, userError string, err error)
- func ExecutePreSaveScript(entityType *EAVEntityType, values EAVRecordValues) (modifiedValues EAVRecordValues, userError string, err error)
- func ExecutePreSaveScriptWithSetup(entityType *EAVEntityType, values EAVRecordValues, setup ScriptEngineSetupFunc) (modifiedValues EAVRecordValues, userError string, err error)
- type EAVValue
- type File
- type Form
- type FormElement
- type Menu
- type MenuItem
- type MenuItemNode
- type Row
- type SQLite
- func (s *SQLite) BeginTransaction() (*Transaction, error)
- func (s *SQLite) CheckEAVValueUnique(attributeID int64, primitiveKind string, value interface{}, ...) (bool, error)
- func (s *SQLite) CheckpointWAL() error
- func (s *SQLite) Close()
- func (s *SQLite) ConsumeMagicLinkToken(token string) (string, error)
- func (s *SQLite) CountFilesByUserID(userID int64) (int, error)
- func (s *SQLite) CountUsersWithUsernamePrefix(prefix string) (int, error)
- func (s *SQLite) CreateEAVAttribute(entityTypeID int64, machineName, label, helpText, primitiveKind string, ...) (*EAVAttribute, error)
- func (s *SQLite) CreateEAVEntityType(name, machineName, description, preSave, posLoad string) (*EAVEntityType, error)
- func (s *SQLite) CreateEAVRecord(entityTypeID int64) (*EAVRecord, error)
- func (s *SQLite) CreateForm(machineName, label, description string, eavEntityTypeID *int64) (*Form, error)
- func (s *SQLite) CreateFormElement(formID int64, parentID *int64, ...) (*FormElement, error)
- func (s *SQLite) CreateMenu(machineName, label, description string) (*Menu, error)
- func (s *SQLite) CreateMenuItem(menuID int64, parentID *int64, ...) (*MenuItem, error)
- func (s *SQLite) CreateMinimalUserForOAuthFallback(email string, avatarURL string) (*User, error)
- func (s *SQLite) DeleteEAVValue(recordID, attributeID int64) error
- func (s *SQLite) DeleteFormElement(id int64) error
- func (s *SQLite) DeleteMenuItem(id int64) error
- func (s *SQLite) Exec(query string, args ...any) error
- func (s *SQLite) GenerateUniqueUsername(baseUsername string) (string, error)
- func (s *SQLite) GetEAVAttributeByID(id int64) (*EAVAttribute, error)
- func (s *SQLite) GetEAVAttributeByRefID(refID string) (*EAVAttribute, error)
- func (s *SQLite) GetEAVEntityTypeByID(id int64) (*EAVEntityType, error)
- func (s *SQLite) GetEAVEntityTypeByMachineName(machineName string) (*EAVEntityType, error)
- func (s *SQLite) GetEAVEntityTypeByRefID(refID string) (*EAVEntityType, error)
- func (s *SQLite) GetEAVRecordByID(id int64) (*EAVRecord, error)
- func (s *SQLite) GetEAVRecordByRefID(refID string) (*EAVRecord, error)
- func (s *SQLite) GetEAVValuesByRecordID(recordID int64) ([]EAVValue, error)
- func (s *SQLite) GetFileByUserIDAndFilename(userID int64, filename string) (*File, error)
- func (s *SQLite) GetFileByUserReferenceIDAndFilename(userRefID string, filename string) (*File, error)
- func (s *SQLite) GetFormByMachineName(machineName string) (*Form, error)
- func (s *SQLite) GetFormByRefID(refID string) (*Form, error)
- func (s *SQLite) GetFormElementByRefID(refID string) (*FormElement, error)
- func (s *SQLite) GetMenuByID(id int64) (*Menu, error)
- func (s *SQLite) GetMenuByMachineName(machineName string) (*Menu, error)
- func (s *SQLite) GetMenuByRefID(refID string) (*Menu, error)
- func (s *SQLite) GetMenuItemByRefID(refID string) (*MenuItem, error)
- func (s *SQLite) GetUserByEmail(email string) (*User, error)
- func (s *SQLite) GetUserByID(userID int64) (*User, error)
- func (s *SQLite) GetUserByOAuthProviderID(provider string, providerID string) (int64, error)
- func (s *SQLite) GetUserOrCreateByEmail(email string) (*User, error)
- func (s *SQLite) GetUserOrCreateByOAuth(provider string, providerID string, email string, username string, ...) (*User, error)
- func (s *SQLite) ListEAVAttributesByEntityTypeID(entityTypeID int64) ([]EAVAttribute, error)
- func (s *SQLite) ListEAVEntityTypes() ([]EAVEntityType, error)
- func (s *SQLite) ListEAVRecordsByEntityTypeID(entityTypeID int64, limit, offset int) ([]EAVRecord, int, error)
- func (s *SQLite) ListFilesByUserID(userID int64, offset int, limit int) ([]*File, error)
- func (s *SQLite) ListFilesByUserIDSorted(userID int64, sort string, offset int, limit int) ([]*File, error)
- func (s *SQLite) ListFormElements(formID int64) ([]FormElement, error)
- func (s *SQLite) ListForms() ([]Form, error)
- func (s *SQLite) ListGroupElements(formID int64) ([]FormElement, error)
- func (s *SQLite) ListMenuItems(menuID int64) ([]MenuItem, error)
- func (s *SQLite) ListMenus() ([]Menu, error)
- func (s *SQLite) ListRelationalTables() ([]TableInfo, error)
- func (s *SQLite) ListSubmenuItems(menuID int64) ([]MenuItem, error)
- func (s *SQLite) MergeOAuthProfileData(userID int64, oauthUsername string, oauthAvatarURL string) (*User, error)
- func (s *SQLite) MoveElementDown(elementID int64) error
- func (s *SQLite) MoveElementUp(elementID int64) error
- func (s *SQLite) MoveMenuItemDown(itemID int64) error
- func (s *SQLite) MoveMenuItemUp(itemID int64) error
- func (s *SQLite) PurgeExpiredMagicLinkTokens() error
- func (s *SQLite) Query(query string, args ...any) (*sql.Rows, error)
- func (s *SQLite) QueryRW(query string, args ...any) (*sql.Rows, error)
- func (s *SQLite) QueryRow(query string, args ...any) *Row
- func (s *SQLite) QueryRowRW(query string, args ...any) *Row
- func (s *SQLite) RO() *sql.DB
- func (s *SQLite) RW() *sql.DB
- func (s *SQLite) SaveFileMetadata(f *File) (*File, error)
- func (s *SQLite) SearchFilesByUserIDFTS(userID int64, query string, sort string, offset int, limit int) ([]*File, error)
- func (s *SQLite) SoftDeleteEAVAttribute(id int64) error
- func (s *SQLite) SoftDeleteEAVEntityType(id int64) error
- func (s *SQLite) SoftDeleteEAVRecord(id int64) error
- func (s *SQLite) SoftDeleteFileByUserAndFilename(userID int64, filename string) error
- func (s *SQLite) SoftDeleteForm(id int64) error
- func (s *SQLite) SoftDeleteMenu(id int64) error
- func (s *SQLite) StoreMagicLinkToken(token string, email string, expiresAt time.Time) error
- func (s *SQLite) UpdateEAVAttribute(id int64, machineName, label, helpText, primitiveKind string, ...) (*EAVAttribute, error)
- func (s *SQLite) UpdateEAVEntityType(id int64, name, description, preSave, posLoad string) (*EAVEntityType, error)
- func (s *SQLite) UpdateEAVRecordRev(id int64, currentRev int) (int, error)
- func (s *SQLite) UpdateEAVRecordStatus(id int64, currentRev int, status string) error
- func (s *SQLite) UpdateFileMetadataByUserAndFilename(userID int64, filename string, description string, tag string) error
- func (s *SQLite) UpdateForm(id int64, machineName, label, description string, eavEntityTypeID *int64, ...) error
- func (s *SQLite) UpdateFormElement(id int64, parentID *int64, machineName, elementKind, label, helpText string, ...) error
- func (s *SQLite) UpdateMenu(id int64, machineName, label, description string) error
- func (s *SQLite) UpdateMenuItem(id int64, parentID *int64, ...) error
- func (s *SQLite) UpdateUserProfile(userID int64, username string, avatarURL string) (*User, error)
- func (s *SQLite) UpsertEAVValue(recordID, attributeID int64, vBool *bool, vInt *int64, vReal *float64, ...) error
- func (s *SQLite) UpsertEAVValueWithRev(recordID, attributeID int64, currentRev int, vBool *bool, vInt *int64, ...) (int, error)
- type ScriptEngineSetupFunc
- type TableInfo
- type Transaction
- type User
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNotFound is returned when an entity, attribute, record, or value is not found. ErrNotFound = errors.New("eav: not found") // ErrConflict is returned when an optimistic lock fails (rev mismatch). ErrConflict = errors.New("eav: conflict") // ErrInvalidValue is returned when a value violates type or column rules. ErrInvalidValue = errors.New("eav: invalid value") )
Sentinel errors for EAV operations.
Functions ¶
func IsValidUsername ¶
IsValidUsername validates a username to prevent abuse.
func RunMigration ¶
func RunMigration() error
RunMigration applies all pending migrations in order:
- Engine migrations (0001-0999) from devengine/db
- Application migrations (1000+) from the configured AppFS
Migrations are sorted lexicographically by ID, ensuring engine migrations run before application migrations due to the numbering convention. RunMigration applies all pending migrations using the global Storage.
func RunMigrationOn ¶
RunMigrationOn applies all pending migrations on the provided SQLite instance.
func SetAppMigrationsFS ¶
SetAppMigrationsFS configures an optional fs.FS containing application migrations. Files must follow the pattern: NNNN_name.up.sql where NNNN is a 4-digit prefix (e.g., 1000_characters.up.sql).
Migration ordering:
- Engine migrations (devengine): 0001-0999
- Application migrations: 1000-9999
Call this function before RunMigration() in your application's main.go:
db.SetAppMigrationsFS(migrations.FS) err := db.RunMigration()
Types ¶
type DescendantItem ¶ added in v0.0.6
DescendantItem represents a menu item with its depth in the hierarchy.
func CollectMenuDescendants ¶ added in v0.0.6
func CollectMenuDescendants(items []MenuItem, parentID int64) []DescendantItem
CollectMenuDescendants recursively collects all descendants of a given parent ID. It includes cycle detection: if an item ID is visited more than once, its children are not processed to prevent infinite recursion.
type EAVAttribute ¶
type EAVAttribute struct {
ID int64 `json:"id"`
ReferenceID string `json:"reference_id"`
EntityTypeID int64 `json:"entity_type_id"`
MachineName string `json:"machine_name"`
Label string `json:"label"`
HelpText string `json:"help_text"`
PrimitiveKind string `json:"primitive_kind"` // BOOL, INT, REAL, TEXT, DATETIME
IsRequired bool `json:"is_required"`
IsUnique bool `json:"is_unique"`
IsIndexed bool `json:"is_indexed"`
MaxLength *int `json:"max_length,omitempty"` // For TEXT fields, NULL for other types
IsComputed bool `json:"is_computed"`
ComputedExpr string `json:"computed_expr"` // Filo expression
// Default values for new records (user-defined)
DefaultVBool *bool `json:"default_v_bool,omitempty"`
DefaultVInt *int64 `json:"default_v_int,omitempty"`
DefaultVReal *float64 `json:"default_v_real,omitempty"`
DefaultVText *string `json:"default_v_text,omitempty"`
DefaultVDatetime *string `json:"default_v_datetime,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt time.Time `json:"deleted_at,omitempty"` // zero value means not deleted
}
EAVAttribute represents a typed field (column) belonging to an entity type.
type EAVEntityType ¶
type EAVEntityType struct {
ID int64 `json:"id"`
ReferenceID string `json:"reference_id"`
MachineName string `json:"machine_name"`
Name string `json:"name"`
Description string `json:"description"`
PreSave string `json:"pre_save"` // Filo script executed before saving records
PosLoad string `json:"pos_load"` // Filo script executed after loading records
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt time.Time `json:"deleted_at,omitempty"` // zero value means not deleted
}
EAVEntityType represents a logical schema (similar to a table in relational databases). This is the new EAV core implementation without workspace or forms concepts.
type EAVRecord ¶
type EAVRecord struct {
ID int64 `json:"id"`
ReferenceID string `json:"reference_id"`
EntityTypeID int64 `json:"entity_type_id"`
Status string `json:"status"` // 'draft' or 'active'
Rev int `json:"rev"` // optimistic lock counter, starts at 1
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt time.Time `json:"deleted_at,omitempty"` // zero value means not deleted
}
EAVRecord represents an instance (row) of an entity type.
type EAVRecordValues ¶ added in v0.0.2
type EAVRecordValues map[string]interface{}
EAVRecordValues holds typed values keyed by attribute machine_name. Values are typed as interface{} and must be one of: bool, int64, float64, string, nil.
func ExecutePosLoadScript ¶ added in v0.0.3
func ExecutePosLoadScript( entityType *EAVEntityType, values EAVRecordValues, ) (modifiedValues EAVRecordValues, userError string, err error)
ExecutePosLoadScript runs the entity type's pos_load Filo script. This is called after loading record data and applying defaults, but before display. It is the last transformation step before the user sees the data.
Parameters:
- entityType: The entity type containing the pos_load script
- values: Current field values keyed by attribute machine_name (after defaults applied)
Returns:
- modifiedValues: Values after script execution (may be modified by script)
- userError: User-facing error message if script set "error" variable
- err: System error if script execution failed
func ExecutePreSaveScript ¶ added in v0.0.3
func ExecutePreSaveScript( entityType *EAVEntityType, values EAVRecordValues, ) (modifiedValues EAVRecordValues, userError string, err error)
ExecutePreSaveScript runs the entity type's pre_save Filo script. This is a core EAV function that must be called before any record is saved, regardless of the caller (sysop tools, forms, APIs, etc.).
Parameters:
- entityType: The entity type containing the pre_save script
- values: Current field values keyed by attribute machine_name
Returns:
- modifiedValues: Values after script execution (may be modified by script)
- userError: User-facing error message if script set "error" variable
- err: System error if script execution failed
func ExecutePreSaveScriptWithSetup ¶ added in v0.0.3
func ExecutePreSaveScriptWithSetup( entityType *EAVEntityType, values EAVRecordValues, setup ScriptEngineSetupFunc, ) (modifiedValues EAVRecordValues, userError string, err error)
ExecutePreSaveScriptWithSetup runs the pre_save script with a custom engine setup. This allows the caller to inject custom builtins (like DB access with a transaction).
Parameters:
- entityType: The entity type containing the pre_save script
- values: Current field values keyed by attribute machine_name
- setup: Custom function to configure the Filo engine (register builtins)
Returns:
- modifiedValues: Values after script execution (may be modified by script)
- userError: User-facing error message if script set "error" variable
- err: System error if script execution failed
type EAVValue ¶
type EAVValue struct {
RecordID int64 `json:"record_id"`
AttributeID int64 `json:"attribute_id"`
VBool *bool `json:"v_bool,omitempty"`
VInt *int64 `json:"v_int,omitempty"`
VReal *float64 `json:"v_real,omitempty"`
VText *string `json:"v_text,omitempty"`
VDatetime *string `json:"v_datetime,omitempty"` // ISO-8601 UTC
UpdatedAt time.Time `json:"updated_at"`
}
EAVValue represents a typed cell value for a (record, attribute) pair. Exactly one of the v_* fields should be set based on the attribute's primitive_kind.
type Form ¶ added in v0.0.4
type Form struct {
ID int64
ReferenceID string
MachineName string
Label string
Description string
EAVEntityTypeID *int64 // NULL if not bound to EAV
HideSubmitButton bool // When true, form does not display submit button
HideCancelButton bool // When true, form does not display cancel button
HideTitle bool // When true, form does not display title header
ShowSystemInfo bool // When true, displays record ID and status in runtime
MenuID *int64 // Associated menu for navbar display when form is active
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}
Form represents a form definition.
type FormElement ¶ added in v0.0.4
type FormElement struct {
ID int64
ReferenceID string
FormID int64
ParentID *int64 // NULL for root-level elements
MachineName string
ElementKind string // 'group', 'field', 'divider', 'button', etc.
Label string
HelpText string
ZOrder int
ColSpan int // Bootstrap column span (1-12, default 12)
Alignment string // Horizontal alignment: 'left', 'center', 'right'
UIKind string // Plugin ID
UIMetaJSON string
EAVAttributeID *int64 // NULL for UI-only elements
IsUIOnly bool
IsReadonly bool
HideLabel bool
HideHelpText bool
ValidateExpr string
ComputedExpr string
// Button-specific properties (only used when ElementKind = 'button')
ButtonFiloCode string // Server-side Filo script (never sent to client)
ButtonRunSave bool // Execute save action in same transaction
ButtonJSCode string // Client-side JavaScript
ButtonStyle string // Bootstrap button style (primary, secondary, etc.)
ButtonConfirmMsg string // Confirmation dialog text
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}
FormElement represents a UI element within a form (field, group, divider, etc.).
func SortElementsHierarchically ¶ added in v0.0.4
func SortElementsHierarchically(elements []FormElement) []FormElement
SortElementsHierarchically sorts elements so that children appear immediately after their parent, respecting z_order within each level. This creates a flat list suitable for display in a table while preserving hierarchy.
type Menu ¶ added in v0.0.6
type Menu struct {
ID int64
ReferenceID string
MachineName string
Label string
Description string
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}
Menu represents a menu definition.
type MenuItem ¶ added in v0.0.6
type MenuItem struct {
ID int64
ReferenceID string
MenuID int64
ParentID *int64 // NULL for root-level items
MachineName string
Label string
Icon string // Optional Bootstrap icon class
ItemType string // 'link', 'separator', 'submenu'
URL string // Optional, for links
JSCode string // JavaScript code to execute client-side
FiloCode string // Filo code to execute server-side
ZOrder int
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}
MenuItem represents a menu item.
func GetDirectChildren ¶ added in v0.0.6
GetDirectChildren returns only the direct children of a parent ID from the items slice.
func SortMenuItemsHierarchically ¶ added in v0.0.6
SortMenuItemsHierarchically sorts items so that children appear immediately after their parent, respecting z_order within each level.
type MenuItemNode ¶ added in v0.0.6
type MenuItemNode struct {
MenuItem
Children []MenuItemNode
MenuMachineName string // Menu machine name for action URLs
}
MenuItemNode represents a menu item with its children as a tree structure.
func BuildMenuItemTree ¶ added in v0.0.6
func BuildMenuItemTree(items []MenuItem) []MenuItemNode
BuildMenuItemTree builds a tree structure for menu items. It returns only the root-level items (items with no parent), each with their children populated recursively.
func BuildMenuItemTreeWithName ¶ added in v0.0.6
func BuildMenuItemTreeWithName(items []MenuItem, menuMachineName string) []MenuItemNode
BuildMenuItemTreeWithName builds a tree structure with the menu machine name propagated to all nodes.
type Row ¶
type Row struct {
// contains filtered or unexported fields
}
Row wraps sql.Row to keep a uniform return type and allow future extension. No context cancellation is used at this layer.
type SQLite ¶
type SQLite struct {
// contains filtered or unexported fields
}
SQLite holds separate read/write pools.
func NewWithPath ¶
NewWithPath creates SQLite pools for a specific file/URI path.
Example ¶
ExampleNewWithPath shows how to open a temporary database, create a table, and read data using the helper methods that apply timeouts automatically.
package main
import (
"fmt"
"os"
"path/filepath"
"github.com/crgimenes/devengine/db"
)
func main() {
tmpDir, err := os.MkdirTemp("", "db-example-")
if err != nil {
panic(err)
}
defer os.RemoveAll(tmpDir)
store, err := db.NewWithPath(filepath.Join(tmpDir, "example.db"))
if err != nil {
panic(err)
}
defer store.Close()
if err := store.Exec(`CREATE TABLE items(name TEXT NOT NULL)`); err != nil {
panic(err)
}
if err := store.Exec(`INSERT INTO items(name) VALUES(?)`, "widget"); err != nil {
panic(err)
}
var name string
if err := store.QueryRow(`SELECT name FROM items`).Scan(&name); err != nil {
panic(err)
}
fmt.Println("name:", name)
}
Output: name: widget
func (*SQLite) BeginTransaction ¶
func (s *SQLite) BeginTransaction() (*Transaction, error)
BeginTransaction starts a write transaction.
IMPORTANT: We intentionally do not propagate context timeouts in this package. Callers should avoid long-lived transactions; SQLite busy_timeout handles transient contention, and application code should keep critical sections short.
func (*SQLite) CheckEAVValueUnique ¶
func (s *SQLite) CheckEAVValueUnique( attributeID int64, primitiveKind string, value interface{}, excludeRecordID int64, ) (bool, error)
CheckEAVValueUnique verifies if a value is unique for a given attribute. Returns true if the value is unique (or NULL), false if a duplicate exists.
Parameters:
- attributeID: The attribute to check
- primitiveKind: Type of the attribute (BOOL, INT, REAL, TEXT, DATETIME)
- value: The value to check (must match primitiveKind type)
- excludeRecordID: Record ID to exclude from check (use 0 for new records)
Rules:
- NULL values are always considered unique (multiple NULLs allowed)
- Only checks against active (non-deleted) records
- Uses read-only pool for optimal concurrency
func (*SQLite) CheckpointWAL ¶
CheckpointWAL triggers a WAL checkpoint with TRUNCATE.
func (*SQLite) Close ¶
func (s *SQLite) Close()
Close closes pools; performs a best-effort WAL checkpoint first.
func (*SQLite) ConsumeMagicLinkToken ¶
ConsumeMagicLinkToken validates and consumes a magic link token, returning the associated email.
func (*SQLite) CountFilesByUserID ¶
CountFilesByUserID returns the total count of non-deleted files for a user.
func (*SQLite) CountUsersWithUsernamePrefix ¶
CountUsersWithUsernamePrefix counts how many users have a username starting with the given prefix (case-insensitive). Used for generating unique usernames when conflicts occur.
func (*SQLite) CreateEAVAttribute ¶
func (s *SQLite) CreateEAVAttribute( entityTypeID int64, machineName, label, helpText, primitiveKind string, isRequired, isUnique, isIndexed bool, maxLength *int, isComputed bool, computedExpr string, defaultVBool *bool, defaultVInt *int64, defaultVReal *float64, defaultVText, defaultVDatetime *string, ) (*EAVAttribute, error)
CreateEAVAttribute creates a new attribute with validation and default values.
func (*SQLite) CreateEAVEntityType ¶
func (s *SQLite) CreateEAVEntityType(name, machineName, description, preSave, posLoad string) (*EAVEntityType, error)
CreateEAVEntityType creates a new entity type with an opaque reference_id.
func (*SQLite) CreateEAVRecord ¶
CreateEAVRecord creates a new record with rev=1 and opaque reference_id.
func (*SQLite) CreateForm ¶ added in v0.0.4
func (s *SQLite) CreateForm(machineName, label, description string, eavEntityTypeID *int64) (*Form, error)
CreateForm creates a new form.
func (*SQLite) CreateFormElement ¶ added in v0.0.4
func (s *SQLite) CreateFormElement( formID int64, parentID *int64, machineName, elementKind, label, helpText string, zOrder, colSpan int, uiKind, uiMetaJSON string, eavAttributeID *int64, isUIOnly, isReadonly bool, ) (*FormElement, error)
CreateFormElement creates a new form element.
func (*SQLite) CreateMenu ¶ added in v0.0.6
CreateMenu creates a new menu.
func (*SQLite) CreateMenuItem ¶ added in v0.0.6
func (s *SQLite) CreateMenuItem( menuID int64, parentID *int64, machineName, label, icon, itemType, url, jsCode, filoCode string, zOrder int, ) (*MenuItem, error)
CreateMenuItem creates a new menu item.
func (*SQLite) CreateMinimalUserForOAuthFallback ¶
func (s *SQLite) CreateMinimalUserForOAuthFallback( email string, avatarURL string, ) (*User, error)
CreateMinimalUserForOAuthFallback creates a minimal user account with email only when OAuth signup fails. This allows the user to complete their profile at /me. Returns error if email is empty or if database operation fails.
func (*SQLite) DeleteEAVValue ¶
DeleteEAVValue removes a value for a (record, attribute) pair.
func (*SQLite) DeleteFormElement ¶ added in v0.0.4
DeleteFormElement permanently deletes a form element.
func (*SQLite) DeleteMenuItem ¶ added in v0.0.6
DeleteMenuItem permanently deletes a menu item.
func (*SQLite) Exec ¶
Exec executes a write statement on the RW pool (outside explicit transactions).
func (*SQLite) GenerateUniqueUsername ¶
GenerateUniqueUsername generates a unique username by appending a number if the base username is taken. If baseUsername is available, returns it unchanged. Otherwise, appends 1, 2, 3, etc. until a unique username is found.
func (*SQLite) GetEAVAttributeByID ¶
func (s *SQLite) GetEAVAttributeByID(id int64) (*EAVAttribute, error)
GetEAVAttributeByID retrieves an attribute by internal ID.
func (*SQLite) GetEAVAttributeByRefID ¶
func (s *SQLite) GetEAVAttributeByRefID(refID string) (*EAVAttribute, error)
GetEAVAttributeByRefID retrieves an attribute by opaque reference_id.
func (*SQLite) GetEAVEntityTypeByID ¶
func (s *SQLite) GetEAVEntityTypeByID(id int64) (*EAVEntityType, error)
GetEAVEntityTypeByID retrieves an entity type by internal ID (for internal use).
func (*SQLite) GetEAVEntityTypeByMachineName ¶
func (s *SQLite) GetEAVEntityTypeByMachineName(machineName string) (*EAVEntityType, error)
GetEAVEntityTypeByMachineName retrieves an entity type by machine_name (for code/routing).
func (*SQLite) GetEAVEntityTypeByRefID ¶
func (s *SQLite) GetEAVEntityTypeByRefID(refID string) (*EAVEntityType, error)
GetEAVEntityTypeByRefID retrieves an entity type by opaque reference_id (for external APIs).
func (*SQLite) GetEAVRecordByID ¶
GetEAVRecordByID retrieves a record by internal ID.
func (*SQLite) GetEAVRecordByRefID ¶
GetEAVRecordByRefID retrieves a record by opaque reference_id.
func (*SQLite) GetEAVValuesByRecordID ¶
GetEAVValuesByRecordID retrieves all values for a record in a single query, excluding values for soft-deleted attributes.
func (*SQLite) GetFileByUserIDAndFilename ¶
GetFileByUserIDAndFilename retrieves a file by user ID and filename.
func (*SQLite) GetFileByUserReferenceIDAndFilename ¶
func (s *SQLite) GetFileByUserReferenceIDAndFilename( userRefID string, filename string, ) (*File, error)
GetFileByUserReferenceIDAndFilename retrieves a file by user reference ID and filename.
func (*SQLite) GetFormByMachineName ¶ added in v0.0.4
GetFormByMachineName retrieves a form by machine_name. Returns nil, nil if not found (soft not-found to allow fallback logic).
func (*SQLite) GetFormByRefID ¶ added in v0.0.4
GetFormByRefID retrieves a form by reference_id.
func (*SQLite) GetFormElementByRefID ¶ added in v0.0.4
func (s *SQLite) GetFormElementByRefID(refID string) (*FormElement, error)
GetFormElementByRefID retrieves a form element by reference_id.
func (*SQLite) GetMenuByID ¶ added in v0.0.6
GetMenuByID retrieves a menu by its ID. Returns nil, nil if not found.
func (*SQLite) GetMenuByMachineName ¶ added in v0.0.6
GetMenuByMachineName retrieves a menu by machine_name. Returns nil, nil if not found (soft not-found to allow fallback logic).
func (*SQLite) GetMenuByRefID ¶ added in v0.0.6
GetMenuByRefID retrieves a menu by reference_id.
func (*SQLite) GetMenuItemByRefID ¶ added in v0.0.6
GetMenuItemByRefID retrieves a menu item by reference_id.
func (*SQLite) GetUserByEmail ¶
GetUserByEmail retrieves a user by their email address. Returns error if user not found.
func (*SQLite) GetUserByID ¶
GetUserByID retrieves a user by their ID.
func (*SQLite) GetUserByOAuthProviderID ¶
GetUserByOAuthProviderID retrieves a user ID by OAuth provider and provider ID.
func (*SQLite) GetUserOrCreateByEmail ¶
GetUserOrCreateByEmail creates or retrieves a user by email.
func (*SQLite) GetUserOrCreateByOAuth ¶
func (s *SQLite) GetUserOrCreateByOAuth( provider string, providerID string, email string, username string, avatarURL string, ) (*User, error)
GetUserOrCreateByOAuth creates or retrieves user via OAuth provider.
func (*SQLite) ListEAVAttributesByEntityTypeID ¶
func (s *SQLite) ListEAVAttributesByEntityTypeID(entityTypeID int64) ([]EAVAttribute, error)
ListEAVAttributesByEntityTypeID returns all active attributes for an entity type, ordered by machine_name for predictable iteration.
func (*SQLite) ListEAVEntityTypes ¶
func (s *SQLite) ListEAVEntityTypes() ([]EAVEntityType, error)
ListEAVEntityTypes returns all active entity types ordered by machine_name.
func (*SQLite) ListEAVRecordsByEntityTypeID ¶
func (s *SQLite) ListEAVRecordsByEntityTypeID(entityTypeID int64, limit, offset int) ([]EAVRecord, int, error)
ListEAVRecordsByEntityTypeID returns paginated records for an entity type, ordered by updated_at DESC, id DESC. Returns records and total count.
func (*SQLite) ListFilesByUserID ¶
ListFilesByUserID returns files for a user with pagination.
func (*SQLite) ListFilesByUserIDSorted ¶
func (s *SQLite) ListFilesByUserIDSorted( userID int64, sort string, offset int, limit int, ) ([]*File, error)
ListFilesByUserIDSorted returns files for a user with explicit sort option. sort supports: "date_desc" (default) and "name_asc".
func (*SQLite) ListFormElements ¶ added in v0.0.4
func (s *SQLite) ListFormElements(formID int64) ([]FormElement, error)
ListFormElements returns all non-deleted elements for a form, ordered by z_order.
func (*SQLite) ListGroupElements ¶ added in v0.0.4
func (s *SQLite) ListGroupElements(formID int64) ([]FormElement, error)
ListGroupElements returns elements that can be parents (groups, accordions, cards, tabs).
func (*SQLite) ListMenuItems ¶ added in v0.0.6
ListMenuItems returns all non-deleted items for a menu, ordered by z_order.
func (*SQLite) ListRelationalTables ¶
ListRelationalTables returns all user-created relational tables from the SQLite schema. Excludes system tables, migrations, FTS tables, and EAV/Forms core tables.
func (*SQLite) ListSubmenuItems ¶ added in v0.0.6
ListSubmenuItems returns items that can be parents (type 'submenu').
func (*SQLite) MergeOAuthProfileData ¶
func (s *SQLite) MergeOAuthProfileData( userID int64, oauthUsername string, oauthAvatarURL string, ) (*User, error)
MergeOAuthProfileData merges OAuth provider data into existing user, updating only blank fields. It updates username (with conflict resolution) if Username is empty and oauthUsername is provided. It updates avatar_url if user.AvatarURL is empty and oauthAvatarURL is provided. Returns updated user with enabled=true if both username and email are now present, or error.
func (*SQLite) MoveElementDown ¶ added in v0.0.4
MoveElementDown swaps this element's z_order with the next element (higher z_order, same parent).
func (*SQLite) MoveElementUp ¶ added in v0.0.4
MoveElementUp swaps this element's z_order with the previous element (lower z_order, same parent).
func (*SQLite) MoveMenuItemDown ¶ added in v0.0.6
MoveMenuItemDown swaps this item's z_order with the next item (higher z_order, same parent).
func (*SQLite) MoveMenuItemUp ¶ added in v0.0.6
MoveMenuItemUp swaps this item's z_order with the previous item (lower z_order, same parent).
func (*SQLite) PurgeExpiredMagicLinkTokens ¶
PurgeExpiredMagicLinkTokens removes expired magic link tokens from the database.
func (*SQLite) RO ¶ added in v0.0.3
RO returns the read-only database connection. This is useful for external integrations that need direct access to sql.DB.
func (*SQLite) RW ¶ added in v0.0.3
RW returns the read-write database connection. This is useful for external integrations that need direct access to sql.DB.
func (*SQLite) SaveFileMetadata ¶
SaveFileMetadata saves file metadata to the database.
func (*SQLite) SearchFilesByUserIDFTS ¶
func (s *SQLite) SearchFilesByUserIDFTS( userID int64, query string, sort string, offset int, limit int, ) ([]*File, error)
SearchFilesByUserIDFTS performs a full-text search across original_filename, filename, filetag, and filedescription using the FTS virtual table. Returns paginated results for a given user. Sort supports: "date_desc" (default) and "name_asc".
func (*SQLite) SoftDeleteEAVAttribute ¶
SoftDeleteEAVAttribute marks an attribute as deleted.
func (*SQLite) SoftDeleteEAVEntityType ¶
SoftDeleteEAVEntityType marks an entity type as deleted.
func (*SQLite) SoftDeleteEAVRecord ¶
SoftDeleteEAVRecord marks a record as deleted.
func (*SQLite) SoftDeleteFileByUserAndFilename ¶
SoftDeleteFileByUserAndFilename marks a file as deleted (soft delete) for a specific user and filename. It does not remove file contents from disk; a background worker may perform physical deletion later.
func (*SQLite) SoftDeleteForm ¶ added in v0.0.4
SoftDeleteForm soft-deletes a form.
func (*SQLite) SoftDeleteMenu ¶ added in v0.0.6
SoftDeleteMenu soft-deletes a menu.
func (*SQLite) StoreMagicLinkToken ¶
StoreMagicLinkToken stores a magic link token for email-based authentication.
func (*SQLite) UpdateEAVAttribute ¶
func (s *SQLite) UpdateEAVAttribute( id int64, machineName, label, helpText, primitiveKind string, isRequired, isUnique, isIndexed bool, maxLength *int, isComputed bool, computedExpr string, defaultVBool *bool, defaultVInt *int64, defaultVReal *float64, defaultVText, defaultVDatetime *string, ) (*EAVAttribute, error)
UpdateEAVAttribute updates an existing attribute including default values.
func (*SQLite) UpdateEAVEntityType ¶ added in v0.0.2
func (s *SQLite) UpdateEAVEntityType(id int64, name, description, preSave, posLoad string) (*EAVEntityType, error)
UpdateEAVEntityType updates an existing entity type's metadata.
func (*SQLite) UpdateEAVRecordRev ¶
UpdateEAVRecordRev implements optimistic locking by incrementing rev only if currentRev matches. The validation is enforced by a SQLite trigger (trg_eav_records_update_rev). Returns the new rev on success, or ErrConflict if the rev doesn't match or trigger fails.
func (*SQLite) UpdateEAVRecordStatus ¶
UpdateEAVRecordStatus updates the status of a record (e.g., from 'draft' to 'active') and increments rev for optimistic locking
func (*SQLite) UpdateFileMetadataByUserAndFilename ¶
func (s *SQLite) UpdateFileMetadataByUserAndFilename( userID int64, filename string, description string, tag string, ) error
UpdateFileMetadataByUserAndFilename updates the file description and tag for a file owned by the given user, only if it is not deleted.
func (*SQLite) UpdateForm ¶ added in v0.0.4
func (s *SQLite) UpdateForm(id int64, machineName, label, description string, eavEntityTypeID *int64, hideSubmitButton, hideCancelButton, hideTitle, showSystemInfo bool, menuID *int64) error
UpdateForm updates a form's basic info.
func (*SQLite) UpdateFormElement ¶ added in v0.0.4
func (s *SQLite) UpdateFormElement( id int64, parentID *int64, machineName, elementKind, label, helpText string, zOrder, colSpan int, alignment string, uiKind, uiMetaJSON string, eavAttributeID *int64, isUIOnly, isReadonly, hideLabel, hideHelpText bool, buttonFiloCode string, buttonRunSave bool, buttonJSCode, buttonStyle, buttonConfirmMsg string, ) error
UpdateFormElement updates an existing form element.
func (*SQLite) UpdateMenu ¶ added in v0.0.6
UpdateMenu updates a menu's basic info.
func (*SQLite) UpdateMenuItem ¶ added in v0.0.6
func (s *SQLite) UpdateMenuItem( id int64, parentID *int64, machineName, label, icon, itemType, url, jsCode, filoCode string, zOrder int, ) error
UpdateMenuItem updates an existing menu item.
func (*SQLite) UpdateUserProfile ¶
func (s *SQLite) UpdateUserProfile( userID int64, username string, avatarURL string, ) (*User, error)
UpdateUserProfile updates username, avatar_url and enables user if email is already validated (email must be non-empty). Validates that username and email are not duplicated (case-insensitive). Returns the updated user or error if validation fails or SQL error occurs.
func (*SQLite) UpsertEAVValue ¶
func (s *SQLite) UpsertEAVValue( recordID, attributeID int64, vBool *bool, vInt *int64, vReal *float64, vText, vDatetime *string, ) error
UpsertEAVValue inserts or updates a value for a (record, attribute) pair. Validates that exactly one value is non-nil and matches the attribute's primitive_kind.
func (*SQLite) UpsertEAVValueWithRev ¶
func (s *SQLite) UpsertEAVValueWithRev( recordID, attributeID int64, currentRev int, vBool *bool, vInt *int64, vReal *float64, vText, vDatetime *string, ) (int, error)
UpsertEAVValueWithRev inserts or updates a value for a (record, attribute) pair and increments the record's rev for optimistic locking. The rev increment validation is enforced by a SQLite trigger (trg_eav_records_update_rev). Returns the new rev on success, or ErrConflict if currentRev doesn't match.
type ScriptEngineSetupFunc ¶ added in v0.0.3
ScriptEngineSetupFunc is a function that configures a Filo engine before execution. This allows callers to register additional builtins (like DB access) without creating circular dependencies.
var CurrentScriptSetup ScriptEngineSetupFunc = DefaultScriptSetup
CurrentScriptSetup is the active setup function. Set this at application startup to register additional builtins like DB access.
var DefaultScriptSetup ScriptEngineSetupFunc = func(eng *filo.Engine) { filostrings.RegisterBuiltins(eng) }
DefaultScriptSetup is the default setup that only registers string builtins.
type Transaction ¶
type Transaction struct {
// contains filtered or unexported fields
}
Transaction wraps a write transaction.
Example ¶
ExampleTransaction demonstrates how to use explicit transactions for grouped writes.
package main
import (
"fmt"
"os"
"path/filepath"
"github.com/crgimenes/devengine/db"
)
func main() {
tmpDir, err := os.MkdirTemp("", "db-example-tx-")
if err != nil {
panic(err)
}
defer os.RemoveAll(tmpDir)
store, err := db.NewWithPath(filepath.Join(tmpDir, "example-tx.db"))
if err != nil {
panic(err)
}
defer store.Close()
if err := store.Exec(`CREATE TABLE kv(k TEXT PRIMARY KEY, v TEXT NOT NULL)`); err != nil {
panic(err)
}
tx, err := store.BeginTransaction()
if err != nil {
panic(err)
}
if err := tx.Exec(`INSERT INTO kv(k, v) VALUES(?, ?)`, "a", "committed"); err != nil {
_ = tx.Rollback()
panic(err)
}
if err := tx.Commit(); err != nil {
panic(err)
}
tx2, err := store.BeginTransaction()
if err != nil {
panic(err)
}
if err := tx2.Exec(`INSERT INTO kv(k, v) VALUES(?, ?)`, "b", "rolled-back"); err != nil {
_ = tx2.Rollback()
panic(err)
}
if err := tx2.Rollback(); err != nil {
panic(err)
}
var value string
if err := store.QueryRow(`SELECT v FROM kv WHERE k = ?`, "a").Scan(&value); err != nil {
panic(err)
}
fmt.Println("stored value:", value)
}
Output: stored value: committed
func (*Transaction) Commit ¶
func (t *Transaction) Commit() error
Commit finalizes a transaction; on error, attempts a rollback.
func (*Transaction) Exec ¶
func (t *Transaction) Exec(query string, args ...any) error
Exec executes a write statement inside the transaction.
func (*Transaction) QueryRow ¶
func (t *Transaction) QueryRow(query string, args ...any) *Row
QueryRow returns a single row inside the transaction.
func (*Transaction) Rollback ¶
func (t *Transaction) Rollback() error
Rollback aborts the transaction.
type User ¶
type User struct {
ID int64 `json:"id"`
ReferenceID string `json:"reference_id"`
Username string `json:"username"`
Email string `json:"email"`
Enabled bool `json:"enabled"`
Sysop bool `json:"sysop"`
AvatarURL string `json:"avatar_url,omitempty"`
CreatedAt time.Time `json:"created_at,omitzero"`
UpdatedAt time.Time `json:"updated_at,omitzero"`
}