dbagent-cli 0.1.6__tar.gz → 0.1.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/PKG-INFO +1 -1
  2. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/__init__.py +1 -1
  3. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/cli.py +183 -92
  4. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/connectors/relational.py +10 -7
  5. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/PKG-INFO +1 -1
  6. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/pyproject.toml +1 -1
  7. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/README.md +0 -0
  8. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/agent/generator.py +0 -0
  9. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/agent/pipeline.py +0 -0
  10. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/agent/validator.py +0 -0
  11. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/config.py +0 -0
  12. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/connectors/base.py +0 -0
  13. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/connectors/factory.py +0 -0
  14. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/connectors/mongo.py +0 -0
  15. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/llm/auto_setup.py +0 -0
  16. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/llm/base.py +0 -0
  17. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/llm/factory.py +0 -0
  18. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/llm/gemini_provider.py +0 -0
  19. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/llm/groq_provider.py +0 -0
  20. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/llm/mock_provider.py +0 -0
  21. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/llm/ollama_provider.py +0 -0
  22. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/llm/openrouter_provider.py +0 -0
  23. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/schema/formatter.py +0 -0
  24. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/schema/models.py +0 -0
  25. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/schema/selector.py +0 -0
  26. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/ui/console.py +0 -0
  27. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent/ui/viewer.py +0 -0
  28. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/SOURCES.txt +0 -0
  29. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/dependency_links.txt +0 -0
  30. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/entry_points.txt +0 -0
  31. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/requires.txt +0 -0
  32. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/top_level.txt +0 -0
  33. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/setup.cfg +0 -0
  34. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/tests/test_cli.py +0 -0
  35. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/tests/test_connectors.py +0 -0
  36. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/tests/test_generator.py +0 -0
  37. {dbagent_cli-0.1.6 → dbagent_cli-0.1.8}/tests/test_schema.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dbagent-cli
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: Universal Database Introspection and Script Generation AI Agent (CLI)
5
5
  Author: Santhosh Gupta
6
6
  Requires-Python: >=3.9
@@ -2,5 +2,5 @@
2
2
  DB-Agent: Universal Database Introspection and Script Generation AI Agent (CLI).
