182 lines
4.8 KiB
Markdown
182 lines
4.8 KiB
Markdown
# Raw SQL Query Setup Guide
|
|
|
|
## Overview
|
|
|
|
The backend now supports raw SQL queries (Script 1 style) for complex options flow analysis. This guide explains how to set it up.
|
|
|
|
## Prerequisites
|
|
|
|
1. **Supabase RPC Function**: You need to create the `exec_sql` function in your Supabase database
|
|
2. **Script 1 SQL**: Your complex SQL query needs to be parameterized and added to the codebase
|
|
|
|
## Step 1: Create RPC Function in Supabase
|
|
|
|
Run the SQL from `database/rpc_functions.sql` in your Supabase SQL Editor:
|
|
|
|
```sql
|
|
CREATE OR REPLACE FUNCTION exec_sql(
|
|
query_text text,
|
|
params jsonb DEFAULT '[]'::jsonb
|
|
)
|
|
RETURNS jsonb
|
|
LANGUAGE plpgsql
|
|
SECURITY DEFINER
|
|
SET search_path = public
|
|
AS $$
|
|
-- See database/rpc_functions.sql for full definition
|
|
$$;
|
|
```
|
|
|
|
## Step 2: Add Your Script 1 SQL Query
|
|
|
|
1. **Open** `backend/src/queries/optionsFlowQuery.js`
|
|
2. **Find** the `optionsFlowQuerySQL` constant (around line 20)
|
|
3. **Replace** the placeholder comment with your actual Script 1 SQL query
|
|
4. **Parameterize** all values using `$1`, `$2`, `$3`, etc.
|
|
|
|
### Example Parameterization
|
|
|
|
**Before (hardcoded):**
|
|
```sql
|
|
WHERE created_at >= '2024-01-01'
|
|
AND created_at <= '2024-01-31'
|
|
AND total_premium >= 1000000
|
|
LIMIT 100;
|
|
```
|
|
|
|
**After (parameterized):**
|
|
```sql
|
|
WHERE created_at >= $1::date
|
|
AND created_at <= $2::date
|
|
AND total_premium >= $3::numeric
|
|
LIMIT $4::integer;
|
|
```
|
|
|
|
## Step 3: Update Parameter Builder
|
|
|
|
Update `buildOptionsFlowParams()` in `optionsFlowQuery.js` to match your SQL parameter order:
|
|
|
|
```javascript
|
|
export function buildOptionsFlowParams(params = {}) {
|
|
return [
|
|
params.startDate, // $1
|
|
params.endDate, // $2
|
|
params.minNotional, // $3
|
|
params.limit // $4
|
|
// Add more as needed
|
|
];
|
|
}
|
|
```
|
|
|
|
## Step 4: Enable Raw SQL in API Calls
|
|
|
|
### In Routes
|
|
|
|
The route automatically supports raw SQL via query parameter:
|
|
|
|
```javascript
|
|
// Use raw SQL
|
|
GET /api/options-flow?useRawSQL=true&startDate=2024-01-01&endDate=2024-01-31
|
|
|
|
// Use query builder (default)
|
|
GET /api/options-flow?startDate=2024-01-01
|
|
```
|
|
|
|
### In Code
|
|
|
|
```javascript
|
|
import { OptionsFlowQuery } from './queries/optionsFlowQuery.js';
|
|
|
|
// Use raw SQL
|
|
const flows = await OptionsFlowQuery.getRecentFlow(filters, true);
|
|
|
|
// Use query builder (default)
|
|
const flows = await OptionsFlowQuery.getRecentFlow(filters, false);
|
|
```
|
|
|
|
## Parameter Types
|
|
|
|
Use these PostgreSQL type casts in your SQL:
|
|
|
|
- **Dates**: `$1::date`, `$2::timestamp`
|
|
- **Numbers**: `$3::numeric`, `$4::integer`, `$5::float`
|
|
- **Text**: `$6::text`, `$7::varchar(10)`
|
|
- **Booleans**: `$8::boolean`
|
|
|
|
## Fallback Behavior
|
|
|
|
If raw SQL fails or isn't configured:
|
|
- The system automatically falls back to the query builder
|
|
- No errors are thrown (warning logged to console)
|
|
- API continues to work normally
|
|
|
|
This ensures backward compatibility and graceful degradation.
|
|
|
|
## Testing
|
|
|
|
### Test in Supabase SQL Editor First
|
|
|
|
```sql
|
|
SELECT * FROM exec_sql(
|
|
'SELECT * FROM options_flow WHERE created_at >= $1::date LIMIT $2::integer',
|
|
'["2024-01-01", 10]'::jsonb
|
|
);
|
|
```
|
|
|
|
### Test via API
|
|
|
|
```bash
|
|
# With raw SQL
|
|
curl "http://localhost:3001/api/options-flow?useRawSQL=true&startDate=2024-01-01&limit=10"
|
|
|
|
# Without (query builder)
|
|
curl "http://localhost:3001/api/options-flow?startDate=2024-01-01&limit=10"
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
Ensure your `.env` has:
|
|
|
|
```env
|
|
SUPABASE_URL=your_url
|
|
SUPABASE_KEY=your_service_key
|
|
SUPABASE_ANON_KEY=your_anon_key # Optional but recommended
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Error: "exec_sql RPC function not found"
|
|
|
|
- Run `database/rpc_functions.sql` in Supabase SQL Editor
|
|
- Verify the function exists: `SELECT proname FROM pg_proc WHERE proname = 'exec_sql';`
|
|
|
|
### Error: "SQL query failed"
|
|
|
|
- Check your SQL syntax in Supabase SQL Editor first
|
|
- Verify parameter types match (e.g., `$1::date` not `$1::text`)
|
|
- Check parameter count matches your `buildOptionsFlowParams()` function
|
|
|
|
### Query returns empty results
|
|
|
|
- Test the SQL directly in Supabase SQL Editor with sample parameters
|
|
- Verify date formats are correct (YYYY-MM-DD)
|
|
- Check table names and column names match your schema
|
|
|
|
## Security Notes
|
|
|
|
⚠️ **Important**: The `exec_sql` function uses `SECURITY DEFINER` which runs with elevated privileges.
|
|
|
|
- Only grant execute permission to trusted roles
|
|
- Always use parameterized queries (never string concatenation)
|
|
- Validate input parameters before passing to `rawQuery()`
|
|
- Consider creating specific stored procedures for each query type instead of generic `exec_sql`
|
|
|
|
## Best Practices
|
|
|
|
1. **Test First**: Always test SQL queries in Supabase SQL Editor before adding to code
|
|
2. **Parameterize Everything**: Never use string interpolation for SQL queries
|
|
3. **Type Safety**: Always use PostgreSQL type casts (`::date`, `::numeric`, etc.)
|
|
4. **Error Handling**: The system falls back gracefully, but log errors for debugging
|
|
5. **Documentation**: Document your SQL query parameters in code comments
|
|
|