api-v1/db/queryHelper/API_REFERENCE.md

195 lines
6.4 KiB
Markdown

# Query Helper API Reference
This document provides a complete reference for the JSON-based database query helper.
## Method Overview
| Method | Description | Notes |
|--------|-------------|-------|
| `select(options)` | Retrieve records from database | JSON-based query builder |
| `insert(options)` | Insert new record(s) | Single or batch insert |
| `update(options)` | Update existing records | Requires WHERE clause |
| `deleteRecord(options)` | Delete records | Requires WHERE clause |
| `execute(options)` | Execute transactions or custom queries | Transactions or raw builder |
## Detailed Method Reference
### SELECT
Retrieve records from database with filtering, sorting, and pagination.
```javascript
const users = await select({
table: 'users',
where: { deleted: false, status: 'active' },
orderBy: { column: 'created_at', direction: 'desc' },
limit: 20
});
```
**Options:**
- `table` (string, required): Table name (must be in whitelist)
- `columns` (string[] | '*', optional): Columns to select (default: '*')
- `where` (object, optional): WHERE conditions
- `orderBy` (object, optional): `{ column: string, direction: 'asc'|'desc' }`
- `limit` (number, optional): Max records (capped at 100)
- `offset` (number, optional): Skip records
- `joins` (array, optional): Join configurations
### INSERT
Insert new record(s) into database.
```javascript
const user = await insert({
table: 'users',
data: { name: 'John', phone: '+1234567890' },
returning: ['id', 'name']
});
```
**Options:**
- `table` (string, required): Table name
- `data` (object | object[], required): Data to insert (single object or array for batch)
- `returning` (string[] | '*', optional): Columns to return (PostgreSQL)
### UPDATE
Update existing records in database.
```javascript
const updated = await update({
table: 'users',
data: { name: 'Jane' },
where: { id: userId }
});
```
**Options:**
- `table` (string, required): Table name
- `data` (object, required): Data to update
- `where` (object, required): WHERE conditions (required for safety)
- `returning` (string[] | '*', optional): Columns to return
### DELETE
Delete records from database.
```javascript
await deleteRecord({
table: 'users',
where: { id: userId }
});
```
**Options:**
- `table` (string, required): Table name
- `where` (object, required): WHERE conditions (required for safety)
- `returning` (string[] | '*', optional): Columns to return
### EXECUTE (Transaction)
Execute transactions or custom query builder logic.
```javascript
await execute({
type: 'transaction',
handler: async (trx) => {
await trx('animals').insert(animalData);
await trx('listings').insert(listingData);
}
});
```
**Options:**
- `type` (string, required): 'transaction' or 'raw-builder'
- `handler` (function, required): Handler function receiving knex/trx instance
## WHERE Clause Operators
| Operator | Description | Example |
|----------|-------------|---------|
| Equality | Simple key-value match | `where: { status: 'active' }` |
| `>` | Greater than | `where: { price: { op: '>', value: 100 } }` |
| `<` | Less than | `where: { age: { op: '<', value: 18 } }` |
| `>=` | Greater than or equal | `where: { price: { op: '>=', value: 100 } }` |
| `<=` | Less than or equal | `where: { age: { op: '<=', value: 65 } }` |
| `!=` or `<>` | Not equal | `where: { status: { op: '!=', value: 'deleted' } }` |
| `in` | In array | `where: { id: { op: 'in', value: [1, 2, 3] } }` |
| `notIn` | Not in array | `where: { id: { op: 'notIn', value: [1, 2, 3] } }` |
| `like` | Case-sensitive LIKE | `where: { name: { op: 'like', value: '%John%' } }` |
| `ilike` | Case-insensitive LIKE | `where: { name: { op: 'ilike', value: '%john%' } }` |
| `between` | Between two values | `where: { age: { op: 'between', value: [18, 65] } }` |
| `isNull` | IS NULL | `where: { deleted_at: { op: 'isNull' } }` |
| `isNotNull` | IS NOT NULL | `where: { deleted_at: { op: 'isNotNull' } }` |
## Supported Operators
| Operator | Description | Example |
|----------|-------------|---------|
| `>` | Greater than | `{ op: '>', value: 100 }` |
| `<` | Less than | `{ op: '<', value: 100 }` |
| `>=` | Greater than or equal | `{ op: '>=', value: 100 }` |
| `<=` | Less than or equal | `{ op: '<=', value: 100 }` |
| `!=` or `<>` | Not equal | `{ op: '!=', value: 'deleted' }` |
| `in` | In array | `{ op: 'in', value: [1, 2, 3] }` |
| `notIn` | Not in array | `{ op: 'notIn', value: [1, 2, 3] }` |
| `like` | Case-sensitive LIKE | `{ op: 'like', value: '%test%' }` |
| `ilike` | Case-insensitive LIKE | `{ op: 'ilike', value: '%test%' }` |
| `between` | Between two values | `{ op: 'between', value: [10, 20] }` |
| `isNull` | IS NULL | `{ op: 'isNull' }` |
| `isNotNull` | IS NOT NULL | `{ op: 'isNotNull' }` |
## Naming Conventions
- **Table names**: lowercase, snake_case (e.g., `users`, `listing_media`)
- **Column names**: lowercase, snake_case (e.g., `created_at`, `user_id`)
- **Options**: camelCase (e.g., `orderBy`, `returning`)
- **Operators**: lowercase (e.g., `op: '>'`)
## Type System
- **JavaScript**: JSON objects with runtime validation
- **Runtime Validation**: Descriptive errors for invalid inputs
- **Type Safety**: Structured JSON prevents SQL injection
## Error Handling
- **Runtime Validation**: All inputs validated at runtime
- **Descriptive Errors**: Clear error messages for debugging
- **Database Errors**: Propagated with context
## Transactions
```javascript
await execute({
type: 'transaction',
handler: async (trx) => {
await trx('users').insert(userData);
await trx('listings').insert(listingData);
}
});
```
## Migration Checklist
When migrating from raw SQL to queryHelper:
- [ ] Replace `pool.query()` with `select()`, `insert()`, `update()`, or `deleteRecord()`
- [ ] Convert SQL WHERE clauses to JSON objects
- [ ] Replace string concatenation with structured options
- [ ] Convert transactions to `execute({ type: 'transaction' })`
- [ ] Update JOINs to use `joins` array
- [ ] Replace parameterized queries with JSON where conditions
- [ ] Test all queries to ensure same results
- [ ] Remove all raw SQL strings from service layer
## Benefits
1. **Type Safety**: Structured JSON prevents SQL injection
2. **Readability**: Clear, self-documenting queries
3. **Maintainability**: Easy to modify and extend
4. **Security**: Table whitelist prevents unauthorized access
5. **Consistency**: Uniform query interface across codebase
6. **Testing**: Easier to mock and test