3
3
  """
4
4
 
5
- __version__ = "0.1.6"
5
+ __version__ = "0.1.8"
6
6
  __author__ = "Santhosh Gupta"
@@ -509,7 +509,7 @@ def chat_command(
509
509
  console.print(f"[bold green]Connected:[/bold green] {db_name} ({dialect}) - {len(table_names)} tables")
510
510
  console.print(f"[bold cyan]AI:[/bold cyan] {llm.name}")
511
511
  console.print("[dim]Type your question in plain English. Read queries auto-execute. Write queries ask for confirmation.[/dim]")
512
- console.print("[dim]Commands: [bold]:tables[/bold] | [bold]:table <name>[/bold] | [bold]:fk <name>[/bold] | [bold]:explain[/bold] | [bold]:history[/bold] | [bold]:auto[/bold]/[bold]:noauto[/bold] | [bold]:run[/bold] | [bold]:export <file>[/bold] | [bold]:exit[/bold][/dim]\n")
512
+ console.print("[dim]Commands: [bold]:tables[/bold] | [bold]:table <name>[/bold] | [bold]:fk <name>[/bold] | [bold]:model <name>[/bold] | [bold]:explain[/bold] | [bold]:history[/bold] | [bold]:auto[/bold]/[bold]:noauto[/bold] | [bold]:run[/bold] | [bold]:export <file>[/bold] | [bold]:exit[/bold][/dim]\n")
513
513
 
514
514
  history_file = config_mgr.config_dir / "chat_history.txt"
515
515
  session = PromptSession(history=FileHistory(str(history_file)))
@@ -524,108 +524,180 @@ def chat_command(
524
524
  if not user_input:
525
525
  continue
526
526
 
527
- # --- REPL commands ---
528
- if user_input.lower() in [":exit", ":quit", "exit", "quit", "q"]:
529
- console.print("[bold cyan]Goodbye![/bold cyan]")
530
- break
527
+ # --- REPL commands (all start with :) ---
528
+ if user_input.startswith(":"):
529
+ cmd_parts = user_input.split(maxsplit=1)
530
+ cmd_name = cmd_parts[0].lower()
531
+ cmd_arg = cmd_parts[1].strip() if len(cmd_parts) > 1 else ""
532
+
533
+ if cmd_name in [":exit", ":quit", ":q"]:
534
+ console.print("[bold cyan]Goodbye![/bold cyan]")
535
+ break
536
+
537
+ if cmd_name in [":help", ":h", ":?"]:
538
+ console.print("\n[bold cyan]Interactive Chat Commands:[/bold cyan]")
539
+ console.print(" [bold]:tables[/bold] -> List all tables in this database")
540
+ console.print(" [bold]:table <name>[/bold] -> Inspect columns, PKs, types & sample data")
541
+ console.print(" [bold]:fk <name>[/bold] -> View mapped foreign keys & related tables")
542
+ console.print(" [bold]:provider <name>[/bold] -> Switch AI provider (ollama, gemini, groq, openrouter)")
543
+ console.print(" [bold]:model <name>[/bold] -> Switch active model name (e.g. gemini-3.6-flash)")
544
+ console.print(" [bold]:models[/bold] -> Show active AI provider and model status")
545
+ console.print(" [bold]:explain[/bold] -> Show generated SQL & query analysis for last turn")
546
+ console.print(" [bold]:history[/bold] -> View history of queries in this session")
547
+ console.print(" [bold]:auto[/bold] / [bold]:noauto[/bold] -> Toggle automatic execution of read queries")
548
+ console.print(" [bold]:run[/bold] -> Re-execute the last generated SQL query")
549
+ console.print(" [bold]:export <file>[/bold] -> Save the last generated SQL to a file")
550
+ console.print(" [bold]:exit[/bold] -> Exit chat session\n")
551
+ continue
531
552
 
532
- if user_input.lower() in [":tables", ":schema", "\\d", "\\dt"]:
533
- with console.status("[bold cyan]Fetching schema...[/bold cyan]"):
534
- schema = connector.inspect_schema(include_samples=False, max_samples=0, include_row_counts=False)
535
- SchemaViewer.display_schema_summary(schema)
536
- continue
553
+ if cmd_name in [":tables", ":schema", ":dt"]:
554
+ with console.status("[bold cyan]Fetching schema...[/bold cyan]"):
555
+ schema = connector.inspect_schema(include_samples=False, max_samples=0, include_row_counts=False)
556
+ SchemaViewer.display_schema_summary(schema)
557
+ continue
537
558
 
538
- if user_input.startswith(":table "):
539
- tname = user_input.split(" ", 1)[1].strip()
540
- exact, fuzzy = connector.resolve_tables(tname)
541
- target = exact[0] if exact else (fuzzy[0] if fuzzy else tname)
542
- with console.status(f"[bold cyan]Inspecting {target}...[/bold cyan]"):
543
- on_demand_schema = connector.inspect_schema(table_names=[target], include_samples=True)
544
- tmodel = on_demand_schema.get_table(target)
545
- if tmodel:
546
- SchemaViewer.display_table_detail(tmodel)
547
- else:
548
- print_error(f"Table '{tname}' not found.")
549
- continue
559
+ if cmd_name == ":table":
560
+ if not cmd_arg:
561
+ print_warning("Usage: :table <table_name> (e.g. :table ivis_users)")
562
+ continue
563
+ exact, fuzzy = connector.resolve_tables(cmd_arg)
564
+ target = exact[0] if exact else (fuzzy[0] if fuzzy else cmd_arg)
565
+ with console.status(f"[bold cyan]Inspecting {target}...[/bold cyan]"):
566
+ on_demand_schema = connector.inspect_schema(table_names=[target], include_samples=True)
567
+ tmodel = on_demand_schema.get_table(target)
568
+ if tmodel:
569
+ SchemaViewer.display_table_detail(tmodel)
570
+ else:
571
+ print_error(f"Table '{cmd_arg}' not found.")
572
+ continue
550
573
 
551
- if user_input.startswith(":relations ") or user_input.startswith(":fk ") or user_input.startswith(":mapped "):
552
- tname = user_input.split(" ", 1)[1].strip()
553
- exact, fuzzy = connector.resolve_tables(tname)
554
- target = exact[0] if exact else (fuzzy[0] if fuzzy else tname)
555
- with console.status(f"[bold cyan]Finding relationships for {target}...[/bold cyan]"):
556
- full_schema = connector.inspect_schema(include_samples=False, max_samples=0)
557
-
558
- # Find FKs where target references others, and others reference target
559
- tmodel = full_schema.get_table(target)
560
- outgoing = tmodel.foreign_keys if tmodel else []
561
- incoming = []
562
- for other in full_schema.tables:
563
- for fk in other.foreign_keys:
564
- if fk.referred_table.lower() == target.lower():
565
- incoming.append((other.name, fk))
566
-
567
- console.print(f"\n[bold cyan]Relationships mapped to table: [bold white]{target}[/bold white][/bold cyan]\n")
568
- if outgoing:
569
- console.print("[bold green]Outgoing (This table references):[/bold green]")
570
- for fk in outgoing:
571
- console.print(f" * ({', '.join(fk.constrained_columns)}) -> [bold]{fk.referred_table}[/bold]({', '.join(fk.referred_columns)})")
572
- if incoming:
573
- console.print("\n[bold yellow]Incoming (Other tables reference this table):[/bold yellow]")
574
- for src_table, fk in incoming:
575
- console.print(f" * [bold]{src_table}[/bold]({', '.join(fk.constrained_columns)}) -> ({', '.join(fk.referred_columns)})")
576
- if not outgoing and not incoming:
577
- console.print(f"[dim]No foreign key constraints found directly mapped to '{target}'.[/dim]")
578
- console.print("")
579
- continue
574
+ if cmd_name in [":fk", ":relations", ":mapped"]:
575
+ if not cmd_arg:
576
+ print_warning("Usage: :fk <table_name> (e.g. :fk ivis_users)")
577
+ continue
578
+ exact, fuzzy = connector.resolve_tables(cmd_arg)
579
+ target = exact[0] if exact else (fuzzy[0] if fuzzy else cmd_arg)
580
+ with console.status(f"[bold cyan]Finding relationships for {target}...[/bold cyan]"):
581
+ full_schema = connector.inspect_schema(include_samples=False, max_samples=0)
582
+
583
+ tmodel = full_schema.get_table(target)
584
+ outgoing = tmodel.foreign_keys if tmodel else []
585
+ incoming = []
586
+ for other in full_schema.tables:
587
+ for fk in other.foreign_keys:
588
+ if fk.referred_table.lower() == target.lower():
589
+ incoming.append((other.name, fk))
590
+
591
+ console.print(f"\n[bold cyan]Relationships mapped to table: [bold white]{target}[/bold white][/bold cyan]\n")
592
+ if outgoing:
593
+ console.print("[bold green]Outgoing (This table references):[/bold green]")
594
+ for fk in outgoing:
595
+ console.print(f" * ({', '.join(fk.constrained_columns)}) -> [bold]{fk.referred_table}[/bold]({', '.join(fk.referred_columns)})")
596
+ if incoming:
597
+ console.print("\n[bold yellow]Incoming (Other tables reference this table):[/bold yellow]")
598
+ for src_table, fk in incoming:
599
+ console.print(f" * [bold]{src_table}[/bold]({', '.join(fk.constrained_columns)}) -> ({', '.join(fk.referred_columns)})")
600
+ if not outgoing and not incoming:
601
+ console.print(f"[dim]No foreign key constraints found directly mapped to '{target}'.[/dim]")
602
+ console.print("")
603
+ continue
580
604
 
581
- if user_input.lower() == ":explain":
582
- if last_result and last_result.sql:
583
- print_code(last_result.sql, "sql", "Last Executed SQL")
584
- console.print(f"[dim]Query type: {last_result.query_type} | Intent: {last_result.intent} | Retries: {last_result.retries}[/dim]")
585
- if last_result.exact_tables:
586
- console.print(f"[dim]Tables (exact): {', '.join(last_result.exact_tables)}[/dim]")
587
- if last_result.fuzzy_tables:
588
- console.print(f"[dim]Tables (fuzzy): {', '.join(last_result.fuzzy_tables)}[/dim]")
589
- else:
590
- print_warning("No previous query to explain.")
591
- continue
605
+ if cmd_name in [":provider", ":use"]:
606
+ if not cmd_arg:
607
+ curr_model = model or getattr(llm, "default_model", "default")
608
+ console.print(f"\n[bold cyan]Active AI Provider:[/bold cyan] [bold white]{llm.name}[/bold white] | Model: [bold green]{curr_model}[/bold green]")
609
+ console.print("[dim]Usage: [bold]:provider <ollama|gemini|groq|openrouter>[/bold][/dim]\n")
610
+ continue
611
+ prov_target = cmd_arg.lower()
612
+ if prov_target in ["ollama", "gemini", "groq", "openrouter", "mock"]:
613
+ llm = get_llm_provider(provider_name=prov_target, config_mgr=config_mgr)
614
+ model = None
615
+ print_success(f"Switched AI provider to [bold cyan]{llm.name}[/bold cyan]")
616
+ else:
617
+ print_error(f"Unknown provider '{cmd_arg}'. Supported: ollama, gemini, groq, openrouter")
618
+ continue
592
619
 
593
- if user_input.lower() == ":history":
594
- if not query_history:
595
- print_warning("No query history in this session.")
620
+ if cmd_name == ":model":
621
+ if not cmd_arg:
622
+ curr_model = model or getattr(llm, "default_model", "default")
623
+ console.print(f"Active Model: [bold green]{curr_model}[/bold green] (Provider: {llm.name})")
624
+ console.print("[dim]Usage: [bold]:model <model_name>[/bold][/dim]")
625
+ continue
626
+ model = cmd_arg
627
+ print_success(f"Switched active model to [bold cyan]{model}[/bold cyan] (Provider: {llm.name})")
596
628
  continue
597
- for i, r in enumerate(query_history[-10:], 1):
598
- status = "[green]OK[/green]" if r.success else "[red]FAIL[/red]"
599
- sql_preview = (r.sql[:80] + "...") if len(r.sql) > 80 else r.sql
600
- console.print(f" {i}. {status} [{r.query_type}] {sql_preview}")
601
- continue
602
629
 
603
- if user_input.lower() == ":auto":
604
- auto_execute = True
605
- print_success("Auto-execute enabled. Read queries will run automatically.")
606
- continue
630
+ if cmd_name in [":models", ":providers", ":ai"]:
631
+ curr_model = model or getattr(llm, "default_model", "default")
632
+ console.print(f"\n[bold cyan]Active AI Provider:[/bold cyan] [bold white]{llm.name}[/bold white]")
633
+ console.print(f"[bold cyan]Active Model:[/bold cyan] [bold green]{curr_model}[/bold green]")
634
+ console.print("[dim]Switch anytime: [bold]:provider <ollama|gemini|groq|openrouter>[/bold] or [bold]:model <name>[/bold][/dim]\n")
635
+ continue
607
636
 
608
- if user_input.lower() == ":noauto":
609
- auto_execute = False
610
- print_info("Auto-execute disabled. All queries will show SQL only. Use :run to execute.")
611
- continue
637
+ if cmd_name == ":explain":
638
+ if last_result and last_result.sql:
639
+ print_code(last_result.sql, "sql", "Last Executed SQL")
640
+ console.print(f"[dim]Query type: {last_result.query_type} | Intent: {last_result.intent} | Retries: {last_result.retries}[/dim]")
641
+ if last_result.exact_tables:
642
+ console.print(f"[dim]Tables (exact): {', '.join(last_result.exact_tables)}[/dim]")
643
+ if last_result.fuzzy_tables:
644
+ console.print(f"[dim]Tables (fuzzy): {', '.join(last_result.fuzzy_tables)}[/dim]")
645
+ else:
646
+ print_warning("No previous query to explain.")
647
+ continue
612
648
 
613
- if user_input.lower() == ":run":
614
- if not last_result or not last_result.sql:
615
- print_warning("No generated SQL query to run.")
649
+ if cmd_name == ":history":
650
+ if not query_history:
651
+ print_warning("No query history in this session.")
652
+ continue
653
+ for i, r in enumerate(query_history[-10:], 1):
654
+ status = "[green]OK[/green]" if r.success else "[red]FAIL[/red]"
655
+ sql_preview = (r.sql[:80] + "...") if len(r.sql) > 80 else r.sql
656
+ console.print(f" {i}. {status} [{r.query_type}] {sql_preview}")
657
+ continue
658
+
659
+ if cmd_name == ":auto":
660
+ auto_execute = True
661
+ print_success("Auto-execute enabled. Read queries will run automatically.")
662
+ continue
663
+
664
+ if cmd_name == ":noauto":
665
+ auto_execute = False
666
+ print_info("Auto-execute disabled. All queries will show SQL only. Use :run to execute.")
667
+ continue
668
+
669
+ if cmd_name == ":run":
670
+ if not last_result or not last_result.sql:
671
+ print_warning("No generated SQL query to run.")
672
+ continue
673
+ if last_result.was_executed:
674
+ console.print("[dim]Re-executing last query...[/dim]")
675
+ cols, rows, err = connector.execute_query(last_result.sql, limit=100)
676
+ if err:
677
+ print_error(f"Execution error: {err}")
678
+ else:
679
+ print_results_table(cols, rows)
680
+ continue
681
+
682
+ if cmd_name == ":export":
683
+ if not cmd_arg:
684
+ print_warning("Usage: :export <file_path> (e.g. :export query.sql)")
685
+ continue
686
+ if not last_result or not last_result.sql:
687
+ print_warning("No code block to export.")
688
+ continue
689
+ p = Path(cmd_arg)
690
+ p.parent.mkdir(parents=True, exist_ok=True)
691
+ p.write_text(last_result.sql, encoding="utf-8")
692
+ print_success(f"SQL saved to {p}")
616
693
  continue
617
- if last_result.was_executed:
618
- # Re-run the last query
619
- console.print("[dim]Re-executing last query...[/dim]")
620
- cols, rows, err = connector.execute_query(last_result.sql, limit=100)
621
- if err:
622
- print_error(f"Execution error: {err}")
623
- else:
624
- print_results_table(cols, rows)
694
+
695
+ print_warning(f"Unknown command '{user_input}'. Type [bold]:help[/bold] to see all in-chat commands.")
625
696
  continue
626
697
 
627
- if user_input.startswith(":export "):
628
- file_target = user_input.split(" ", 1)[1].strip()
698
+ if user_input.lower() in ["exit", "quit", "q"]:
699
+ console.print("[bold cyan]Goodbye![/bold cyan]")
700
+ break
629
701
  if not last_result or not last_result.sql:
630
702
  print_warning("No code block to export.")
631
703
  continue
@@ -782,7 +854,7 @@ def models_command():
782
854
  gemini = get_llm_provider("gemini")
783
855
  gemini_status = "[green]Configured[/green]" if gemini.is_available() else "[yellow]Not Configured (Free Key: aistudio.google.com)[/yellow]"
784
856
  console.print(f"\n2. [bold white]Google Gemini (Free Tier)[/bold white] - Status: {gemini_status}")
785
- console.print(" Available Models: `gemini-2.0-flash`, `gemini-1.5-flash`, `gemini-1.5-pro`")
857
+ console.print(" Available Models: `gemini-3.6-flash`, `gemini-2.5-flash`, `gemini-2.5-pro`")
786
858
 
787
859
  groq = get_llm_provider("groq")
788
860
  groq_status = "[green]Configured[/green]" if groq.is_available() else "[yellow]Not Configured (Free Key: console.groq.com)[/yellow]"
@@ -922,5 +994,24 @@ def setup_command(
922
994
  console.print(" * [bold]db-agent guide[/bold] -> View full command reference\n")
923
995
 
924
996
 
997
+ # ---- use ----
998
+
999
+ @app.command(name="use")
1000
+ def use_command(
1001
+ provider_name: str = typer.Argument(..., help="AI provider name (ollama, gemini, groq, openrouter)"),
1002
+ model: Optional[str] = typer.Option(None, "--model", "-m", help="Optional default model name"),
1003
+ ):
1004
+ """Switch the default AI provider (e.g. `db-agent use gemini` or `db-agent use ollama`)."""
1005
+ p = provider_name.lower()
1006
+ if p not in ["ollama", "gemini", "groq", "openrouter", "mock"]:
1007
+ print_error(f"Invalid provider '{provider_name}'. Supported: ollama, gemini, groq, openrouter")
1008
+ raise typer.Exit(1)
1009
+
1010
+ config_mgr.set_setting("default_provider", p)
1011
+ if model:
1012
+ config_mgr.set_setting(f"{p}_default_model", model)
1013
+ print_success(f"Default AI provider switched to [bold cyan]{p}[/bold cyan]!")
1014
+
1015
+
925
1016
  if __name__ == "__main__":
926
1017
  app()
@@ -447,19 +447,22 @@ class RelationalConnector(BaseConnector):
447
447
  limit: int = 100,
448
448
  ) -> Tuple[List[str], List[Dict[str, Any]], Optional[str]]:
449
449
  """Safely execute a query with row limit."""
450
+ clean_q = query.strip()
450
451
  try:
451
452
  with self.engine.connect() as conn:
452
453
  try:
453
- result = conn.exec_driver_sql(query)
454
+ conn = conn.execution_options(isolation_level="AUTOCOMMIT")
454
455
  except Exception:
455
- result = conn.execute(text(query))
456
+ pass
457
+
458
+ try:
459
+ result = conn.exec_driver_sql(clean_q)
460
+ except Exception:
461
+ result = conn.execute(text(clean_q))
462
+
456
463
  if not result.returns_rows:
457
- # DML: commit and report affected rows
458
- try:
459
- conn.commit()
460
- except Exception:
461
- pass
462
464
  return ["status"], [{"status": "Query executed successfully."}], None
465
+
463
466
  columns = list(result.keys())
464
467
  raw_rows = result.fetchmany(limit)
465
468
  rows = [
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dbagent-cli
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: Universal Database Introspection and Script Generation AI Agent (CLI)
5
5
  Author: Santhosh Gupta
6
6
  Requires-Python: >=3.9
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dbagent-cli"
7
- version = "0.1.6"
7
+ version = "0.1.8"
8
8
  description = "Universal Database Introspection and Script Generation AI Agent (CLI)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
File without changes
File without changes