Skip to content

Commit c083c00

Browse files
committed
docs: Add /query/sql endpoint and RETURN DISTINCT to wiki
- Document POST /query/sql production endpoint with array format - Add examples for curl, Python, PowerShell - Document role management (SET ROLE in array) - Add RETURN DISTINCT documentation with use cases - Note distinction between /query?sql_only=true (deprecated) vs /query/sql (preferred)
1 parent 7ac304b commit c083c00

2 files changed

Lines changed: 169 additions & 0 deletions

File tree

docs/wiki/API-Reference-HTTP.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,130 @@ Invoke-RestMethod -Method POST -Uri "http://localhost:8080/query" `
173173

174174
---
175175

176+
### POST /query/sql
177+
178+
**SQL Generation Endpoint** - Translate Cypher to ClickHouse SQL without execution.
179+
180+
This production endpoint returns SQL statements as an array, including role management commands when applicable.
181+
182+
**Request:**
183+
```http
184+
POST /query/sql HTTP/1.1
185+
Content-Type: application/json
186+
187+
{
188+
"query": "MATCH (u:User)-[:FOLLOWS]->(f:User) WHERE u.name = 'Alice' RETURN f.name",
189+
"schema_name": "social_network",
190+
"role": "analyst"
191+
}
192+
```
193+
194+
**Parameters:**
195+
- `query` (string, required): Cypher query to translate
196+
- `schema_name` (string, optional): Schema to use (defaults to "default")
197+
- `target_database` (string, optional): Target SQL dialect - "clickhouse" (default) or "postgresql" (future)
198+
- `parameters` (object, optional): Query parameters for `$param` placeholders
199+
- `view_parameters` (object, optional): Parameters for parameterized views
200+
- `role` (string, optional): ClickHouse role for RBAC
201+
- `include_plan` (boolean, optional): Include logical plan in response (default: false)
202+
203+
**Response:**
204+
```json
205+
{
206+
"cypher_query": "MATCH (u:User)-[:FOLLOWS]->(f:User) WHERE u.name = 'Alice' RETURN f.name",
207+
"target_database": "clickhouse",
208+
"sql": [
209+
"SET ROLE analyst",
210+
"SELECT f.full_name AS \"f.name\" FROM users AS u INNER JOIN follows ON follows.follower_id = u.user_id INNER JOIN users AS f ON f.user_id = follows.followed_id WHERE u.full_name = 'Alice'"
211+
],
212+
"role": "analyst",
213+
"metadata": {
214+
"query_type": "read",
215+
"cache_status": "HIT",
216+
"parse_time_ms": 0.152,
217+
"planning_time_ms": 2.341,
218+
"sql_generation_time_ms": 0.892,
219+
"total_time_ms": 3.385
220+
}
221+
}
222+
```
223+
224+
**Key Features:**
225+
- **Array Format**: SQL returned as array of statements to execute in order
226+
- **Role Management**: Includes `SET ROLE` statement when role parameter provided
227+
- **No Execution**: SQL is generated but not executed against ClickHouse
228+
- **Performance Metrics**: Detailed timing breakdown for optimization
229+
- **Cache Status**: Shows if SQL was retrieved from query cache
230+
231+
**Use Cases:**
232+
- **Query Debugging**: Inspect generated SQL before execution
233+
- **External Execution**: Use SQL in other tools or pipelines
234+
- **Performance Analysis**: Understand query planning decisions
235+
- **Integration**: Embed ClickGraph translation in existing workflows
236+
237+
**Examples:**
238+
239+
**curl:**
240+
```bash
241+
# Basic SQL generation
242+
curl -X POST http://localhost:8080/query/sql \
243+
-H "Content-Type: application/json" \
244+
-d '{"query": "MATCH (u:User) RETURN u.name LIMIT 10"}'
245+
246+
# With role (includes SET ROLE in array)
247+
curl -X POST http://localhost:8080/query/sql \
248+
-H "Content-Type: application/json" \
249+
-d '{
250+
"query": "MATCH (u:User) WHERE u.age > 25 RETURN u.name",
251+
"role": "analyst"
252+
}'
253+
254+
# With logical plan
255+
curl -X POST http://localhost:8080/query/sql \
256+
-H "Content-Type: application/json" \
257+
-d '{
258+
"query": "MATCH (u:User)-[:FOLLOWS*1..3]->(f) RETURN f.name",
259+
"include_plan": true
260+
}'
261+
```
262+
263+
**Python:**
264+
```python
265+
import requests
266+
267+
# Generate SQL with role
268+
response = requests.post('http://localhost:8080/query/sql', json={
269+
'query': 'MATCH (u:User)-[:FOLLOWS]->(f) WHERE u.name = $name RETURN f.name',
270+
'parameters': {'name': 'Alice'},
271+
'role': 'analyst'
272+
})
273+
274+
data = response.json()
275+
print(f"SQL Statements: {data['sql']}")
276+
print(f"Generation Time: {data['metadata']['total_time_ms']}ms")
277+
278+
# Execute SQL externally (without SET ROLE)
279+
from clickhouse_driver import Client
280+
ch_client = Client(host='localhost')
281+
for stmt in data['sql']:
282+
if not stmt.startswith('SET ROLE'):
283+
result = ch_client.execute(stmt)
284+
```
285+
286+
**PowerShell:**
287+
```powershell
288+
# Generate SQL
289+
$response = Invoke-RestMethod -Method POST -Uri "http://localhost:8080/query/sql" `
290+
-ContentType "application/json" `
291+
-Body '{"query":"MATCH (u:User) RETURN u.name LIMIT 10"}'
292+
293+
$response.sql
294+
```
295+
296+
> **Note**: The older `/query?sql_only=true` endpoint returns SQL as a single string in `generated_sql` field. The `/query/sql` endpoint is preferred as it returns an array and includes role management statements.
297+
298+
---
299+
176300
## Schema Management
177301

178302
### GET /schemas

docs/wiki/Cypher-Language-Reference.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,51 @@ WHERE (a)-[:FOLLOWS*1..2]->(b)
254254

255255
Specify what to return from the query.
256256

257+
### RETURN DISTINCT
258+
259+
De-duplicate results when multiple paths lead to the same node.
260+
261+
**Syntax:**
262+
```cypher
263+
RETURN DISTINCT expression [AS alias]
264+
```
265+
266+
**When to Use:**
267+
- Multi-hop traversals where multiple paths reach the same node
268+
- Avoiding duplicate results in complex graph patterns
269+
- Queries with multiple relationship types to the same target
270+
271+
**Examples:**
272+
273+
```cypher
274+
// Friend-of-friend with de-duplication
275+
MATCH (me:User)-[:FOLLOWS]->(friend)-[:FOLLOWS]->(fof:User)
276+
WHERE me.name = 'Alice'
277+
RETURN DISTINCT fof.name
278+
// Without DISTINCT: May return same person multiple times (via different friends)
279+
// With DISTINCT: Each person appears once
280+
281+
// Find all users connected within 2 hops
282+
MATCH (start:User)-[:FOLLOWS*1..2]->(connected:User)
283+
WHERE start.user_id = 1
284+
RETURN DISTINCT connected.name
285+
286+
// Multiple relationship types
287+
MATCH (a:User)-[:FOLLOWS|FRIENDS_WITH]->(b:User)
288+
RETURN DISTINCT b.name
289+
```
290+
291+
**Implementation:**
292+
- Generates `SELECT DISTINCT` in ClickHouse SQL
293+
- Applied after all filters and joins
294+
- Works with expressions, not just node properties
295+
296+
```cypher
297+
// DISTINCT on computed values
298+
MATCH (u:User)
299+
RETURN DISTINCT u.age / 10 AS age_decade
300+
```
301+
257302
### Basic Returns
258303

259304
```cypher

0 commit comments

Comments
 (0)