@rohit_patil/db-core
v1.0.4
Published
Core database layer with PostgreSQL and Redis caching for microservices
Maintainers
Readme
@rohit_patil/db-core
A comprehensive TypeScript-based database core layer for microservices with PostgreSQL and Redis caching support.
Version: 1.0.4 | License: MIT | Language: TypeScript
🚀 Quick Links
- Installation
- Quick Start
- Auto-Sync Feature (NEW!)
- Read/Write Replicas (NEW!)
- 30+ Supported Models
- Complete Documentation
- API Reference
✨ Features
Core Database Features
- 🗄️ PostgreSQL Connection Pooling - Efficient connection management with pg
- 💾 Redis Caching - Automatic query result caching
- 🔨 Query Builder - Fluent API for building SQL queries
- 📦 Repository Pattern - Clean data access layer
- 🔄 Transaction Support - ACID-compliant transactions
- 📊 Migration System - Database version control
- 🎯 TypeScript - Full type safety and IntelliSense
- ⚡ Performance - Optimized queries with caching
- 🔍 Logging - Built-in query and error logging
New in v1.0.1 🎉
- 🚀 Auto-Sync - Automatic database creation and schema synchronization
- 📋 30+ Models - Complete model definitions (tenants, users, properties, tax, activities, meetings, etc.)
- 🔀 Read/Write Replicas - Horizontal scaling with separate read and write databases
- ⚖️ Load Balancing - Round-robin, weighted, and random strategies
- 🎯 Microservice Ready - Production-ready patterns for distributed systems
Installation
npm install @rohit_patil/db-core pg redisQuick Start
1. Environment Configuration
Create a .env file:
# Primary Database Configuration (Write)
DB_HOST=localhost
DB_PORT=5432
DB_NAME=your_database
DB_USER=postgres
DB_PASSWORD=your_password
DB_POOL_MIN=2
DB_POOL_MAX=10
# Read Replicas (Optional - for scaling)
DB_READ_REPLICA_1_HOST=replica-1.example.com
DB_READ_REPLICA_1_PORT=5432
DB_READ_REPLICA_1_WEIGHT=2
DB_LOAD_BALANCING=weighted
# Redis Configuration
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
REDIS_KEY_PREFIX=app:
REDIS_DEFAULT_TTL=36002. Initialize DBCore
import { DBCore } from '@rohit_patil/db-core';
const db = new DBCore();
try {
// Basic initialization
await db.initialize();
console.log('✅ Connected to database');
// OR with auto-sync (creates database and all tables automatically)
await db.initialize({
ensureDatabase: true, // Create database if it doesn't exist
syncSchema: true, // Create all 30+ tables automatically
});
console.log('✅ Database and schema ready!');
} catch (error) {
console.error('❌ Connection failed:', error);
}
// Use the database
const users = await db.table('users').get();
// Close connections when done
await db.close();
📚 Core Features
Auto-Sync Feature (NEW! 🎉)
Automatically create database and sync all 30+ tables:
import { DBCore } from '@rohit_patil/db-core';
// Option 1: Auto-sync on initialization
const db = new DBCore(undefined, undefined, { autoSync: true });
await db.initialize({ ensureDatabase: true, syncSchema: true });
// Option 2: Manual sync after initialization
const db2 = new DBCore();
await db2.initialize();
await db2.syncSchema();
// Check schema status
const isUpToDate = await db.isSchemaUpToDate();
const tables = await db.getExistingTables();
console.log(`Tables: ${tables.length}, Up to date: ${isUpToDate}`);📚 See AUTO_SYNC.md for complete guide
Read/Write Replicas (NEW! 🎉)
Scale your database horizontally with read replicas:
import { ReplicaManager, getDatabaseConfigWithReplicas } from '@rohit_patil/db-core';
// Initialize with replicas
const rm = new ReplicaManager(getDatabaseConfigWithReplicas());
await rm.connect();
// Writes go to primary database
await rm.executeWrite(
'INSERT INTO users (username, email) VALUES ($1, $2)',
['john', '[email protected]']
);
// Reads go to replica databases (load balanced)
const users = await rm.executeRead('SELECT * FROM users WHERE is_active = true');
// Transactions always on primary
await rm.transaction(async (client) => {
await client.query('UPDATE accounts SET balance = balance - 100 WHERE id = 1');
await client.query('UPDATE accounts SET balance = balance + 100 WHERE id = 2');
});
// Monitor connection stats
const stats = rm.getStats();
console.log('Write pool:', stats.write);
console.log('Read replicas:', stats.read.length);Benefits:
- ✅ Distribute read load across multiple databases
- ✅ Reduce primary database load by 50-80%
- ✅ 2-3x faster read performance
- ✅ Horizontal scalability
- ✅ Automatic failover to primary if replicas unavailable
📚 See READ_REPLICAS.md for complete guide
Query Builder
// Select with conditions
const activeUsers = await db.table('users')
.select('id', 'username', 'email')
.where('is_active', '=', true)
.where('created_at', '>', '2024-01-01')
.orderBy('created_at', 'DESC')
.limit(10)
.get();
// Joins
const usersWithRoles = await db.table('users')
.select('users.*', 'roles.name as role_name')
.innerJoin('user_roles', 'users.id = user_roles.user_id')
.innerJoin('roles', 'user_roles.role_id = roles.id')
.get();
// Pagination
const paginatedUsers = await db.table('users')
.paginate({ page: 1, limit: 20 });
// With caching
const cachedUsers = await db.table('users')
.withCache(3600, 'users') // Cache for 1 hour
.get();
// Aggregations
const userCount = await db.table('users')
.where('is_active', '=', true)
.count();Repository Pattern
// Basic CRUD operations
const userRepo = db.repository('users');
// Create
const newUser = await userRepo.create({
username: 'john_doe',
email: '[email protected]',
password_hash: 'hashed_password',
full_name: 'John Doe'
});
// Find by ID
const user = await userRepo.findById(1);
// Find by column
const usersByEmail = await userRepo.findBy('email', '[email protected]');
// Update
await userRepo.update(1, { full_name: 'John Smith' });
// Delete
await userRepo.delete(1);
// Pagination
const paginatedResult = await userRepo.findPaginated({ page: 1, limit: 20 });Custom Repository
import { BaseRepository, User } from '@your-org/db-core';
class UserRepository extends BaseRepository<User> {
constructor(db, cache) {
super('users', db, cache, 'user');
}
async findByUsername(username: string): Promise<User | null> {
return this.findOneBy('username', username);
}
async findActiveUsers(): Promise<User[]> {
return this.query()
.where('is_active', '=', true)
.orderBy('created_at', 'DESC')
.get();
}
async search(query: string): Promise<User[]> {
const sql = `
SELECT * FROM users
WHERE full_name ILIKE $1 OR email ILIKE $1
ORDER BY created_at DESC
`;
return this.raw(sql, [`%${query}%`]);
}
}
// Usage
const userRepo = new UserRepository(db.getDatabase(), db.getCache());
const user = await userRepo.findByUsername('john_doe');Transactions
await db.transaction(async (client) => {
// All queries within this callback are part of the same transaction
await client.query(
'INSERT INTO users (username, email, password_hash, full_name) VALUES ($1, $2, $3, $4)',
['jane_doe', '[email protected]', 'hashed_password', 'Jane Doe']
);
await client.query(
'INSERT INTO user_roles (user_id, role_id) VALUES ($1, $2)',
[2, 1]
);
// If any query fails, all changes are rolled back
});Redis Caching
const cache = db.getCache();
if (cache) {
// Set value with TTL
await cache.set('user:1', { id: 1, name: 'John' }, 3600);
// Get value
const user = await cache.get('user:1');
// Delete value
await cache.del('user:1');
// Delete pattern
await cache.delPattern('user:*');
// Check existence
const exists = await cache.exists('user:1');
// Increment/Decrement
await cache.incr('views:post:123');
await cache.decr('views:post:123');
}Migrations
import { MigrationManager, Migration } from '@your-org/db-core';
// Define migration
const createUsersTable: Migration = {
id: '001',
name: '001_create_users_table',
async up(client) {
await client.query(`
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
},
async down(client) {
await client.query('DROP TABLE users');
}
};
// Run migrations
const migrationManager = new MigrationManager(db.getDatabase());
migrationManager.register(createUsersTable);
// Run pending migrations
await migrationManager.up();
// Rollback last migration
await migrationManager.down();
// Check status
const status = await migrationManager.status();
console.log('Executed:', status.executed);
console.log('Pending:', status.pending);Advanced Configuration
Custom Configuration
import { DBCore, DatabaseConfig, RedisConfig } from '@your-org/db-core';
const dbConfig: DatabaseConfig = {
host: 'localhost',
port: 5432,
database: 'mydb',
user: 'postgres',
password: 'password',
min: 2,
max: 10,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 5000,
ssl: false
};
const redisConfig: RedisConfig = {
host: 'localhost',
port: 6379,
password: undefined,
db: 0,
keyPrefix: 'myapp:',
defaultTTL: 3600
};
const db = new DBCore(dbConfig, redisConfig);
await db.initialize();Event Listeners
// Listen to database events
db.on('connect', () => {
console.log('Database connected');
});
db.on('disconnect', () => {
console.log('Database disconnected');
});
db.on('error', (error) => {
console.error('Database error:', error);
});
db.on('query', (data) => {
console.log('Query executed:', data);
});API Reference
DBCore
Main class that combines database and cache functionality.
Methods
initialize(options?)- Connect to database and cacheoptions.ensureDatabase- Create database if it doesn't existoptions.syncSchema- Synchronize database schema
close()- Close all connectionstable(tableName)- Create a query builderrepository(tableName, cachePrefix?)- Create a repositorytransaction(callback)- Execute a transactionquery(sql, params?)- Execute raw queryqueryOne(sql, params?)- Execute query and return first rowqueryMany(sql, params?)- Execute query and return all rowssyncSchema()- Manually sync database schema (NEW)getExistingTables()- Get list of existing tables (NEW)isSchemaUpToDate()- Check if schema is up to date (NEW)getDatabase()- Get database managergetCache()- Get cache managergetPoolStats()- Get connection pool statisticson(event, listener)- Add event listener
QueryBuilder
Fluent interface for building SQL queries.
Methods
select(...columns)- Select columnswhere(column, operator, value)- Add WHERE conditionwhereIn(column, values)- Add WHERE IN conditionwhereNotIn(column, values)- Add WHERE NOT IN conditionwhereBetween(column, value1, value2)- Add WHERE BETWEEN conditionwhereNull(column)- Add WHERE NULL conditionwhereNotNull(column)- Add WHERE NOT NULL conditionjoin(type, table, on, alias?)- Add JOINinnerJoin(table, on, alias?)- Add INNER JOINleftJoin(table, on, alias?)- Add LEFT JOINorderBy(column, direction)- Add ORDER BYgroupBy(...columns)- Add GROUP BYhaving(condition)- Add HAVINGlimit(value)- Set LIMIToffset(value)- Set OFFSETwithCache(ttl?, keyPrefix?)- Enable cachingget()- Execute and return all resultsfirst()- Execute and return first resultpaginate(options)- Execute with paginationcount()- Execute count queryinsert(data)- Insert recordupdate(data)- Update recordsdelete()- Delete records
BaseRepository
Base class for creating custom repositories.
Methods
findById(id)- Find by IDfindAll()- Find all recordsfindPaginated(options)- Find with paginationfindBy(column, value)- Find by columnfindOneBy(column, value)- Find one by columncreate(data)- Create recordupdate(id, data)- Update recorddelete(id)- Delete recordcount()- Count recordsexists(id)- Check if exists
RedisManager
Redis cache management.
Methods
connect()- Connect to Redisdisconnect()- Disconnect from Redisset(key, value, ttl?)- Set valueget(key)- Get valuedel(key)- Delete valuedelPattern(pattern)- Delete by patternexists(key)- Check if existsexpire(key, ttl)- Set expirationttl(key)- Get TTLclear()- Clear all keys with prefixincr(key)- Increment valuedecr(key)- Decrement value
ReplicaManager (NEW)
Read/write replica management for horizontal scaling.
Methods
connect()- Connect to primary and replica databasesdisconnect()- Disconnect from all databasesexecuteWrite(sql, params?)- Execute write query on primaryexecuteRead(sql, params?)- Execute read query on replicatransaction(callback)- Execute transaction on primarygetWritePool()- Get primary database poolgetReadPool()- Get read replica pool (load balanced)getStats()- Get connection statistics for all poolsisConnected()- Check if connected
SchemaManager (NEW)
Database schema management and synchronization.
Methods
ensureDatabaseExists()- Create database if it doesn't existsyncSchema(pool)- Synchronize all tablesgetExistingTables(pool)- Get list of existing tablesisSchemaUpToDate(pool)- Check if all tables exist
Supported Models (30+ Tables)
All models from your reference Sequelize implementation are included:
Core Models
- Tenant & Users: tenants, users, roles, user_roles
- Properties: wards, property_types, property_addresses, properties
- Tax System: tax_types, tax_calculation_types, tax_rates, tax_contracts, tax_assessments, tax_payments, tax_receipts, miscellaneous_payments
- Activities: activity_types, activity_templates, activities, activity_participants, activity_reports
- Meetings: meetings, meeting_templates, meeting_attendees, meeting_topics, meeting_resolutions
- System: audit_logs
All tables include:
- Primary keys with auto-increment
- Foreign key relationships
- Indexes for performance
- Multi-tenant support (tenant_id)
- Timestamps (created_at, updated_at)
- Soft deletes where applicable
TypeScript Support
This package is written in TypeScript and includes full type definitions.
import { DBCore, User, QueryBuilder, Tenant, Property } from '@rohit_patil/db-core';
// Type-safe queries
const db = new DBCore();
const userQuery: QueryBuilder<User> = db.table<User>('users');
const users: User[] = await userQuery.get();
// All 30+ models have type definitions
const tenants: Tenant[] = await db.table('tenants').get();
const properties: Property[] = await db.table('properties').get();Best Practices
General
- Always close connections - Use
db.close()when done - Use transactions - For operations that need to be atomic
- Enable caching - For frequently accessed data
- Use repositories - For complex domain logic
- Handle errors - Always use try-catch blocks
- Use connection pooling - Don't create multiple DBCore instances
- Monitor pool stats - Use
getPoolStats()for debugging
Read/Write Replicas
- Use
executeReadfor SELECT queries - Distribute load to replicas - Use
executeWritefor INSERT/UPDATE/DELETE - Ensure data consistency - Use transactions for multi-query operations - Always on primary
- Be aware of replication lag - Read from primary after writes if critical
- Monitor replica health - Check
getStats()regularly - Size pools appropriately - More connections for read replicas
Auto-Sync
- Use in development - Fast iteration with automatic schema creation
- Verify in production - Use
isSchemaUpToDate()before starting - Keep schema definitions updated - Single source of truth
- Test migrations - Before applying to production
- Backup before sync - Always backup production databases
Performance Tips
- Use prepared statements (parameterized queries)
- Enable query caching for read-heavy operations
- Use pagination for large result sets
- Create appropriate database indexes
- Monitor connection pool usage
- Use transactions sparingly
Troubleshooting
Connection Issues
// Check if connected
if (db.initialized()) {
console.log('Connected');
}
// Check pool stats
const stats = db.getPoolStats();
console.log('Pool stats:', stats);Cache Issues
// Check if Redis is available
const cache = db.getCache();
if (cache && cache.connected()) {
console.log('Redis connected');
} else {
console.log('Redis not available');
}Contributing
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch
- Write tests for new features
- Ensure all tests pass
- Submit a pull request
License
MIT
📖 Documentation
Comprehensive guides for all features:
- README.md - This file, overview and quick start
- AUTO_SYNC.md - Complete auto-sync feature guide
- READ_REPLICAS.md - Read/write replica setup and usage
- MIGRATION_STRATEGY.md - Migration approach and strategy
- QUICK_START.md - 5-minute quick start guide
- COMPLETE_FEATURES.md - All features with examples
- UPDATE_SUMMARY.md - What's new in v1.0.1
- examples/ - Working code examples
Support
For issues and questions, please open an issue on GitHub.
Changelog
v1.0.0
- Initial release with core features
v1.0.1
- bug fix
v1.0.2
- Added automatic database creation and schema synchronization
- Added 30+ model definitions from Sequelize reference
- Added read/write replica support for horizontal scaling
- Added load balancing strategies (round-robin, weighted, random)
- Added comprehensive documentation and examples
- Enhanced DBCore with schema management methods
v1.0.3
- Added cache invalidation strategies
- Added cache key builder
- Added cache invalidation manager
v1.0.4 (Latest)
- Documentation updates
- Cache invalidation examples
