# 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