AI-powered query generation for Lotus.
Configuration
Configure AI in your application config:
config :lotus,
ai: [
enabled: true,
model: "anthropic:claude-opus-4",
api_key: {:system, "ANTHROPIC_API_KEY"}
]The model key accepts any model string supported by ReqLLM, e.g.:
"openai:gpt-4o"(default)"anthropic:claude-opus-4""google:gemini-2.0-flash""groq:llama-3.3-70b-versatile"- Any other provider supported by ReqLLM
Usage
{:ok, result} = Lotus.AI.generate_query(
prompt: "Show me all users who signed up last month",
data_source: "postgres"
)
# Returns:
# %{
# sql: "SELECT * FROM users WHERE created_at >= ...",
# variables: [],
# model: "openai:gpt-4o",
# usage: %{total_tokens: 150}
# }Error Handling
The generate_query/1 function returns structured error tuples that clients can
pattern match on for custom handling and internationalization (i18n):
{:ok, result}- Successfully generated SQL query{:error, :not_configured}- AI features not enabled in config{:error, :api_key_not_configured}- API key missing or invalid{:error, {:unable_to_generate, reason}}- LLM refused (non-SQL question){:error, term}- Other errors (API failures, network issues, etc.)
Summary
Functions
Check if AI features are enabled and configured.
Get an AI-powered plain-language explanation of a SQL query.
Generate SQL query from natural language prompt.
Generate SQL query from natural language prompt with conversation context.
Get the configured AI model string.
Get AI-powered optimization suggestions for a SQL query.
Functions
@spec enabled?() :: boolean()
Check if AI features are enabled and configured.
Returns true if AI is properly configured, false otherwise.
Examples
Lotus.AI.enabled?()
# => true
Get an AI-powered plain-language explanation of a SQL query.
Supports explaining a full query or a selected fragment. When a fragment is provided, the full query is sent as context so the AI can explain even isolated terms accurately.
Options
:sql(required) - The full SQL query:fragment(optional) - A selected portion of the query to explain:data_source(required) - Name of the data source to resolve schema context
Returns
{:ok, result}- Map with:explanation,:model, and:usage{:error, term}- Structured error tuple
Examples
# Explain a full query
{:ok, result} = Lotus.AI.explain_query(
sql: "SELECT d.name, COUNT(o.id) FROM departments d LEFT JOIN orders o ...",
data_source: "postgres"
)
result.explanation
# => "This query shows departments ranked by total order count..."
# Explain a selected fragment
{:ok, result} = Lotus.AI.explain_query(
sql: "SELECT d.name FROM departments d LEFT JOIN employees e ON e.department_id = d.id",
fragment: "LEFT JOIN employees e ON e.department_id = d.id",
data_source: "postgres"
)
Generate SQL query from natural language prompt.
Uses the globally configured AI provider from application config.
Options
:prompt(required) - Natural language description of desired query:data_source(required) - Name of the data source to query against:read_only(optional) - Whentrue(default), the AI only generates read-only queries. Set tofalseto allow the AI to generate write queries.
Returns
{:ok, result}- Successfully generated SQL with metadata{:error, term}- Structured error tuple (see module docs for error types)
Examples
{:ok, result} = Lotus.AI.generate_query(
prompt: "Count active users by signup month",
data_source: "postgres"
)
result.sql
# => "SELECT DATE_TRUNC('month', created_at) as month, COUNT(*) FROM users WHERE status = 'active' GROUP BY month"
result.model
# => "openai:gpt-4o"
result.usage
# => %{prompt_tokens: 150, completion_tokens: 50, total_tokens: 200}
# Error handling with pattern matching
{:error, :not_configured} = Lotus.AI.generate_query(
prompt: "some query",
data_source: "postgres"
)
Generate SQL query from natural language prompt with conversation context.
Enables multi-turn conversations by accepting conversation history. The AI can refine queries, fix errors, and provide iterative improvements.
Options
:prompt(required) - Natural language description of desired query:data_source(required) - Name of the data source to query against:conversation(optional) - Conversation struct with message history:read_only(optional) - Whentrue(default), the AI only generates read-only queries. Set tofalseto allow the AI to generate write queries.
Returns
{:ok, result}- Successfully generated SQL with metadata{:error, term}- Structured error tuple (see module docs for error types)
Examples
# Simple single-turn (same as generate_query/1)
{:ok, result} = Lotus.AI.generate_query_with_context(
prompt: "Show active users",
data_source: "postgres"
)
# Multi-turn with conversation history
conversation = Conversation.new()
conversation = Conversation.add_user_message(conversation, "Show active users")
{:ok, result} = Lotus.AI.generate_query_with_context(
prompt: "Show active users",
data_source: "postgres",
conversation: conversation
)
# If query fails, add error to conversation
conversation = Conversation.add_query_result(conversation, {:error, "column 'status' not found"})
# AI can now fix the error with full context
{:ok, fixed_result} = Lotus.AI.generate_query_with_context(
prompt: "Fix the error",
data_source: "postgres",
conversation: conversation
)
@spec model() :: {:ok, String.t()} | {:error, :not_configured}
Get the configured AI model string.
Returns the full model string (e.g. "openai:gpt-4o") if configured.
Examples
Lotus.AI.model()
# => {:ok, "openai:gpt-4o"}
Get AI-powered optimization suggestions for a SQL query.
Runs EXPLAIN on the query to get the execution plan, then uses AI to analyze both the SQL and plan for potential improvements.
Options
:sql(required) - The SQL query to optimize:data_source(required) - Name of the data source to run against:params(optional) - Query parameters (default:[]):search_path(optional) - PostgreSQL search path
Returns
{:ok, result}- Map with suggestions list, model, and usage info{:error, term}- Structured error tuple
Examples
{:ok, result} = Lotus.AI.suggest_optimizations(
sql: "SELECT * FROM orders WHERE created_at > '2024-01-01'",
data_source: "postgres"
)
result.suggestions
# => [
# %{
# "type" => "index",
# "impact" => "high",
# "title" => "Add index on orders.created_at",
# "suggestion" => "..."
# }
# ]