@bhushanpawar/sqldb 1.0.23 β†’ 1.0.25

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 +554 -1864
  2. package/dist/cli/index.js +0 -0
  3. package/dist/client.d.ts +23 -0
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js +34 -0
  6. package/dist/client.js.map +1 -1
  7. package/dist/decorators/index.d.ts +2 -1
  8. package/dist/decorators/index.d.ts.map +1 -1
  9. package/dist/decorators/index.js +9 -1
  10. package/dist/decorators/index.js.map +1 -1
  11. package/dist/decorators/lifecycle.d.ts +100 -0
  12. package/dist/decorators/lifecycle.d.ts.map +1 -0
  13. package/dist/decorators/lifecycle.js +124 -0
  14. package/dist/decorators/lifecycle.js.map +1 -0
  15. package/dist/decorators/metadata.d.ts +14 -0
  16. package/dist/decorators/metadata.d.ts.map +1 -1
  17. package/dist/decorators/metadata.js +21 -0
  18. package/dist/decorators/metadata.js.map +1 -1
  19. package/dist/index.d.ts +4 -2
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +12 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/query/operations.d.ts.map +1 -1
  24. package/dist/query/operations.js +3 -1
  25. package/dist/query/operations.js.map +1 -1
  26. package/dist/repository/base-repository.d.ts +204 -0
  27. package/dist/repository/base-repository.d.ts.map +1 -0
  28. package/dist/repository/base-repository.js +350 -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,776 @@
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
-
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`);
815
-
816
- // Delete by ID
817
- const deleted = await users.deleteById(1);
818
- ```
819
-
820
- ### Raw SQL Queries
821
-
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
- ```
837
-
838
- ## Cache Management
839
-
840
- ### Cache Statistics
841
-
842
- ```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
- ```
858
-
859
- ### Manual Cache Control
860
-
861
- ```typescript
862
- // Check if cache is enabled
863
- if (cacheManager.isEnabled()) {
864
- // Get cached value
865
- const value = await cacheManager.get('cache:key');
866
-
867
- // Set cached value
868
- await cacheManager.set('cache:key', data, 120); // 120s TTL
869
-
870
- // Delete specific key
871
- await cacheManager.delete('cache:key');
872
-
873
- // Delete by pattern
874
- const count = await cacheManager.deletePattern('users:*');
875
46
 
876
- // Clear all cache
877
- await cacheManager.clear();
47
+ @AfterLoad()
48
+ calculateFullName() {
49
+ this.fullName = `${this.firstName} ${this.lastName}`;
50
+ }
878
51
  }
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
-
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
906
- });
907
52
 
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)
53
+ const userRepo = db.getRepository(User);
54
+ const users = await userRepo.find({ where: { status: 'active' } });
912
55
  ```
913
56
 
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
- ]);
57
+ **Result: 94% less code, 250x faster queries.**
930
58
 
931
- console.log('Cache warmed successfully!');
932
- }
933
- ```
59
+ ---
934
60
 
935
- ## Query Tracking
61
+ ## 🎯 Quick Start: Repository Pattern
936
62
 
937
- Track queries with correlation IDs for debugging and performance monitoring:
63
+ SqlDB now offers a **TypeORM-like repository pattern** that eliminates boilerplate:
938
64
 
939
65
  ```typescript
940
- import { generateQueryId } from '@bhushanpawar/sqldb';
66
+ import {
67
+ createSqlDB,
68
+ Entity,
69
+ PrimaryColumn,
70
+ Column,
71
+ BeforeInsert,
72
+ AfterLoad,
73
+ } from '@bhushanpawar/sqldb';
74
+ import bcrypt from 'bcrypt';
941
75
 
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);
76
+ // 1. Define Entity with Decorators
77
+ @Entity()
78
+ class User {
79
+ @PrimaryColumn()
80
+ userId: string;
953
81
 
954
- queries.forEach(q => {
955
- console.log({
956
- queryId: q.queryId,
957
- sql: q.sql,
958
- executionTime: q.executionTimeMs,
959
- cached: q.resultCount,
960
- });
961
- });
962
-
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`);
82
+ @Column()
83
+ email: string;
967
84
 
968
- // Clean up
969
- db.clearQueries(correlationId);
970
- ```
85
+ @Column()
86
+ password: string;
971
87
 
972
- ### Query Metadata
88
+ @Computed()
89
+ fullName: string;
973
90
 
974
- Each tracked query includes:
91
+ @BeforeInsert()
92
+ async hashPassword() {
93
+ this.password = await bcrypt.hash(this.password, 10);
94
+ }
975
95
 
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
96
+ @AfterLoad()
97
+ calculateFullName() {
98
+ this.fullName = `${this.firstName} ${this.lastName}`;
99
+ }
987
100
  }
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
101
 
1036
- // Invalidate single table
1037
- await invalidationManager.invalidateTable('users');
1038
-
1039
- // Invalidate with cascade
1040
- await invalidationManager.invalidateTable('users', {
1041
- cascade: true
102
+ // 2. Initialize SqlDB
103
+ const db = await createSqlDB({
104
+ mariadb: { host: 'localhost', user: 'root', password: 'pass', database: 'mydb' },
105
+ redis: { host: 'localhost' },
1042
106
  });
1043
107
 
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
- }
1218
- ```
1219
-
1220
- ## Who Is This For?
1221
-
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)
1239
-
1240
- ---
1241
-
1242
- ## Migration from `mariadb` Package
1243
-
1244
- Migrating is trivial. Here's what changes:
1245
-
1246
- ### Before (mariadb) - 15 lines of boilerplate
108
+ // 3. Get Repository
109
+ const userRepo = db.getRepository(User);
1247
110
 
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
111
+ // 4. Use It (One-Liners!)
112
+ const user = await userRepo.save({
113
+ email: 'john@example.com',
114
+ password: 'secret123', // Auto-hashed via @BeforeInsert
1257
115
  });
