Skip to content

Commit 0e80b6c

Browse files
committed
connect-db-postgresql and connect-db-sqlite
1 parent 96b0541 commit 0e80b6c

4 files changed

Lines changed: 216 additions & 0 deletions

File tree

cmd/scmd/main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ func main() {
5151
setup.SetupPostgreSQL()
5252
} else if arg1 == "--create-db-sqlite" {
5353
setup.SetupSQLite()
54+
} else if arg1 == "--connect-db-sqlite" {
55+
setup.ConnectSQLite()
56+
} else if arg1 == "--connect-db-postgresql" {
57+
setup.ConnectPostgreSQL()
5458
} else if arg1 == "--server-ollama" {
5559
setup.SetupOllama()
5660
} else if arg1 == "--server-gemini" {

images/infographic.png

5.17 MB
Loading

internal/cli/helpmenu.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ func PrintHelp(name string) {
102102
fmt.Printf(NoticeColor, "*** Interactive SQLite database setup (lightweight, no server required, saves to ~/.scmd/)\n\r")
103103
fmt.Println("Usage: \t", name, "--create-db-sqlite")
104104
fmt.Println()
105+
fmt.Printf(NoticeColor, "*** Connect to an existing SQLite database (auto-detects file in ~/.scmd/, verifies connection)\n\r")
106+
fmt.Println("Usage: \t", name, "--connect-db-sqlite")
107+
fmt.Println()
108+
fmt.Printf(NoticeColor, "*** Connect to an existing PostgreSQL database (interactive step-by-step, saves config, tests connection)\n\r")
109+
fmt.Println("Usage: \t", name, "--connect-db-postgresql")
110+
fmt.Println()
105111
fmt.Printf(NoticeColor, "*** Interactive Ollama AI server setup (prompts for host, model, embedding config)\n\r")
106112
fmt.Println("Usage: \t", name, "--server-ollama")
107113
fmt.Println()

internal/setup/setup.go

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,212 @@ func SetupOllama() {
222222
fmt.Println()
223223
}
224224

225+
// ConnectSQLite auto-detects an existing SQLite database and verifies the connection.
226+
// It reads the current config for the DB name, tests the file exists, and saves/confirms config.
227+
func ConnectSQLite() {
228+
reader := bufio.NewReader(os.Stdin)
229+
cfg := config.CurrentConfig()
230+
231+
fmt.Println()
232+
fmt.Printf(noticeColor, "=== Connect to Existing SQLite Database ===\n")
233+
fmt.Println()
234+
fmt.Println(" This will connect SCMD to an already-existing SQLite database.")
235+
fmt.Println(" The database file must exist in ~/.scmd/")
236+
fmt.Println(" Press Enter to accept the default value shown in brackets.")
237+
fmt.Println()
238+
239+
if cfg.DBName == "" {
240+
cfg.DBName = "scmd"
241+
}
242+
cfg.DBName = prompt(reader, "Database name (filename without .db)", cfg.DBName)
243+
244+
if cfg.TBName == "" {
245+
cfg.TBName = "data"
246+
}
247+
cfg.TBName = prompt(reader, "Table name", cfg.TBName)
248+
249+
if cfg.EmbeddingDim == "" {
250+
cfg.EmbeddingDim = "384"
251+
}
252+
cfg.EmbeddingDim = prompt(reader, "Embedding dimension", cfg.EmbeddingDim)
253+
254+
// Set db_type and clear PostgreSQL-specific fields
255+
cfg.DBType = "sqlite"
256+
cfg.DBHost = ""
257+
cfg.DBPort = ""
258+
cfg.DBUser = ""
259+
cfg.DBPass = ""
260+
261+
// Derive the expected file path
262+
home, err := os.UserHomeDir()
263+
if err != nil {
264+
fmt.Printf(errorColor, fmt.Sprintf(" Error: cannot determine home directory: %v\n", err))
265+
os.Exit(1)
266+
}
267+
dbPath := home + "/.scmd/" + cfg.DBName + ".db"
268+
269+
fmt.Println()
270+
fmt.Printf(" Checking for database file: %s\n", dbPath)
271+
272+
if _, err := os.Stat(dbPath); os.IsNotExist(err) {
273+
fmt.Printf(errorColor, fmt.Sprintf("\n Error: database file not found: %s\n", dbPath))
274+
fmt.Println()
275+
fmt.Println(" If you want to create a new SQLite database, use:")
276+
fmt.Println(" scmd --create-db-sqlite")
277+
fmt.Println()
278+
os.Exit(1)
279+
}
280+
fmt.Printf(successColor, " ✓ Database file found.\n")
281+
282+
// Save config
283+
fmt.Println()
284+
fmt.Printf(noticeColor, "Saving configuration...\n")
285+
if err := config.SaveConfig(cfg); err != nil {
286+
fmt.Printf(errorColor, fmt.Sprintf("Error saving config: %v\n", err))
287+
os.Exit(1)
288+
}
289+
fmt.Printf(successColor, fmt.Sprintf(" ✓ Config saved to %s\n", config.ConfigFilePath()))
290+
291+
// Reload and verify connection
292+
config.LoadConfig()
293+
fmt.Println()
294+
fmt.Printf(noticeColor, "Verifying connection...\n")
295+
if err := database.InitDB(); err != nil {
296+
fmt.Printf(errorColor, fmt.Sprintf(" ✗ Could not connect: %v\n", err))
297+
os.Exit(1)
298+
}
299+
database.CloseDB()
300+
301+
fmt.Println()
302+
fmt.Printf(successColor, "=== SQLite Connection Configured ===\n")
303+
fmt.Println()
304+
fmt.Printf(" Database file: %s\n", dbPath)
305+
fmt.Printf(" Table name: %s\n", cfg.TBName)
306+
fmt.Println()
307+
fmt.Println(" You can now run scmd normally.")
308+
fmt.Println()
309+
}
310+
311+
// ConnectPostgreSQL runs an interactive wizard to connect to an existing PostgreSQL database.
312+
// It prompts for all connection details step-by-step, tests the connection, and saves config.
313+
func ConnectPostgreSQL() {
314+
reader := bufio.NewReader(os.Stdin)
315+
cfg := config.CurrentConfig()
316+
317+
fmt.Println()
318+
fmt.Printf(noticeColor, "=== Connect to Existing PostgreSQL Database ===\n")
319+
fmt.Println()
320+
fmt.Println(" This will configure SCMD to connect to an already-existing PostgreSQL database.")
321+
fmt.Println(" The database and table must already exist.")
322+
fmt.Println(" Press Enter to accept the default value shown in brackets.")
323+
fmt.Println()
324+
325+
// Step 1: host
326+
if cfg.DBHost == "" {
327+
cfg.DBHost = "localhost"
328+
}
329+
fmt.Printf(noticeColor, " Step 1 of 7: Database host\n")
330+
cfg.DBHost = prompt(reader, "Host", cfg.DBHost)
331+
fmt.Println()
332+
333+
// Step 2: port
334+
if cfg.DBPort == "" {
335+
cfg.DBPort = "5432"
336+
}
337+
fmt.Printf(noticeColor, " Step 2 of 7: Database port\n")
338+
cfg.DBPort = prompt(reader, "Port", cfg.DBPort)
339+
fmt.Println()
340+
341+
// Step 3: user
342+
fmt.Printf(noticeColor, " Step 3 of 7: Database user\n")
343+
cfg.DBUser = prompt(reader, "User", cfg.DBUser)
344+
fmt.Println()
345+
346+
// Step 4: password
347+
fmt.Printf(noticeColor, " Step 4 of 7: Database password\n")
348+
cfg.DBPass = promptPassword(reader, "Password", cfg.DBPass)
349+
fmt.Println()
350+
351+
// Step 5: database name
352+
if cfg.DBName == "" {
353+
cfg.DBName = "scmd"
354+
}
355+
fmt.Printf(noticeColor, " Step 5 of 7: Database name\n")
356+
cfg.DBName = prompt(reader, "Database name", cfg.DBName)
357+
fmt.Println()
358+
359+
// Step 6: table name
360+
if cfg.TBName == "" {
361+
cfg.TBName = "data"
362+
}
363+
fmt.Printf(noticeColor, " Step 6 of 7: Table name\n")
364+
cfg.TBName = prompt(reader, "Table name", cfg.TBName)
365+
fmt.Println()
366+
367+
// Step 7: embedding dimension
368+
if cfg.EmbeddingDim == "" {
369+
cfg.EmbeddingDim = "384"
370+
}
371+
fmt.Printf(noticeColor, " Step 7 of 7: Embedding dimension\n")
372+
cfg.EmbeddingDim = prompt(reader, "Embedding dimension", cfg.EmbeddingDim)
373+
fmt.Println()
374+
375+
// Set db_type
376+
cfg.DBType = "postgresql"
377+
378+
// Summary before saving
379+
fmt.Println()
380+
fmt.Printf(noticeColor, " Connection summary:\n")
381+
fmt.Printf(" Host: %s\n", cfg.DBHost)
382+
fmt.Printf(" Port: %s\n", cfg.DBPort)
383+
fmt.Printf(" User: %s\n", cfg.DBUser)
384+
fmt.Printf(" Password: ****\n")
385+
fmt.Printf(" Database: %s\n", cfg.DBName)
386+
fmt.Printf(" Table: %s\n", cfg.TBName)
387+
fmt.Printf(" Emb. dim: %s\n", cfg.EmbeddingDim)
388+
fmt.Println()
389+
390+
confirm := prompt(reader, "Save and test this connection? (yes/no)", "yes")
391+
if confirm != "yes" && confirm != "y" {
392+
fmt.Printf(errorColor, " Cancelled. No changes were saved.\n")
393+
fmt.Println()
394+
os.Exit(0)
395+
}
396+
397+
// Save config
398+
fmt.Println()
399+
fmt.Printf(noticeColor, "Saving configuration...\n")
400+
if err := config.SaveConfig(cfg); err != nil {
401+
fmt.Printf(errorColor, fmt.Sprintf(" Error saving config: %v\n", err))
402+
os.Exit(1)
403+
}
404+
fmt.Printf(successColor, fmt.Sprintf(" ✓ Config saved to %s\n", config.ConfigFilePath()))
405+
406+
// Reload and test connection
407+
config.LoadConfig()
408+
fmt.Println()
409+
fmt.Printf(noticeColor, "Testing connection...\n")
410+
if err := database.InitDB(); err != nil {
411+
fmt.Printf(errorColor, fmt.Sprintf(" ✗ Connection failed: %v\n", err))
412+
fmt.Println()
413+
fmt.Println(" Check your credentials and ensure the PostgreSQL server is reachable.")
414+
fmt.Println(" Config has been saved — re-run this command to update it.")
415+
fmt.Println()
416+
os.Exit(1)
417+
}
418+
database.CloseDB()
419+
420+
fmt.Println()
421+
fmt.Printf(successColor, "=== PostgreSQL Connection Configured ===\n")
422+
fmt.Println()
423+
fmt.Printf(" Host: %s:%s\n", cfg.DBHost, cfg.DBPort)
424+
fmt.Printf(" Database: %s\n", cfg.DBName)
425+
fmt.Printf(" Table: %s\n", cfg.TBName)
426+
fmt.Println()
427+
fmt.Println(" You can now run scmd normally.")
428+
fmt.Println()
429+
}
430+
225431
// SetupGemini runs the interactive Gemini AI server setup wizard.
226432
func SetupGemini() {
227433
reader := bufio.NewReader(os.Stdin)

0 commit comments

Comments
 (0)