Something went wrong. Try again.
cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 🍃
charm leaflet readability golang
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182package store
import ( "database/sql" "embed" "fmt" "os" "path/filepath" "runtime"
_ "github.com/mattn/go-sqlite3")
var ( sqlOpen = sql.Open pragmaExec = func(db *sql.DB, stmt string) (sql.Result, error) { return db.Exec(stmt) } createMigrationRunner = CreateMigrationRunner getRuntime = func() string { return runtime.GOOS } getHomeDir = os.UserHomeDir mkdirAll = os.MkdirAll)
//go:embed sql/migrationsvar migrationFiles embed.FS
// Database wraps [sql.DB] with application-specific methodstype Database struct { *sql.DB path string}
// GetConfigDir returns the appropriate configuration directory based on [runtime.GOOS]var GetConfigDir = func() (string, error) { var configDir string
switch getRuntime() { case "windows": appData := os.Getenv("APPDATA") if appData == "" { return "", fmt.Errorf("APPDATA environment variable not set") } configDir = filepath.Join(appData, "noteleaf") case "darwin": homeDir, err := getHomeDir() if err != nil { return "", fmt.Errorf("failed to get user home directory: %w", err) } configDir = filepath.Join(homeDir, "Library", "Application Support", "noteleaf") default: xdgConfigHome := os.Getenv("XDG_CONFIG_HOME") if xdgConfigHome == "" { homeDir, err := getHomeDir() if err != nil { return "", fmt.Errorf("failed to get user home directory: %w", err) } xdgConfigHome = filepath.Join(homeDir, ".config") } configDir = filepath.Join(xdgConfigHome, "noteleaf") }
if err := mkdirAll(configDir, 0755); err != nil { return "", fmt.Errorf("failed to create config directory: %w", err) }
return configDir, nil}
// GetDataDir returns the appropriate data directory based on [runtime.GOOS] or NOTELEAF_DATA_DIRvar GetDataDir = func() (string, error) { if envDataDir := os.Getenv("NOTELEAF_DATA_DIR"); envDataDir != "" { if err := mkdirAll(envDataDir, 0755); err != nil { return "", fmt.Errorf("failed to create data directory: %w", err) } return envDataDir, nil }
var dataDir string
switch getRuntime() { case "windows": localAppData := os.Getenv("LOCALAPPDATA") if localAppData == "" { return "", fmt.Errorf("LOCALAPPDATA environment variable not set") } dataDir = filepath.Join(localAppData, "noteleaf") case "darwin": homeDir, err := getHomeDir() if err != nil { return "", fmt.Errorf("failed to get user home directory: %w", err) } dataDir = filepath.Join(homeDir, "Library", "Application Support", "noteleaf") default: xdgDataHome := os.Getenv("XDG_DATA_HOME") if xdgDataHome == "" { homeDir, err := getHomeDir() if err != nil { return "", fmt.Errorf("failed to get user home directory: %w", err) } xdgDataHome = filepath.Join(homeDir, ".local", "share") } dataDir = filepath.Join(xdgDataHome, "noteleaf") }
if err := mkdirAll(dataDir, 0755); err != nil { return "", fmt.Errorf("failed to create data directory: %w", err) }
return dataDir, nil}
// NewDatabase creates and initializes a new database connectionvar NewDatabase = func() (*Database, error) { return NewDatabaseWithConfig(nil)}
// NewDatabaseWithConfig creates and initializes a new [Database] connection using the provided [Config]func NewDatabaseWithConfig(config *Config) (*Database, error) { if config == nil { var err error config, err = LoadConfig() if err != nil { return nil, fmt.Errorf("failed to load config: %w", err) } }
var dbPath string if config.DatabasePath != "" { dbPath = config.DatabasePath dbDir := filepath.Dir(dbPath) if err := mkdirAll(dbDir, 0755); err != nil { return nil, fmt.Errorf("failed to create database directory: %w", err) } } else if config.DataDir != "" { dbPath = filepath.Join(config.DataDir, "noteleaf.db") } else { dataDir, err := GetDataDir() if err != nil { return nil, fmt.Errorf("failed to get data directory: %w", err) } dbPath = filepath.Join(dataDir, "noteleaf.db") }
db, err := sqlOpen("sqlite3", dbPath) if err != nil { return nil, fmt.Errorf("failed to open database: %w", err) }
if _, err := pragmaExec(db, "PRAGMA foreign_keys = ON"); err != nil { db.Close() return nil, fmt.Errorf("failed to enable foreign keys: %w", err) }
if _, err := pragmaExec(db, "PRAGMA journal_mode = WAL"); err != nil { db.Close() return nil, fmt.Errorf("failed to enable WAL mode: %w", err) }
database := &Database{DB: db, path: dbPath} runner := createMigrationRunner(db, migrationFiles) if err := runner.RunMigrations(); err != nil { db.Close() return nil, fmt.Errorf("failed to run migrations: %w", err) }
return database, nil}
// NewMigrationRunner creates a new migration runner from a Database instancefunc NewMigrationRunner(db *Database) *MigrationRunner { return createMigrationRunner(db.DB, migrationFiles)}
// GetPath returns the database file pathfunc (db *Database) GetPath() string { return db.path}
// Close closes the database connectionfunc (db *Database) Close() error { return db.DB.Close()}