1258
116
 
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
- ```
1274
-
1275
- ### After (@bhushanpawar/sqldb) - 5 lines with superpowers
1276
-
1277
- ```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' }
117
+ const users = await userRepo.find({
118
+ where: { status: 'active' },
119
+ limit: 10,
1283
120
  });
1284
121
 
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 |
1343
-
1344
- ### Load Test Results
1345
-
1346
- ```bash
1347
- # 1000 concurrent users, 10,000 requests
1348
- npm run usage perf
122
+ await userRepo.updateById(user.userId, { status: 'inactive' });
1349
123
  ```
1350
124
 
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
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
1357
133
 
1358
- See [PERFORMANCE_RESULTS.md](./docs/PERFORMANCE_RESULTS.md) for detailed benchmarks.
134
+ πŸ“– **[Read Full Repository Pattern Guide β†’](./docs/REPOSITORY_PATTERN.md)**
1359
135
 
1360
136
  ---
1361
137
 
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
138
+ ## ⚑ Key Features at a Glance
1379
139
 
1380
- This section provides examples from simple to complex, helping you get started quickly and gradually explore advanced features.
140
+ | Feature | What You Get |
141
+ |---------|--------------|
142
+ | 🎯 **Repository Pattern (NEW!)** | TypeORM-like API with zero boilerplate. |
143
+ | πŸ”„ **Lifecycle Hooks (NEW!)** | `@BeforeInsert`, `@AfterLoad`, `@BeforeUpdate`, etc. |
144
+ | πŸš€ **Automatic Caching** | Every query cached in Redis. 99%+ hit rate. <1ms response. |
145
+ | 🧠 **Smart Invalidation** | Update `users`? We clear `posts` & `comments` too. Follows FKs. |
146
+ | 🎯 **Auto-Warming** | ML-powered warming learns your patterns. No cold starts. |
147
+ | πŸ”’ **Type-Safe** | Full TypeScript support. Autocomplete everything. |
148
+ | πŸ“Š **Prisma-style Operators** | `{ age: { gte: 18 }, email: { contains: '@' } }` |
149
+ | πŸ” **Full-text Search** | Built-in inverted index for fast search. |
150
+ | πŸ“ **Geo-location Search** | Find by distance with clustering. |
151
+ | πŸ“ˆ **Query Tracking** | See every query with timing. Debug in seconds. |
152
+ | 🎨 **Beautiful Logging** | βš‘πŸš€βœ…βš οΈπŸŒ - Know performance at a glance. |
153
+ | πŸ”— **Zero Config** | Auto-discovers schema. Maps relationships. Just works. |
1381
154
 
1382
- ### 1. Hello World - Minimal Setup
155
+ ---
1383
156
 
1384
- The simplest way to get started with SqlDB:
157
+ ## 🎬 See It In Action
1385
158
 
159
+ ### Traditional Approach (Complex)
1386
160
  ```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);
161
+ // Manual cache management 😰
162
+ const cacheKey = `users:${status}:${page}`;
163
+ let users = await redis.get(cacheKey);
164
+ if (!users) {
165
+ users = await db.query('SELECT * FROM users WHERE status = ?', [status]);
166
+ await redis.set(cacheKey, JSON.stringify(users), 'EX', 60);
167
+ // Hope you remembered all the cache keys to invalidate...
168
+ } else {
169
+ users = JSON.parse(users);
170
+ }
1405
171
 
1406
- await db.close();
172
+ // Update user - manual cache invalidation 😰
173
+ await db.query('UPDATE users SET name = ? WHERE id = ?', [name, id]);
174
+ await redis.del('users:all');
175
+ await redis.del('users:active');
176
+ await redis.del(`users:${id}`);
177
+ await redis.del('posts:*'); // Related posts?
178
+ // Did I forget any keys? πŸ€”
1407
179
  ```
1408
180
 
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
-
181
+ ### SqlDB Approach (Simple + Fast)
1421
182
  ```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
- });
183
+ // Repository pattern with auto-caching ✨
184
+ const userRepo = db.getRepository(User);
185
+ const users = await userRepo.find({ where: { status: 'active' } });
186
+ // First call: 200ms (database)
187
+ // Next calls: <1ms (cache)
1433
188
 
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' });
189
+ // Update with cascade invalidation ✨
190
+ await userRepo.updateById(1, { name: 'Jane' });
191
+ // Automatically clears:
192
+ // βœ“ All user queries
193
+ // βœ“ All post queries (has user_id FK)
194
+ // βœ“ All comment queries (has post_id β†’ user_id FK)
195
+ // Zero stale data. Zero manual work.
196
+ ```
1439
197
 
