Documentation
¶
Overview ¶
TODO: handle `modified` time sqlite database management
Copyright (c) 2025 Chakib Ben Ziane <contact@blob42.xyz> and [`gosuki` contributors](https://github.com/blob42/gosuki/graphs/contributors). All rights reserved.
SPDX-License-Identifier: AGPL-3.0-or-later
This file is part of GoSuki.
GoSuki is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
GoSuki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with gosuki. If not, see <http://www.gnu.org/licenses/>.
Package database provides functionality for managing and synchronizing SQLite databases, specifically for bookmark data. It includes methods for syncing data between databases, caching, and disk persistence.
The package supports:
- Syncing data from one database to another (upsert or update)
- Synchronizing in-memory cache databases to disk
- Copying entire databases
- Scheduling periodic sync operations
- Handling SQLite-specific constraints and errors
The `SyncTo` method implements a manual UPSERT operation, which attempts to insert records from a source database to a destination database. If an insertion fails due to a constraint (e.g., duplicate URL), it will attempt to update the existing record.
The `SyncToDisk` method provides a way to sync a database to a specified disk path, using SQLite's backup API for efficient copying.
The `SyncFromDisk` method allows for restoring data from a disk file into a database.
The `CopyTo` method is used to copy an entire database from one location to another.
The `SyncToCache` method is used to sync a database to an in-memory cache, either by copying the entire database or by performing a sync operation if the cache is not empty.
This package also includes a scheduler for debounced sync operations to disk, which prevents excessive disk writes and ensures that syncs happen at regular intervals.
The package uses the `sqlx` package for database operations and `log` for logging.
See the individual function documentation for more details about their usage and behavior.
Index ¶
- Constants
- Variables
- func CountTotalBookmarks(ctx context.Context) (uint, error)
- func DebugPrintRow(rows *sql.Rows)
- func DebugPrintRows(rows *sql.Rows)
- func DotxQuery(file string) (*dotsqlx.DotSqlx, error)
- func DotxQueryEmbedFS(fs embed.FS, filename string) (*dotsqlx.DotSqlx, error)
- func GetDBDir() string
- func GetDBFullPath() string
- func GetDBPath() string
- func Init()
- func InitDiskConn(dbPath string) error
- func LoadBookmarks(load loadFunc, modName string) error
- func RegisterSqliteHooks()
- func SQLFuncFoo(in string) string
- func SQLFuzzy(test, in string) bool
- func ScheduleSyncToDisk()
- func StartSyncScheduler()
- func SyncTreeToBuffer(node *Node, buffer *DB)
- func SyncURLIndexToBuffer(urls []string, index Index, buffer *DB)
- type Bookmark
- type CacheDB
- type DB
- func (db *DB) AttachTo(attached *DB)
- func (db *DB) Close() error
- func (src *DB) CopyTo(dst *DB)
- func (db *DB) CountRows(table string) int
- func (db *DB) Init() (*DB, error)
- func (db *DB) InitSchema() error
- func (db *DB) InsertBookmark(bk *Bookmark)
- func (db *DB) IsEmpty() (bool, error)
- func (db *DB) Locked() (bool, error)
- func (db *DB) PrintBookmarks() error
- func (dst *DB) SyncFromDisk(dbpath string) error
- func (src *DB) SyncTo(dst *DB)
- func (src *DB) SyncToCache() error
- func (src *DB) SyncToDisk(dbpath string) error
- func (db *DB) UpsertBookmark(bk *Bookmark) error
- type DBConfig
- type DBError
- type DBType
- type DsnOptions
- type Index
- type LockChecker
- type Node
- type Opener
- type PaginationParams
- type QueryResult
- func BookmarksByTag(ctx context.Context, tag string, pagination *PaginationParams) (*QueryResult, error)
- func ListBookmarks(ctx context.Context, pagination *PaginationParams) (*QueryResult, error)
- func QueryBookmarks(ctx context.Context, query string, fuzzy bool, pagination *PaginationParams) (*QueryResult, error)
- func QueryBookmarksByTag(ctx context.Context, query, tag string, fuzzy bool, ...) (*QueryResult, error)
- type RawBookmark
- type RawBookmarks
- type SQLXDBOpener
- type SQLXOpener
- type Tags
- type VFSLockChecker
Constants ¶
const ( CacheName = "memcache" //MemcacheFmt = "file:%s?mode=memory&cache=shared" //BufferFmt = "file:%s?mode=memory&cache=shared" DBTypeInMemoryDSN = "file:%s?mode=memory&cache=shared" DBTypeCacheDSN = DBTypeInMemoryDSN )
const ( DBFileName = "gosuki.db" DBTypeFileDSN = "file:%s" // Opening DBs with this driver allows to track connections // This is used to perform sqlite backup DriverBackupMode = "sqlite_hook_backup" GosukiMainTable = "bookmarks" )
const ( WhereQueryBookmarks = ` URL like '%%%s%%' OR metadata like '%%%s%%' OR tags like '%%%s%%' ` WhereQueryBookmarksFuzzy = ` fuzzy('%s', URL) OR fuzzy('%s', metadata) OR fuzzy('%s', tags) ` WhereQueryBookmarksByTag = ` (URL LIKE '%%%s%%' OR metadata LIKE '%%%s%%') AND tags LIKE '%%%s%%' ` WhereQueryBookmarksByTagFuzzy = ` (fuzzy('%s', URL) OR fuzzy('%s', metadata)) AND tags LIKE '%%%s%%' ` QQueryPaginate = ` LIMIT %d OFFSET %d` )
const ( // metadata: name or title of resource // modified: time.Now().Unix() // // flags: designed to be extended in future using bitwise masks // Masks: // 0b00000001: set title immutable ((do not change title when updating the bookmarks from the web )) QCreateBookmarksTable = `` /* 279-byte string literal not displayed */ )
Database schemas used for the creation of new databases
const TagSep = ","
Default separator used to join tags in the DB
Variables ¶
var ( // Global in memory cache of gosuki database // Main in memory db, is synced with disc // `CacheDB` is a memory replica of disk db Cache = &CacheDB{} )
var (
// Default sqlite3 driver
DriverDefault = "sqlite3_gosuki"
)
var (
ErrVfsLocked = errors.New("vfs locked")
)
Functions ¶
func DebugPrintRow ¶
Print debug a single row (does not run rows.next())
func DotxQueryEmbedFS ¶
Loads a dotsql from an embedded FS
func GetDBFullPath ¶
func GetDBFullPath() string
func InitDiskConn ¶
Initialize the connection to ondisk gosuki db
func LoadBookmarks ¶
internal loading function called by modules
func RegisterSqliteHooks ¶
func RegisterSqliteHooks()
RegisterSqliteHooks registers a SQLite backup hook with additional connection tracking.
func StartSyncScheduler ¶
func StartSyncScheduler()
func SyncTreeToBuffer ¶
func SyncURLIndexToBuffer ¶
Types ¶
type CacheDB ¶
type CacheDB struct {
*DB
}
func GetCacheDB ¶
func GetCacheDB() *CacheDB
func (*CacheDB) IsInitialized ¶
type DB ¶
type DB struct {
Name string
Path string
Handle *sqlx.DB
EngineMode string
AttachedTo []string
Type DBType
SQLXOpener
LockChecker
// contains filtered or unexported fields
}
DB encapsulates an sql.DB struct. All interactions with memory/buffer and disk databases are done through the DB instance.
var ( //FIXME: hard coded path DefaultDBPath = "~/.local/share/gosuki/" // Handle to on-disk gosuki database DiskDB *DB )
func NewDB ¶
func NewDB(name string, dbPath string, dbFormat string, opts ...DsnOptions) *DB
dbPath is empty string ("") when using in memory sqlite db Call to Init() required before using
func (*DB) Init ¶
We should export Open() in its own method and wrap with interface so we can mock it and test the lock status in Init() Initialize a sqlite database with Gosuki Schema if not already done
func (*DB) InitSchema ¶
func (*DB) InsertBookmark ¶
Inserts a bookmarks to the passed DB In case of conflict follow the default rules which for sqlite is a fail with the error `sqlite3.ErrConstraint`
func (*DB) PrintBookmarks ¶
func (*DB) SyncFromDisk ¶
func (*DB) SyncTo ¶
Manual UPSERT: For every row in `src` try to insert it into `dst`. if if fails then try to update it. It means `src` is synced to `dst`
func (*DB) SyncToCache ¶
func (*DB) SyncToDisk ¶
func (*DB) UpsertBookmark ¶
Inserts or updates a bookmarks to the passed DB In case of a conflict for a UNIQUE URL constraint, update the existing bookmark TODO: use context
type DBError ¶
type DsnOptions ¶
type Index ¶
This is a RedBlack Tree Hashmap that holds in memory the last state of the bookmark tree.It is used as fast db queries. Each URL holds a pointer to a node in [nodeTree]
type LockChecker ¶
type PaginationParams ¶
func DefaultPagination ¶
func DefaultPagination() *PaginationParams
type QueryResult ¶
func BookmarksByTag ¶
func BookmarksByTag( ctx context.Context, tag string, pagination *PaginationParams, ) (*QueryResult, error)
func ListBookmarks ¶
func ListBookmarks( ctx context.Context, pagination *PaginationParams, ) (*QueryResult, error)
func QueryBookmarks ¶
func QueryBookmarks( ctx context.Context, query string, fuzzy bool, pagination *PaginationParams, ) (*QueryResult, error)
func QueryBookmarksByTag ¶
func QueryBookmarksByTag( ctx context.Context, query, tag string, fuzzy bool, pagination *PaginationParams, ) (*QueryResult, error)
type RawBookmark ¶
type RawBookmarks ¶
type RawBookmarks []*RawBookmark
func (RawBookmarks) AsBookmarks ¶
func (raws RawBookmarks) AsBookmarks() []*gosuki.Bookmark
type SQLXDBOpener ¶
type SQLXDBOpener struct {
// contains filtered or unexported fields
}
func (*SQLXDBOpener) Get ¶
func (o *SQLXDBOpener) Get() *sqlx.DB
type SQLXOpener ¶
type Tags ¶
type Tags struct {
// contains filtered or unexported fields
}
func TagsFromString ¶
Builds a list of tags from a string as a Tags struct. It also removes empty tags
func (*Tags) PreSanitize ¶
Sanitize the list of tags before saving them to the DB
func (Tags) String ¶
String representation of the tags. It can wrap the tags with the delim if wrap is true. This is done for compatibility with Buku DB format.
func (Tags) StringWrap ¶
String representation of the tags. It wraps the tags with the delim.
type VFSLockChecker ¶
type VFSLockChecker struct {
// contains filtered or unexported fields
}
func (*VFSLockChecker) Locked ¶
func (checker *VFSLockChecker) Locked() (bool, error)