A secure, intelligent text-to-database query converter with LLM integration for building AI-powered chatbots and natural language database interfaces.
- Features
- Installation
- Quick Start
- Configuration
- Usage Examples
- Security Features
- API Reference
- JavaScript Usage
- Testing
- Troubleshooting
- Best Practices
- Contributing
- Easy Integration: One-line setup with Sequelize, Prisma, or direct database connections
- Multiple LLM Support: OpenAI (GPT-4, GPT-3.5) or Claude (Anthropic)
- Database Support: PostgreSQL, MySQL, SQLite, MongoDB, MS SQL Server
- Security First:
- SQL injection prevention
- Query operation restrictions
- Table and column access control
- Row-level security (automatic user filtering)
- Sensitive data protection
- Custom validation rules
- TypeScript & JavaScript: Full support for both environments
- Intelligent: Context-aware query generation with user permissions
- Well Tested: 63+ tests with 90%+ coverage on security components
npm install text-db-query-ai
# Install your ORM (optional)
npm install sequelize # For Sequelize
npm install @prisma/client prisma # For Prisma
# Install database driver (choose one)
npm install pg # For PostgreSQL
npm install mysql2 # For MySQL
npm install sqlite3 # For SQLiteimport { createChatbotFromSequelize } from 'text-db-query-ai';
// Just pass your Sequelize instance - schema is automatically extracted!
const chatbot = await createChatbotFromSequelize(sequelize, {
llmProvider: 'openai',
apiKey: process.env.OPENAI_API_KEY!,
});
// Ask questions and get results!
const result = await chatbot.ask('Show all users');
console.log(result.results); // Actual data from your database
console.log(result.query); // Generated SQL queryimport { PrismaClient } from '@prisma/client';
import { createChatbotFromPrisma } from 'text-db-query-ai';
const prisma = new PrismaClient();
const chatbot = await createChatbotFromPrisma(prisma, 'postgres', {
llmProvider: 'openai',
apiKey: process.env.OPENAI_API_KEY!,
});
const result = await chatbot.ask('Show my recent orders', {
userId: 123,
role: 'user',
});import pg from 'pg';
import { createChatbotFromDatabase } from 'text-db-query-ai';
const pool = new pg.Pool({
host: 'localhost',
database: 'mydb',
user: 'user',
password: 'password',
});
const chatbot = await createChatbotFromDatabase(pool, 'postgres', {
llmProvider: 'openai',
apiKey: process.env.OPENAI_API_KEY!,
});
const result = await chatbot.ask('Show all orders from last week');interface EasySetupOptions {
llmProvider: 'openai' | 'claude';
apiKey: string;
model?: string; // Optional: defaults to 'gpt-4o-mini' or 'claude-3-5-sonnet-20241022'
temperature?: number; // Optional: defaults to 0.1 for consistency
security?: SecurityConfig;
}interface SecurityConfig {
// Only allow specific SQL operations
allowedOperations?: ('SELECT' | 'INSERT' | 'UPDATE' | 'DELETE')[];
// Only allow access to specific tables
allowedTables?: string[];
// Block access to sensitive columns
restrictedColumns?: string[];
// Maximum rows that can be returned
maxRowLimit?: number;
// Require user context for all queries
requireUserContext?: boolean;
// Automatically filter queries by user_id
enableRowLevelSecurity?: boolean;
// Custom validation function
customValidator?: (query: string, context?: UserContext) => Promise<boolean>;
}const chatbot = await createChatbotFromSequelize(
sequelize,
{
llmProvider: 'openai',
apiKey: process.env.OPENAI_API_KEY!,
security: {
allowedOperations: ['SELECT'], // Read-only
allowedTables: ['users', 'orders'], // Only these tables
restrictedColumns: ['password', 'ssn'], // Never access these
maxRowLimit: 100, // Max 100 rows per query
enableRowLevelSecurity: true, // Auto-filter by user_id
requireUserContext: true, // Must provide user info
},
},
{
markSensitiveColumns: ['password', 'ssn', 'credit_card'],
}
);const chatbot = await createChatbotFromSequelize(sequelize, {
llmProvider: 'openai',
apiKey: process.env.OPENAI_API_KEY!,
});
// Simple query
const result = await chatbot.ask('Show active users from last month');
console.log(result.query); // Generated SQL
console.log(result.results); // Query results
console.log(result.warnings); // Any security warnings
// Query with user context (for row-level security)
const result2 = await chatbot.ask('Show my orders', {
userId: 123,
role: 'customer',
});
// Query with explanation
const result3 = await chatbot.askWithExplanation('Top 10 customers by revenue');
console.log(result3.explanation);
// "This query aggregates order totals by customer and sorts them..."import express from 'express';
import { createChatbotFromDatabase } from 'text-db-query-ai';
import pg from 'pg';
const app = express();
app.use(express.json());
const pool = new pg.Pool({ /* config */ });
const chatbot = await createChatbotFromDatabase(pool, 'postgres', {
llmProvider: 'openai',
apiKey: process.env.OPENAI_API_KEY!,
security: {
allowedOperations: ['SELECT'],
maxRowLimit: 100,
enableRowLevelSecurity: true,
},
});
app.post('/api/query', async (req, res) => {
try {
const { message, userId, role } = req.body;
// Generate and execute query
const result = await chatbot.ask(message, { userId, role });
res.json({
success: true,
data: result.results,
query: result.query,
warnings: result.warnings,
});
} catch (error: any) {
res.status(400).json({
success: false,
error: error.message,
});
}
});
app.listen(3000, () => {
console.log('Chatbot API running on http://localhost:3000');
});const chatbot = await createChatbotFromSequelize(sequelize, {
llmProvider: 'openai',
apiKey: process.env.OPENAI_API_KEY!,
security: {
allowedOperations: ['SELECT', 'INSERT'],
customValidator: async (query, userContext) => {
// Admins can do anything
if (userContext?.role === 'admin') {
return true;
}
// Regular users cannot use DELETE
if (query.toLowerCase().includes('delete')) {
return false;
}
// Business-specific validation
return true;
},
},
});const chatbot = await createChatbotFromPrisma(
prisma,
'postgres',
{
llmProvider: 'openai',
apiKey: process.env.OPENAI_API_KEY!,
security: {
// Block these columns from ever being accessed
restrictedColumns: ['password', 'ssn', 'credit_card'],
},
},
{
// Mark these as sensitive in schema (LLM will avoid them)
markSensitiveColumns: ['password', 'ssn', 'credit_card'],
}
);For complete control over configuration:
import { createQueryGenerator } from 'text-db-query-ai';
const generator = createQueryGenerator({
llm: {
provider: 'openai',
apiKey: process.env.OPENAI_API_KEY!,
model: 'gpt-4o-mini',
temperature: 0.1,
maxTokens: 1000,
},
database: {
databaseType: 'postgres',
tables: [
{
name: 'users',
columns: [
{ name: 'id', type: 'integer', description: 'User ID' },
{ name: 'email', type: 'varchar', description: 'User email' },
{ name: 'name', type: 'varchar', description: 'User name' },
{ name: 'created_at', type: 'timestamp' },
],
primaryKey: 'id',
},
{
name: 'orders',
columns: [
{ name: 'id', type: 'integer' },
{ name: 'user_id', type: 'integer' },
{ name: 'total', type: 'decimal' },
{ name: 'status', type: 'varchar' },
],
primaryKey: 'id',
foreignKeys: [
{ column: 'user_id', referencedTable: 'users', referencedColumn: 'id' },
],
},
],
},
security: {
allowedOperations: ['SELECT'],
maxRowLimit: 100,
},
});
// Generate query (doesn't execute)
const result = await generator.generateQuery(
'Show me orders from last week',
{ userId: 123, role: 'user' }
);
// You execute the query yourself
const data = await pool.query(result.query, result.parameters);Automatically detects and blocks:
- Multiple statements:
SELECT * FROM users; DROP TABLE users - UNION attacks:
SELECT * FROM users UNION SELECT * FROM passwords - Command execution:
EXEC xp_cmdshell 'dir' - Dangerous commands:
DROP,TRUNCATE,ALTER,CREATE - SQL comments: Used for injection attacks
Automatically filters queries by user ID:
// User asks: "Show all orders"
// Without RLS: SELECT * FROM orders
// With RLS: SELECT * FROM orders WHERE user_id = 123
const result = await chatbot.ask('Show all orders', {
userId: 123,
role: 'user',
});Fine-grained control over what can be accessed:
security: {
allowedOperations: ['SELECT'], // Only reads
allowedTables: ['users', 'orders'], // Only these tables
restrictedColumns: ['password', 'ssn'], // Never access these
maxRowLimit: 100, // Max 100 rows
}Require authentication for all queries:
security: {
requireUserContext: true,
}
// This will fail
await chatbot.ask('Show users'); // Error: User context required
// This works
await chatbot.ask('Show users', { userId: 123, role: 'admin' });Main class for easy integration:
class ChatbotHelper {
// Ask a question and get results
async ask(question: string, userContext?: UserContext): Promise<{
question: string;
query: string;
results: any[];
metadata?: {
operation: 'SELECT' | 'INSERT' | 'UPDATE' | 'DELETE';
tables: string[];
};
warnings?: string[];
}>
// Ask with detailed explanation
async askWithExplanation(question: string, userContext?: UserContext): Promise<{
question: string;
query: string;
explanation: string;
results: any[];
}>
}Lower-level API for advanced usage:
class QueryGenerator {
// Generate SQL from natural language
async generateQuery(userInput: string, userContext?: UserContext): Promise<QueryResult>
// Generate with explanation
async generateQueryWithExplanation(userInput: string, userContext?: UserContext): Promise<QueryResult>
// Validate LLM API key
async validateApiKey(): Promise<boolean>
// Get database schema as formatted string
getSchema(): string
// Get example queries for the schema
getExampleQueries(): string[]
}interface UserContext {
userId: string | number;
role: string;
permissions?: string[];
metadata?: Record<string, any>;
}
interface QueryResult {
query: string;
parameters?: any[];
explanation?: string;
warnings?: string[];
metadata?: {
operation: 'SELECT' | 'INSERT' | 'UPDATE' | 'DELETE';
tables: string[];
estimatedComplexity?: 'low' | 'medium' | 'high';
};
}The package works seamlessly with JavaScript (no TypeScript required):
const { createChatbotFromSequelize } = require('text-db-query-ai');
async function main() {
const chatbot = await createChatbotFromSequelize(sequelize, {
llmProvider: 'openai',
apiKey: process.env.OPENAI_API_KEY,
});
const result = await chatbot.ask('Show all users');
console.log(result.results);
}
main();import { createChatbotFromDatabase } from 'text-db-query-ai';
import pg from 'pg';
const pool = new pg.Pool({ /* config */ });
const chatbot = await createChatbotFromDatabase(pool, 'postgres', {
llmProvider: 'openai',
apiKey: process.env.OPENAI_API_KEY,
});
const result = await chatbot.ask('Show recent orders');
console.log(result.results);import { TextToQueryError } from 'text-db-query-ai';
try {
const result = await chatbot.ask('dangerous query');
} catch (error) {
if (error instanceof TextToQueryError) {
console.error(`Error Code: ${error.code}`);
console.error(`Message: ${error.message}`);
// Common error codes:
switch (error.code) {
case 'SECURITY_VALIDATION_FAILED':
// Query blocked by security rules
break;
case 'INVALID_SQL_SYNTAX':
// Generated SQL is invalid
break;
case 'OPENAI_API_ERROR':
case 'CLAUDE_API_ERROR':
// LLM API error (check API key, quota, etc.)
break;
case 'UNSUPPORTED_PROVIDER':
// Invalid LLM provider specified
break;
}
}
}# Run all tests
npm test
# Run with coverage report
npm run test:coverage
# Run security tests only
npm run test:security
# Run integration tests
npm run test:integration
# Watch mode for development
npm run test:watchThe package has comprehensive test coverage:
- Security Validator: 90% coverage (SQL injection, access control)
- Query Sanitizer: 95% coverage (input cleaning, validation)
- Schema Analyzer: 93% coverage (schema generation)
- Sequelize Adapter: 80% coverage (ORM integration)
- 63 total tests covering all critical functionality
Example test for custom integration:
import { createChatbotFromSequelize } from 'text-db-query-ai';
describe('My Chatbot', () => {
it('should generate safe queries', async () => {
const chatbot = await createChatbotFromSequelize(sequelize, {
llmProvider: 'openai',
apiKey: 'test-key',
security: {
allowedOperations: ['SELECT'],
},
});
const result = await chatbot.ask('Show users');
expect(result.query).toContain('SELECT');
expect(result.query).not.toContain('DROP');
});
});Problem: OPENAI_API_ERROR or CLAUDE_API_ERROR
Solutions:
- Verify API key is correct
- Check you have API credits/quota
- Ensure environment variable is loaded:
console.log(process.env.OPENAI_API_KEY); // Should not be undefined
- For OpenAI, check at https://platform.openai.com/api-keys
- For Claude, check at https://console.anthropic.com/
Problem: Queries are being blocked
Solutions:
- Check
allowedOperationsincludes the operation you need - Verify table names are in
allowedTables(if specified) - Ensure columns aren't in
restrictedColumns - Check if
requireUserContextis true but no context provided - Review custom validator logic if using one
Problem: Users can see other users' data
Solutions:
- Ensure
enableRowLevelSecurity: truein config - Always pass
userContextwithuserId:await chatbot.ask('Show orders', { userId: 123, role: 'user' });
- Verify your tables have a
user_idcolumn
Problem: Schema not detected from Sequelize/Prisma
Solutions:
- Ensure models are defined before calling setup function
- For Sequelize: call
sequelize.sync()first - For Prisma: run
prisma generatefirst - Check database connection is working
Problem: Generated queries are incorrect or suboptimal
Solutions:
- Add descriptions to your schema columns
- Use more specific questions
- Try different model (GPT-4 vs GPT-3.5)
- Add table/column descriptions in schema
- Use
askWithExplanation()to understand the reasoning
Problem: Cannot install package or dependencies
Solutions:
- Use Node.js 16 or higher:
node --version - Clear npm cache:
npm cache clean --force - Delete
node_modulesandpackage-lock.json, then reinstall - For sqlite3 issues, may need:
npm install sqlite3 --build-from-source
Create a .env file in your project:
# Required: Choose one LLM provider
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
# Database (if using direct connection)
DB_HOST=localhost
DB_PORT=5432
DB_NAME=mydb
DB_USER=user
DB_PASSWORD=passwordLoad with dotenv:
import 'dotenv/config';// Bad - no user context
const result = await chatbot.ask('Show orders');
// Good - includes user context for security
const result = await chatbot.ask('Show orders', {
userId: req.user.id,
role: req.user.role,
});security: {
allowedOperations: ['SELECT'], // Read-only
}security: {
maxRowLimit: 100, // Prevent large data dumps
}security: {
restrictedColumns: ['password', 'ssn', 'credit_card', 'api_key'],
}security: {
allowedTables: ['users', 'orders', 'products'], // Only these
}security: {
enableRowLevelSecurity: true, // Auto-filter by user_id
}const isValid = await generator.validateApiKey();
if (!isValid) {
throw new Error('Invalid LLM API key');
}try {
const result = await chatbot.ask(userInput);
return result;
} catch (error) {
if (error instanceof TextToQueryError) {
// Log error and return user-friendly message
console.error('Query error:', error.code, error.message);
return { error: 'Unable to process query. Please try again.' };
}
throw error;
}const result = await chatbot.askWithExplanation('complex query');
// Show explanation to user so they understand what's being queried
console.log(result.explanation);const result = await chatbot.ask(userInput, userContext);
// Log for audit trail
logger.info({
user: userContext.userId,
question: userInput,
query: result.query,
timestamp: new Date(),
});- PostgreSQL - Full support via
pg - MySQL - Full support via
mysql2 - SQLite - Full support via
sqlite3 - MongoDB - Supported (NoSQL queries)
- MS SQL Server - Supported via
mssql
- Sequelize - Automatic schema extraction
- Prisma - Automatic schema extraction
- Direct Database - Manual schema definition
Check the /examples directory for complete working examples:
basic-usage.ts- Simple getting started examplesequelize-integration.ts- Full Sequelize setupprisma-integration.ts- Full Prisma setupdirect-database.ts- Direct database connectionchatbot-express.ts- Express.js REST APIadvanced-security.ts- Complex security rulesjavascript-usage.js- CommonJS JavaScript examplejavascript-esm.mjs- ES Modules JavaScript example
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Make your changes
- Add tests for new functionality
- Ensure all tests pass:
npm test - Commit your changes:
git commit -am 'Add feature' - Push to the branch:
git push origin feature-name - Create a Pull Request
# Clone the repo
git clone https://github.com/yourusername/text-db-query-ai.git
cd text-db-query-ai
# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test
# Watch mode for development
npm run devMIT License - see LICENSE file for details
- Issues: Open an issue on GitHub
- Questions: Check the troubleshooting section above
- Feature Requests: Open an issue with the "enhancement" label
- Initial release
- OpenAI and Claude support
- Sequelize and Prisma integration
- Comprehensive security features
- 63+ tests with high coverage
- Full TypeScript and JavaScript support
Made with ❤️ for developers building AI-powered database interfaces