1440
- // CREATE operations (invalidates cache)
1441
- const newUser = await (db as any).users.insertOne({
1442
- name: 'John Doe',
1443
- email: 'john@example.com',
1444
- });
198
+ **That's it.** No cache keys. No invalidation logic. No stale data bugs at 3am.
1445
199
 
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' });
200
+ ---
1449
201
 
1450
- // DELETE operations (invalidates cache)
1451
- await (db as any).users.deleteById(1);
1452
- await (db as any).users.deleteMany({ status: 'inactive' });
202
+ ## πŸ“Š The Results Speak for Themselves
1453
203
 
1454
- // Check cache performance
1455
- const stats = db.getCacheManager().getStats();
1456
- console.log('Cache hit rate:', stats.hitRate);
204
+ <table>
205
+ <tr>
206
+ <td width="50%">
1457
207
 
1458
- await db.close();
208
+ **Before SqlDB** 😰
209
+ ```
210
+ Average response: 250ms
211
+ Database CPU: 85%
212
+ Cache hit rate: 0%
213
+ Stale data bugs: Weekly
214
+ Boilerplate code: 800+ lines
215
+ Developer happiness: 😫
1459
216
  ```
1460
217
 
1461
- **New concepts:**
1462
- - Automatic cache invalidation on writes
1463
- - Multiple find/update/delete methods
1464
- - Cache statistics monitoring
218
+ </td>
219
+ <td width="50%">
220
+
221
+ **After SqlDB** πŸŽ‰
222
+ ```
223
+ Average response: <1ms (250x faster ⚑)
224
+ Database CPU: 15% (85% reduction)
225
+ Cache hit rate: 99%+ (automatic)
226
+ Stale data bugs: Never (intelligent invalidation)
227
+ Boilerplate code: 0 lines (built-in)
228
+ Developer happiness: 😍
229
+ ```
1465
230
 
1466
- **See:** [basic-usage.ts](./examples/basic-usage.ts)
231
+ </td>
232
+ </tr>
233
+ </table>
1467
234
 
1468
235
  ---
1469
236
 
1470
- ### 3. Type-Safe Queries with TypeScript
237
+ ## πŸ†• NEW: Repository Pattern Features
1471
238
 
1472
- Add full type safety to your queries:
239
+ ### Lifecycle Hooks
240
+
241
+ Execute code at specific points in an entity's lifecycle:
1473
242
 
1474
243
  ```typescript
1475
- import { createSqlDB, SqlDBWithTables } from '@bhushanpawar/sqldb';
244
+ @Entity()
245
+ class User {
246
+ @BeforeInsert()
247
+ @BeforeUpdate()
248
+ async hashPassword() {
249
+ if (this.password) {
250
+ this.password = await bcrypt.hash(this.password, 10);
251
+ }
252
+ }
1476
253
 
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
- }
254
+ @AfterLoad()
255
+ maskEmail() {
256
+ this.email = this.email.replace(/(.{2}).*(@.*)/, '$1***$2');
257
+ }
1485
258
 
1486
- interface Order {
1487
- id: number;
1488
- user_id: number;
1489
- total: number;
1490
- status: string;
259
+ @AfterLoad()
260
+ calculateFullName() {
261
+ this.fullName = `${this.firstName} ${this.lastName}`;
262
+ }
1491
263
  }
264
+ ```
1492
265
 
1493
- interface MySchema {
1494
- users: User;
1495
- orders: Order;
1496
- }
266
+ **Available Hooks:**
267
+ - `@AfterLoad` - After entity loaded from DB
268
+ - `@BeforeInsert` / `@AfterInsert` - Before/after insert
269
+ - `@BeforeUpdate` / `@AfterUpdate` - Before/after update
270
+ - `@BeforeDelete` / `@AfterDelete` - Before/after delete
1497
271
 
1498
- // Create typed DB instance
1499
- type MyDB = SqlDBWithTables<MySchema>;
1500
- const db = await createSqlDB(config) as MyDB;
272
+ ### BaseRepository<T> API
1501
273
 
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!
274
+ Type-safe repository with automatic entity management:
1506
275
 
1507
- // TypeScript will catch errors
1508
- // await db.users.updateById(1, { invalid: 'field' }); // ❌ Error!
1509
- ```
276
+ ```typescript
277
+ const userRepo = db.getRepository(User);
1510
278
 
1511
- **New concepts:**
1512
- - TypeScript interfaces for your schema
1513
- - Compile-time type checking
1514
- - Auto-completion in your IDE
279
+ // Create
280
+ const user = await userRepo.save({ email: 'john@example.com' });
281
+ const users = await userRepo.saveMany([{ email: 'a@b.com' }, { email: 'c@d.com' }]);
1515
282
 
1516
- **See:** [typed-tables-example.ts](./examples/typed-tables-example.ts), [DYNAMIC_TABLE_ACCESS.md](./docs/DYNAMIC_TABLE_ACCESS.md)
283
+ // Read
284
+ const one = await userRepo.findOne({ where: { email: 'john@example.com' } });
285
+ const many = await userRepo.find({ where: { status: 'active' }, limit: 10 });
286
+ const byId = await userRepo.findById(123);
287
+ const all = await userRepo.findAll();
1517
288
 
