🎨 Refactoring the extension service and the keybinding service
This commit is contained in:
211
internal/services/database_service.go
Normal file
211
internal/services/database_service.go
Normal file
@@ -0,0 +1,211 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
"github.com/wailsapp/wails/v3/pkg/services/log"
|
||||
_ "modernc.org/sqlite" // SQLite driver
|
||||
)
|
||||
|
||||
const (
|
||||
dbName = "voidraft.db"
|
||||
|
||||
// SQLite performance optimization settings
|
||||
sqlOptimizationSettings = `
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA synchronous = NORMAL;
|
||||
PRAGMA cache_size = -64000;
|
||||
PRAGMA temp_store = MEMORY;
|
||||
PRAGMA foreign_keys = ON;`
|
||||
|
||||
// Documents table
|
||||
sqlCreateDocumentsTable = `
|
||||
CREATE TABLE IF NOT EXISTS documents (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
title TEXT NOT NULL,
|
||||
content TEXT DEFAULT '∞∞∞text-a',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
is_deleted INTEGER DEFAULT 0
|
||||
)`
|
||||
|
||||
// Extensions table
|
||||
sqlCreateExtensionsTable = `
|
||||
CREATE TABLE IF NOT EXISTS extensions (
|
||||
id TEXT PRIMARY KEY,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
is_default INTEGER NOT NULL DEFAULT 0,
|
||||
config TEXT DEFAULT '{}',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)`
|
||||
|
||||
// Key bindings table
|
||||
sqlCreateKeyBindingsTable = `
|
||||
CREATE TABLE IF NOT EXISTS key_bindings (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
command TEXT NOT NULL,
|
||||
extension TEXT NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
is_default INTEGER NOT NULL DEFAULT 0,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(command, extension)
|
||||
)`
|
||||
)
|
||||
|
||||
// DatabaseService provides shared database functionality
|
||||
type DatabaseService struct {
|
||||
configService *ConfigService
|
||||
logger *log.LoggerService
|
||||
db *sql.DB
|
||||
mu sync.RWMutex
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewDatabaseService creates a new database service
|
||||
func NewDatabaseService(configService *ConfigService, logger *log.LoggerService) *DatabaseService {
|
||||
if logger == nil {
|
||||
logger = log.New()
|
||||
}
|
||||
|
||||
return &DatabaseService{
|
||||
configService: configService,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// OnStartup initializes the service when the application starts
|
||||
func (ds *DatabaseService) OnStartup(ctx context.Context, _ application.ServiceOptions) error {
|
||||
ds.ctx = ctx
|
||||
return ds.initDatabase()
|
||||
}
|
||||
|
||||
// initDatabase initializes the SQLite database
|
||||
func (ds *DatabaseService) initDatabase() error {
|
||||
dbPath, err := ds.getDatabasePath()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get database path: %w", err)
|
||||
}
|
||||
|
||||
// 确保数据库目录存在
|
||||
dbDir := filepath.Dir(dbPath)
|
||||
if err := os.MkdirAll(dbDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create database directory: %w", err)
|
||||
}
|
||||
|
||||
// 检查数据库文件是否存在,如果不存在则创建
|
||||
if _, err := os.Stat(dbPath); os.IsNotExist(err) {
|
||||
// 创建空文件
|
||||
file, err := os.Create(dbPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create database file: %w", err)
|
||||
}
|
||||
file.Close()
|
||||
}
|
||||
|
||||
db, err := sql.Open("sqlite", dbPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open database: %w", err)
|
||||
}
|
||||
|
||||
ds.db = db
|
||||
|
||||
// Apply optimization settings
|
||||
if _, err := db.Exec(sqlOptimizationSettings); err != nil {
|
||||
return fmt.Errorf("failed to apply optimization settings: %w", err)
|
||||
}
|
||||
|
||||
// Create all tables
|
||||
if err := ds.createTables(); err != nil {
|
||||
return fmt.Errorf("failed to create tables: %w", err)
|
||||
}
|
||||
|
||||
// Create indexes
|
||||
if err := ds.createIndexes(); err != nil {
|
||||
return fmt.Errorf("failed to create indexes: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getDatabasePath gets the database file path
|
||||
func (ds *DatabaseService) getDatabasePath() (string, error) {
|
||||
config, err := ds.configService.GetConfig()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(config.General.DataPath, dbName), nil
|
||||
}
|
||||
|
||||
// createTables creates all database tables
|
||||
func (ds *DatabaseService) createTables() error {
|
||||
tables := []string{
|
||||
sqlCreateDocumentsTable,
|
||||
sqlCreateExtensionsTable,
|
||||
sqlCreateKeyBindingsTable,
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
if _, err := ds.db.Exec(table); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// createIndexes creates database indexes
|
||||
func (ds *DatabaseService) createIndexes() error {
|
||||
indexes := []string{
|
||||
// Documents indexes
|
||||
`CREATE INDEX IF NOT EXISTS idx_documents_updated_at ON documents(updated_at DESC)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_documents_title ON documents(title)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_documents_is_deleted ON documents(is_deleted)`,
|
||||
// Extensions indexes
|
||||
`CREATE INDEX IF NOT EXISTS idx_extensions_enabled ON extensions(enabled)`,
|
||||
// Key bindings indexes
|
||||
`CREATE INDEX IF NOT EXISTS idx_key_bindings_command ON key_bindings(command)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_key_bindings_extension ON key_bindings(extension)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_key_bindings_enabled ON key_bindings(enabled)`,
|
||||
}
|
||||
|
||||
for _, index := range indexes {
|
||||
if _, err := ds.db.Exec(index); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDB returns the database connection
|
||||
func (ds *DatabaseService) GetDB() *sql.DB {
|
||||
ds.mu.RLock()
|
||||
defer ds.mu.RUnlock()
|
||||
return ds.db
|
||||
}
|
||||
|
||||
// OnShutdown shuts down the service when the application closes
|
||||
func (ds *DatabaseService) OnShutdown() error {
|
||||
if ds.db != nil {
|
||||
return ds.db.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnDataPathChanged handles data path changes
|
||||
func (ds *DatabaseService) OnDataPathChanged() error {
|
||||
// Close existing database
|
||||
if ds.db != nil {
|
||||
ds.db.Close()
|
||||
}
|
||||
|
||||
// Reinitialize with new path
|
||||
return ds.initDatabase()
|
||||
}
|
Reference in New Issue
Block a user