Skip to content

Commit a94a557

Browse files
evantahlerCopilot
andauthored
Update postgres docs (#368)
* Update postgres docs * Update pages/toolkits/databases/postgres.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent bc202c1 commit a94a557

7 files changed

Lines changed: 150 additions & 26 deletions

pages/toolkits/databases/postgres.mdx

Lines changed: 95 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,64 @@ import ToolFooter from "@/components/ToolFooter";
1616

1717
<Badges repo="arcadeai/arcade-postgres" />
1818

19-
The Arcade Postgres toolkit provides a pre-built set of tools for interacting with PostgreSQL databases in a read-only manner.
19+
The Arcade Postgres toolkit provides a pre-built set of tools for interacting with PostgreSQL databases in a read-only manner. This toolkit enables agents to discover database schemas, explore table structures, and execute SELECT queries safely. This toolkit is a companion to the blog post [Designing SQL Tools for AI Agents](https://blog.arcade.dev/sql-tools-ai-agents-security).
2020

2121
<Note>
22-
This toolkit is meant to be an example of how to build a toolkit for a database, and is not intended to be used in production. For production use, we recommend forking this repository and building your own toolkit with use-case specific tools.
22+
This toolkit is meant to be an example of how to build a toolkit for a database, and is not intended to be used in production. For production use, we recommend forking this repository and building your own toolkit with use-case specific tools.
2323
</Note>
2424

25+
## Key Features
2526

26-
This repository demonstrates a few concepts to aid in LLM-powered database interactions.
27-
* Re-use an existing database pool for all tool calls
28-
* Enforce read-only access to the database
29-
* Hint to the LLM that both table and schema discovery is required before executing a query
30-
* Enforce a limit on the number of rows returned by a query
27+
This toolkit demonstrates several important concepts for LLM-powered database interactions:
28+
29+
* **Schema Discovery**: Automatically discover available database schemas
30+
* **Table Exploration**: Find all tables within a specific schema
31+
* **Schema Inspection**: Get detailed column information including data types, primary keys, and indexes
32+
* **Safe Query Execution**: Execute SELECT queries with built-in safety measures
33+
* **Connection Pooling**: Reuse database connections efficiently
34+
* **Read-Only Access**: Enforce read-only access to prevent data modification
35+
* **Row Limits**: Automatically limit query results to prevent overwhelming responses
3136

3237
## Available Tools
3338

3439
<TableOfContents
3540
headers={["Tool Name", "Description"]}
3641
data={
3742
[
38-
['Postgres.DiscoverTables', "Discover all tables in a PostgreSQL database."],
39-
['Postgres.GetTableSchema', "Get the schema of a table in a PostgreSQL database."],
40-
['Postgres.ExecuteQuery', "Execute a query on a PostgreSQL database."],
43+
['Postgres.DiscoverSchemas', "Discover all schemas in a PostgreSQL database."],
44+
['Postgres.DiscoverTables', "Discover all tables in a specific schema."],
45+
['Postgres.GetTableSchema', "Get the detailed schema of a specific table."],
46+
['Postgres.ExecuteSelectQuery', "Execute a SELECT query with comprehensive clause support."],
4147
]
4248
}
4349
/>
4450

4551
Note that all tools require the `DATABASE_CONNECTION_STRING` secret to be set.
4652

53+
## Postgres.DiscoverSchemas
54+
55+
Discover all schemas in a PostgreSQL database. This tool returns a list of all available schemas, excluding the `information_schema` for security.
56+
57+
<TabbedCodeBlock
58+
tabs={[
59+
{
60+
label: "Call the Tool",
61+
content: {
62+
Python: [
63+
"/examples/integrations/toolkits/postgres/discover_schemas_example_call_tool.py",
64+
],
65+
JavaScript: ["/examples/integrations/toolkits/postgres/discover_schemas_example_call_tool.js"],
66+
},
67+
}
68+
]}
69+
/>
70+
4771
## Postgres.DiscoverTables
4872

49-
Discover all tables in a PostgreSQL database.
73+
Discover all tables in a specific schema. This tool should be used before any other tool that requires a table name.
74+
75+
**Parameters:**
76+
- `schema_name` (str): The database schema to discover tables in (default: "public")
5077

5178
<TabbedCodeBlock
5279
tabs={[
@@ -61,9 +88,14 @@ Discover all tables in a PostgreSQL database.
6188
}
6289
]}
6390
/>
91+
6492
## Postgres.GetTableSchema
6593

66-
Get the schema of a table in a PostgreSQL database.
94+
Get the detailed schema of a specific table. This tool provides column information including data types, primary key indicators, and index information. Always use this tool before executing any query.
95+
96+
**Parameters:**
97+
- `schema_name` (str): The database schema containing the table
98+
- `table_name` (str): The name of the table to inspect
6799

68100
<TabbedCodeBlock
69101
tabs={[
@@ -78,20 +110,67 @@ Get the schema of a table in a PostgreSQL database.
78110
}
79111
]}
80112
/>
81-
## Postgres.ExecuteQuery
113+
114+
## Postgres.ExecuteSelectQuery
115+
116+
Execute a SELECT query with comprehensive clause support. This tool allows you to build complex queries using individual clauses while maintaining safety and performance.
117+
118+
**Parameters:**
119+
- `select_clause` (str): Columns to select (without SELECT keyword)
120+
- `from_clause` (str): Table(s) to query from (without FROM keyword)
121+
- `limit` (int): Maximum rows to return (default: 100)
122+
- `offset` (int): Number of rows to skip (default: 0)
123+
- `join_clause` (str, optional): JOIN conditions (without JOIN keyword)
124+
- `where_clause` (str, optional): WHERE conditions (without WHERE keyword)
125+
- `having_clause` (str, optional): HAVING conditions (without HAVING keyword)
126+
- `group_by_clause` (str, optional): GROUP BY columns (without GROUP BY keyword)
127+
- `order_by_clause` (str, optional): ORDER BY columns (without ORDER BY keyword)
128+
- `with_clause` (str, optional): WITH clause for CTEs (without WITH keyword)
129+
130+
**Query Construction:**
131+
The final query is constructed as:
132+
```sql
133+
SELECT {select_clause} FROM {from_clause}
134+
JOIN {join_clause}
135+
WHERE {where_clause}
136+
HAVING {having_clause}
137+
GROUP BY {group_by_clause}
138+
ORDER BY {order_by_clause}
139+
LIMIT {limit} OFFSET {offset}
140+
```
141+
142+
**Best Practices:**
143+
- Always use `discover_tables` and `get_table_schema` before executing queries
144+
- Never use "SELECT *" - always specify the columns you need
145+
- Order results by primary keys or important columns
146+
- Use case-insensitive string matching
147+
- Trim strings in queries
148+
- Prefer LIKE queries over exact matches or regex
149+
- Only join on indexed columns or primary keys
82150