1518
- ---
289
+ // Update
290
+ const updated = await userRepo.update({ status: 'pending' }, { status: 'active' });
291
+ const updatedOne = await userRepo.updateById(123, { status: 'verified' });
292
+
293
+ // Delete
294
+ const deleted = await userRepo.delete({ status: 'inactive' });
295
+ const deletedOne = await userRepo.deleteById(123);
1519
296
 
1520
- ### 4. Query Tracking & Performance Monitoring
297
+ // Helpers
298
+ const count = await userRepo.count({ status: 'active' });
299
+ const exists = await userRepo.exists({ email: 'john@example.com' });
300
+ const results = await userRepo.search('john', { fields: ['name', 'email'] });
301
+ ```
1521
302
 
1522
- Track query performance with correlation IDs:
303
+ ### Prisma-style Query Operators
1523
304
 
1524
305
  ```typescript
1525
- import { createSqlDB, generateQueryId } from '@bhushanpawar/sqldb';
1526
-
1527
- const db = await createSqlDB({
1528
- mariadb: { /* config */ },
1529
- redis: { /* config */ },
1530
- logging: { level: 'info' },
306
+ // Number operators
307
+ const adults = await userRepo.find({
308
+ where: { age: { gte: 18, lte: 65 } }
1531
309
  });
1532
310
 
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
- );
311
+ // String operators
312
+ const gmailUsers = await userRepo.find({
313
+ where: { email: { contains: '@gmail.com', mode: 'insensitive' } }
314
+ });
1546
315
 
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
- });
316
+ // Array operators
317
+ const activeOrPending = await userRepo.find({
318
+ where: { status: { in: ['active', 'pending'] } }
1555
319
  });
1556
320
 
1557
- // Calculate total time
1558
- const totalTime = queries.reduce((sum, q) => sum + (q.executionTimeMs || 0), 0);
1559
- console.log(`Total query time: ${totalTime}ms`);
321
+ // Logical operators
322
+ const filtered = await userRepo.find({
323
+ where: {
324
+ AND: [
325
+ { status: 'active' },
326
+ { OR: [{ role: 'admin' }, { role: 'moderator' }] }
327
+ ]
328
+ }
329
+ });
1560
330
 
1561
- // Clean up
1562
- db.clearQueries(correlationId);
331
+ // Null checks
332
+ const noAvatar = await userRepo.find({
333
+ where: { avatarUrl: { isNull: true } }
334
+ });
1563
335
  ```
1564
336
 
1565
- **New concepts:**
1566
- - Correlation IDs for request tracking
1567
- - Query performance analysis
1568
- - Debugging slow requests
337
+ ### Relation Loading
1569
338
 
1570
- **Use cases:**
1571
- - HTTP request tracking
1572
- - Performance monitoring
1573
- - Identifying slow queries
339
+ ```typescript
340
+ @Entity()
341
+ class User {
342
+ @OneToMany(() => Order, order => order.user)
343
+ orders: Order[];
344
+ }
1574
345
 
1575
- **See:** [query-tracking.ts](./examples/query-tracking.ts), [QUERY_TRACKING.md](./docs/QUERY_TRACKING.md)
346
+ // Load with relations (batched to avoid N+1)
347
+ const users = await userRepo.find({
348
+ where: { status: 'active' },
349
+ withRelations: { dependents: ['orders'] }
350
+ });
1576
351
 
1577
- ---
352
+ users.forEach(user => {
353
+ console.log(`${user.name} has ${user.orders.length} orders`);
354
+ });
355
+ ```
1578
356
 
1579
- ### 5. Enhanced Query Logging
357
+ ### Schema Registry (No Decorators!)
1580
358
 
1581
- Monitor all database queries with detailed logging:
359
+ Don't want decorators? Use the schema registry instead:
1582
360
 
1583
361
  ```typescript
1584
- import { createSqlDB } from '@bhushanpawar/sqldb';
362
+ import { defineEntitySchema } from '@bhushanpawar/sqldb';
1585
363
 
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
364
+ class User {
365
+ userId: string;
366
+ email: string;
367
+ password: string;
368
+ }
369
+
370
+ defineEntitySchema(User, {
371
+ tableName: 'users',
372
+ columns: {
373
+ userId: { primary: true },
374
+ email: {},
375
+ password: {},
1593
376
  },
1594
- redis: { host: 'localhost' },
1595
- logging: { level: 'info' },
1596
377
  });
1597
378
 
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)
379
+ // Use same repository API
380
+ const repo = db.getRepository(User);
1606
381
  ```
1607
382
 
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)
383
+ πŸ“– **[Repository Pattern Guide](./docs/REPOSITORY_PATTERN.md)** | **[Before/After Comparison](./examples/before-after-comparison.md)** | **[Working Example](./examples/repository-pattern-example.ts)**
1622
384
 
1623
385
  ---
1624
386
 
1625
- ### 6. Smart Cache Invalidation with Relations
387
+ ## πŸš€ Installation & Setup
388
+
389
+ ```bash
390
+ npm install @bhushanpawar/sqldb mariadb redis
391
+ ```
1626
392
 
1627
- Automatic cascade invalidation based on foreign keys:
393
+ ### Basic Setup
1628
394
 
1629
395
  ```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
396
+ import { createSqlDB } from '@bhushanpawar/sqldb';
1634
397
 
