@bhushanpawar/sqldb 1.0.24 β†’ 1.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +581 -1854
  2. package/dist/client.d.ts +23 -0
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +34 -0
  5. package/dist/client.js.map +1 -1
  6. package/dist/decorators/index.d.ts +2 -1
  7. package/dist/decorators/index.d.ts.map +1 -1
  8. package/dist/decorators/index.js +9 -1
  9. package/dist/decorators/index.js.map +1 -1
  10. package/dist/decorators/lifecycle.d.ts +100 -0
  11. package/dist/decorators/lifecycle.d.ts.map +1 -0
  12. package/dist/decorators/lifecycle.js +124 -0
  13. package/dist/decorators/lifecycle.js.map +1 -0
  14. package/dist/decorators/metadata.d.ts +14 -0
  15. package/dist/decorators/metadata.d.ts.map +1 -1
  16. package/dist/decorators/metadata.js +21 -0
  17. package/dist/decorators/metadata.js.map +1 -1
  18. package/dist/index.d.ts +4 -2
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +12 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/query/query-builder.d.ts +36 -0
  23. package/dist/query/query-builder.d.ts.map +1 -1
  24. package/dist/query/query-builder.js +117 -0
  25. package/dist/query/query-builder.js.map +1 -1
  26. package/dist/repository/base-repository.d.ts +256 -0
  27. package/dist/repository/base-repository.d.ts.map +1 -0
  28. package/dist/repository/base-repository.js +460 -0
  29. package/dist/repository/base-repository.js.map +1 -0
  30. package/dist/repository/entity-manager.d.ts +111 -0
  31. package/dist/repository/entity-manager.d.ts.map +1 -0
  32. package/dist/repository/entity-manager.js +192 -0
  33. package/dist/repository/entity-manager.js.map +1 -0
  34. package/dist/repository/index.d.ts +9 -0
  35. package/dist/repository/index.d.ts.map +1 -0
  36. package/dist/repository/index.js +13 -0
  37. package/dist/repository/index.js.map +1 -0
  38. package/package.json +1 -1
package/README.md CHANGED
@@ -1,2088 +1,813 @@
1
1
  # @bhushanpawar/sqldb
2
2
 
3
- > πŸš€ **The MariaDB client that makes your database feel like Redis**
3
+ > πŸš€ **The TypeORM-like MariaDB client with Redis caching superpowers**
4
4
 
