|
|
||
|---|---|---|
| .. | ||
| API_REFERENCE.md | ||
| DEVELOPER_GUIDE.md | ||
| QUICK_REFERENCE.md | ||
| README.md | ||
| index.js | ||
| knex.js | ||
README.md
Query Helper - JSON-Based Database Interface
A centralized, SQL-string-free database query helper built on Knex.js that provides a safe, structured interface for all database operations.
🎯 Goals
- No Raw SQL: All queries built using Knex query builder
- JSON-Based: Structured JSON objects instead of SQL strings
- Type Safe: Parameterized queries prevent SQL injection
- Server-Only: Internal helper, not exposed to API clients
- Production Ready: Error handling, validation, and security built-in
📦 Installation
Knex.js is already installed. The query helper uses the existing database connection from db/pool.js.
🚀 Quick Start
import { select, insert, update, deleteRecord, execute } from '../db/queryHelper/index.js';
// SELECT
const users = await select({
table: 'users',
where: { deleted: false },
limit: 10
});
// INSERT
const user = await insert({
table: 'users',
data: { name: 'John', phone_number: '+1234567890' },
returning: '*'
});
// UPDATE
const updated = await update({
table: 'users',
data: { name: 'Jane' },
where: { id: userId },
returning: '*'
});
// DELETE
await deleteRecord({
table: 'users',
where: { id: userId }
});
// TRANSACTION
await execute({
type: 'transaction',
handler: async (trx) => {
await trx('users').insert(userData);
await trx('listings').insert(listingData);
}
});
📚 API Reference
select(options)
Retrieve records from database.
Options:
table(string, required): Table name (must be in whitelist)columns(string[] | '', optional): Columns to select (default: '')where(object, optional): WHERE conditionsorderBy(object, optional):{ column: string, direction: 'asc'|'desc' }limit(number, optional): Max records (capped at 100)offset(number, optional): Skip recordsjoins(array, optional): Join configurations
Returns: Promise<object[]>
insert(options)
Insert new record(s).
Options:
table(string, required): Table namedata(object | object[], required): Data to insertreturning(string[] | '*', optional): Columns to return
Returns: Promise<object | object[]>
update(options)
Update existing records.
Options:
table(string, required): Table namedata(object, required): Data to updatewhere(object, required): WHERE conditions (required for safety)returning(string[] | '*', optional): Columns to return
Returns: Promise<object[]>
deleteRecord(options)
Delete records.
Options:
table(string, required): Table namewhere(object, required): WHERE conditions (required for safety)returning(string[] | '*', optional): Columns to return
Returns: Promise<object[]>
execute(options)
Execute transactions or custom query builder logic.
Options:
type(string, required): 'transaction' or 'raw-builder'handler(function, required): Handler function receiving knex/trx instance
Returns: Promise<any>
🔍 WHERE Clause Operators
Simple Equality
where: { status: 'active' }
// WHERE status = 'active'
Comparison Operators
where: {
price: { op: '>=', value: 1000 },
age: { op: '<', value: 65 }
}
// WHERE price >= 1000 AND age < 65
IN Operator
where: {
id: { op: 'in', value: ['uuid1', 'uuid2', 'uuid3'] }
}
// WHERE id IN ('uuid1', 'uuid2', 'uuid3')
LIKE Operator
where: {
name: { op: 'ilike', value: '%john%' }
}
// WHERE name ILIKE '%john%'
BETWEEN Operator
where: {
age: { op: 'between', value: [18, 65] }
}
// WHERE age BETWEEN 18 AND 65
NULL Checks
where: {
deleted_at: { op: 'isNull' }
}
// WHERE deleted_at IS NULL
🔒 Security Features
- Table Whitelist: Only allowed tables can be queried
- Parameterized Queries: All values are parameterized
- WHERE Required: UPDATE/DELETE require WHERE clause
- Limit Caps: Maximum 100 records per query
- No SQL Strings: Impossible to inject SQL
📋 Allowed Tables
The following tables are whitelisted:
userslistingsanimalslocationsspeciesbreedslisting_mediaconversationsmessagescommunication_recordsfavoritesuser_devicessubscription_plansotp_requestsauth_audit
To add more tables, update ALLOWED_TABLES in queryHelper.js.
🎓 Examples
See db/queryHelper/examples.js for comprehensive examples.
📖 Migration Guide
See db/MIGRATION_EXAMPLE.md for before/after comparisons.
🔄 API Reference
See db/QUERY_HELPER_MAPPING.md for complete method reference and examples.
⚠️ Important Notes
- No Raw SQL: Never use
pool.query()with SQL strings - Always Use WHERE: UPDATE/DELETE must include WHERE clause
- Table Names: Must be in whitelist (case-sensitive)
- Transactions: Use
execute({ type: 'transaction' })for multi-step operations - Complex Queries: Use
execute({ type: 'raw-builder' })for advanced cases
🐛 Error Handling
The query helper throws descriptive errors:
Table 'xxx' is not allowed- Table not in whitelistWHERE clause is required- Missing WHERE for UPDATE/DELETEUnsupported operator: xxx- Invalid operator- Database errors are propagated with context
📝 Best Practices
- Use Transactions: For multi-step operations
- Soft Deletes: Use UPDATE instead of DELETE
- Limit Results: Always set reasonable limits
- Validate Input: Validate data before passing to helper
- Handle Errors: Wrap in try-catch blocks
- Use Returning: Get inserted/updated records back
🔧 Advanced Usage
Complex Joins
const results = await select({
table: 'listings',
columns: ['listings.*', 'animals.*'],
joins: [
{
type: 'inner',
table: 'animals',
on: 'listings.animal_id = animals.id'
}
],
where: { 'listings.deleted': false }
});
Custom Query Builder
const results = await execute({
type: 'raw-builder',
handler: async (knex) => {
return await knex('listings')
.select('listings.*')
.join('animals', 'listings.animal_id', 'animals.id')
.where('listings.deleted', false)
.where('animals.species_id', speciesId)
.orderBy('listings.created_at', 'desc')
.limit(20);
}
});
📚 Documentation
- DEVELOPER_GUIDE.md - Complete developer guide with examples, flow diagrams, and best practices
- QUICK_REFERENCE.md - One-page quick reference card for daily use
- API_REFERENCE.md - Complete API reference with all methods and options
📞 Support
For questions or issues, refer to:
DEVELOPER_GUIDE.md- Comprehensive guide with real-world examples from the codebaseQUICK_REFERENCE.md- Quick lookup for common patternsAPI_REFERENCE.md- Complete method documentation