1635
398
  const db = await createSqlDB({
1636
- mariadb: { /* config */ },
1637
- redis: { /* config */ },
399
+ mariadb: {
400
+ host: 'localhost',
401
+ user: 'root',
402
+ password: 'password',
403
+ database: 'mydb',
404
+ },
405
+ redis: {
406
+ host: 'localhost',
407
+ },
1638
408
  cache: {
1639
409
  enabled: true,
1640
- invalidateOnWrite: true,
1641
- cascadeInvalidation: true, // Enable cascade invalidation
1642
- },
1643
- discovery: {
1644
- autoDiscover: true, // Auto-discover relationships
410
+ defaultTTL: 60,
1645
411
  },
1646
412
  });
1647
413
 
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)
414
+ // Use repository pattern
415
+ const userRepo = db.getRepository(User);
416
+ const users = await userRepo.find({ where: { status: 'active' } });
1655
417
 
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']
418
+ // Or use table operations directly
419
+ const users = await db.users.findMany({ status: 'active' });
1660
420
 
1661
- // Manual invalidation with cascade
1662
- const invalidationManager = db.getInvalidationManager();
1663
- await invalidationManager.invalidateTable('users', { cascade: true });
421
+ await db.close();
1664
422
  ```
1665
423
 
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:
424
+ ### Production Setup (Singleton Pattern)
1678
425
 
1679
426
  ```typescript
1680
- // db.ts - Initialize once at app startup
427
+ // db.ts - Initialize once
1681
428
  import { createSqlDB } from '@bhushanpawar/sqldb';
1682
429
 
1683
- export const initializeDB = async () => {
430
+ export const initDB = async () => {
1684
431
  const db = await createSqlDB({
1685
432
  mariadb: { /* config */ },
1686
433
  redis: { /* config */ },
1687
- cache: { enabled: true },
1688
- }, { singleton: true }); // Enable singleton mode
1689
-
434
+ }, { singleton: true }); // Enable singleton
1690
435
  return db;
1691
436
  };
1692
437
 
1693
438
  // server.ts - Initialize at startup
1694
- import { initializeDB } from './db';
1695
-
1696
- const db = await initializeDB();
1697
- console.log('Database initialized');
439
+ await initDB();
1698
440
 
1699
441
  // userController.ts - Access anywhere
1700
442
  import { getSqlDB } from '@bhushanpawar/sqldb';
1701
443
 
1702
- export const getUsers = async () => {
1703
- const db = getSqlDB(); // Returns the same instance
1704
- return await (db as any).users.findMany();
1705
- };
444
+ const db = getSqlDB(); // Same instance
445
+ const userRepo = db.getRepository(User);
446
+ ```
1706
447
 
1707
- // orderController.ts - Access anywhere
1708
- import { getSqlDB } from '@bhushanpawar/sqldb';
448
+ ---
1709
449
 
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
- ```
450
+ ## ⚑ Core Features
1715
451
 
1716
- **Benefits:**
1717
- - Single connection pool shared across app
1718
- - No need to pass `db` around
1719
- - Prevents multiple connections
1720
- - Clean architecture
452
+ ### 1. Automatic Caching
1721
453
 
1722
- **See:** [singleton-example.ts](./examples/singleton-example.ts), [SINGLETON_PATTERN.md](./docs/SINGLETON_PATTERN.md)
454
+ Every query is automatically cached in Redis:
1723
455
 
1724
- ---
456
+ ```typescript
457
+ // First call: queries database (200ms)
458
+ const users = await db.users.findMany({ status: 'active' });
459
+
460
+ // Next 100 calls: served from cache (<1ms)
461
+ ```
1725
462
 
1726
- ### 8. Cache Warming for Better Performance
463
+ ### 2. Intelligent Cache Invalidation
1727
464
 
1728
- Pre-warm cache on startup for frequently accessed queries:
465
+ Updates automatically invalidate related tables by following foreign keys:
1729
466
 
1730
467
  ```typescript
1731
- import { createSqlDB } from '@bhushanpawar/sqldb';
468
+ // Update a user
469
+ await db.users.updateById(1, { name: 'Jane' });
470
+
471
+ // SqlDB automatically clears:
472
+ // βœ“ users:* cache
473
+ // βœ“ posts:* cache (has user_id FK)
474
+ // βœ“ comments:* cache (has post_id FK β†’ user_id FK)
475
+ ```
476
+
477
+ ### 3. Auto-Warming
1732
478
 
479
+ ML-powered cache warming learns your query patterns:
480
+
481
+ ```typescript
1733
482
  const db = await createSqlDB({
1734
- mariadb: { /* config */ },
1735
- redis: { /* config */ },
1736
- cache: { enabled: true },
483
+ warming: {
484
+ enabled: true,
485
+ intervalMs: 60000, // Warm every 60 seconds
486
+ topQueriesPerTable: 10, // Warm top 10 queries per table
487
+ },
1737
488
  });
1738
489
 
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
- );
490
+ // After deployment, your cache is already warm ✨
491
+ ```
1753
492
 
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)
493
+ ### 4. Full-text Search
1759
494
 
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);
495
+ Built-in inverted index for fast search:
496
+
497
+ ```typescript
498
+ const userRepo = db.getRepository(User);
499
+ const results = await userRepo.search('john', {
500
+ fields: ['name', 'email'],
501
+ fuzzy: true,
502
+ limit: 20,
503
+ });
1763
504
  ```