83151
<TabbedCodeBlock
84152
tabs={[
85153
{
86154
label: "Call the Tool",
87155
content: {
88156
Python: [
89-
"/examples/integrations/toolkits/postgres/execute_query_example_call_tool.py",
157+
"/examples/integrations/toolkits/postgres/execute_select_query_example_call_tool.py",
90158
],
91-
JavaScript: ["/examples/integrations/toolkits/postgres/execute_query_example_call_tool.js"],
159+
JavaScript: ["/examples/integrations/toolkits/postgres/execute_select_query_example_call_tool.js"],
92160
},
93161
}
94162
]}
95163
/>
96164

97-
Execute a query on a PostgreSQL database. Be sure that your agent runs the `Postgres.DiscoverTables` and `Postgres.GetTableSchema` tools before executing a query.
165+
## Usage Workflow
166+
167+
For optimal results, follow this workflow when using the Postgres toolkit:
168+
169+
1. **Discover Schemas**: Use `discover_schemas` to see available schemas
170+
2. **Discover Tables**: Use `discover_tables` with your target schema
171+
3. **Get Table Schema**: Use `get_table_schema` for each table you plan to query
172+
4. **Execute Query**: Use `execute_select_query` with the schema information
173+
174+
This workflow ensures your agent has complete information about the database structure before attempting queries, reducing errors and improving query performance.
175+
176+
<ToolFooter />

public/examples/integrations/toolkits/postgres/execute_query_example_call_tool.js renamed to public/examples/integrations/toolkits/postgres/discover_schemas_example_call_tool.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ import { Arcade } from "@arcadeai/arcadejs";
33
const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
44

55
const USER_ID = "{arcade_user_id}";
6-
const TOOL_NAME = "Postgres.ExecuteQuery";
6+
const TOOL_NAME = "Postgres.DiscoverSchemas";
77

8-
const toolInput = {
9-
query: "SELECT * FROM users",
10-
};
8+
const toolInput = {};
119

1210
const response = await client.tools.execute({
1311
tool_name: TOOL_NAME,

public/examples/integrations/toolkits/postgres/execute_query_example_call_tool.py renamed to public/examples/integrations/toolkits/postgres/discover_schemas_example_call_tool.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22

33
client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
44

5-
TOOL_NAME = "Postgres.ExecuteQuery"
5+
TOOL_NAME = "Postgres.DiscoverSchemas"
66

77
user_id = "{arcade_user_id}"
88

9-
tool_input = {
10-
"query": "SELECT * FROM users",
11-
}
9+
tool_input = {}
1210

1311
response = client.tools.execute(
1412
tool_name=TOOL_NAME,

public/examples/integrations/toolkits/postgres/discover_tables_example_call_tool.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env var
55
const USER_ID = "{arcade_user_id}";
66
const TOOL_NAME = "Postgres.DiscoverTables";
77

8-
const toolInput = {};
8+
const toolInput = {
9+
schema_name: "public",
10+
};
911

1012
const response = await client.tools.execute({
1113
tool_name: TOOL_NAME,

public/examples/integrations/toolkits/postgres/discover_tables_example_call_tool.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
user_id = "{arcade_user_id}"
88

9-
tool_input = {}
9+
tool_input = {
10+
"schema_name": "public",
11+
}
1012

1113
response = client.tools.execute(
1214
tool_name=TOOL_NAME,
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Arcade } from "@arcadeai/arcadejs";
2+
3+
const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
4+
5+
const USER_ID = "{arcade_user_id}";
6+
const TOOL_NAME = "Postgres.ExecuteSelectQuery";
7+
8+
const toolInput = {
9+
select_clause: "id, name, email",
10+
from_clause: "users",
11+
where_clause: "active = true",
12+
order_by_clause: "name",
13+
limit: 10,
14+
};
15+
16+
const response = await client.tools.execute({
17+
tool_name: TOOL_NAME,
18+
input: toolInput,
19+
user_id: USER_ID,
20+
});
21+
22+
console.log(response.output.value);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from arcadepy import Arcade
2+
3+
client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
4+
5+
TOOL_NAME = "Postgres.ExecuteSelectQuery"
6+
7+
user_id = "{arcade_user_id}"
8+
9+
tool_input = {
10+
"select_clause": "id, name, email",
11+
"from_clause": "users",
12+
"where_clause": "active = true",
13+
"order_by_clause": "name",
14+
"limit": 10,
15+
}
16+
17+
response = client.tools.execute(
18+
tool_name=TOOL_NAME,
19+
input=tool_input,
20+
user_id=user_id,
21+
)
22+
23+
print(response.output.value)

0 commit comments

Comments
 (0)