dbagent-cli 0.1.7__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.7 → dbagent_cli-0.1.8}/PKG-INFO +1 -1
  2. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/__init__.py +1 -1
  3. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/cli.py +177 -108
  4. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/connectors/relational.py +10 -7
  5. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/PKG-INFO +1 -1
  6. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/pyproject.toml +1 -1
  7. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/README.md +0 -0
  8. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/agent/generator.py +0 -0
  9. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/agent/pipeline.py +0 -0
  10. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/agent/validator.py +0 -0
  11. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/config.py +0 -0
  12. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/connectors/base.py +0 -0
  13. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/connectors/factory.py +0 -0
  14. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/connectors/mongo.py +0 -0
  15. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/auto_setup.py +0 -0
  16. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/base.py +0 -0
  17. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/factory.py +0 -0
  18. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/gemini_provider.py +0 -0
  19. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/groq_provider.py +0 -0
  20. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/mock_provider.py +0 -0
  21. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/ollama_provider.py +0 -0
  22. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/llm/openrouter_provider.py +0 -0
  23. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/schema/formatter.py +0 -0
  24. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/schema/models.py +0 -0
  25. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/schema/selector.py +0 -0
  26. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/ui/console.py +0 -0
  27. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent/ui/viewer.py +0 -0
  28. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/SOURCES.txt +0 -0
  29. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/dependency_links.txt +0 -0
  30. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/entry_points.txt +0 -0
  31. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/requires.txt +0 -0
  32. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/dbagent_cli.egg-info/top_level.txt +0 -0
  33. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/setup.cfg +0 -0
  34. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/tests/test_cli.py +0 -0
  35. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/tests/test_connectors.py +0 -0
  36. {dbagent_cli-0.1.7 → dbagent_cli-0.1.8}/tests/test_generator.py +0 -0
  37. {dbagent_cli-0.1.7 → 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.7
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.7"
5
+ __version__ = "0.1.8"
6
6
  __author__ = "Santhosh Gupta"
@@ -524,130 +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.startswith(":model ") or user_input.startswith(":provider ") or user_input.startswith(":use "):
582
- parts = user_input.split(maxsplit=2)
583
- if len(parts) > 1:
584
- new_target = parts[1].strip()
585
- if new_target.lower() in ["ollama", "gemini", "groq", "openrouter", "mock"]:
586
- llm = get_llm_provider(provider_name=new_target.lower(), config_mgr=config_mgr)
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)
587
614
  model = None
588
615
  print_success(f"Switched AI provider to [bold cyan]{llm.name}[/bold cyan]")
589
616
  else:
590
- model = new_target
591
- print_success(f"Switched active model to [bold cyan]{model}[/bold cyan] (Provider: {llm.name})")
592
- else:
593
- print_info(f"Active AI Provider: [bold cyan]{llm.name}[/bold cyan] | Model: [bold green]{model or getattr(llm, 'default_model', 'default')}[/bold green]")
594
- continue
617
+ print_error(f"Unknown provider '{cmd_arg}'. Supported: ollama, gemini, groq, openrouter")
618
+ continue
595
619
 
596
- if user_input.lower() in [":models", ":providers", ":ai"]:
597
- curr_model = model or getattr(llm, "default_model", "default")
598
- console.print(f"\n[bold cyan]Active AI Provider:[/bold cyan] [bold white]{llm.name}[/bold white]")
599
- console.print(f"[bold cyan]Active Model:[/bold cyan] [bold green]{curr_model}[/bold green]")
600
- console.print("[dim]Switch on the fly: [bold]:provider <ollama|gemini|groq|openrouter>[/bold] or [bold]:model <model_name>[/bold][/dim]\n")
601
- continue
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})")
628
+ continue
602
629
 
603
- if user_input.lower() == ":explain":
604
- if last_result and last_result.sql:
605
- print_code(last_result.sql, "sql", "Last Executed SQL")
606
- console.print(f"[dim]Query type: {last_result.query_type} | Intent: {last_result.intent} | Retries: {last_result.retries}[/dim]")
607
- if last_result.exact_tables:
608
- console.print(f"[dim]Tables (exact): {', '.join(last_result.exact_tables)}[/dim]")
609
- if last_result.fuzzy_tables:
610
- console.print(f"[dim]Tables (fuzzy): {', '.join(last_result.fuzzy_tables)}[/dim]")
611
- else:
612
- print_warning("No previous query to explain.")
613
- 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
614
636
 
615
- if user_input.lower() == ":history":
616
- if not query_history:
617
- print_warning("No query history in this session.")
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.")
618
647
  continue
619
- for i, r in enumerate(query_history[-10:], 1):
620
- status = "[green]OK[/green]" if r.success else "[red]FAIL[/red]"
621
- sql_preview = (r.sql[:80] + "...") if len(r.sql) > 80 else r.sql
622
- console.print(f" {i}. {status} [{r.query_type}] {sql_preview}")
623
- continue
624
648
 
625
- if user_input.lower() == ":auto":
626
- auto_execute = True
627
- print_success("Auto-execute enabled. Read queries will run automatically.")
628
- continue
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
629
658
 
630
- if user_input.lower() == ":noauto":
631
- auto_execute = False
632
- print_info("Auto-execute disabled. All queries will show SQL only. Use :run to execute.")
633
- continue
659
+ if cmd_name == ":auto":
660
+ auto_execute = True
661
+ print_success("Auto-execute enabled. Read queries will run automatically.")
662
+ continue
634
663
 
635
- if user_input.lower() == ":run":
636
- if not last_result or not last_result.sql:
637
- print_warning("No generated SQL query to run.")
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}")
638
693
  continue
639
- if last_result.was_executed:
640
- # Re-run the last query
641
- console.print("[dim]Re-executing last query...[/dim]")
642
- cols, rows, err = connector.execute_query(last_result.sql, limit=100)
643
- if err:
644
- print_error(f"Execution error: {err}")
645
- else:
646
- print_results_table(cols, rows)
694
+
695
+ print_warning(f"Unknown command '{user_input}'. Type [bold]:help[/bold] to see all in-chat commands.")
647
696
  continue
648
697
 
649
- if user_input.startswith(":export "):
650
- 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
651
701
  if not last_result or not last_result.sql:
652
702
  print_warning("No code block to export.")
653
703
  continue
@@ -804,7 +854,7 @@ def models_command():
804
854
  gemini = get_llm_provider("gemini")
805
855
  gemini_status = "[green]Configured[/green]" if gemini.is_available() else "[yellow]Not Configured (Free Key: aistudio.google.com)[/yellow]"
806
856
  console.print(f"\n2. [bold white]Google Gemini (Free Tier)[/bold white] - Status: {gemini_status}")
807
- 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`")
808
858
 
809
859
  groq = get_llm_provider("groq")
810
860
  groq_status = "[green]Configured[/green]" if groq.is_available() else "[yellow]Not Configured (Free Key: console.groq.com)[/yellow]"
@@ -944,5 +994,24 @@ def setup_command(
944
994
  console.print(" * [bold]db-agent guide[/bold] -> View full command reference\n")
945
995
 
946
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
+
947
1016
  if __name__ == "__main__":
948
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.7
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.7"
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