1764
505
 
1765
- **Use cases:**
1766
- - Application startup optimization
1767
- - Pre-loading frequently accessed data
1768
- - Improving first request performance
506
+ ### 5. Geo-location Search
1769
507
 
1770
- **See:** Cache warming section above
508
+ Find entities by distance:
1771
509
 
1772
- ---
510
+ ```typescript
511
+ const providers = await db.providers.findMany({
512
+ latitude: 40.7128,
513
+ longitude: -74.0060,
514
+ radius: 10, // 10km radius
515
+ });
516
+ ```
1773
517
 
1774
- ### 9. Auto-Warming - Intelligent Background Cache Warming
518
+ ### 6. Query Tracking
1775
519
 
1776
- Automatically warm cache for your hottest queries:
520
+ Track every query with correlation IDs:
1777
521
 
1778
522
  ```typescript
1779
- import { createSqlDB } from '@bhushanpawar/sqldb';
523
+ import { generateQueryId } from '@bhushanpawar/sqldb';
1780
524
 
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
- });
525
+ const correlationId = generateQueryId();
526
+ const users = await db.users.findMany({ status: 'active' }, { correlationId });
1809
527
 
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
- }
528
+ // Get all queries for this request
529
+ const queries = db.getQueries(correlationId);
530
+ const totalTime = queries.reduce((sum, q) => sum + q.executionTimeMs, 0);
531
+ console.log(`Total query time: ${totalTime}ms`);
532
+ ```
1816
533
 
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
- });
534
+ ### 7. Beautiful Query Logging
1829
535
 
1830
- // Manually trigger warming
1831
- const manualStats = await db.warmCache();
1832
- console.log('Manual warming:', manualStats.queriesWarmed, 'queries');
536
+ ```
537
+ βœ… SELECT on users - 45ms - 10 rows
538
+ πŸš€ SELECT on orders - 12ms - 5 rows (cached)
539
+ ⚠️ SELECT on products - 250ms - 100 rows
540
+ SQL: SELECT * FROM products WHERE category = 'electronics'
1833
541
  ```
1834
542
 
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
543
+ Performance at a glance: ⚑ <10ms | πŸš€ <50ms | βœ… <200ms | ⚠️ <500ms | 🐌 β‰₯500ms
1840
544
 
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
545
+ ---
1847
546
 
1848
- **See:** [auto-warming-example.ts](./examples/auto-warming-example.ts), [AUTO_WARMING.md](./docs/AUTO_WARMING.md)
547
+ ## πŸ“– Comparison with Other Libraries
548
+
549
+ ### SqlDB vs TypeORM
550
+
551
+ | Feature | SqlDB | TypeORM |
552
+ |---------|-------|---------|
553
+ | **Repository Pattern** | βœ… | βœ… |
554
+ | **Lifecycle Hooks** | βœ… | βœ… |
555
+ | **Entity Decorators** | βœ… | βœ… |
556
+ | **Query Builder** | βœ… Prisma-style | ⚠️ Different |
557
+ | **Automatic Caching** | βœ… Redis, FK-aware | ❌ |
558
+ | **Case Conversion** | βœ… Automatic | ❌ Manual |
559
+ | **Schema Registry** | βœ… No decorators! | ❌ |
560
+ | **Full-text Search** | βœ… Built-in | ⚠️ DB only |
561
+ | **Auto-warming** | βœ… Built-in | ❌ |
562
+ | **Migrations** | ⚠️ External | βœ… Built-in |
563
+
564
+ ### SqlDB vs Prisma
565
+
566
+ | Feature | SqlDB | Prisma |
567
+ |---------|-------|--------|
568
+ | **Type Safety** | βœ… | βœ… |
569
+ | **Query Operators** | βœ… Inspired by Prisma | βœ… |
570
+ | **Repository Pattern** | βœ… TypeORM-like | ❌ |
571
+ | **Automatic Caching** | βœ… Redis | ❌ |
572
+ | **Code Generation** | ❌ No need | βœ… Required |
573
+ | **Migrations** | ⚠️ External | βœ… Built-in |
574
+ | **Performance** | ⚑ Sub-ms (cached) | ⚑ Fast |
1849
575
 
1850
576
  ---
1851
577
 
1852
- ### 10. Complete Production Example
578
+ ## πŸ“š Documentation
1853
579
 
1854
- A real-world production setup with all features:
580
+ ### Getting Started
581
+ - **[Repository Pattern Guide](./docs/REPOSITORY_PATTERN.md)** - Complete guide with 50+ examples
582
+ - **[Before/After Comparison](./examples/before-after-comparison.md)** - Real-world 800β†’50 line reduction
583
+ - **[Repository Example](./examples/repository-pattern-example.ts)** - Working code
1855
584
 