5
- Stop wasting hours on cache invalidation bugs. Stop paying for database CPU you don't need. Get **99% cache hit rates** and **sub-millisecond queries**β€”automatically.
5
+ Stop writing boilerplate CRUD services. Stop managing cache keys. Stop worrying about stale data. Get **TypeORM-like ergonomics** with **automatic caching**, **intelligent invalidation**, and **sub-millisecond queries**β€”out of the box.
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/@bhushanpawar/sqldb?color=blue&style=flat-square)](https://www.npmjs.com/package/@bhushanpawar/sqldb)
8
8
  [![TypeScript](https://img.shields.io/badge/TypeScript-100%25-blue?style=flat-square&logo=typescript)](https://www.typescriptlang.org/)
9
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=flat-square)](https://opensource.org/licenses/MIT)
10
10
 
11
- **[⚑ Quick Start](#getting-started-in-60-seconds)** β€’ **[πŸ“– Docs](#documentation)** β€’ **[🎯 Examples](#examples)** β€’ **[⭐ Star on GitHub](https://github.com/erBhushanPawar/sqldb)**
11
+ **[⚑ Quick Start](#quick-start-repository-pattern)** β€’ **[πŸ“– Docs](#documentation)** β€’ **[🎯 Examples](#examples)** β€’ **[⭐ Star on GitHub](https://github.com/bhushanpawar/sqldb)**
12
12
 
13
13
  ---
14
14
 
15
15
  ## πŸ’Ž What Makes This Special?
16
16
 
17
- **Most database libraries make you choose:** 🐌 Simple & slow ORM **OR** ⚑ Fast but complex manual caching
17
+ **Most database libraries make you choose:** 🐌 Simple ORM (slow) **OR** ⚑ Fast manual caching (complex)
18
18
 
19
- **SqlDB gives you both.**
19
+ **SqlDB gives you both** + zero boilerplate:
20
20
 
21
21
  ```typescript
22
- // Replace this mess...
23
- const cacheKey = `users:${status}:${page}`;
24
- let users = await redis.get(cacheKey);
25
- if (!users) {
26
- users = await db.query('SELECT * FROM users WHERE status = ?', [status]);
27
- await redis.set(cacheKey, JSON.stringify(users), 'EX', 60);
28
- // Hope you remembered all the cache keys to invalidate...
29
- } else {
30
- users = JSON.parse(users);
31
- }
32
-
33
- // ...with this magic ✨
34
- const users = await db.users.findMany({ status });
35
- // Cached automatically. Invalidated intelligently. Type-safe. Done.
36
- ```
37
-
38
- ## 🎯 The Results Speak for Themselves
39
-
40
- <table>
41
- <tr>
42
- <td width="50%">
43
-
44
- **Before SqlDB** 😰
45
- ```
46
- Average response: 250ms
47
- Database CPU: 85%
48
- Cache hit rate: 0%
49
- Stale data bugs: Weekly
50
- Cache code: 500+ lines
51
- Developer happiness: 😫
52
- ```
53
-
54
- </td>
55
- <td width="50%">
56
-
57
- **After SqlDB** πŸŽ‰
58
- ```
59
- Average response: <1ms (250x faster ⚑)
60
- Database CPU: 15% (85% reduction)
61
- Cache hit rate: 99%+ (automatic)
62
- Stale data bugs: Never (intelligent invalidation)
63
- Cache code: 0 lines (built-in)
64
- Developer happiness: 😍
65
- ```
66
-
67
- </td>
68
- </tr>
69
- </table>
70
-
71
- ## ⚑ Key Features at a Glance
72
-
73
- | Feature | What You Get |
74
- |---------|--------------|
75
- | πŸš€ **Automatic Caching** | Every query cached in Redis. 99%+ hit rate. <1ms response. |
76
- | 🧠 **Smart Invalidation** | Update `users`? We clear `posts` & `comments` too. Follows FKs. |
77
- | 🎯 **Auto-Warming** | ML-powered warming learns your patterns. No cold starts. Ever. |
78
- | πŸ”’ **Type-Safe** | Full TypeScript support. Autocomplete everything. Catch errors at compile-time. |
79
- | πŸ“Š **Query Tracking** | See every query with timing. Find slow requests in milliseconds. |
80
- | 🎨 **Beautiful Logging** | βš‘πŸš€βœ…βš οΈπŸŒ - Know performance at a glance. |
81
- | πŸ”— **Zero Config** | Auto-discovers schema. Maps relationships. Just works. |
82
- | πŸ—οΈ **Production Ready** | Singleton pattern. Health checks. Graceful shutdown. Connection pooling. |
83
-
84
- ## 🎬 See It In Action
85
-
86
- ```typescript
87
- import { createSqlDB } from '@bhushanpawar/sqldb';
88
-
89
- // 1. Initialize (auto-discovers your entire schema)
90
- const db = await createSqlDB({
91
- mariadb: { host: 'localhost', user: 'root', password: 'pass', database: 'mydb' },
92
- redis: { host: 'localhost' }
93
- });
94
-
95
- // 2. Query with automatic caching ⚑
96
- const users = await db.users.findMany({ status: 'active' });
97
- // First call: 200ms (database)
98
- // Next calls: <1ms (cache)
99
-
100
- // 3. Update with cascade invalidation ✨
101
- await db.users.updateById(1, { name: 'Jane' });
102
- // Automatically clears:
103
- // βœ“ All user queries
104
- // βœ“ All post queries (has user_id FK)
105
- // βœ“ All comment queries (has post_id β†’ user_id FK)
106
- // Zero stale data. Zero manual work.
107
-
108
- // 4. Monitor everything πŸ“Š
109
- const stats = db.getCacheManager().getStats();
110
- console.log(stats.hitRate); // "99.5%"
111
- ```
112
-
113
- **That's it.** No cache keys. No invalidation logic. No stale data bugs at 3am.
114
-
115
- ---
116
-
117
- ## Why @bhushanpawar/sqldb?
118
-
119
- **Stop writing boilerplate.** Stop managing cache keys. Stop worrying about stale data.
120
-
121
- Most ORMs and database clients make you choose between:
122
- - 🐌 **Simplicity** (but slow)
123
- - ⚑ **Performance** (but complex caching logic)
124
-
125
- **We give you both.**
126
-
127
- ### The Problem
128
-
129
- ```typescript
130
- // Traditional approach - SLOW ❌
131
- app.get('/users', async (req, res) => {
132
- const users = await db.query('SELECT * FROM users'); // 200ms every time
133
- res.json(users);
134
- });
135
-
136
- // Manual caching - COMPLEX ❌
137
- app.get('/users', async (req, res) => {
138
- const cacheKey = 'users:all';
139
- let users = await redis.get(cacheKey);
140
-
141
- if (!users) {
142
- users = await db.query('SELECT * FROM users');
143
- await redis.set(cacheKey, JSON.stringify(users), 'EX', 60);
144
- } else {
145
- users = JSON.parse(users);
146
- }
147
-
148
- res.json(users);
149
- });
150
-
151
- // When updating - FRAGILE ❌
152
- app.post('/users', async (req, res) => {
153
- await db.query('INSERT INTO users ...', [data]);
154
- await redis.del('users:all'); // Did you remember all cache keys?
155
- await redis.del('users:active'); // What about related tables?
156
- await redis.del('posts:by-user:*'); // This is getting messy...
157
- });
158
- ```
159
-
160
- ### The Solution
161
-
162
- ```typescript
163
- // SqlDB - SIMPLE βœ… FAST βœ… AUTOMATIC βœ…
164
- app.get('/users', async (req, res) => {
165
- const users = await db.users.findMany(); // 1ms (cached) after first request
166
- res.json(users);
167
- });
168
-
169
- app.post('/users', async (req, res) => {
170
- await db.users.insertOne(data);
171
- // Cache automatically invalidated ✨
172
- // Related tables (posts, comments) also invalidated ✨
173
- // No manual cache management needed ✨
174
- });
175
- ```
176
-
177
- ## Features That Actually Matter
178
-
179
- ### πŸš€ **Automatic Caching** - Set It and Forget It
180
- Every query is automatically cached in Redis. **99%+ cache hit rate** in production. **Sub-millisecond** response times.
181
-
182
- ```typescript
183
- // First call: queries database (200ms)
184
- const users = await db.users.findMany({ status: 'active' });
185
-
186
- // Next 100 calls: served from cache (<1ms)
187
- // Automatically expires after TTL or on updates
188
- ```
189
-
190
- ### 🧠 **Intelligent Cache Invalidation** - Never Serve Stale Data
191
- Updates to `users` automatically invalidate `posts` and `comments` caches. **Follows foreign keys**. Zero configuration.
192
-
193
- ```typescript
194
- // Update a user
195
- await db.users.updateById(1, { name: 'Jane' });
196
-
197
- // SqlDB automatically clears:
198
- // βœ“ users:* cache
199
- // βœ“ posts:* cache (has user_id FK)
200
- // βœ“ comments:* cache (has post_id FK β†’ user_id FK)
201
- // βœ“ All related queries
202
- ```
203
-
204
- ### 🎯 **Auto-Warming** - Always Fast, Even After Restart
205
- ML-powered cache warming learns your query patterns and pre-warms hot queries in the background. **No cold starts**.
206
-
207
- ```typescript
208
- warming: {
209
- enabled: true,
210
- // Tracks query frequency, auto-warms top queries
211
- // Runs in separate pool (zero impact on your app)
212
- // Persists stats across restarts
213
- }
214
-
215
- // After deployment, your cache is already warm ✨
216
- ```
217
-
218
- ### πŸ“Š **Query Tracking** - Debug Like a Pro
219
- Track every query with correlation IDs. Find slow requests in milliseconds.
220
-
221
- ```typescript
222
- // Middleware adds correlation ID
223
- req.correlationId = generateQueryId();
224
-
225
- // All queries tracked automatically
226
- const queries = db.getQueries(req.correlationId);
227
-
228
- // See exactly what happened
229
- console.log(queries.map(q => ({
230
- sql: q.sql,
231
- time: q.executionTimeMs,
232
- cached: q.resultCount
233
- })));
234
- ```
235
-
236
- ### 🎨 **Beautiful Query Logging** - Know What's Happening
237
-
238
- ```
239
- βœ… SELECT on users - 45ms - 10 rows
240
- πŸš€ SELECT on orders - 12ms - 5 rows (cached)
241
- ⚠️ SELECT on products - 250ms - 100 rows
242
- SQL: SELECT * FROM products WHERE category = 'electronics'
243
- ```
244
-
245
- Performance at a glance: ⚑ <10ms | πŸš€ <50ms | βœ… <200ms | ⚠️ <500ms | 🐌 β‰₯500ms
246
-
247
- ### πŸ”’ **Type-Safe** - Full TypeScript Support
248
-
249
- ```typescript
250
- interface User {
251
- id: number;
252
- email: string;
253
- status: 'active' | 'inactive';
254
- }
255
-
256
- type MyDB = SqlDBWithTables<{ users: User }>;
257
- const db = await createSqlDB(config) as MyDB;
258
-
259
- // Full autocomplete and type checking ✨
260
- const users = await db.users.findMany(); // Type: User[]
261
- await db.users.updateById(1, { status: 'verified' }); // βœ“ Type-safe
262
- await db.users.updateById(1, { invalid: 'field' }); // ❌ TypeScript error
263
- ```
264
-
265
- ### πŸ”— **Zero Configuration** - Works Out of the Box
266
-
267
- ```typescript
268
- const db = await createSqlDB({
269
- mariadb: { host: 'localhost', user: 'root', password: 'pass', database: 'mydb' },
270
- redis: { host: 'localhost' }
271
- });
272
-
273
- // That's it. Schema auto-discovered. Relationships mapped. Cache ready.
274
- ```
275
-
276
- ### πŸ“ˆ **Production-Ready** - Battle-Tested at Scale
277
-
278
- - ⚑ **10,000+ queries/second** with Redis cache
279
- - 🎯 **99%+ cache hit rate** in production
280
- - πŸ“Š **<1ms** cached query response time
281
- - πŸ”„ **Connection pooling** built-in
282
- - πŸ₯ **Health checks** included
283
- - 🎭 **Singleton pattern** for clean architecture
284
- - πŸ”₯ **Zero downtime** schema refreshes
285
-
286
- ## Real-World Performance
287
-
288
- **Before SqlDB:**
289
- ```
290
- Average API response time: 250ms
291
- Database load: 85% CPU
292
- Redis: Not used
293
- Cache hit rate: 0%
294
- Lines of caching code: 500+
295
- ```
296
-
297
- **After SqlDB:**
298
- ```
299
- Average API response time: 12ms (20x faster ⚑)
300
- Database load: 15% CPU (85% reduction)
301
- Redis: 98% cache hit rate
302
- Cache invalidation: Automatic
303
- Lines of caching code: 0
304
- ```
305
-
306
- ## Quick Comparison
307
-
308
- | Feature | Traditional ORM | Manual Cache | **SqlDB** |
309
- |---------|----------------|--------------|-------------|
310
- | Query Speed | 🐌 200ms | ⚑ 2ms | ⚑ **<1ms** |
311
- | Auto-Caching | ❌ | ❌ | βœ… **Built-in** |
312
- | Cache Invalidation | ❌ Manual | ❌ Error-prone | βœ… **Automatic** |
313
- | Relationship Tracking | ⚠️ Limited | ❌ None | βœ… **Auto-discovered** |
314
- | Type Safety | βœ… | ❌ | βœ… **Full** |
315
- | Learning Curve | πŸ“š High | πŸ“š High | πŸ“– **Minimal** |
316
- | Boilerplate Code | πŸ”₯ Lots | πŸ”₯πŸ”₯ Tons | βœ… **Zero** |
317
- | Cache Warming | ❌ | ❌ Manual | βœ… **AI-Powered** |
318
- | Query Tracking | ⚠️ Basic | ❌ | βœ… **Advanced** |
319
-
320
- ---
321
-
322
- ## Table of Contents
323
-
324
- - [Installation](#installation)
325
- - [Getting Started in 60 Seconds](#getting-started-in-60-seconds)
326
- - [Complete Quick Start](#complete-quick-start)
327
- - [Core Concepts](#core-concepts)
328
- - [Examples (Simple β†’ Complex)](#examples)
329
- - [Configuration](#configuration)
330
- - [CRUD Operations](#crud-operations)
331
- - [Cache Management](#cache-management)
332
- - [Performance Optimization](#performance-optimization)
333
- - [API Reference](#api-reference)
334
- - [Migration Guide](#migration-from-mariadb)
335
- - [Documentation](#documentation)
336
-
337
- ---
338
-
339
- ## Installation
340
-
341
- ```bash
342
- npm install @bhushanpawar/sqldb mariadb redis
343
- ```
344
-
345
- ## Getting Started in 60 Seconds
346
-
347
- ### 1. Install
348
- ```bash
349
- npm install @bhushanpawar/sqldb mariadb redis
350
- ```
351
-
352
- ### 2. Initialize
353
- ```typescript
354
- import { createSqlDB } from '@bhushanpawar/sqldb';
355
-
356
- const db = await createSqlDB({
357
- mariadb: { host: 'localhost', user: 'root', password: 'pass', database: 'mydb' },
358
- redis: { host: 'localhost' }
359
- });
360
- ```
361
-
362
- ### 3. Use
363
- ```typescript
364
- // Query with automatic caching ⚑
365
- const users = await db.users.findMany({ status: 'active' });
366
-
367
- // Update with automatic cache invalidation ✨
368
- await db.users.updateById(1, { status: 'verified' });
369
-
370
- // That's it! No boilerplate, no cache keys, no invalidation logic.
371
- ```
372
-
373
- ### 4. Profit πŸ“ˆ
374
- ```
375
- First request: 200ms (database)
376
- Next requests: <1ms (cache)
377
- Cache hit rate: 99%+
378
- Lines of code: 3 (vs 50+)
379
- ```
380
-
381
- ## Complete Quick Start
382
-
383
- Here's a more complete example with all the bells and whistles:
384
-
385
- ```typescript
386
- import { createSqlDB } from '@bhushanpawar/sqldb';
387
-
388
- const db = await createSqlDB({
389
- // Database connection
390
- mariadb: {
391
- host: 'localhost',
392
- port: 3306,
393
- user: 'root',
394
- password: 'password',
395
- database: 'mydb',
396
- connectionLimit: 10,
397
- logging: true, // See all queries with performance metrics
398
- },
399
-
400
- // Redis cache
401
- redis: {
402
- host: 'localhost',
403
- port: 6379,
404
- keyPrefix: 'myapp:',
405
- },
406
-
407
- // Caching configuration
408
- cache: {
409
- enabled: true,
410
- defaultTTL: 60, // Cache for 60 seconds
411
- maxKeys: 1000, // Max 1000 cache keys
412
- invalidateOnWrite: true, // Auto-clear on INSERT/UPDATE/DELETE
413
- cascadeInvalidation: true, // Clear related tables too
414
- },
415
-
416
- // Auto-discovery
417
- discovery: {
418
- autoDiscover: true, // Discover schema on startup
419
- refreshInterval: 3600000, // Refresh every hour
420
- },
421
-
422
- // Auto-warming (optional but awesome)
423
- warming: {
424
- enabled: true,
425
- intervalMs: 60000, // Warm cache every minute
426
- topQueriesPerTable: 10, // Warm top 10 queries per table
427
- },
428
- });
429
-
430
- // ========================================
431
- // READ - Automatically cached
432
- // ========================================
433
-
434
- // Find all
435
- const allUsers = await db.users.findMany();
436
-
437
- // Find with conditions
438
- const activeUsers = await db.users.findMany({ status: 'active' });
439
-
440
- // Find one
441
- const user = await db.users.findOne({ email: 'john@example.com' });
442
-
443
- // Find by ID (optimized)
444
- const userById = await db.users.findById(1);
445
-
446
- // Count
447
- const count = await db.users.count({ status: 'active' });
448
-
449
- // ========================================
450
- // WRITE - Automatically invalidates cache
451
- // ========================================
452
-
453
- // Insert
454
- const newUser = await db.users.insertOne({
455
- name: 'John Doe',
456
- email: 'john@example.com',
457
- status: 'active'
458
- });
459
-
460
- // Update
461
- await db.users.updateById(1, { status: 'verified' });
462
-
463
- // Delete
464
- await db.users.deleteById(1);
465
-
466
- // ========================================
467
- // MONITORING - See what's happening
468
- // ========================================
469
-
470
- // Cache stats
471
- const stats = db.getCacheManager().getStats();
472
- console.log(`Cache hit rate: ${stats.hitRate}`);
473
- // Output: Cache hit rate: 99.5%
474
-
475
- // Query tracking
476
- const queries = db.getQueries(correlationId);
477
- console.log(`Total time: ${queries.reduce((sum, q) => sum + q.executionTimeMs, 0)}ms`);
478
-
479
- // Health check
480
- const health = await db.healthCheck();
481
- console.log(health); // { mariadb: true, redis: true }
482
-
483
- // ========================================
484
- // CLEANUP
485
- // ========================================
486
-
487
- await db.close();
488
- ```
489
-
490
- ### Singleton Pattern (Recommended)
491
-
492
- For production applications, use singleton mode to share a single connection pool:
493
-
494
- ```typescript
495
- import { createSqlDB, getSqlDB } from '@bhushanpawar/sqldb';
496
-
497
- // Initialize once at app startup
498
- const db = await createSqlDB({
499
- mariadb: { /* config */ },
500
- redis: { /* config */ },
501
- cache: { enabled: true },
502
- }, { singleton: true }); // Enable singleton mode
503
-
504
- // Access anywhere in your app
505
- import { getSqlDB } from '@bhushanpawar/sqldb';
506
-
507
- const db = getSqlDB(); // Returns the same instance
508
- const users = db.getTableOperations('users');
509
- ```
510
-
511
- See [SINGLETON_PATTERN.md](./docs/SINGLETON_PATTERN.md) for detailed usage.
512
-
513
- ### Dynamic Table Access (TypeScript-Friendly)
514
-
515
- Access tables directly as properties with full type safety:
516
-
517
- ```typescript
518
- import { createSqlDB, SqlDBWithTables } from '@bhushanpawar/sqldb';
519
-
520
- // Define your schema
521
- interface MySchema {
522
- users: { id: number; name: string; email: string };
523
- orders: { id: number; user_id: number; total: number };
524
- }
525
-
526
- type MyDB = SqlDBWithTables<MySchema>;
527
-
528
- const db = await createSqlDB(config) as MyDB;
529
-
530
- // Clean, typed access
531
- const users = await db.users.findMany(); // Type: MySchema['users'][]
532
- const order = await db.orders.findById(123); // Type: MySchema['orders'] | null
533
- await db.users.updateById(1, { name: 'Jane' }); // Fully type-checked
534
-
535
- // Still works the old way too
536
- const usersTable = db.getTableOperations('users');
537
- ```
538
-
539
- See [DYNAMIC_TABLE_ACCESS.md](./docs/DYNAMIC_TABLE_ACCESS.md) for detailed usage.
540
-
541
- ### Raw Query Caching
542
-
543
- The `raw` method supports caching custom SQL queries with a configurable TTL (default: 1 minute):
544
-
545
- ```typescript
546
- const users = db.getTableOperations('users');
547
-
548
- // First call - queries database and caches result for 60 seconds
549
- const results = await users.raw(
550
- 'SELECT * FROM users WHERE status = ? ORDER BY created_at DESC LIMIT 10',
551
- ['active']
552
- );
553
-
554
- // Subsequent calls within 60 seconds - served from cache
555
- const cachedResults = await users.raw(
556
- 'SELECT * FROM users WHERE status = ? ORDER BY created_at DESC LIMIT 10',
557
- ['active']
558
- );
559
-
560
- // Cache stats show hits and misses
561
- const stats = db.getCacheManager().getStats();
562
- console.log(stats);
563
- // { hits: 99, misses: 1, evictions: 0, hitRate: '99.00%' }
564
- ```
565
-
566
- The raw query cache:
567
- - Uses the full SQL query and parameters as the cache key
568
- - Has a fixed 60-second TTL (optimized for dynamic queries)
569
- - Automatically expires when the table is modified
570
- - Supports correlation IDs for query tracking
571
-
572
- ## Table of Contents
573
-
574
- - [Core Concepts](#core-concepts)
575
- - [Configuration](#configuration)
576
- - [CRUD Operations](#crud-operations)
577
- - [Cache Management](#cache-management)
578
- - [Query Tracking](#query-tracking)
579
- - [Smart Cache Invalidation](#smart-cache-invalidation)
580
- - [Performance Optimization](#performance-optimization)
581
- - [API Reference](#api-reference)
582
-
583
- ## Core Concepts
584
-
585
- ### Schema Discovery
586
-
587
- SqlDB automatically discovers your database schema on initialization:
588
-
589
- ```typescript
590
- const db = await createSqlDB({
591
- discovery: {
592
- autoDiscover: true,
593
- includedTables: ['users', 'posts', 'comments'], // Optional: specific tables
594
- excludedTables: ['temp_*'], // Optional: exclude patterns
595
- refreshInterval: 3600000, // Refresh every hour
596
- },
597
- });
598
-
599
- // Get discovered tables
600
- const tables = db.getDiscoveredTables();
601
- console.log(tables); // ['users', 'posts', 'comments', ...]
602
-
603
- // Get dependency graph
604
- const graph = db.getDependencyGraph();
605
- const deps = graph.getDependencies('users'); // Tables that depend on users
606
- ```
607
-
608
- ### Relationship Mapping
609
-
610
- SqlDB automatically maps foreign key relationships:
611
-
612
- ```typescript
613
- // Schema example:
614
- // posts (id, user_id, title)
615
- // comments (id, post_id, user_id, content)
616
-
617
- // Updating a user invalidates related posts and comments
618
- await users.updateById(1, { name: 'Jane' });
619
- // Cache invalidated: users:*, posts:*, comments:*
620
-
621
- // With cascadeInvalidation: false, only users cache is invalidated
622
- ```
623
-
624
- ### Cache Invalidation Strategies
625
-
626
- ```typescript
627
- // 1. Automatic invalidation on write (recommended)
628
- await createSqlDB({
629
- cache: {
630
- invalidateOnWrite: true,
631
- cascadeInvalidation: true, // Invalidate related tables
632
- },
633
- });
634
-
635
- // 2. Manual invalidation
636
- const users = db.getTableOperations('users');
637
- await users.invalidateCache();
638
-
639
- // 3. Invalidation via manager
640
- const invalidationManager = db.getInvalidationManager();
641
- await invalidationManager.invalidateTable('users', { cascade: true });
642
-
643
- // 4. Clear entire cache
644
- const cacheManager = db.getCacheManager();
645
- await cacheManager.clear();
646
- ```
647
-
648
- ## Configuration
649
-
650
- ### Complete Configuration Example
651
-
652
- ```typescript
653
- import { createSqlDB, SqlDBConfig } from '@bhushanpawar/sqldb';
654
-
655
- const config: SqlDBConfig = {
656
- // MariaDB connection
657
- mariadb: {
658
- host: 'localhost',
659
- port: 3306,
660
- user: 'root',
661
- password: 'password',
662
- database: 'mydb',
663
- connectionLimit: 10,
664
- acquireTimeout: 10000,
665
- connectTimeout: 10000,
666
- },
667
-
668
- // Redis connection
669
- redis: {
670
- host: 'localhost',
671
- port: 6379,
672
- password: 'redis-password', // Optional
673
- db: 0,
674
- keyPrefix: 'myapp:',
675
- },
676
-
677
- // Cache configuration
678
- cache: {
679
- enabled: true,
680
- defaultTTL: 60, // Default: 60 seconds
681
- maxKeys: 1000, // Max cached queries
682
- invalidateOnWrite: true, // Auto-invalidate on INSERT/UPDATE/DELETE
683
- cascadeInvalidation: true, // Invalidate related tables
684
- },
685
-
686
- // Schema discovery
687
- discovery: {
688
- autoDiscover: true,
689
- includedTables: [], // Empty = all tables
690
- excludedTables: [],
691
- maxGraphDepth: 3, // Cascade depth
692
- refreshInterval: 3600000, // 1 hour
693
- },
694
-
695
- // Logging
696
- logging: {
697
- level: 'info', // 'debug' | 'info' | 'warn' | 'error'
698
- logger: (level, message, meta) => {
699
- console.log(`[${level}] ${message}`, meta);
700
- },
701
- },
702
- };
703
-
704
- const db = await createSqlDB(config);
705
- ```
706
-
707
- ### Configuration Options
708
-
709
- #### Cache Options
710
-
711
- | Option | Type | Default | Description |
712
- |--------|------|---------|-------------|
713
- | `enabled` | boolean | true | Enable/disable caching |
714
- | `defaultTTL` | number | 60 | Default cache TTL in seconds |
715
- | `maxKeys` | number | 1000 | Maximum cached keys (LRU eviction) |
716
- | `invalidateOnWrite` | boolean | true | Auto-invalidate on writes |
717
- | `cascadeInvalidation` | boolean | true | Cascade invalidation to related tables |
718
-
719
- #### Discovery Options
720
-
721
- | Option | Type | Default | Description |
722
- |--------|------|---------|-------------|
723
- | `autoDiscover` | boolean | true | Auto-discover schema on init |
724
- | `includedTables` | string[] | [] | Tables to include (empty = all) |
725
- | `excludedTables` | string[] | [] | Tables to exclude (supports patterns) |
726
- | `maxGraphDepth` | number | 3 | Max cascade depth for relationships |
727
- | `refreshInterval` | number | 0 | Schema refresh interval (0 = disabled) |
728
-
729
- ## CRUD Operations
730
-
731
- ### Find Operations
732
-
733
- ```typescript
734
- const users = db.getTableOperations<User>('users');
22
+ // Before: 800+ lines of custom CRUD service 😰
23
+ export class UnifiedCRUDService<T> {
24
+ // Custom query builder (200 lines)
25
+ // JSON aggregation for relations (100 lines)
26
+ // Lifecycle hooks management (100 lines)
27
+ // Case conversion (100 lines)
28
+ // Entity transformation (100 lines)
29
+ // Primary key handling (50 lines)
30
+ // ... 150 more lines
31
+ }
735
32
 
736
- // Find all
737
- const all = await users.findMany();
33
+ // After: 50 lines with SqlDB πŸŽ‰
34
+ @Entity()
35
+ class User {
36
+ @PrimaryColumn()
37
+ userId: string;
738
38
 
739
- // Find with conditions
740
- const active = await users.findMany({
741
- status: 'active'
742
- });
39
+ @Column()
40
+ email: string;
743
41
 
744
- // Find with options
745
- const paginated = await users.findMany(
746
- { status: 'active' },
747
- {
748
- limit: 10,
749
- offset: 20,
750
- orderBy: 'created_at',
751
- order: 'DESC',
752
- skipCache: false, // Force cache bypass
42
+ @BeforeInsert()
43
+ async hashPassword() {
44
+ this.password = await bcrypt.hash(this.password, 10);
753
45
  }
754
- );
755
-
756
- // Find one
757
- const user = await users.findOne({ email: 'john@example.com' });
758
-
759
- // Find by ID
760
- const userById = await users.findById(1);
761
-
762
- // Count
763
- const count = await users.count({ status: 'active' });
764
- ```
765
-
766
- ### Insert Operations
767
-
768
- ```typescript
769
- // Insert one
770
- const newUser = await users.insertOne({
771
- name: 'John Doe',
772
- email: 'john@example.com',
773
- status: 'active',
774
- });
775
- console.log(newUser.id); // Auto-generated ID
776
-
777
- // Insert many
778
- const newUsers = await users.insertMany([
779
- { name: 'Alice', email: 'alice@example.com' },
780
- { name: 'Bob', email: 'bob@example.com' },
781
- ]);
782
- console.log(newUsers.map(u => u.id)); // [1, 2]
783
- ```
784
-
785
- ### Update Operations
786
-
787
- ```typescript
788
- // Update one
789
- const updated = await users.updateOne(
790
- { id: 1 },
791
- { status: 'inactive' }
792
- );
793
-
794
- // Update many
795
- const count = await users.updateMany(
796
- { status: 'pending' },
797
- { status: 'active' }
798
- );
799
- console.log(`Updated ${count} users`);
800
-
801
- // Update by ID
802
- const user = await users.updateById(1, { name: 'Jane Doe' });
803
- ```
804
46
 
805
- ### Delete Operations
806
-
807
- ```typescript
808
- // Delete one
809
- const deleted = await users.deleteOne({ id: 1 });
810
- console.log(deleted); // true/false
811
-
812
- // Delete many
813
- const count = await users.deleteMany({ status: 'inactive' });
814
- console.log(`Deleted ${count} users`);
47
+ @AfterLoad()
48
+ calculateFullName() {
49
+ this.fullName = `${this.firstName} ${this.lastName}`;
50
+ }
51
+ }
815
52
 
816
- // Delete by ID
817
- const deleted = await users.deleteById(1);
53
+ const userRepo = db.getRepository(User);
54
+ const users = await userRepo.find({ where: { status: 'active' } });
818
55
  ```
819
56
 
820
- ### Raw SQL Queries
57
+ **Result: 94% less code, 250x faster queries.**
821
58
 
822
- ```typescript
823
- // Raw query with caching (60s TTL)
824
- const results = await users.raw<User[]>(
825
- 'SELECT * FROM users WHERE created_at > ? ORDER BY id DESC',
826
- ['2024-01-01']
827
- );
828
-
829
- // With correlation ID for tracking
830
- const correlationId = 'request-123';
831
- const results = await users.raw(
832
- 'SELECT COUNT(*) as total FROM users',
833
- [],
834
- correlationId
835
- );
836
- ```
59
+ ---
837
60
 
838
- ## Cache Management
61
+ ## 🎯 Quick Start: Repository Pattern
839
62
 
840
- ### Cache Statistics
63
+ SqlDB now offers a **TypeORM-like repository pattern** that eliminates boilerplate:
841
64
 
842
65
  ```typescript
843
- const cacheManager = db.getCacheManager();
844
- const stats = cacheManager.getStats();
845
-
846
- console.log(stats);
847
- // {
848
- // hits: 1500,
849
- // misses: 100,
850
- // evictions: 50,
851
- // size: 0,
852
- // hitRate: '93.75%'
853
- // }
854
-
855
- // Reset stats
856
- cacheManager.resetStats();
857
- ```
66
+ import {
67
+ createSqlDB,
68
+ Entity,
69
+ PrimaryColumn,
70
+ Column,
71
+ BeforeInsert,
72
+ AfterLoad,
73
+ } from '@bhushanpawar/sqldb';
74
+ import bcrypt from 'bcrypt';
858
75
 
859
- ### Manual Cache Control
76
+ // 1. Define Entity with Decorators
77
+ @Entity()
78
+ class User {
79
+ @PrimaryColumn()
80
+ userId: string;
860
81
 
861
- ```typescript
862
- // Check if cache is enabled
863
- if (cacheManager.isEnabled()) {
864
- // Get cached value
865
- const value = await cacheManager.get('cache:key');
82
+ @Column()
83
+ email: string;
866
84
 
867
- // Set cached value
868
- await cacheManager.set('cache:key', data, 120); // 120s TTL
85
+ @Column()
86
+ password: string;
869
87
 
870
- // Delete specific key
871
- await cacheManager.delete('cache:key');
88
+ @Computed()
89
+ fullName: string;
872
90
 
873
- // Delete by pattern
874
- const count = await cacheManager.deletePattern('users:*');
91
+ @BeforeInsert()
92
+ async hashPassword() {
93
+ this.password = await bcrypt.hash(this.password, 10);
94
+ }
875
95
 
876
- // Clear all cache
877
- await cacheManager.clear();
96
+ @AfterLoad()
97
+ calculateFullName() {
98
+ this.fullName = `${this.firstName} ${this.lastName}`;
99
+ }
878
100
  }
879
- ```
880
-
881
- ### Cache Warming
882
-
883
- ```typescript
884
- const users = db.getTableOperations('users');
885
-
886
- // Pre-warm cache with common queries
887
- await users.warmCache({ status: 'active' });
888
-
889
- // This will now be served from cache
890
- const active = await users.findMany({ status: 'active' });
891
- ```
892
101
 
893
- ### Cache Warming with Relations
894
-
895
- Pre-warm cache for a table and all its related tables based on the dependency graph:
896
-
897
- ```typescript
898
- const provider = db.getTableOperations('provider');
899
-
900
- // Warm cache for provider and all related tables
901
- await provider.warmCacheWithRelations({}, {
902
- correlationId: 'startup-warming',
903
- depth: 1, // How deep to traverse relationships
904
- warmDependents: true, // Warm tables that reference this table
905
- warmDependencies: true, // Warm tables this table references
102
+ // 2. Initialize SqlDB
103
+ const db = await createSqlDB({
104
+ mariadb: { host: 'localhost', user: 'root', password: 'pass', database: 'mydb' },
105
+ redis: { host: 'localhost' },
906
106
  });
907
107
 
908
- // Now provider and all related tables are cached:
909
- // - provider (main table)
910
- // - user (table that provider depends on)
911
- // - orders, services, bank_details, etc. (tables that depend on provider)
912
- ```
913
-
914
- **Use Cases:**
915
- - **Application startup**: Pre-warm frequently accessed tables and their relations
916
- - **API endpoints**: Warm cache before handling requests for better response times
917
- - **Batch operations**: Pre-load related data before processing
918
-
919
- **Example - Warm on Startup:**
920
- ```typescript
921
- async function warmCacheOnStartup(db: SqlDBClient) {
922
- // Warm most frequently accessed tables with their relations
923
- const provider = db.getTableOperations('provider');
924
- const orders = db.getTableOperations('orders');
925
-
926
- await Promise.all([
927
- provider.warmCacheWithRelations({}, { depth: 1, warmDependents: true }),
928
- orders.warmCacheWithRelations({}, { depth: 1, warmDependencies: true }),
929
- ]);
930
-
931
- console.log('Cache warmed successfully!');
932
- }
933
- ```
934
-
935
- ## Query Tracking
936
-
937
- Track queries with correlation IDs for debugging and performance monitoring:
938
-
939
- ```typescript
940
- import { generateQueryId } from '@bhushanpawar/sqldb';
941
-
942
- // Generate correlation ID for a request
943
- const correlationId = generateQueryId();
944
-
945
- // Use across multiple operations
946
- const users = db.getTableOperations('users');
947
- await users.findMany({ status: 'active' }, { correlationId });
948
- await users.count({ status: 'active' }, correlationId);
949
- await users.findById(1, correlationId);
950
-
951
- // Get all queries for this correlation
952
- const queries = db.getQueries(correlationId);
108
+ // 3. Get Repository
109
+ const userRepo = db.getRepository(User);
953
110
 
954
- queries.forEach(q => {
955
- console.log({
956
- queryId: q.queryId,
957
- sql: q.sql,
958
- executionTime: q.executionTimeMs,
959
- cached: q.resultCount,
960
- });
111
+ // 4. Use It (One-Liners!)
112
+ const user = await userRepo.save({
113
+ email: 'john@example.com',
114
+ password: 'secret123', // Auto-hashed via @BeforeInsert
961
115
  });
962
116
 
963
- // Performance analysis
964
- const totalTime = queries.reduce((sum, q) => sum + (q.executionTimeMs || 0), 0);
965
- const avgTime = totalTime / queries.length;
966
- console.log(`Total: ${totalTime}ms, Average: ${avgTime}ms`);
967
-
968
- // Clean up
969
- db.clearQueries(correlationId);
970
- ```
971
-
972
- ### Query Metadata
973
-
974
- Each tracked query includes:
975
-
976
- ```typescript
977
- interface QueryMetadata {
978
- queryId: string; // Unique UUID
979
- correlationId?: string; // Optional correlation ID
980
- sql: string; // SQL query
981
- params?: any[]; // Query parameters
982
- startTime: number; // Unix timestamp
983
- endTime?: number; // Unix timestamp
984
- executionTimeMs?: number; // Execution time
985
- resultCount?: number; // Rows returned/affected
986
- error?: string; // Error message if failed
987
- }
988
- ```
989
-
990
- ## Smart Cache Invalidation
991
-
992
- ### How It Works
993
-
994
- ```typescript
995
- // Database schema:
996
- // users (id, name)
997
- // posts (id, user_id, title) -- FK to users
998
- // comments (id, post_id, content) -- FK to posts
999
-
1000
- // When you update a user:
1001
- await users.updateById(1, { name: 'Updated Name' });
1002
-
1003
- // SqlDB invalidates:
1004
- // 1. users:* (direct table)
1005
- // 2. posts:* (depends on users via user_id)
1006
- // 3. comments:* (depends on posts via post_id)
1007
- ```
1008
-
1009
- ### Dependency Graph
1010
-
1011
- ```typescript
1012
- const graph = db.getDependencyGraph();
1013
-
1014
- // Get tables that depend on 'users'
1015
- const deps = graph.getDependencies('users');
1016
- console.log(deps); // ['posts', 'comments']
1017
-
1018
- // Get all tables 'comments' depends on
1019
- const parents = graph.getParents('comments');
1020
- console.log(parents); // ['posts', 'users']
1021
-
1022
- // Check if there's a path
1023
- const hasPath = graph.hasPath('users', 'comments');
1024
- console.log(hasPath); // true
1025
-
1026
- // Get graph info
1027
- const info = graph.getGraphInfo();
1028
- console.log(info); // { tables: 3, relationships: 2 }
1029
- ```
1030
-
1031
- ### Manual Invalidation
1032
-
1033
- ```typescript
1034
- const invalidationManager = db.getInvalidationManager();
1035
-
1036
- // Invalidate single table
1037
- await invalidationManager.invalidateTable('users');
1038
-
1039
- // Invalidate with cascade
1040
- await invalidationManager.invalidateTable('users', {
1041
- cascade: true
117
+ const users = await userRepo.find({
118
+ where: { status: 'active' },
119
+ limit: 10,
1042
120
  });
1043
121
 
1044
- // Invalidate multiple tables
1045
- await invalidationManager.invalidateTables(['users', 'posts']);
1046
-
1047
- // Invalidate by operation
1048
- const cacheManager = db.getCacheManager();
1049
- await cacheManager.deletePattern('users:findMany:*');
1050
- ```
1051
-
1052
- ## Performance Optimization
1053
-
1054
- ### Best Practices
1055
-
1056
- 1. **Configure Appropriate TTL**
1057
- ```typescript
1058
- // High-churn data: short TTL
1059
- cache: { defaultTTL: 30 }
1060
-
1061
- // Stable data: longer TTL
1062
- cache: { defaultTTL: 300 }
1063
- ```
1064
-
1065
- 2. **Use Selective Caching**
1066
- ```typescript
1067
- // Skip cache for real-time data
1068
- const users = await users.findMany(
1069
- { status: 'online' },
1070
- { skipCache: true }
1071
- );
1072
- ```
1073
-
1074
- 3. **Warm Cache for Common Queries**
1075
- ```typescript
1076
- // Pre-warm after deployment
1077
- await users.warmCache({ status: 'active' });
1078
- await posts.warmCache({ published: true });
1079
- ```
1080
-
1081
- 4. **Monitor Cache Performance**
1082
- ```typescript
1083
- const stats = db.getCacheManager().getStats();
1084
-
1085
- if (parseFloat(stats.hitRate) < 80) {
1086
- console.warn('Low cache hit rate:', stats);
1087
- }
1088
- ```
1089
-
1090
- 5. **Use Correlation IDs**
1091
- ```typescript
1092
- // Track request performance
1093
- app.use((req, res, next) => {
1094
- req.correlationId = generateQueryId();
1095
- next();
1096
- });
1097
-
1098
- // Log slow requests
1099
- app.use((req, res, next) => {
1100
- const queries = db.getQueries(req.correlationId);
1101
- const totalTime = queries.reduce((sum, q) =>
1102
- sum + (q.executionTimeMs || 0), 0);
1103
-
1104
- if (totalTime > 1000) {
1105
- console.warn('Slow request:', {
1106
- path: req.path,
1107
- time: totalTime,
1108
- queries: queries.length
1109
- });
1110
- }
1111
- next();
1112
- });
1113
- ```
1114
-
1115
- ### Performance Testing
1116
-
1117
- ```typescript
1118
- // Example performance test
1119
- const iterations = 100;
1120
- const correlationId = generateQueryId();
1121
-
1122
- console.time('100 queries');
1123
- for (let i = 0; i < iterations; i++) {
1124
- await users.findMany({ status: 'active' }, { correlationId });
1125
- }
1126
- console.timeEnd('100 queries');
1127
-
1128
- // Check cache effectiveness
1129
- const stats = db.getCacheManager().getStats();
1130
- console.log(`Hit rate: ${stats.hitRate}`);
1131
- console.log(`Hits: ${stats.hits}, Misses: ${stats.misses}`);
1132
-
1133
- // Analyze query performance
1134
- const queries = db.getQueries(correlationId);
1135
- console.log(`Total queries executed: ${queries.length}`); // Should be 1 if cache works
1136
- ```
1137
-
1138
- ## API Reference
1139
-
1140
- ### SqlDBClient
1141
-
1142
- ```typescript
1143
- class SqlDBClient {
1144
- // Initialize client
1145
- async initialize(): Promise<void>;
1146
-
1147
- // Get table operations
1148
- getTableOperations<T>(tableName: string): TableOperations<T>;
1149
-
1150
- // Get managers
1151
- getCacheManager(): CacheManager;
1152
- getInvalidationManager(): InvalidationManager;
1153
- getDependencyGraph(): DependencyGraph;
1154
-
1155
- // Schema discovery
1156
- getDiscoveredTables(): string[];
1157
- async refreshSchema(): Promise<void>;
1158
-
1159
- // Query tracking
1160
- getQueries(correlationId?: string): QueryMetadata[];
1161
- clearQueries(correlationId?: string): void;
1162
-
1163
- // Health and lifecycle
1164
- async healthCheck(): Promise<HealthStatus>;
1165
- async close(): Promise<void>;
1166
- }
1167
- ```
1168
-
1169
- ### TableOperations
1170
-
1171
- ```typescript
1172
- interface TableOperations<T> {
1173
- // Find operations
1174
- findOne(where: WhereClause<T>, options?: FindOptions): Promise<T | null>;
1175
- findMany(where?: WhereClause<T>, options?: FindOptions): Promise<T[]>;
1176
- findById(id: string | number, correlationId?: string): Promise<T | null>;
1177
- count(where?: WhereClause<T>, correlationId?: string): Promise<number>;
1178
-
1179
- // Insert operations
1180
- insertOne(data: Omit<T, 'id'>, correlationId?: string): Promise<T>;
1181
- insertMany(data: Omit<T, 'id'>[], correlationId?: string): Promise<T[]>;
1182
-
1183
- // Update operations
1184
- updateOne(where: WhereClause<T>, data: Partial<T>, correlationId?: string): Promise<T | null>;
1185
- updateMany(where: WhereClause<T>, data: Partial<T>, correlationId?: string): Promise<number>;
1186
- updateById(id: string | number, data: Partial<T>, correlationId?: string): Promise<T | null>;
1187
-
1188
- // Delete operations
1189
- deleteOne(where: WhereClause<T>, correlationId?: string): Promise<boolean>;
1190
- deleteMany(where: WhereClause<T>, correlationId?: string): Promise<number>;
1191
- deleteById(id: string | number, correlationId?: string): Promise<boolean>;
1192
-
1193
- // Raw queries
1194
- raw<R = any>(sql: string, params?: any[], correlationId?: string): Promise<R>;
1195
-
1196
- // Cache management
1197
- invalidateCache(): Promise<void>;
1198
- warmCache(where?: WhereClause<T>, correlationId?: string): Promise<void>;
1199
- }
1200
- ```
1201
-
1202
- ### CacheManager
1203
-
1204
- ```typescript
1205
- class CacheManager {
1206
- async get<T>(key: string): Promise<T | null>;
1207
- async set(key: string, value: any, ttl?: number): Promise<void>;
1208
- async delete(key: string): Promise<void>;
1209
- async deletePattern(pattern: string): Promise<number>;
1210
- async exists(key: string): Promise<boolean>;
1211
- async clear(): Promise<void>;
1212
-
1213
- getStats(): CacheStats;
1214
- resetStats(): void;
1215
- isEnabled(): boolean;
1216
- getKeyBuilder(): CacheKeyBuilder;
1217
- }
122
+ await userRepo.updateById(user.userId, { status: 'inactive' });
1218
123
  ```
1219
124
 
1220
- ## Who Is This For?
125
+ **What You Get:**
126
+ - βœ… **Zero boilerplate** - No custom CRUD services
127
+ - βœ… **Automatic lifecycle hooks** - `@BeforeInsert`, `@AfterLoad`, etc.
128
+ - βœ… **Type-safe queries** - Full autocomplete + type checking
129
+ - βœ… **Automatic caching** - Redis-backed, FK-aware
130
+ - βœ… **94% less code** compared to manual implementations
131
+ - βœ… **Prisma-style operators** - `{ age: { gte: 18 } }`
132
+ - βœ… **Relation loading** - N+1 prevention with batching
1221
133
 
1222
- ### βœ… Perfect for you if:
1223
-
1224
- - πŸš€ **You want better performance** without rewriting your app
1225
- - πŸ’° **You're tired of paying for database CPU** that could be cached
1226
- - πŸ› **You've debugged stale cache bugs** at 3am
1227
- - πŸ“š **You hate writing cache invalidation logic**
1228
- - ⚑ **You need <10ms API response times**
1229
- - πŸ”₯ **You're scaling and your database is the bottleneck**
1230
- - 🎯 **You want type safety** without code generation
1231
- - πŸ“Š **You need query observability** built-in
1232
-
1233
- ### ❌ Not for you if:
1234
-
1235
- - Your app has <100 requests/day (caching overhead not worth it)
1236
- - You exclusively write data (writes bypass cache)
1237
- - You don't have Redis available
1238
- - You need MySQL-specific features (use MariaDB instead)
134
+ πŸ“– **[Read Full Repository Pattern Guide β†’](./docs/REPOSITORY_PATTERN.md)**
1239
135
 
1240
136
  ---
1241
137
 
1242
- ## Migration from `mariadb` Package
1243
-
1244
- Migrating is trivial. Here's what changes:
1245
-
1246
- ### Before (mariadb) - 15 lines of boilerplate
1247
-
1248
- ```typescript
1249
- import mariadb from 'mariadb';
1250
-
1251
- const pool = mariadb.createPool({
1252
- host: 'localhost',
1253
- user: 'root',
1254
- password: 'password',
1255
- database: 'mydb',
1256
- connectionLimit: 10
1257
- });
1258
-
1259
- // Every query needs manual connection management
1260
- const conn = await pool.getConnection();
1261
- try {
1262
- const users = await conn.query('SELECT * FROM users WHERE status = ?', ['active']);
1263
- const count = await conn.query('SELECT COUNT(*) as total FROM users WHERE status = ?', ['active']);
1264
- return users;
1265
- } finally {
1266
- conn.release();
1267
- }
1268
-
1269
- // No caching
1270
- // No type safety
1271
- // Manual connection pooling
1272
- // Verbose error handling
1273
- ```
138
+ ## πŸ”„ Easy Migration from Custom CRUD Services
1274
139
 
1275
- ### After (@bhushanpawar/sqldb) - 5 lines with superpowers
140
+ If you have existing code using custom `UnifiedCRUDService` or similar patterns, SqlDB's backward compatibility methods make migration seamless:
1276
141
 
1277
142
  ```typescript
1278
- import { createSqlDB } from '@bhushanpawar/sqldb';
1279
-
1280
- const db = await createSqlDB({
1281
- mariadb: { host: 'localhost', user: 'root', password: 'password', database: 'mydb' },
1282
- redis: { host: 'localhost' }
1283
- });
1284
-
1285
- // Clean API + automatic caching + type safety
1286
- const users = await db.users.findMany({ status: 'active' });
1287
- const count = await db.users.count({ status: 'active' });
1288
-
1289
- // ✨ Cached automatically
1290
- // ✨ Invalidated on writes
1291
- // ✨ Type-safe
1292
- // ✨ Connection pooling handled
1293
- // ✨ Error handling built-in
1294
- ```
1295
-
1296
- ### What You Gain
1297
-
1298
- | Before | After | Improvement |
1299
- |--------|-------|-------------|
1300
- | Manual `query()` calls | Clean `findMany()`, `findById()` | **10x less code** |
1301
- | No caching | Automatic Redis cache | **20x faster** |
1302
- | Manual connection management | Automatic pooling | **0 bugs** |
1303
- | Raw SQL everywhere | Type-safe methods | **TypeScript bliss** |
1304
- | No invalidation | Cascade invalidation | **0 stale data** |
1305
- | Basic logging | Performance metrics | **Debug in seconds** |
1306
-
1307
- ### Migration Checklist
1308
-
1309
- - [ ] Install packages: `npm install @bhushanpawar/sqldb mariadb redis`
1310
- - [ ] Set up Redis (if not already running)
1311
- - [ ] Replace `mariadb.createPool()` with `createSqlDB()`
1312
- - [ ] Replace `conn.query()` with `db.table.findMany()`, `findById()`, etc.
1313
- - [ ] Remove manual connection management (`getConnection()`, `release()`)
1314
- - [ ] Remove manual caching logic (if any)
1315
- - [ ] Add TypeScript interfaces for tables (optional but recommended)
1316
- - [ ] Test and deploy
1317
- - [ ] Watch your response times drop πŸ“‰
1318
- - [ ] Celebrate πŸŽ‰
1319
-
1320
- ## Performance Benchmarks
1321
-
1322
- Real-world results from production deployments:
1323
-
1324
- ### Response Times
1325
- ```
1326
- Database Query: 200ms 🐌
1327
- Manual Cache: 15ms ⚠️
1328
- SqlDB (cold): 45ms βœ…
1329
- SqlDB (warm): 0.8ms ⚑ 250x faster!
1330
- ```
1331
-
1332
- ### Metrics That Matter
1333
-
1334
- | Metric | Value | Impact |
1335
- |--------|-------|--------|
1336
- | **Cache Hit Rate** | 99.2% | Only 1 in 100 queries hits DB |
1337
- | **P50 Response Time** | <1ms | Instant for users |
1338
- | **P99 Response Time** | 12ms | Fast even at extremes |
1339
- | **Throughput** | 10,000+ qps | Handle Black Friday traffic |
1340
- | **DB CPU Reduction** | 85% ↓ | Save $$$$ on database |
1341
- | **Memory per Query** | ~1KB | Efficient caching |
1342
- | **Schema Discovery** | 2.2s | 9x faster than v1 |
143
+ // Your old service code works immediately!
144
+ const userRepo = db.getRepository(User);
1343
145
 
1344
- ### Load Test Results
146
+ // Legacy methods (drop-in replacements)
147
+ await userRepo.findByPK(userId, ['orders', 'addresses']);
148
+ await userRepo.findByPaginationQuery({ page: 1, limit: 20, orderBy: 'createdAt' });
149
+ await userRepo.findBySearchFilterModel({ search: 'john', searchFields: ['email'] });
150
+ await userRepo.countByQuery({ status: 'active' });
1345
151
 
1346
- ```bash
1347
- # 1000 concurrent users, 10,000 requests
1348
- npm run usage perf
152
+ // Then migrate incrementally to modern syntax
153
+ await userRepo.findById(userId, { withRelations: { dependents: ['orders'] } });
154
+ await userRepo.find({ limit: 20, offset: 20, orderBy: { column: 'createdAt', direction: 'DESC' } });
1349
155
  ```
1350
156
 
1351
- **Results:**
1352
- - Average response: **0.9ms**
1353
- - P99 response: **8ms**
1354
- - Throughput: **12,450 req/s**
1355
- - Database queries: **124** (99% cache hit)
1356
- - No errors, no timeouts, no cache misses
157
+ **Available Legacy Methods:**
158
+ - `findByPK(id, relationsToFetch?)` - Drop-in for custom `findByPK`
159
+ - `findByQuery(query)` - Accepts legacy query objects
160
+ - `findAllRecords(filters?)` - Replaces `findAllRecords`
161
+ - `findByPaginationQuery(paginationQuery)` - Pagination helper
162
+ - `findBySearchFilterModel(searchFilter)` - Search filter helper
163
+ - `countByQuery(query)` / `countAll()` - Count helpers
164
+ - `deleteByQuery(query)` - Delete with legacy format
1357
165
 
1358
- See [PERFORMANCE_RESULTS.md](./docs/PERFORMANCE_RESULTS.md) for detailed benchmarks.
166
+ **Migration Strategy:**
167
+ 1. Replace `UnifiedCRUDService` extends with `db.getRepository(Entity)`
168
+ 2. Code works immediately (zero changes!)
169
+ 3. Migrate methods incrementally to modern syntax
170
+ 4. Enjoy 94% code reduction
1359
171
 
1360
172
  ---
1361
173
 
1362
- ## Testing
1363
-
1364
- ```bash
1365
- # Run all tests
1366
- npm test
1367
-
1368
- # Run with coverage
1369
- npm run test:coverage
1370
-
1371
- # Run performance benchmarks
1372
- npm run usage
1373
-
1374
- # Run specific example
1375
- npm run usage -- examples/auto-warming-example.ts
1376
- ```
1377
-
1378
- ## Examples
174
+ ## ⚑ Key Features at a Glance
1379
175
 
1380
- This section provides examples from simple to complex, helping you get started quickly and gradually explore advanced features.
176
+ | Feature | What You Get |
177
+ |---------|--------------|
178
+ | 🎯 **Repository Pattern (NEW!)** | TypeORM-like API with zero boilerplate. |
179
+ | πŸ”„ **Lifecycle Hooks (NEW!)** | `@BeforeInsert`, `@AfterLoad`, `@BeforeUpdate`, etc. |
180
+ | πŸš€ **Automatic Caching** | Every query cached in Redis. 99%+ hit rate. <1ms response. |
181
+ | 🧠 **Smart Invalidation** | Update `users`? We clear `posts` & `comments` too. Follows FKs. |
182
+ | 🎯 **Auto-Warming** | ML-powered warming learns your patterns. No cold starts. |
183
+ | πŸ”’ **Type-Safe** | Full TypeScript support. Autocomplete everything. |
184
+ | πŸ“Š **Prisma-style Operators** | `{ age: { gte: 18 }, email: { contains: '@' } }` |
185
+ | πŸ” **Full-text Search** | Built-in inverted index for fast search. |
186
+ | πŸ“ **Geo-location Search** | Find by distance with clustering. |
187
+ | πŸ“ˆ **Query Tracking** | See every query with timing. Debug in seconds. |
188
+ | 🎨 **Beautiful Logging** | βš‘πŸš€βœ…βš οΈπŸŒ - Know performance at a glance. |
189
+ | πŸ”— **Zero Config** | Auto-discovers schema. Maps relationships. Just works. |
1381
190
 
1382
- ### 1. Hello World - Minimal Setup
191
+ ---
1383
192
 
1384
- The simplest way to get started with SqlDB:
193
+ ## 🎬 See It In Action
1385
194
 
195
+ ### Traditional Approach (Complex)
1386
196
  ```typescript
1387
- import { createSqlDB } from '@bhushanpawar/sqldb';
1388
-
1389
- // Initialize with minimal config
1390
- const db = await createSqlDB({
1391
- mariadb: {
1392
- host: 'localhost',
1393
- user: 'root',
1394
- password: 'password',
1395
- database: 'mydb',
1396
- },
1397
- redis: {
1398
- host: 'localhost',
1399
- },
1400
- });
1401
-
1402
- // Query users - automatically cached!
1403
- const users = await (db as any).users.findMany();
1404
- console.log('Found users:', users.length);
197
+ // Manual cache management 😰
198
+ const cacheKey = `users:${status}:${page}`;
199
+ let users = await redis.get(cacheKey);
200
+ if (!users) {
201
+ users = await db.query('SELECT * FROM users WHERE status = ?', [status]);
202
+ await redis.set(cacheKey, JSON.stringify(users), 'EX', 60);
203
+ // Hope you remembered all the cache keys to invalidate...
204
+ } else {
205
+ users = JSON.parse(users);
206
+ }
1405
207
 
1406
- await db.close();
208
+ // Update user - manual cache invalidation 😰
209
+ await db.query('UPDATE users SET name = ? WHERE id = ?', [name, id]);
210
+ await redis.del('users:all');
211
+ await redis.del('users:active');
212
+ await redis.del(`users:${id}`);
213
+ await redis.del('posts:*'); // Related posts?
214
+ // Did I forget any keys? πŸ€”
1407
215
  ```
1408
216
 
1409
- **What this does:**
1410
- - Connects to MariaDB and Redis
1411
- - Auto-discovers all tables in your database
1412
- - Enables caching with smart defaults (60s TTL)
1413
- - Provides simple CRUD operations
1414
-
1415
- ---
1416
-
1417
- ### 2. Basic CRUD Operations
1418
-
1419
- Learn all the basic operations with caching:
1420
-
217
+ ### SqlDB Approach (Simple + Fast)
1421
218
  ```typescript
1422
- import { createSqlDB } from '@bhushanpawar/sqldb';
1423
-
1424
- const db = await createSqlDB({
1425
- mariadb: { host: 'localhost', user: 'root', password: 'password', database: 'mydb' },
1426
- redis: { host: 'localhost' },
1427
- cache: {
1428
- enabled: true,
1429
- defaultTTL: 60,
1430
- invalidateOnWrite: true, // Auto-clear cache on INSERT/UPDATE/DELETE
1431
- },
1432
- });
219
+ // Repository pattern with auto-caching ✨
220
+ const userRepo = db.getRepository(User);
221
+ const users = await userRepo.find({ where: { status: 'active' } });
222
+ // First call: 200ms (database)
223
+ // Next calls: <1ms (cache)
1433
224
 
1434
- // READ operations (cached automatically)
1435
- const allUsers = await (db as any).users.findMany();
1436
- const activeUsers = await (db as any).users.findMany({ status: 'active' });
1437
- const user = await (db as any).users.findById(1);
1438
- const count = await (db as any).users.count({ status: 'active' });
225
+ // Update with cascade invalidation ✨
226
+ await userRepo.updateById(1, { name: 'Jane' });
227
+ // Automatically clears:
228
+ // βœ“ All user queries
229
+ // βœ“ All post queries (has user_id FK)
230
+ // βœ“ All comment queries (has post_id β†’ user_id FK)
231
+ // Zero stale data. Zero manual work.
232
+ ```
1439
233
 
1440
- // CREATE operations (invalidates cache)
1441
- const newUser = await (db as any).users.insertOne({
1442
- name: 'John Doe',
1443
- email: 'john@example.com',
1444
- });
234
+ **That's it.** No cache keys. No invalidation logic. No stale data bugs at 3am.
1445
235
 
1446
- // UPDATE operations (invalidates cache)
1447
- await (db as any).users.updateById(1, { status: 'verified' });
1448
- await (db as any).users.updateMany({ status: 'pending' }, { status: 'active' });
236
+ ---
1449
237
 
1450
- // DELETE operations (invalidates cache)
1451
- await (db as any).users.deleteById(1);
1452
- await (db as any).users.deleteMany({ status: 'inactive' });
238
+ ## πŸ“Š The Results Speak for Themselves
1453
239
 
1454
- // Check cache performance
1455
- const stats = db.getCacheManager().getStats();
1456
- console.log('Cache hit rate:', stats.hitRate);
240
+ <table>
241
+ <tr>
242
+ <td width="50%">
1457
243
 
1458
- await db.close();
244
+ **Before SqlDB** 😰
245
+ ```
246
+ Average response: 250ms
247
+ Database CPU: 85%
248
+ Cache hit rate: 0%
249
+ Stale data bugs: Weekly
250
+ Boilerplate code: 800+ lines
251
+ Developer happiness: 😫
1459
252
  ```
1460
253
 
1461
- **New concepts:**
1462
- - Automatic cache invalidation on writes
1463
- - Multiple find/update/delete methods
1464
- - Cache statistics monitoring
254
+ </td>
255
+ <td width="50%">
256
+
257
+ **After SqlDB** πŸŽ‰
258
+ ```
259
+ Average response: <1ms (250x faster ⚑)
260
+ Database CPU: 15% (85% reduction)
261
+ Cache hit rate: 99%+ (automatic)
262
+ Stale data bugs: Never (intelligent invalidation)
263
+ Boilerplate code: 0 lines (built-in)
264
+ Developer happiness: 😍
265
+ ```
1465
266
 
1466
- **See:** [basic-usage.ts](./examples/basic-usage.ts)
267
+ </td>
268
+ </tr>
269
+ </table>
1467
270
 
1468
271
  ---
1469
272
 
1470
- ### 3. Type-Safe Queries with TypeScript
273
+ ## πŸ†• NEW: Repository Pattern Features
1471
274
 
1472
- Add full type safety to your queries:
275
+ ### Lifecycle Hooks
276
+
277
+ Execute code at specific points in an entity's lifecycle:
1473
278
 
1474
279
  ```typescript
1475
- import { createSqlDB, SqlDBWithTables } from '@bhushanpawar/sqldb';
280
+ @Entity()
281
+ class User {
282
+ @BeforeInsert()
283
+ @BeforeUpdate()
284
+ async hashPassword() {
285
+ if (this.password) {
286
+ this.password = await bcrypt.hash(this.password, 10);
287
+ }
288
+ }
1476
289
 
1477
- // Define your schema
1478
- interface User {
1479
- id: number;
1480
- name: string;
1481
- email: string;
1482
- status: 'active' | 'inactive' | 'verified';
1483
- created_at: Date;
1484
- }
290
+ @AfterLoad()
291
+ maskEmail() {
292
+ this.email = this.email.replace(/(.{2}).*(@.*)/, '$1***$2');
293
+ }
1485
294
 
1486
- interface Order {
1487
- id: number;
1488
- user_id: number;
1489
- total: number;
1490
- status: string;
295
+ @AfterLoad()
296
+ calculateFullName() {
297
+ this.fullName = `${this.firstName} ${this.lastName}`;
298
+ }
1491
299
  }
300
+ ```
1492
301
 
1493
- interface MySchema {
1494
- users: User;
1495
- orders: Order;
1496
- }
302
+ **Available Hooks:**
303
+ - `@AfterLoad` - After entity loaded from DB
304
+ - `@BeforeInsert` / `@AfterInsert` - Before/after insert
305
+ - `@BeforeUpdate` / `@AfterUpdate` - Before/after update
306
+ - `@BeforeDelete` / `@AfterDelete` - Before/after delete
1497
307
 
1498
- // Create typed DB instance
1499
- type MyDB = SqlDBWithTables<MySchema>;
1500
- const db = await createSqlDB(config) as MyDB;
308
+ ### BaseRepository<T> API
1501
309
 
1502
- // Full type safety!
1503
- const users = await db.users.findMany(); // Type: User[]
1504
- const user = await db.users.findById(1); // Type: User | null
1505
- await db.users.updateById(1, { status: 'verified' }); // Type-checked!
310
+ Type-safe repository with automatic entity management:
1506
311
 
1507
- // TypeScript will catch errors
1508
- // await db.users.updateById(1, { invalid: 'field' }); // ❌ Error!
1509
- ```
312
+ ```typescript
313
+ const userRepo = db.getRepository(User);
1510
314
 
1511
- **New concepts:**
1512
- - TypeScript interfaces for your schema
1513
- - Compile-time type checking
1514
- - Auto-completion in your IDE
315
+ // Create
316
+ const user = await userRepo.save({ email: 'john@example.com' });
317
+ const users = await userRepo.saveMany([{ email: 'a@b.com' }, { email: 'c@d.com' }]);
1515
318
 
1516
- **See:** [typed-tables-example.ts](./examples/typed-tables-example.ts), [DYNAMIC_TABLE_ACCESS.md](./docs/DYNAMIC_TABLE_ACCESS.md)
319
+ // Read
320
+ const one = await userRepo.findOne({ where: { email: 'john@example.com' } });
321
+ const many = await userRepo.find({ where: { status: 'active' }, limit: 10 });
322
+ const byId = await userRepo.findById(123);
323
+ const all = await userRepo.findAll();
1517
324
 
1518
- ---
325
+ // Update
326
+ const updated = await userRepo.update({ status: 'pending' }, { status: 'active' });
327
+ const updatedOne = await userRepo.updateById(123, { status: 'verified' });
328
+
329
+ // Delete
330
+ const deleted = await userRepo.delete({ status: 'inactive' });
331
+ const deletedOne = await userRepo.deleteById(123);
1519
332
 
1520
- ### 4. Query Tracking & Performance Monitoring
333
+ // Helpers
334
+ const count = await userRepo.count({ status: 'active' });
335
+ const exists = await userRepo.exists({ email: 'john@example.com' });
336
+ const results = await userRepo.search('john', { fields: ['name', 'email'] });
337
+ ```
1521
338
 
1522
- Track query performance with correlation IDs:
339
+ ### Prisma-style Query Operators
1523
340
 
1524
341
  ```typescript
1525
- import { createSqlDB, generateQueryId } from '@bhushanpawar/sqldb';
1526
-
1527
- const db = await createSqlDB({
1528
- mariadb: { /* config */ },
1529
- redis: { /* config */ },
1530
- logging: { level: 'info' },
342
+ // Number operators
343
+ const adults = await userRepo.find({
344
+ where: { age: { gte: 18, lte: 65 } }
1531
345
  });
1532
346
 
1533
- // Generate a correlation ID (e.g., per HTTP request)
1534
- const correlationId = generateQueryId();
1535
-
1536
- // All queries with same correlationId are tracked together
1537
- const users = await (db as any).users.findMany(
1538
- { status: 'active' },
1539
- { correlationId }
1540
- );
1541
-
1542
- const count = await (db as any).users.count(
1543
- { status: 'active' },
1544
- correlationId
1545
- );
347
+ // String operators
348
+ const gmailUsers = await userRepo.find({
349
+ where: { email: { contains: '@gmail.com', mode: 'insensitive' } }
350
+ });
1546
351
 
1547
- // Analyze performance
1548
- const queries = db.getQueries(correlationId);
1549
- queries.forEach(q => {
1550
- console.log({
1551
- table: q.sql.match(/FROM (\w+)/)?.[1],
1552
- executionTime: q.executionTimeMs + 'ms',
1553
- cached: q.resultCount,
1554
- });
352
+ // Array operators
353
+ const activeOrPending = await userRepo.find({
354
+ where: { status: { in: ['active', 'pending'] } }
1555
355
  });
1556
356
 
1557
- // Calculate total time
1558
- const totalTime = queries.reduce((sum, q) => sum + (q.executionTimeMs || 0), 0);
1559
- console.log(`Total query time: ${totalTime}ms`);
357
+ // Logical operators
358
+ const filtered = await userRepo.find({
359
+ where: {
360
+ AND: [
361
+ { status: 'active' },
362
+ { OR: [{ role: 'admin' }, { role: 'moderator' }] }
363
+ ]
364
+ }
365
+ });
1560
366
 
1561
- // Clean up
1562
- db.clearQueries(correlationId);
367
+ // Null checks
368
+ const noAvatar = await userRepo.find({
369
+ where: { avatarUrl: { isNull: true } }
370
+ });
1563
371
  ```
1564
372
 
1565
- **New concepts:**
1566
- - Correlation IDs for request tracking
1567
- - Query performance analysis
1568
- - Debugging slow requests
373
+ ### Relation Loading
1569
374
 
1570
- **Use cases:**
1571
- - HTTP request tracking
1572
- - Performance monitoring
1573
- - Identifying slow queries
375
+ ```typescript
376
+ @Entity()
377
+ class User {
378
+ @OneToMany(() => Order, order => order.user)
379
+ orders: Order[];
380
+ }
1574
381
 
1575
- **See:** [query-tracking.ts](./examples/query-tracking.ts), [QUERY_TRACKING.md](./docs/QUERY_TRACKING.md)
382
+ // Load with relations (batched to avoid N+1)
383
+ const users = await userRepo.find({
384
+ where: { status: 'active' },
385
+ withRelations: { dependents: ['orders'] }
386
+ });
1576
387
 
1577
- ---
388
+ users.forEach(user => {
389
+ console.log(`${user.name} has ${user.orders.length} orders`);
390
+ });
391
+ ```
1578
392
 
1579
- ### 5. Enhanced Query Logging
393
+ ### Schema Registry (No Decorators!)
1580
394
 
1581
- Monitor all database queries with detailed logging:
395
+ Don't want decorators? Use the schema registry instead:
1582
396
 
1583
397
  ```typescript
1584
- import { createSqlDB } from '@bhushanpawar/sqldb';
398
+ import { defineEntitySchema } from '@bhushanpawar/sqldb';
1585
399
 
1586
- const db = await createSqlDB({
1587
- mariadb: {
1588
- host: 'localhost',
1589
- user: 'root',
1590
- password: 'password',
1591
- database: 'mydb',
1592
- logging: true, // Enable query logging
400
+ class User {
401
+ userId: string;
402
+ email: string;
403
+ password: string;
404
+ }
405
+
406
+ defineEntitySchema(User, {
407
+ tableName: 'users',
408
+ columns: {
409
+ userId: { primary: true },
410
+ email: {},
411
+ password: {},
1593
412
  },
1594
- redis: { host: 'localhost' },
1595
- logging: { level: 'info' },
1596
413
  });
1597
414
 
1598
- // Run queries - they'll be logged automatically
1599
- const users = await (db as any).users.findMany({ status: 'active' });
1600
- const count = await (db as any).users.count({});
1601
-
1602
- // Console output shows:
1603
- // βœ… SELECT on users - 45ms - 10 rows
1604
- // πŸš€ SELECT on users - 12ms - 1 rows
1605
- // ⚠️ SELECT on orders - 250ms - 100 rows (shows SQL for slow queries)
415
+ // Use same repository API
416
+ const repo = db.getRepository(User);
1606
417
  ```
1607
418
 
1608
- **Logging features:**
1609
- - Query type (SELECT, INSERT, UPDATE, DELETE)
1610
- - Table name extraction
1611
- - Execution time with performance emojis
1612
- - Automatic SQL display for slow queries (>200ms)
1613
-
1614
- **Performance emojis:**
1615
- - ⚑ Very fast (<10ms)
1616
- - πŸš€ Fast (<50ms)
1617
- - βœ… Good (<200ms)
1618
- - ⚠️ Slow (<500ms)
1619
- - 🐌 Very slow (β‰₯500ms)
1620
-
1621
- **See:** [query-logging-example.ts](./examples/query-logging-example.ts), [QUERY_LOGGING.md](./docs/QUERY_LOGGING.md)
419
+ πŸ“– **[Repository Pattern Guide](./docs/REPOSITORY_PATTERN.md)** | **[Before/After Comparison](./examples/before-after-comparison.md)** | **[Working Example](./examples/repository-pattern-example.ts)**
1622
420
 
1623
421
  ---
1624
422
 
1625
- ### 6. Smart Cache Invalidation with Relations
423
+ ## πŸš€ Installation & Setup
424
+
425
+ ```bash
426
+ npm install @bhushanpawar/sqldb mariadb redis
427
+ ```
1626
428
 
1627
- Automatic cascade invalidation based on foreign keys:
429
+ ### Basic Setup
1628
430
 
1629
431
  ```typescript
1630
- // Database schema:
1631
- // users (id, name)
1632
- // posts (id, user_id, title) ← FK to users
1633
- // comments (id, post_id, content) ← FK to posts
432
+ import { createSqlDB } from '@bhushanpawar/sqldb';
1634
433
 
1635
434
  const db = await createSqlDB({
1636
- mariadb: { /* config */ },
1637
- redis: { /* config */ },
435
+ mariadb: {
436
+ host: 'localhost',
437
+ user: 'root',
438
+ password: 'password',
439
+ database: 'mydb',
440
+ },
441
+ redis: {
442
+ host: 'localhost',
443
+ },
1638
444
  cache: {
1639
445
  enabled: true,
1640
- invalidateOnWrite: true,
1641
- cascadeInvalidation: true, // Enable cascade invalidation
1642
- },
1643
- discovery: {
1644
- autoDiscover: true, // Auto-discover relationships
446
+ defaultTTL: 60,
1645
447
  },
1646
448
  });
1647
449
 
1648
- // When you update a user...
1649
- await (db as any).users.updateById(1, { name: 'Updated Name' });
1650
-
1651
- // SqlDB automatically invalidates:
1652
- // 1. users:* (direct table)
1653
- // 2. posts:* (depends on users via user_id)
1654
- // 3. comments:* (depends on posts via post_id)
450
+ // Use repository pattern
451
+ const userRepo = db.getRepository(User);
452
+ const users = await userRepo.find({ where: { status: 'active' } });
1655
453
 
1656
- // View the dependency graph
1657
- const graph = db.getDependencyGraph();
1658
- const dependencies = graph.getDependencies('users');
1659
- console.log('Tables that depend on users:', dependencies); // ['posts', 'comments']
454
+ // Or use table operations directly
455
+ const users = await db.users.findMany({ status: 'active' });
1660
456
 
1661
- // Manual invalidation with cascade
1662
- const invalidationManager = db.getInvalidationManager();
1663
- await invalidationManager.invalidateTable('users', { cascade: true });
457
+ await db.close();
1664
458
  ```
1665
459
 
1666
- **New concepts:**
1667
- - Automatic relationship discovery
1668
- - Cascade cache invalidation
1669
- - Dependency graph visualization
1670
-
1671
- **See:** [relationships-example.ts](./examples/relationships-example.ts)
1672
-
1673
- ---
1674
-
1675
- ### 7. Singleton Pattern for Production
1676
-
1677
- Share a single SqlDB instance across your entire application:
460
+ ### Production Setup (Singleton Pattern)
1678
461
 
1679
462
  ```typescript
1680
- // db.ts - Initialize once at app startup
463
+ // db.ts - Initialize once
1681
464
  import { createSqlDB } from '@bhushanpawar/sqldb';
1682
465
 
1683
- export const initializeDB = async () => {
466
+ export const initDB = async () => {
1684
467
  const db = await createSqlDB({
1685
468
  mariadb: { /* config */ },
1686
469
  redis: { /* config */ },
1687
- cache: { enabled: true },
1688
- }, { singleton: true }); // Enable singleton mode
1689
-
470
+ }, { singleton: true }); // Enable singleton
1690
471
  return db;
1691
472
  };
1692
473
 
1693
474
  // server.ts - Initialize at startup
1694
- import { initializeDB } from './db';
1695
-
1696
- const db = await initializeDB();
1697
- console.log('Database initialized');
475
+ await initDB();
1698
476
 
1699
477
  // userController.ts - Access anywhere
1700
478
  import { getSqlDB } from '@bhushanpawar/sqldb';
1701
479
 
1702
- export const getUsers = async () => {
1703
- const db = getSqlDB(); // Returns the same instance
1704
- return await (db as any).users.findMany();
1705
- };
480
+ const db = getSqlDB(); // Same instance
481
+ const userRepo = db.getRepository(User);
482
+ ```
1706
483
 
1707
- // orderController.ts - Access anywhere
1708
- import { getSqlDB } from '@bhushanpawar/sqldb';
484
+ ---
1709
485
 
1710
- export const getOrders = async (userId: number) => {
1711
- const db = getSqlDB(); // Same instance
1712
- return await (db as any).orders.findMany({ user_id: userId });
1713
- };
1714
- ```
486
+ ## ⚑ Core Features
1715
487
 
1716
- **Benefits:**
1717
- - Single connection pool shared across app
1718
- - No need to pass `db` around
1719
- - Prevents multiple connections
1720
- - Clean architecture
488
+ ### 1. Automatic Caching
1721
489
 
1722
- **See:** [singleton-example.ts](./examples/singleton-example.ts), [SINGLETON_PATTERN.md](./docs/SINGLETON_PATTERN.md)
490
+ Every query is automatically cached in Redis:
1723
491
 
1724
- ---
492
+ ```typescript
493
+ // First call: queries database (200ms)
494
+ const users = await db.users.findMany({ status: 'active' });
495
+
496
+ // Next 100 calls: served from cache (<1ms)
497
+ ```
1725
498
 
1726
- ### 8. Cache Warming for Better Performance
499
+ ### 2. Intelligent Cache Invalidation
1727
500
 
1728
- Pre-warm cache on startup for frequently accessed queries:
501
+ Updates automatically invalidate related tables by following foreign keys:
1729
502
 
1730
503
  ```typescript
1731
- import { createSqlDB } from '@bhushanpawar/sqldb';
504
+ // Update a user
505
+ await db.users.updateById(1, { name: 'Jane' });
506
+
507
+ // SqlDB automatically clears:
508
+ // βœ“ users:* cache
509
+ // βœ“ posts:* cache (has user_id FK)
510
+ // βœ“ comments:* cache (has post_id FK β†’ user_id FK)
511
+ ```
512
+
513
+ ### 3. Auto-Warming
1732
514
 
515
+ ML-powered cache warming learns your query patterns:
516
+
517
+ ```typescript
1733
518
  const db = await createSqlDB({
1734
- mariadb: { /* config */ },
1735
- redis: { /* config */ },
1736
- cache: { enabled: true },
519
+ warming: {
520
+ enabled: true,
521
+ intervalMs: 60000, // Warm every 60 seconds
522
+ topQueriesPerTable: 10, // Warm top 10 queries per table
523
+ },
1737
524
  });
1738
525
 
1739
- // Warm cache for specific queries
1740
- await (db as any).users.warmCache({ status: 'active' });
1741
- await (db as any).products.warmCache({ featured: true });
1742
-
1743
- // Warm cache with related tables (follows foreign keys)
1744
- await (db as any).orders.warmCacheWithRelations(
1745
- { status: 'pending' },
1746
- {
1747
- depth: 1, // How deep to traverse relationships
1748
- warmDependents: true, // Warm tables that reference this table
1749
- warmDependencies: true, // Warm tables this table references
1750
- correlationId: 'startup-warming',
1751
- }
1752
- );
526
+ // After deployment, your cache is already warm ✨
527
+ ```
1753
528
 
1754
- // This warms:
1755
- // - orders (main table)
1756
- // - users (orders.user_id β†’ users.id)
1757
- // - order_items (order_items.order_id β†’ orders.id)
1758
- // - products (order_items.product_id β†’ products.id)
529
+ ### 4. Full-text Search
1759
530
 
1760
- // Now these queries are instant (served from cache)
1761
- const orders = await (db as any).orders.findMany({ status: 'pending' });
1762
- const user = await (db as any).users.findById(orders[0].user_id);
531
+ Built-in inverted index for fast search:
532
+
533
+ ```typescript
534
+ const userRepo = db.getRepository(User);
535
+ const results = await userRepo.search('john', {
536
+ fields: ['name', 'email'],
537
+ fuzzy: true,
538
+ limit: 20,
539
+ });
1763
540
  ```
1764
541
 
1765
- **Use cases:**
1766
- - Application startup optimization
1767
- - Pre-loading frequently accessed data
1768
- - Improving first request performance
542
+ ### 5. Geo-location Search
1769
543
 
1770
- **See:** Cache warming section above
544
+ Find entities by distance:
1771
545
 
1772
- ---
546
+ ```typescript
547
+ const providers = await db.providers.findMany({
548
+ latitude: 40.7128,
549
+ longitude: -74.0060,
550
+ radius: 10, // 10km radius
551
+ });
552
+ ```
1773
553
 
1774
- ### 9. Auto-Warming - Intelligent Background Cache Warming
554
+ ### 6. Query Tracking
1775
555
 
1776
- Automatically warm cache for your hottest queries:
556
+ Track every query with correlation IDs:
1777
557
 
1778
558
  ```typescript
1779
- import { createSqlDB } from '@bhushanpawar/sqldb';
559
+ import { generateQueryId } from '@bhushanpawar/sqldb';
1780
560
 
1781
- const db = await createSqlDB({
1782
- mariadb: { /* config */ },
1783
- redis: { /* config */ },
1784
- cache: { enabled: true },
1785
- warming: {
1786
- enabled: true, // Enable auto-warming
1787
- intervalMs: 60000, // Warm every 60 seconds
1788
- topQueriesPerTable: 10, // Warm top 10 queries per table
1789
- minAccessCount: 3, // Must be accessed at least 3 times
1790
- maxStatsAge: 3600000, // Consider queries from last hour
1791
- useSeperatePool: true, // Use separate connection pool
1792
- warmingPoolSize: 2, // 2 connections for warming
1793
- trackInDatabase: true, // Persist stats in database
1794
- statsTableName: '__sqldb_query_stats',
1795
-
1796
- // Callbacks
1797
- onWarmingComplete: (stats) => {
1798
- console.log('Warming complete:', {
1799
- queriesWarmed: stats.queriesWarmed,
1800
- cacheHitRateBefore: (stats.cacheHitRateBefore * 100).toFixed(1) + '%',
1801
- cacheHitRateAfter: (stats.cacheHitRateAfter * 100).toFixed(1) + '%',
1802
- });
1803
- },
1804
- onWarmingError: (error) => {
1805
- console.error('Warming error:', error.message);
1806
- },
1807
- },
1808
- });
561
+ const correlationId = generateQueryId();
562
+ const users = await db.users.findMany({ status: 'active' }, { correlationId });
1809
563
 
1810
- // Use your app normally - auto-warming tracks which queries are hot
1811
- for (let i = 0; i < 10; i++) {
1812
- const users = await (db as any).users.findMany({ status: 'active' });
1813
- const orders = await (db as any).orders.findMany({ status: 'pending' });
1814
- await new Promise(r => setTimeout(r, 1000));
1815
- }
564
+ // Get all queries for this request
565
+ const queries = db.getQueries(correlationId);
566
+ const totalTime = queries.reduce((sum, q) => sum + q.executionTimeMs, 0);
567
+ console.log(`Total query time: ${totalTime}ms`);
568
+ ```
1816
569
 
1817
- // After 60 seconds, auto-warming will:
1818
- // 1. Identify the most frequently accessed queries
1819
- // 2. Pre-warm them in the background
1820
- // 3. Improve cache hit rate automatically
1821
-
1822
- // Check warming stats
1823
- const warmingStats = db.getWarmingStats();
1824
- console.log('Latest warming:', {
1825
- queriesWarmed: warmingStats.queriesWarmed,
1826
- totalTime: warmingStats.totalTimeMs + 'ms',
1827
- perTable: warmingStats.tables,
1828
- });
570
+ ### 7. Beautiful Query Logging
1829
571
 
1830
- // Manually trigger warming
1831
- const manualStats = await db.warmCache();
1832
- console.log('Manual warming:', manualStats.queriesWarmed, 'queries');
572
+ ```
573
+ βœ… SELECT on users - 45ms - 10 rows
574
+ πŸš€ SELECT on orders - 12ms - 5 rows (cached)
575
+ ⚠️ SELECT on products - 250ms - 100 rows
576
+ SQL: SELECT * FROM products WHERE category = 'electronics'
1833
577
  ```
1834
578
 
1835
- **How it works:**
1836
- 1. Tracks query frequency per table in `__sqldb_query_stats` table
1837
- 2. Every X seconds, identifies the hottest queries
1838
- 3. Pre-warms them using a separate connection pool (no impact on app)
1839
- 4. Persists stats across restarts
579
+ Performance at a glance: ⚑ <10ms | πŸš€ <50ms | βœ… <200ms | ⚠️ <500ms | 🐌 β‰₯500ms
1840
580
 
1841
- **Benefits:**
1842
- - Automatic - no manual configuration
1843
- - Intelligent - only warms frequently used queries
1844
- - Non-blocking - uses separate connection pool
1845
- - Persistent - stats survive app restarts
1846
- - Observable - callbacks for monitoring
581
+ ---
1847
582
 
1848
- **See:** [auto-warming-example.ts](./examples/auto-warming-example.ts), [AUTO_WARMING.md](./docs/AUTO_WARMING.md)
583
+ ## πŸ“– Comparison with Other Libraries
584
+
585
+ ### SqlDB vs TypeORM
586
+
587
+ | Feature | SqlDB | TypeORM |
588
+ |---------|-------|---------|
589
+ | **Repository Pattern** | βœ… | βœ… |
590
+ | **Lifecycle Hooks** | βœ… | βœ… |
591
+ | **Entity Decorators** | βœ… | βœ… |
592
+ | **Query Builder** | βœ… Prisma-style | ⚠️ Different |
593
+ | **Automatic Caching** | βœ… Redis, FK-aware | ❌ |
594
+ | **Case Conversion** | βœ… Automatic | ❌ Manual |
595
+ | **Schema Registry** | βœ… No decorators! | ❌ |
596
+ | **Full-text Search** | βœ… Built-in | ⚠️ DB only |
597
+ | **Auto-warming** | βœ… Built-in | ❌ |
598
+ | **Migrations** | ⚠️ External | βœ… Built-in |
599
+
600
+ ### SqlDB vs Prisma
601
+
602
+ | Feature | SqlDB | Prisma |
603
+ |---------|-------|--------|
604
+ | **Type Safety** | βœ… | βœ… |
605
+ | **Query Operators** | βœ… Inspired by Prisma | βœ… |
606
+ | **Repository Pattern** | βœ… TypeORM-like | ❌ |
607
+ | **Automatic Caching** | βœ… Redis | ❌ |
608
+ | **Code Generation** | ❌ No need | βœ… Required |
609
+ | **Migrations** | ⚠️ External | βœ… Built-in |
610
+ | **Performance** | ⚑ Sub-ms (cached) | ⚑ Fast |
1849
611
 
1850
612
  ---
1851
613
 
1852
- ### 10. Complete Production Example
614
+ ## πŸ“š Documentation
1853
615
 
1854
- A real-world production setup with all features:
616
+ ### Getting Started
617
+ - **[Repository Pattern Guide](./docs/REPOSITORY_PATTERN.md)** - Complete guide with 50+ examples
618
+ - **[Before/After Comparison](./examples/before-after-comparison.md)** - Real-world 800β†’50 line reduction
619
+ - **[Repository Example](./examples/repository-pattern-example.ts)** - Working code
1855
620
 
1856
- ```typescript
1857
- import { createSqlDB, generateQueryId } from '@bhushanpawar/sqldb';
621
+ ### Core Guides
622
+ - **[Query Tracking](./docs/QUERY_TRACKING.md)** - Track and debug queries
623
+ - **[Query Logging](./docs/QUERY_LOGGING.md)** - Beautiful performance logs
624
+ - **[Auto-Warming](./docs/AUTO_WARMING.md)** - Intelligent cache warming
625
+ - **[Singleton Pattern](./docs/SINGLETON_PATTERN.md)** - Production setup
626
+ - **[Dynamic Table Access](./docs/DYNAMIC_TABLE_ACCESS.md)** - Type-safe table access
627
+
628
+ ### Advanced Topics
629
+ - **[Decorators Guide](./docs/DECORATORS.md)** - Full decorator reference
630
+ - **[Schema Definition](./docs/SCHEMA_DEFINITION.md)** - Schema registry (no decorators)
631
+ - **[Performance Testing](./docs/PERFORMANCE_TESTING.md)** - Benchmark your app
632
+ - **[Performance Results](./docs/PERFORMANCE_RESULTS.md)** - Real-world benchmarks
633
+ - **[Relation Loading Performance](./docs/PERFORMANCE_RELATIONS.md)** - Optimized relation queries
634
+ - **[Schema Generator](./docs/SCHEMA_GENERATOR.md)** - Generate TypeScript schemas
635
+
636
+ ---
637
+
638
+ ## 🎯 Examples
639
+
640
+ ### Simple Examples
641
+ - [basic-usage.ts](./examples/basic-usage.ts) - Basic CRUD operations
642
+ - [repository-pattern-example.ts](./examples/repository-pattern-example.ts) - **NEW!** Repository pattern
643
+ - [typed-tables-example.ts](./examples/typed-tables-example.ts) - TypeScript type safety
1858
644
 
1859
- // Production configuration
645
+ ### Advanced Examples
646
+ - [query-tracking.ts](./examples/query-tracking.ts) - Query tracking with correlation IDs
647
+ - [relationships-example.ts](./examples/relationships-example.ts) - Smart cache invalidation
648
+ - [auto-warming-example.ts](./examples/auto-warming-example.ts) - Auto-warming system
649
+ - [singleton-example.ts](./examples/singleton-example.ts) - Singleton pattern
650
+
651
+ ---
652
+
653
+ ## πŸ”§ Configuration
654
+
655
+ ### Complete Configuration
656
+
657
+ ```typescript
1860
658
  const db = await createSqlDB({
659
+ // Database connection
1861
660
  mariadb: {
1862
- host: process.env.DB_HOST,
1863
- port: parseInt(process.env.DB_PORT || '3306'),
1864
- user: process.env.DB_USER,
1865
- password: process.env.DB_PASSWORD,
1866
- database: process.env.DB_NAME,
1867
- connectionLimit: 20,
1868
- acquireTimeout: 10000,
1869
- connectTimeout: 10000,
1870
- logging: process.env.NODE_ENV === 'development',
661
+ host: 'localhost',
662
+ port: 3306,
663
+ user: 'root',
664
+ password: 'password',
665
+ database: 'mydb',
666
+ connectionLimit: 10,
1871
667
  },
668
+
669
+ // Redis cache
1872
670
  redis: {
1873
- host: process.env.REDIS_HOST,
1874
- port: parseInt(process.env.REDIS_PORT || '6379'),
1875
- password: process.env.REDIS_PASSWORD,
671
+ host: 'localhost',
672
+ port: 6379,
1876
673
  keyPrefix: 'myapp:',
1877
674
  },
675
+
676
+ // Caching
1878
677
  cache: {
1879
678
  enabled: true,
1880
- defaultTTL: 300, // 5 minutes
1881
- maxKeys: 10000,
679
+ defaultTTL: 60,
1882
680
  invalidateOnWrite: true,
1883
681
  cascadeInvalidation: true,
1884
682
  },
683
+
684
+ // Schema discovery
1885
685
  discovery: {
1886
686
  autoDiscover: true,
1887
- excludedTables: ['migrations', 'temp_*'],
1888
- maxGraphDepth: 3,
1889
- refreshInterval: 3600000, // Refresh schema every hour
687
+ refreshInterval: 3600000,
1890
688
  },
689
+
690
+ // Auto-warming
1891
691
  warming: {
1892
- enabled: process.env.NODE_ENV === 'production',
1893
- intervalMs: 300000, // Warm every 5 minutes
1894
- topQueriesPerTable: 20,
1895
- minAccessCount: 5,
1896
- useSeperatePool: true,
1897
- trackInDatabase: true,
1898
- onWarmingComplete: (stats) => {
1899
- logger.info('Cache warming complete', {
1900
- queriesWarmed: stats.queriesWarmed,
1901
- hitRateImprovement:
1902
- ((stats.cacheHitRateAfter - stats.cacheHitRateBefore) * 100).toFixed(2) + '%',
1903
- });
1904
- },
1905
- },
1906
- logging: {
1907
- level: process.env.LOG_LEVEL || 'info',
1908
- logger: (level, message, meta) => {
1909
- // Use your preferred logger (Winston, Pino, etc.)
1910
- logger[level](message, meta);
1911
- },
692
+ enabled: true,
693
+ intervalMs: 60000,
694
+ topQueriesPerTable: 10,
1912
695
  },
1913
- }, { singleton: true });
1914
-
1915
- // Express middleware for request tracking
1916
- app.use((req, res, next) => {
1917
- req.correlationId = generateQueryId();
1918
- res.on('finish', () => {
1919
- const queries = db.getQueries(req.correlationId);
1920
- const totalTime = queries.reduce((sum, q) => sum + (q.executionTimeMs || 0), 0);
1921
-
1922
- // Log slow requests
1923
- if (totalTime > 1000) {
1924
- logger.warn('Slow request', {
1925
- path: req.path,
1926
- method: req.method,
1927
- totalTime,
1928
- queryCount: queries.length,
1929
- correlationId: req.correlationId,
1930
- });
1931
- }
1932
-
1933
- db.clearQueries(req.correlationId);
1934
- });
1935
- next();
1936
- });
1937
-
1938
- // Health check endpoint
1939
- app.get('/health', async (req, res) => {
1940
- const health = await db.healthCheck();
1941
- const stats = db.getCacheManager().getStats();
1942
-
1943
- res.json({
1944
- status: health.mariadb && health.redis ? 'healthy' : 'unhealthy',
1945
- ...health,
1946
- cache: stats,
1947
- timestamp: new Date().toISOString(),
1948
- });
1949
- });
1950
696
 
1951
- // Graceful shutdown
1952
- process.on('SIGTERM', async () => {
1953
- logger.info('SIGTERM received, closing connections...');
1954
- await db.close();
1955
- process.exit(0);
697
+ // Search
698
+ search: {
699
+ enabled: true,
700
+ invertedIndex: { enabled: true },
701
+ geo: { enabled: true },
702
+ },
1956
703
  });
1957
704
  ```
1958
705
 
1959
- **Production best practices:**
1960
- - Environment-based configuration
1961
- - Connection pooling optimization
1962
- - Schema refresh scheduling
1963
- - Auto-warming in production only
1964
- - Request tracking middleware
1965
- - Performance monitoring
1966
- - Health checks
1967
- - Graceful shutdown
1968
-
1969
706
  ---
1970
707
 
1971
- ### More Examples
1972
-
1973
- For complete working examples, see the [examples](./examples) directory:
1974
-
1975
- - [basic-usage.ts](./examples/basic-usage.ts) - Basic CRUD operations
1976
- - [typed-tables-example.ts](./examples/typed-tables-example.ts) - TypeScript type safety
1977
- - [query-tracking.ts](./examples/query-tracking.ts) - Query tracking with correlation IDs
1978
- - [query-logging-example.ts](./examples/query-logging-example.ts) - Enhanced query logging
1979
- - [relationships-example.ts](./examples/relationships-example.ts) - Smart cache invalidation
1980
- - [singleton-example.ts](./examples/singleton-example.ts) - Singleton pattern
1981
- - [auto-warming-example.ts](./examples/auto-warming-example.ts) - Auto-warming system
1982
- - [hooks-example.ts](./examples/hooks-example.ts) - Custom hooks and extensibility
1983
-
1984
- ## Documentation
708
+ ## πŸš€ Performance Benchmarks
1985
709
 
1986
- ### Core Guides
1987
- - πŸ“– [Query Tracking Guide](./QUERY_TRACKING.md) - Track and debug queries
1988
- - πŸ“Š [Query Logging](./QUERY_LOGGING.md) - Beautiful query logs with performance metrics
1989
- - 🎯 [Auto-Warming](./AUTO_WARMING.md) - Intelligent cache warming system
1990
- - 🎭 [Singleton Pattern](./docs/SINGLETON_PATTERN.md) - Production-ready singleton setup
1991
- - πŸ”— [Dynamic Table Access](./docs/DYNAMIC_TABLE_ACCESS.md) - Type-safe table access
1992
- - πŸ—ΊοΈ [Schema Generator](./SCHEMA_GENERATOR.md) - Generate TypeScript schemas
710
+ Real-world results from production:
1993
711
 
1994
- ### Advanced Topics
1995
- - ⚑ [Performance Testing](./PERFORMANCE_TESTING.md) - Benchmark your app
1996
- - πŸ“ˆ [Performance Results](./docs/PERFORMANCE_RESULTS.md) - Real-world benchmarks
1997
- - πŸ”„ [CLI Usage](./CLI_USAGE.md) - Command-line tools
1998
- - πŸ“ [Changelog](./CHANGELOG_QUERY_TRACKING.md) - What's new
712
+ | Metric | Value | Impact |
713
+ |--------|-------|--------|
714
+ | **Cache Hit Rate** | 99.2% | Only 1 in 100 queries hits DB |
715
+ | **P50 Response Time** | <1ms | Instant for users |
716
+ | **P99 Response Time** | 12ms | Fast even at extremes |
717
+ | **Throughput** | 10,000+ qps | Handle Black Friday traffic |
718
+ | **DB CPU Reduction** | 85% ↓ | Save $$$$ on database |
719
+ | **Code Reduction** | 94% ↓ | 800 lines β†’ 50 lines |
1999
720
 
2000
721
  ---
2001
722
 
2002
- ## Why You'll Love This
723
+ ## 🀝 Migration Guide
2003
724
 
2004
- ### Developer Experience
2005
- - βœ… **Zero Learning Curve** - If you know SQL, you know SqlDB
2006
- - βœ… **TypeScript First** - Full type safety with autocomplete
2007
- - βœ… **Beautiful Logs** - See performance at a glance
2008
- - βœ… **Debugging Tools** - Find slow queries in seconds
2009
- - βœ… **No Surprises** - Predictable, well-documented behavior
725
+ ### From TypeORM
2010
726
 
2011
- ### Performance
2012
- - βœ… **Instant Queries** - Sub-millisecond response times
2013
- - βœ… **Smart Caching** - 99%+ hit rate without tuning
2014
- - βœ… **Auto Warming** - No cold starts ever
2015
- - βœ… **Scale Effortlessly** - Handle 10,000+ req/s
2016
-
2017
- ### Reliability
2018
- - βœ… **Battle-Tested** - Running in production
2019
- - βœ… **No Stale Data** - Intelligent cache invalidation
2020
- - βœ… **Connection Pooling** - Never run out of connections
2021
- - βœ… **Health Checks** - Know when things break
727
+ ```typescript
728
+ // Before (TypeORM)
729
+ @Entity()
730
+ class User {
731
+ @PrimaryGeneratedColumn()
732
+ id: number;
2022
733
 
2023
- ---
734
+ @Column()
735
+ email: string;
736
+ }
2024
737
 
2025
- ## Roadmap
738
+ const userRepo = connection.getRepository(User);
739
+ const users = await userRepo.find({ where: { status: 'active' } });
2026
740
 
2027
- Vote for features you want! πŸ—³οΈ
741
+ // After (SqlDB) - Almost identical!
742
+ @Entity()
743
+ class User {
744
+ @PrimaryColumn()
745
+ userId: string;
2028
746
 
2029
- ### Coming Soon
2030
- - [ ] Support for complex WHERE clauses (IN, LIKE, BETWEEN)
2031
- - [ ] Built-in pagination with cursor support
2032
- - [ ] Redis Cluster support
2033
- - [ ] Query result transformers
2034
- - [ ] Prisma-like schema migrations
2035
- - [ ] Admin UI for cache monitoring
2036
- - [ ] GraphQL integration
2037
- - [ ] Read replicas support
2038
- - [ ] Automatic query optimization suggestions
747
+ @Column()
748
+ email: string;
749
+ }
2039
750
 
2040
- ### Under Consideration
2041
- - [ ] MongoDB adapter
2042
- - [ ] PostgreSQL adapter
2043
- - [ ] Write-through caching
2044
- - [ ] Distributed tracing integration
2045
- - [ ] Real-time query analytics dashboard
751
+ const userRepo = db.getRepository(User);
752
+ const users = await userRepo.find({ where: { status: 'active' } });
753
+ ```
2046
754
 
2047
- **Want a feature?** [Open an issue](https://github.com/erBhushanPawar/sqldb/issues) and let's discuss!
755
+ **What's different:**
756
+ - βœ… Automatic Redis caching
757
+ - βœ… Automatic cache invalidation
758
+ - βœ… Prisma-style operators: `{ age: { gte: 18 } }`
759
+ - βœ… Auto-warming
760
+ - βœ… Full-text search built-in
2048
761
 
2049
- ---
762
+ ### From Raw MariaDB
2050
763
 
2051
- ## Contributing
764
+ ```typescript
765
+ // Before (15 lines of boilerplate)
766
+ const conn = await pool.getConnection();
767
+ try {
768
+ const users = await conn.query('SELECT * FROM users WHERE status = ?', ['active']);
769
+ return users;
770
+ } finally {
771
+ conn.release();
772
+ }
2052
773
 
2053
- We love contributions! πŸŽ‰
774
+ // After (1 line with superpowers)
775
+ const users = await db.users.findMany({ status: 'active' });
776
+ ```
2054
777
 
2055
- ### How to Contribute
2056
- 1. 🍴 Fork the repo
2057
- 2. 🌿 Create a feature branch (`git checkout -b feature/amazing`)
2058
- 3. ✨ Make your changes
2059
- 4. βœ… Add tests
2060
- 5. πŸ“ Update docs
2061
- 6. πŸš€ Submit a PR
778
+ **What you gain:**
779
+ - βœ… 10x less code
780
+ - βœ… 20x faster (caching)
781
+ - βœ… Type-safe
782
+ - βœ… Auto cache invalidation
783
+ - βœ… No connection management
2062
784
 
2063
- ### Development Setup
2064
- ```bash
2065
- git clone https://github.com/erBhushanPawar/sqldb.git
2066
- cd sqldb
2067
- npm install
2068
- npm test
2069
- ```
785
+ ---
2070
786
 
2071
- ### Areas We Need Help
2072
- - πŸ“š Documentation improvements
2073
- - πŸ› Bug fixes
2074
- - ✨ New features
2075
- - πŸ§ͺ More test coverage
2076
- - πŸ“Š Performance optimizations
2077
- - 🌍 Real-world use case examples
787
+ ## πŸ—ΊοΈ Roadmap
788
+
789
+ ### Recently Added βœ…
790
+ - βœ… Repository pattern (TypeORM-like)
791
+ - βœ… Lifecycle hooks decorators
792
+ - βœ… Prisma-style query operators
793
+ - βœ… EntityManager
794
+ - βœ… Schema registry (no decorators)
795
+
796
+ ### Coming Soon πŸš€
797
+ - [ ] Transactions support
798
+ - [ ] Single-query JSON aggregation for relations
799
+ - [ ] Soft deletes (`@SoftDelete`)
800
+ - [ ] Custom repositories
801
+ - [ ] Schema migrations CLI
802
+ - [ ] GraphQL integration
2078
803
 
2079
804
  ---
2080
805
 
2081
- ## Support
806
+ ## πŸ’¬ Support
2082
807
 
2083
808
  ### Getting Help
2084
- - πŸ“– **Documentation**: You're reading it!
2085
- - πŸ’¬ **GitHub Issues**: [Report bugs or request features](https://github.com/erBhushanPawar/sqldb/issues)
809
+ - πŸ“– **Documentation**: See [docs](./docs) folder
810
+ - πŸ’¬ **GitHub Issues**: [Report bugs or request features](https://github.com/bhushanpawar/sqldb/issues)
2086
811
  - πŸ“§ **Email**: For private inquiries
2087
812
 
2088
813
  ### Show Your Support
@@ -2090,13 +815,13 @@ If SqlDB saves you time and money:
2090
815
  - ⭐ **Star this repo** on GitHub
2091
816
  - 🐦 **Tweet** about your experience
2092
817
  - πŸ“ **Write** a blog post
2093
- - πŸ’¬ **Tell** a friend who's struggling with caching
818
+ - πŸ’¬ **Tell** a friend
2094
819
 
2095
820
  ---
2096
821
 
2097
- ## License
822
+ ## πŸ“„ License
2098
823
 
2099
- MIT Β© [Bhushan Pawar](https://github.com/erBhushanPawar)
824
+ MIT Β© [Bhushan Pawar](https://github.com/bhushanpawar)
2100
825
 
2101
826
  Free for personal and commercial use. Do whatever you want with it.
2102
827
 
@@ -2104,7 +829,9 @@ Free for personal and commercial use. Do whatever you want with it.
2104
829
 
2105
830
  <div align="center">
2106
831
 
2107
- **Made with ❀️ for developers who hate writing cache logic**
832
+ **Made with ❀️ for developers who hate writing boilerplate**
833
+
834
+ **Stop writing cache logic. Start shipping features.**
2108
835
 
2109
836
  [⬆ Back to Top](#bhushanpawarsqldb)
2110
837