fix(dolt): proper server mode support for routing and storage

- FindDatabasePath now handles Dolt server mode (no local dir required)
- main.go uses NewFromConfigWithOptions for Dolt to read server settings
- Routing uses factory via callback to respect backend configuration
- Handle Dolt "database exists" error (error 1007) gracefully

Previously, Dolt server mode failed because:
1. FindDatabasePath required a local directory to exist
2. main.go bypassed server mode config when creating Dolt storage
3. Routing always opened SQLite regardless of backend config

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
beads/crew/emma
2026-01-24 00:26:23 -08:00
committed by Steve Yegge
parent 13c362e67e
commit e82f5136c1
5 changed files with 71 additions and 41 deletions

View File

@@ -232,7 +232,11 @@ func findDatabaseInBeadsDir(beadsDir string, warnOnIssues bool) string {
if cfg, err := configfile.Load(beadsDir); err == nil && cfg != nil {
backend := cfg.GetBackend()
if backend == configfile.BackendDolt {
// For Dolt, check if the configured database directory exists
// For Dolt server mode, database is on the server - no local directory required
if cfg.IsDoltServerMode() {
return cfg.DatabasePath(beadsDir)
}
// For embedded Dolt, check if the configured database directory exists
doltPath := cfg.DatabasePath(beadsDir)
if info, err := os.Stat(doltPath); err == nil && info.IsDir() {
return doltPath

View File

@@ -425,12 +425,27 @@ func (rs *RoutedStorage) Close() error {
return nil
}
// StorageOpener is a function that opens storage for a given beads directory.
// This allows callers to provide custom storage opening logic (e.g., using factory).
type StorageOpener func(ctx context.Context, beadsDir string) (storage.Storage, error)
// GetRoutedStorageForID returns a storage connection for the given issue ID.
// If the ID matches a route, it opens a connection to the routed database using SQLite.
// Otherwise, it returns nil (caller should use their existing storage).
//
// DEPRECATED: Use GetRoutedStorageWithOpener for proper backend support.
// The caller is responsible for closing the returned RoutedStorage.
func GetRoutedStorageForID(ctx context.Context, id, currentBeadsDir string) (*RoutedStorage, error) {
return GetRoutedStorageWithOpener(ctx, id, currentBeadsDir, nil)
}
// GetRoutedStorageWithOpener returns a storage connection for the given issue ID.
// If the ID matches a route, it opens a connection to the routed database.
// The opener function is used to create storage; if nil, defaults to SQLite.
// Otherwise, it returns nil (caller should use their existing storage).
//
// The caller is responsible for closing the returned RoutedStorage.
func GetRoutedStorageForID(ctx context.Context, id, currentBeadsDir string) (*RoutedStorage, error) {
func GetRoutedStorageWithOpener(ctx context.Context, id, currentBeadsDir string, opener StorageOpener) (*RoutedStorage, error) {
beadsDir, routed, err := ResolveBeadsDirForID(ctx, id, currentBeadsDir)
if err != nil {
return nil, err
@@ -441,8 +456,14 @@ func GetRoutedStorageForID(ctx context.Context, id, currentBeadsDir string) (*Ro
}
// Open storage for the routed directory
dbPath := filepath.Join(beadsDir, "beads.db")
store, err := sqlite.New(ctx, dbPath)
var store storage.Storage
if opener != nil {
store, err = opener(ctx, beadsDir)
} else {
// Default to SQLite for backward compatibility
dbPath := filepath.Join(beadsDir, "beads.db")
store, err = sqlite.New(ctx, dbPath)
}
if err != nil {
return nil, err
}

View File

@@ -312,8 +312,13 @@ func openServerConnection(ctx context.Context, cfg *Config) (*sql.DB, string, er
_, err = initDB.ExecContext(ctx, fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", cfg.Database))
if err != nil {
_ = db.Close()
return nil, "", fmt.Errorf("failed to create database: %w", err)
// Dolt may return error 1007 even with IF NOT EXISTS - ignore if database already exists
errLower := strings.ToLower(err.Error())
if !strings.Contains(errLower, "database exists") && !strings.Contains(errLower, "1007") {
_ = db.Close()
return nil, "", fmt.Errorf("failed to create database: %w", err)
}
// Database already exists - that's fine, continue
}
return db, connStr, nil