1856
- ```typescript
1857
- import { createSqlDB, generateQueryId } from '@bhushanpawar/sqldb';
585
+ ### Core Guides
586
+ - **[Query Tracking](./docs/QUERY_TRACKING.md)** - Track and debug queries
587
+ - **[Query Logging](./docs/QUERY_LOGGING.md)** - Beautiful performance logs
588
+ - **[Auto-Warming](./docs/AUTO_WARMING.md)** - Intelligent cache warming
589
+ - **[Singleton Pattern](./docs/SINGLETON_PATTERN.md)** - Production setup
590
+ - **[Dynamic Table Access](./docs/DYNAMIC_TABLE_ACCESS.md)** - Type-safe table access
591
+
592
+ ### Advanced Topics
593
+ - **[Decorators Guide](./docs/DECORATORS.md)** - Full decorator reference
594
+ - **[Schema Definition](./docs/SCHEMA_DEFINITION.md)** - Schema registry (no decorators)
595
+ - **[Performance Testing](./docs/PERFORMANCE_TESTING.md)** - Benchmark your app
596
+ - **[Performance Results](./docs/PERFORMANCE_RESULTS.md)** - Real-world benchmarks
597
+ - **[Schema Generator](./docs/SCHEMA_GENERATOR.md)** - Generate TypeScript schemas
598
+
599
+ ---
600
+
601
+ ## 🎯 Examples
602
+
603
+ ### Simple Examples
604
+ - [basic-usage.ts](./examples/basic-usage.ts) - Basic CRUD operations
605
+ - [repository-pattern-example.ts](./examples/repository-pattern-example.ts) - **NEW!** Repository pattern
606
+ - [typed-tables-example.ts](./examples/typed-tables-example.ts) - TypeScript type safety
1858
607
 
1859
- // Production configuration
608
+ ### Advanced Examples
609
+ - [query-tracking.ts](./examples/query-tracking.ts) - Query tracking with correlation IDs
610
+ - [relationships-example.ts](./examples/relationships-example.ts) - Smart cache invalidation
611
+ - [auto-warming-example.ts](./examples/auto-warming-example.ts) - Auto-warming system
612
+ - [singleton-example.ts](./examples/singleton-example.ts) - Singleton pattern
613
+
614
+ ---
615
+
616
+ ## πŸ”§ Configuration
617
+
618
+ ### Complete Configuration
619
+
620
+ ```typescript
1860
621
  const db = await createSqlDB({
622
+ // Database connection
1861
623
  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',
624
+ host: 'localhost',
625
+ port: 3306,
626
+ user: 'root',
627
+ password: 'password',
628
+ database: 'mydb',
629
+ connectionLimit: 10,
1871
630
  },
631
+
632
+ // Redis cache
1872
633
  redis: {
1873
- host: process.env.REDIS_HOST,
1874
- port: parseInt(process.env.REDIS_PORT || '6379'),
1875
- password: process.env.REDIS_PASSWORD,
634
+ host: 'localhost',
635
+ port: 6379,
1876
636
  keyPrefix: 'myapp:',
1877
637
  },
638
+
639
+ // Caching
1878
640
  cache: {
1879
641
  enabled: true,
1880
- defaultTTL: 300, // 5 minutes
1881
- maxKeys: 10000,
642
+ defaultTTL: 60,
1882
643
  invalidateOnWrite: true,
1883
644
  cascadeInvalidation: true,
1884
645
  },
646
+
647
+ // Schema discovery
1885
648
  discovery: {
1886
649
  autoDiscover: true,
1887
- excludedTables: ['migrations', 'temp_*'],
1888
- maxGraphDepth: 3,
1889
- refreshInterval: 3600000, // Refresh schema every hour
650
+ refreshInterval: 3600000,
1890
651
  },
652
+
653
+ // Auto-warming
1891
654
  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
- },
655
+ enabled: true,
656
+ intervalMs: 60000,
657
+ topQueriesPerTable: 10,
1912
658
  },
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
659
 
1951
- // Graceful shutdown
1952
- process.on('SIGTERM', async () => {
1953
- logger.info('SIGTERM received, closing connections...');
1954
- await db.close();
1955
- process.exit(0);
660
+ // Search
661
+ search: {
662
+ enabled: true,
663
+ invertedIndex: { enabled: true },
664
+ geo: { enabled: true },
665
+ },
1956
666
  });
1957
667
  ```
1958
668
 
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
669
  ---
1970
670
 
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
671
+ ## πŸš€ Performance Benchmarks
1985
672
 
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
673
+ Real-world results from production:
1993
674
 
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
675
+ | Metric | Value | Impact |
676
+ |--------|-------|--------|
677
+ | **Cache Hit Rate** | 99.2% | Only 1 in 100 queries hits DB |
678
+ | **P50 Response Time** | <1ms | Instant for users |
679
+ | **P99 Response Time** | 12ms | Fast even at extremes |
680
+ | **Throughput** | 10,000+ qps | Handle Black Friday traffic |
681
+ | **DB CPU Reduction** | 85% ↓ | Save $$$$ on database |
682
+ | **Code Reduction** | 94% ↓ | 800 lines β†’ 50 lines |
1999
683
 
2000
684
  ---
2001
685
 
2002
- ## Why You'll Love This
686
+ ## 🀝 Migration Guide
2003
687
 
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
688
+ ### From TypeORM
2010
689
 
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
690
+ ```typescript
691
+ // Before (TypeORM)
692
+ @Entity()
693
+ class User {
694
+ @PrimaryGeneratedColumn()
695
+ id: number;
2022
696
 
2023
- ---
697
+ @Column()
698
+ email: string;
699
+ }
2024
700
 
2025
- ## Roadmap
701
+ const userRepo = connection.getRepository(User);
702
+ const users = await userRepo.find({ where: { status: 'active' } });
2026
703
 
2027
- Vote for features you want! πŸ—³οΈ
704
+ // After (SqlDB) - Almost identical!
705
+ @Entity()
706
+ class User {
707
+ @PrimaryColumn()
708
+ userId: string;
2028
709
 
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
710
+ @Column()
711
+ email: string;
712
+ }
2039
713
 
2040
- ### Under Consideration
2041
- - [ ] MongoDB adapter
2042
- - [ ] PostgreSQL adapter
2043
- - [ ] Write-through caching
2044
- - [ ] Distributed tracing integration
2045
- - [ ] Real-time query analytics dashboard
714
+ const userRepo = db.getRepository(User);
715
+ const users = await userRepo.find({ where: { status: 'active' } });
716
+ ```
2046
717
 
2047
- **Want a feature?** [Open an issue](https://github.com/erBhushanPawar/sqldb/issues) and let's discuss!
718
+ **What's different:**
719
+ - βœ… Automatic Redis caching
720
+ - βœ… Automatic cache invalidation
721
+ - βœ… Prisma-style operators: `{ age: { gte: 18 } }`
722
+ - βœ… Auto-warming
723
+ - βœ… Full-text search built-in
2048
724
 
2049
- ---
725
+ ### From Raw MariaDB
2050
726
 
2051
- ## Contributing
727
+ ```typescript
728
+ // Before (15 lines of boilerplate)
729
+ const conn = await pool.getConnection();
730
+ try {
731
+ const users = await conn.query('SELECT * FROM users WHERE status = ?', ['active']);
732
+ return users;
733
+ } finally {
734
+ conn.release();
735
+ }
2052
736
 
2053
- We love contributions! πŸŽ‰
737
+ // After (1 line with superpowers)
738
+ const users = await db.users.findMany({ status: 'active' });
739
+ ```
2054
740
 
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
741
+ **What you gain:**
742
+ - βœ… 10x less code
743
+ - βœ… 20x faster (caching)
744
+ - βœ… Type-safe
745
+ - βœ… Auto cache invalidation
746
+ - βœ… No connection management
2062
747
 
2063
- ### Development Setup
2064
- ```bash
2065
- git clone https://github.com/erBhushanPawar/sqldb.git
2066
- cd sqldb
2067
- npm install
2068
- npm test
2069
- ```
748
+ ---
2070
749
 
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
750
+ ## πŸ—ΊοΈ Roadmap
751
+
752
+ ### Recently Added βœ…
753
+ - βœ… Repository pattern (TypeORM-like)
754
+ - βœ… Lifecycle hooks decorators
755
+ - βœ… Prisma-style query operators
756
+ - βœ… EntityManager
757
+ - βœ… Schema registry (no decorators)
758
+
759
+ ### Coming Soon πŸš€
760
+ - [ ] Transactions support
761
+ - [ ] Single-query JSON aggregation for relations
762
+ - [ ] Soft deletes (`@SoftDelete`)
763
+ - [ ] Custom repositories
764
+ - [ ] Schema migrations CLI
765
+ - [ ] GraphQL integration
2078
766
 
2079
767
  ---
2080
768
 
2081
- ## Support
769
+ ## πŸ’¬ Support
2082
770
 
2083
771
  ### Getting Help
2084
- - πŸ“– **Documentation**: You're reading it!
2085
- - πŸ’¬ **GitHub Issues**: [Report bugs or request features](https://github.com/erBhushanPawar/sqldb/issues)
772
+ - πŸ“– **Documentation**: See [docs](./docs) folder
773
+ - πŸ’¬ **GitHub Issues**: [Report bugs or request features](https://github.com/bhushanpawar/sqldb/issues)
2086
774
  - πŸ“§ **Email**: For private inquiries
2087
775
 
2088
776
  ### Show Your Support
@@ -2090,13 +778,13 @@ If SqlDB saves you time and money:
2090
778
  - ⭐ **Star this repo** on GitHub
2091
779
  - 🐦 **Tweet** about your experience
2092
780
  - πŸ“ **Write** a blog post
2093
- - πŸ’¬ **Tell** a friend who's struggling with caching
781
+ - πŸ’¬ **Tell** a friend
2094
782
 
2095
783
  ---
2096
784
 
2097
- ## License
785
+ ## πŸ“„ License
2098
786
 
2099
- MIT Β© [Bhushan Pawar](https://github.com/erBhushanPawar)
787
+ MIT Β© [Bhushan Pawar](https://github.com/bhushanpawar)
2100
788
 
2101
789
  Free for personal and commercial use. Do whatever you want with it.
2102
790
 
@@ -2104,7 +792,9 @@ Free for personal and commercial use. Do whatever you want with it.
2104
792
 
2105
793
  <div align="center">
2106
794
 
2107
- **Made with ❀️ for developers who hate writing cache logic**
795
+ **Made with ❀️ for developers who hate writing boilerplate**
796
+
797
+ **Stop writing cache logic. Start shipping features.**
2108
798
 
2109
799
  [⬆ Back to Top](#bhushanpawarsqldb)
2110
800