@plyaz/db 0.0.0
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.
- package/README.md +169 -0
- package/dist/adapters/drizzle/DrizzleAdapter.d.ts +269 -0
- package/dist/adapters/drizzle/DrizzleAdapter.d.ts.map +1 -0
- package/dist/adapters/index.d.ts +20 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/sql/SQLAdapter.d.ts +282 -0
- package/dist/adapters/sql/SQLAdapter.d.ts.map +1 -0
- package/dist/adapters/supabase/SupabaseAdapter.d.ts +305 -0
- package/dist/adapters/supabase/SupabaseAdapter.d.ts.map +1 -0
- package/dist/advanced/backup/BackupService.d.ts +159 -0
- package/dist/advanced/backup/BackupService.d.ts.map +1 -0
- package/dist/advanced/backup/index.d.ts +2 -0
- package/dist/advanced/backup/index.d.ts.map +1 -0
- package/dist/advanced/caching/CacheEvict.decorator.d.ts +3 -0
- package/dist/advanced/caching/CacheEvict.decorator.d.ts.map +1 -0
- package/dist/advanced/caching/Cacheable.decorator.d.ts +99 -0
- package/dist/advanced/caching/Cacheable.decorator.d.ts.map +1 -0
- package/dist/advanced/caching/RedisCache.d.ts +417 -0
- package/dist/advanced/caching/RedisCache.d.ts.map +1 -0
- package/dist/advanced/caching/index.d.ts +4 -0
- package/dist/advanced/caching/index.d.ts.map +1 -0
- package/dist/advanced/connection-pool/DynamicPool.d.ts +234 -0
- package/dist/advanced/connection-pool/DynamicPool.d.ts.map +1 -0
- package/dist/advanced/connection-pool/index.d.ts +2 -0
- package/dist/advanced/connection-pool/index.d.ts.map +1 -0
- package/dist/advanced/index.d.ts +8 -0
- package/dist/advanced/index.d.ts.map +1 -0
- package/dist/advanced/monitoring/AlertManager.d.ts +72 -0
- package/dist/advanced/monitoring/AlertManager.d.ts.map +1 -0
- package/dist/advanced/monitoring/MetricsCollector.d.ts +81 -0
- package/dist/advanced/monitoring/MetricsCollector.d.ts.map +1 -0
- package/dist/advanced/monitoring/index.d.ts +3 -0
- package/dist/advanced/monitoring/index.d.ts.map +1 -0
- package/dist/advanced/multi-tenancy/TenantContext.d.ts +52 -0
- package/dist/advanced/multi-tenancy/TenantContext.d.ts.map +1 -0
- package/dist/advanced/multi-tenancy/TenantRepository.d.ts +292 -0
- package/dist/advanced/multi-tenancy/TenantRepository.d.ts.map +1 -0
- package/dist/advanced/multi-tenancy/index.d.ts +3 -0
- package/dist/advanced/multi-tenancy/index.d.ts.map +1 -0
- package/dist/advanced/read-replica/ReadReplicaAdapter.d.ts +516 -0
- package/dist/advanced/read-replica/ReadReplicaAdapter.d.ts.map +1 -0
- package/dist/advanced/read-replica/ReadReplicaManager.d.ts +68 -0
- package/dist/advanced/read-replica/ReadReplicaManager.d.ts.map +1 -0
- package/dist/advanced/read-replica/UseReplica.decorator.d.ts +24 -0
- package/dist/advanced/read-replica/UseReplica.decorator.d.ts.map +1 -0
- package/dist/advanced/read-replica/index.d.ts +3 -0
- package/dist/advanced/read-replica/index.d.ts.map +1 -0
- package/dist/advanced/sharding/ShardKey.d.ts +80 -0
- package/dist/advanced/sharding/ShardKey.d.ts.map +1 -0
- package/dist/advanced/sharding/ShardRouter.d.ts +66 -0
- package/dist/advanced/sharding/ShardRouter.d.ts.map +1 -0
- package/dist/advanced/sharding/index.d.ts +3 -0
- package/dist/advanced/sharding/index.d.ts.map +1 -0
- package/dist/builder/query/index.d.ts +7 -0
- package/dist/builder/query/index.d.ts.map +1 -0
- package/dist/builder/query/orm.d.ts +22 -0
- package/dist/builder/query/orm.d.ts.map +1 -0
- package/dist/builder/query/sql.d.ts +29 -0
- package/dist/builder/query/sql.d.ts.map +1 -0
- package/dist/extensions/AuditExtension.d.ts +468 -0
- package/dist/extensions/AuditExtension.d.ts.map +1 -0
- package/dist/extensions/CachingAdapter.d.ts +451 -0
- package/dist/extensions/CachingAdapter.d.ts.map +1 -0
- package/dist/extensions/EncryptionExtension.d.ts +95 -0
- package/dist/extensions/EncryptionExtension.d.ts.map +1 -0
- package/dist/extensions/ReadReplicaAdapter.d.ts +32 -0
- package/dist/extensions/ReadReplicaAdapter.d.ts.map +1 -0
- package/dist/extensions/SoftDeleteExtension.d.ts +430 -0
- package/dist/extensions/SoftDeleteExtension.d.ts.map +1 -0
- package/dist/extensions/index.d.ts +79 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/factory/AdapterFactory.d.ts +111 -0
- package/dist/factory/AdapterFactory.d.ts.map +1 -0
- package/dist/factory/createDatabaseService.d.ts +121 -0
- package/dist/factory/createDatabaseService.d.ts.map +1 -0
- package/dist/index.cjs +8518 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +8480 -0
- package/dist/index.mjs.map +1 -0
- package/dist/repository/BaseRepository.d.ts +209 -0
- package/dist/repository/BaseRepository.d.ts.map +1 -0
- package/dist/repository/index.d.ts +80 -0
- package/dist/repository/index.d.ts.map +1 -0
- package/dist/security/index.cjs +118 -0
- package/dist/security/index.cjs.map +1 -0
- package/dist/security/index.d.ts +3 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.mjs +114 -0
- package/dist/security/index.mjs.map +1 -0
- package/dist/security/sanitizers/html.sanitizer.d.ts +31 -0
- package/dist/security/sanitizers/html.sanitizer.d.ts.map +1 -0
- package/dist/security/serializers/DataValidation.d.ts +34 -0
- package/dist/security/serializers/DataValidation.d.ts.map +1 -0
- package/dist/service/DatabaseService.d.ts +136 -0
- package/dist/service/DatabaseService.d.ts.map +1 -0
- package/dist/service/EventEmitter.d.ts +110 -0
- package/dist/service/EventEmitter.d.ts.map +1 -0
- package/dist/service/HealthManager.d.ts +166 -0
- package/dist/service/HealthManager.d.ts.map +1 -0
- package/dist/utils/ConfigMerger.d.ts +227 -0
- package/dist/utils/ConfigMerger.d.ts.map +1 -0
- package/dist/utils/databaseResultHelpers.d.ts +98 -0
- package/dist/utils/databaseResultHelpers.d.ts.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/normalizeDetails.d.ts +111 -0
- package/dist/utils/normalizeDetails.d.ts.map +1 -0
- package/dist/utils/pagination.d.ts +77 -0
- package/dist/utils/pagination.d.ts.map +1 -0
- package/dist/utils/regex.d.ts +199 -0
- package/dist/utils/regex.d.ts.map +1 -0
- package/dist/utils/typeGuards.d.ts +57 -0
- package/dist/utils/typeGuards.d.ts.map +1 -0
- package/dist/utils/validation.d.ts +146 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/package.json +156 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type { BackupConfig, BackupInfo, DatabaseResult } from "@plyaz/types/db";
|
|
2
|
+
/**
|
|
3
|
+
* Manages database backups with compression, encryption, and cloud storage.
|
|
4
|
+
* Provides automated scheduling and retention management.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* const config = {
|
|
9
|
+
* connectionString: 'postgres://user:pass@localhost:5432/db',
|
|
10
|
+
* backupDir: './backups',
|
|
11
|
+
* retentionDays: 30,
|
|
12
|
+
* compression: true,
|
|
13
|
+
* encryption: {
|
|
14
|
+
* enabled: true,
|
|
15
|
+
* key: 'encryption-key'
|
|
16
|
+
* },
|
|
17
|
+
* s3: {
|
|
18
|
+
* enabled: true,
|
|
19
|
+
* bucket: 'my-backup-bucket',
|
|
20
|
+
* region: 'us-east-1',
|
|
21
|
+
* accessKey: 'aws-access-key',
|
|
22
|
+
* secretKey: 'aws-secret-key'
|
|
23
|
+
* }
|
|
24
|
+
* };
|
|
25
|
+
*
|
|
26
|
+
* const backupService = new BackupService(config);
|
|
27
|
+
*
|
|
28
|
+
* // Create a backup
|
|
29
|
+
* const backup = await backupService.createBackup();
|
|
30
|
+
* console.log(`Backup created: ${backup.value.filename}`);
|
|
31
|
+
*
|
|
32
|
+
* // List all backups
|
|
33
|
+
* const backups = await backupService.listBackups();
|
|
34
|
+
*
|
|
35
|
+
* // Restore from backup
|
|
36
|
+
* await backupService.restoreBackup(backup.value.id);
|
|
37
|
+
*
|
|
38
|
+
* // Clean up expired backups
|
|
39
|
+
* await backupService.cleanupExpiredBackups();
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare class BackupService {
|
|
43
|
+
private config;
|
|
44
|
+
private backups;
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new BackupService instance.
|
|
47
|
+
* @param config Backup configuration
|
|
48
|
+
*/
|
|
49
|
+
constructor(config: BackupConfig);
|
|
50
|
+
/**
|
|
51
|
+
* Creates a new database backup.
|
|
52
|
+
* @returns Information about the created backup
|
|
53
|
+
*/
|
|
54
|
+
createBackup(): Promise<DatabaseResult<BackupInfo>>;
|
|
55
|
+
/**
|
|
56
|
+
* Restores database from a backup.
|
|
57
|
+
* @param backupId ID of the backup to restore
|
|
58
|
+
* @returns Operation result
|
|
59
|
+
*/
|
|
60
|
+
restoreBackup(backupId: string): Promise<DatabaseResult<null>>;
|
|
61
|
+
/**
|
|
62
|
+
* Lists all available backups.
|
|
63
|
+
* @returns Array of backup information
|
|
64
|
+
*/
|
|
65
|
+
listBackups(): Promise<DatabaseResult<BackupInfo[]>>;
|
|
66
|
+
/**
|
|
67
|
+
* Creates a scheduled backup.
|
|
68
|
+
* @returns Information about the created backup
|
|
69
|
+
*/
|
|
70
|
+
scheduleBackup(): Promise<DatabaseResult<BackupInfo>>;
|
|
71
|
+
/**
|
|
72
|
+
* Removes expired backups from storage.
|
|
73
|
+
* @returns Operation result
|
|
74
|
+
*/
|
|
75
|
+
cleanupExpiredBackups(): Promise<DatabaseResult<null>>;
|
|
76
|
+
/**
|
|
77
|
+
* Deletes a specific backup.
|
|
78
|
+
* @param backupId ID of the backup to delete
|
|
79
|
+
*/
|
|
80
|
+
private deleteBackup;
|
|
81
|
+
/**
|
|
82
|
+
* Ensures backup directory exists.
|
|
83
|
+
*/
|
|
84
|
+
private ensureBackupDir;
|
|
85
|
+
/**
|
|
86
|
+
* Loads existing backups from the backup directory.
|
|
87
|
+
*/
|
|
88
|
+
private loadExistingBackups;
|
|
89
|
+
/**
|
|
90
|
+
* Generates a unique backup ID.
|
|
91
|
+
* @returns Unique backup identifier
|
|
92
|
+
*/
|
|
93
|
+
private generateBackupId;
|
|
94
|
+
/**
|
|
95
|
+
* Gets file size in bytes.
|
|
96
|
+
* @param filepath Path to the file
|
|
97
|
+
* @returns File size in bytes
|
|
98
|
+
*/
|
|
99
|
+
private getFileSize;
|
|
100
|
+
/**
|
|
101
|
+
* Compresses a file using gzip.
|
|
102
|
+
* @param filepath Path to the file to compress
|
|
103
|
+
*/
|
|
104
|
+
private compressFile;
|
|
105
|
+
/**
|
|
106
|
+
* Decompresses a gzipped file.
|
|
107
|
+
* @param filepath Path to the gzipped file
|
|
108
|
+
*/
|
|
109
|
+
private decompressFile;
|
|
110
|
+
/**
|
|
111
|
+
* Encrypts a file using OpenSSL.
|
|
112
|
+
* @param filepath Path to the file to encrypt
|
|
113
|
+
*/
|
|
114
|
+
private encryptFile;
|
|
115
|
+
/**
|
|
116
|
+
* Decrypts a file using OpenSSL.
|
|
117
|
+
* @param filepath Path to the encrypted file
|
|
118
|
+
*/
|
|
119
|
+
private decryptFile;
|
|
120
|
+
/**
|
|
121
|
+
* Uploads a backup to S3.
|
|
122
|
+
* @param backup Backup information
|
|
123
|
+
*/
|
|
124
|
+
private uploadToS3;
|
|
125
|
+
/**
|
|
126
|
+
* Downloads a backup from S3.
|
|
127
|
+
* @param backup Backup information
|
|
128
|
+
* @returns Local path to downloaded file
|
|
129
|
+
*/
|
|
130
|
+
private downloadFromS3;
|
|
131
|
+
/**
|
|
132
|
+
* Deletes a backup from S3.
|
|
133
|
+
* @param backup Backup information
|
|
134
|
+
*/
|
|
135
|
+
private deleteFromS3;
|
|
136
|
+
/**
|
|
137
|
+
* Sets up scheduled backups using cron.
|
|
138
|
+
*/
|
|
139
|
+
private scheduleBackups;
|
|
140
|
+
/**
|
|
141
|
+
* Validates file paths to prevent path traversal attacks.
|
|
142
|
+
* @param filepath Path to validate
|
|
143
|
+
* @returns True if path is valid and safe
|
|
144
|
+
*/
|
|
145
|
+
private isValidPath;
|
|
146
|
+
/**
|
|
147
|
+
* Escapes shell arguments to prevent command injection.
|
|
148
|
+
* @param arg Argument to escape
|
|
149
|
+
* @returns Escaped argument safe for shell execution
|
|
150
|
+
*/
|
|
151
|
+
private escapeShellArg;
|
|
152
|
+
/**
|
|
153
|
+
* Sanitizes strings for safe logging to prevent log injection.
|
|
154
|
+
* @param input String to sanitize
|
|
155
|
+
* @returns Sanitized string safe for logging
|
|
156
|
+
*/
|
|
157
|
+
private sanitizeForLog;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=BackupService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BackupService.d.ts","sourceRoot":"","sources":["../../../src/advanced/backup/BackupService.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAOhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,OAAO,CAAsC;IAErD;;;OAGG;gBACS,MAAM,EAAE,YAAY;IAchC;;;OAGG;IAIG,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IA6HzD;;;;OAIG;IAEG,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IA4GpE;;;OAGG;IACG,WAAW,IAAI,OAAO,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC,CAAC;IAiB1D;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IAI3D;;;OAGG;IACG,qBAAqB,IAAI,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAuC5D;;;OAGG;YACW,YAAY;IAmB1B;;OAEG;IACH,OAAO,CAAC,eAAe;IAUvB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAqC3B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAMxB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAInB;;;OAGG;YACW,YAAY;IAW1B;;;OAGG;YACW,cAAc;IAW5B;;;OAGG;YACW,WAAW;IAkBzB;;;OAGG;YACW,WAAW;IAuCzB;;;OAGG;YACW,UAAU;IAqCxB;;;;OAIG;YACW,cAAc;IAqC5B;;;OAGG;YACW,YAAY;IA2B1B;;OAEG;IACH,OAAO,CAAC,eAAe;IA8BvB;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAwBnB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAatB;;;;OAIG;IACH,OAAO,CAAC,cAAc;CAQvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/advanced/backup/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CacheEvict.decorator.d.ts","sourceRoot":"","sources":["../../../src/advanced/caching/CacheEvict.decorator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAmPtD,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,eAAe,CAsC3E"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { CacheableOptions } from "@plyaz/types/db";
|
|
2
|
+
/**
|
|
3
|
+
* Decorator that caches the result of a method.
|
|
4
|
+
* Automatically generates cache keys and handles TTL.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ### Basic Usage
|
|
8
|
+
* ```typescript
|
|
9
|
+
* class UserService {
|
|
10
|
+
* constructor(private cache: RedisCache) {}
|
|
11
|
+
*
|
|
12
|
+
* @Cacheable({ ttl: 300 }) // Cache for 5 minutes
|
|
13
|
+
* async getUserById(id: string): Promise<DatabaseResult<User>> {
|
|
14
|
+
* // First call: executes query and caches result
|
|
15
|
+
* // Subsequent calls: returns cached result for 5 minutes
|
|
16
|
+
* return this.db.findById('users', id);
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ### Custom Cache Key
|
|
23
|
+
* ```typescript
|
|
24
|
+
* class ProductService {
|
|
25
|
+
* constructor(private cache: RedisCache) {}
|
|
26
|
+
*
|
|
27
|
+
* @Cacheable({
|
|
28
|
+
* key: 'featured-products',
|
|
29
|
+
* ttl: 1800 // Cache for 30 minutes
|
|
30
|
+
* })
|
|
31
|
+
* async getFeaturedProducts(): Promise<DatabaseResult<Product[]>> {
|
|
32
|
+
* // Uses custom cache key 'featured-products'
|
|
33
|
+
* return this.db.findMany('products', {
|
|
34
|
+
* filter: { field: 'featured', operator: 'eq', value: true }
|
|
35
|
+
* });
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ### Conditional Caching
|
|
42
|
+
* ```typescript
|
|
43
|
+
* class OrderService {
|
|
44
|
+
* constructor(private cache: RedisCache) {}
|
|
45
|
+
*
|
|
46
|
+
* @Cacheable({
|
|
47
|
+
* ttl: 600,
|
|
48
|
+
* condition: (result) => result.success && result.value?.length > 0
|
|
49
|
+
* })
|
|
50
|
+
* async getRecentOrders(): Promise<DatabaseResult<Order[]>> {
|
|
51
|
+
* // Only caches successful responses with non-empty results
|
|
52
|
+
* // Prevents caching empty arrays or error responses
|
|
53
|
+
* return this.db.findMany('orders', {
|
|
54
|
+
* sort: [{ field: 'createdAt', direction: 'desc' }],
|
|
55
|
+
* pagination: { limit: 10 }
|
|
56
|
+
* });
|
|
57
|
+
* }
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ### User Profile Caching
|
|
63
|
+
* ```typescript
|
|
64
|
+
* class ProfileService {
|
|
65
|
+
* constructor(private cache: RedisCache) {}
|
|
66
|
+
*
|
|
67
|
+
* @Cacheable({ ttl: 3600 }) // Cache for 1 hour
|
|
68
|
+
* async getUserProfile(userId: string): Promise<DatabaseResult<Profile>> {
|
|
69
|
+
* // User profiles change infrequently, perfect for caching
|
|
70
|
+
* return this.db.findById('profiles', userId);
|
|
71
|
+
* }
|
|
72
|
+
*
|
|
73
|
+
* @CacheEvict({ key: 'user-profile' })
|
|
74
|
+
* async updateProfile(userId: string, data: Partial<Profile>): Promise<DatabaseResult<Profile>> {
|
|
75
|
+
* // When profile is updated, evict the cached version
|
|
76
|
+
* return this.db.update('profiles', userId, data);
|
|
77
|
+
* }
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ### Analytics Data Caching
|
|
83
|
+
* ```typescript
|
|
84
|
+
* class AnalyticsService {
|
|
85
|
+
* constructor(private cache: RedisCache) {}
|
|
86
|
+
*
|
|
87
|
+
* @Cacheable({
|
|
88
|
+
* ttl: 7200, // Cache for 2 hours
|
|
89
|
+
* key: 'daily-stats'
|
|
90
|
+
* })
|
|
91
|
+
* async getDailyStats(date: string): Promise<DatabaseResult<DailyStats>> {
|
|
92
|
+
* // Analytics queries are expensive, cache them longer
|
|
93
|
+
* return this.db.findById('daily_stats', date);
|
|
94
|
+
* }
|
|
95
|
+
* }
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export declare function Cacheable(options?: CacheableOptions): MethodDecorator;
|
|
99
|
+
//# sourceMappingURL=Cacheable.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Cacheable.decorator.d.ts","sourceRoot":"","sources":["../../../src/advanced/caching/Cacheable.decorator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAkB,MAAM,iBAAiB,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+FG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,eAAe,CAsDzE"}
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import type { DatabaseResult } from "@plyaz/types/db";
|
|
2
|
+
/**
|
|
3
|
+
* Redis-based caching service for database query results.
|
|
4
|
+
* Provides automatic serialization/deserialization, TTL management, and pattern-based invalidation.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ### Basic Usage
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const cache = new RedisCache({
|
|
10
|
+
* url: 'redis://localhost:6379',
|
|
11
|
+
* defaultTTL: 3600 // 1 hour
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* // Set a value
|
|
15
|
+
* await cache.set('user:123', { id: 123, name: 'John' });
|
|
16
|
+
*
|
|
17
|
+
* // Get a value
|
|
18
|
+
* const result = await cache.get('user:123');
|
|
19
|
+
* if (result.success) {
|
|
20
|
+
* console.log(result.value); // { id: 123, name: 'John' }
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* // Delete a value
|
|
24
|
+
* await cache.del('user:123');
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ### User Profile Caching
|
|
29
|
+
* ```typescript
|
|
30
|
+
* class UserProfileCache {
|
|
31
|
+
* constructor(private cache: RedisCache) {}
|
|
32
|
+
*
|
|
33
|
+
* async getUserProfile(userId: string): Promise<DatabaseResult<UserProfile>> {
|
|
34
|
+
* const cacheKey = `profile:${userId}`;
|
|
35
|
+
*
|
|
36
|
+
* // Try cache first
|
|
37
|
+
* const cached = await this.cache.get<UserProfile>(cacheKey);
|
|
38
|
+
* if (cached.success && cached.value) {
|
|
39
|
+
* return cached;
|
|
40
|
+
* }
|
|
41
|
+
*
|
|
42
|
+
* // Fetch from database
|
|
43
|
+
* const profile = await this.db.findById('profiles', userId);
|
|
44
|
+
*
|
|
45
|
+
* // Cache the result
|
|
46
|
+
* if (profile.success) {
|
|
47
|
+
* await this.cache.set(cacheKey, profile.value, 1800); // 30 minutes
|
|
48
|
+
* }
|
|
49
|
+
*
|
|
50
|
+
* return profile;
|
|
51
|
+
* }
|
|
52
|
+
*
|
|
53
|
+
* async updateUserProfile(userId: string, data: Partial<UserProfile>): Promise<DatabaseResult<UserProfile>> {
|
|
54
|
+
* const updated = await this.db.update('profiles', userId, data);
|
|
55
|
+
*
|
|
56
|
+
* // Invalidate cache on successful update
|
|
57
|
+
* if (updated.success) {
|
|
58
|
+
* await this.cache.del(`profile:${userId}`);
|
|
59
|
+
* // Also invalidate related caches
|
|
60
|
+
* await this.cache.invalidatePattern(`user:${userId}:*`);
|
|
61
|
+
* }
|
|
62
|
+
*
|
|
63
|
+
* return updated;
|
|
64
|
+
* }
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ### Product Catalog Caching
|
|
70
|
+
* ```typescript
|
|
71
|
+
* class ProductCatalogCache {
|
|
72
|
+
* constructor(private cache: RedisCache) {}
|
|
73
|
+
*
|
|
74
|
+
* async getProductsByCategory(categoryId: string): Promise<DatabaseResult<Product[]>> {
|
|
75
|
+
* const cacheKey = `products:category:${categoryId}`;
|
|
76
|
+
*
|
|
77
|
+
* const cached = await this.cache.get<Product[]>(cacheKey);
|
|
78
|
+
* if (cached.success && cached.value) {
|
|
79
|
+
* return cached;
|
|
80
|
+
* }
|
|
81
|
+
*
|
|
82
|
+
* const products = await this.db.findMany('products', {
|
|
83
|
+
* filter: { field: 'categoryId', operator: 'eq', value: categoryId }
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* // Cache product lists longer (2 hours) as they change less frequently
|
|
87
|
+
* if (products.success) {
|
|
88
|
+
* await this.cache.set(cacheKey, products.value, 7200);
|
|
89
|
+
* }
|
|
90
|
+
*
|
|
91
|
+
* return products;
|
|
92
|
+
* }
|
|
93
|
+
*
|
|
94
|
+
* async updateProductStock(productId: string, quantity: number): Promise<DatabaseResult<void>> {
|
|
95
|
+
* await this.db.update('inventory', productId, { quantity });
|
|
96
|
+
*
|
|
97
|
+
* // Invalidate product cache and related caches
|
|
98
|
+
* await this.cache.del(`product:${productId}`);
|
|
99
|
+
* await this.cache.invalidatePattern(`products:category:*`);
|
|
100
|
+
* await this.cache.invalidatePattern(`inventory:low-stock`);
|
|
101
|
+
* }
|
|
102
|
+
* }
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ### Multi-tenant Caching
|
|
107
|
+
* ```typescript
|
|
108
|
+
* class MultiTenantCache {
|
|
109
|
+
* constructor(private cache: RedisCache) {}
|
|
110
|
+
*
|
|
111
|
+
* async getTenantConfig(tenantId: string): Promise<DatabaseResult<TenantConfig>> {
|
|
112
|
+
* const cacheKey = `tenant:${tenantId}:config`;
|
|
113
|
+
*
|
|
114
|
+
* const cached = await this.cache.get<TenantConfig>(cacheKey);
|
|
115
|
+
* if (cached.success && cached.value) {
|
|
116
|
+
* return cached;
|
|
117
|
+
* }
|
|
118
|
+
*
|
|
119
|
+
* const config = await this.db.findById('tenant_configs', tenantId);
|
|
120
|
+
*
|
|
121
|
+
* // Cache configs longer (4 hours) as they rarely change
|
|
122
|
+
* if (config.success) {
|
|
123
|
+
* await this.cache.set(cacheKey, config.value, 14400);
|
|
124
|
+
* }
|
|
125
|
+
*
|
|
126
|
+
* return config;
|
|
127
|
+
* }
|
|
128
|
+
*
|
|
129
|
+
* async updateTenantSettings(tenantId: string): Promise<DatabaseResult<void>> {
|
|
130
|
+
* await this.db.update('tenant_settings', tenantId, { updatedAt: new Date() });
|
|
131
|
+
*
|
|
132
|
+
* // Invalidate all tenant-related caches
|
|
133
|
+
* await this.cache.invalidatePattern(`tenant:${tenantId}:*`);
|
|
134
|
+
* }
|
|
135
|
+
* }
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ### Analytics Data Caching
|
|
140
|
+
* ```typescript
|
|
141
|
+
* class AnalyticsCache {
|
|
142
|
+
* constructor(private cache: RedisCache) {}
|
|
143
|
+
*
|
|
144
|
+
* async getDailyStats(date: string): Promise<DatabaseResult<DailyStats>> {
|
|
145
|
+
* const cacheKey = `analytics:daily:${date}`;
|
|
146
|
+
*
|
|
147
|
+
* const cached = await this.cache.get<DailyStats>(cacheKey);
|
|
148
|
+
* if (cached.success && cached.value) {
|
|
149
|
+
* return cached;
|
|
150
|
+
* }
|
|
151
|
+
*
|
|
152
|
+
* // Analytics queries are expensive, cache them longer
|
|
153
|
+
* const stats = await this.db.findById('daily_stats', date);
|
|
154
|
+
*
|
|
155
|
+
* if (stats.success) {
|
|
156
|
+
* // Cache for 6 hours as analytics data doesn't change frequently
|
|
157
|
+
* await this.cache.set(cacheKey, stats.value, 21600);
|
|
158
|
+
* }
|
|
159
|
+
*
|
|
160
|
+
* return stats;
|
|
161
|
+
* }
|
|
162
|
+
*
|
|
163
|
+
* async recordMetric(metric: MetricData): Promise<DatabaseResult<void>> {
|
|
164
|
+
* await this.db.create('metrics', metric);
|
|
165
|
+
*
|
|
166
|
+
* // Invalidate aggregated analytics caches
|
|
167
|
+
* await this.cache.invalidatePattern('analytics:aggregated:*');
|
|
168
|
+
* await this.cache.invalidatePattern('analytics:dashboard:*');
|
|
169
|
+
* }
|
|
170
|
+
* }
|
|
171
|
+
* ```
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ### Session Management
|
|
175
|
+
* ```typescript
|
|
176
|
+
* class SessionCache {
|
|
177
|
+
* constructor(private cache: RedisCache) {}
|
|
178
|
+
*
|
|
179
|
+
* async getUserSession(sessionId: string): Promise<DatabaseResult<Session>> {
|
|
180
|
+
* const cacheKey = `session:${sessionId}`;
|
|
181
|
+
*
|
|
182
|
+
* // Sessions are accessed frequently, cache them but with short TTL
|
|
183
|
+
* const cached = await this.cache.get<Session>(cacheKey);
|
|
184
|
+
* if (cached.success && cached.value) {
|
|
185
|
+
* return cached;
|
|
186
|
+
* }
|
|
187
|
+
*
|
|
188
|
+
* const session = await this.db.findById('sessions', sessionId);
|
|
189
|
+
*
|
|
190
|
+
* if (session.success) {
|
|
191
|
+
* // Cache sessions for 15 minutes
|
|
192
|
+
* await this.cache.set(cacheKey, session.value, 900);
|
|
193
|
+
* }
|
|
194
|
+
*
|
|
195
|
+
* return session;
|
|
196
|
+
* }
|
|
197
|
+
*
|
|
198
|
+
* async invalidateUserSessions(userId: string): Promise<DatabaseResult<void>> {
|
|
199
|
+
* // Invalidate all sessions for a user (e.g., on logout or password change)
|
|
200
|
+
* await this.cache.invalidatePattern(`session:user:${userId}:*`);
|
|
201
|
+
* }
|
|
202
|
+
* }
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
export declare class RedisCache {
|
|
206
|
+
private redis;
|
|
207
|
+
private defaultTTL;
|
|
208
|
+
/**
|
|
209
|
+
* Creates a new RedisCache instance.
|
|
210
|
+
* @param config Redis configuration
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* // Basic configuration
|
|
215
|
+
* const cache = new RedisCache({
|
|
216
|
+
* url: 'redis://localhost:6379'
|
|
217
|
+
* });
|
|
218
|
+
*
|
|
219
|
+
* // With custom default TTL
|
|
220
|
+
* const cacheWithCustomTTL = new RedisCache({
|
|
221
|
+
* url: 'redis://localhost:6379',
|
|
222
|
+
* defaultTTL: 1800 // 30 minutes
|
|
223
|
+
* });
|
|
224
|
+
*
|
|
225
|
+
* // Production configuration with options
|
|
226
|
+
* const productionCache = new RedisCache({
|
|
227
|
+
* url: 'redis://redis-cluster.example.com:6379',
|
|
228
|
+
* defaultTTL: 3600,
|
|
229
|
+
* // Additional Redis options can be passed here
|
|
230
|
+
* });
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
constructor(config: {
|
|
234
|
+
url: string;
|
|
235
|
+
defaultTTL?: number;
|
|
236
|
+
});
|
|
237
|
+
/**
|
|
238
|
+
* Retrieves a value from cache by key.
|
|
239
|
+
* Automatically handles JSON deserialization.
|
|
240
|
+
*
|
|
241
|
+
* @param key Cache key
|
|
242
|
+
* @returns DatabaseResult containing cached value or null if not found
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* // Get user profile
|
|
247
|
+
* const result = await cache.get<UserProfile>('profile:123');
|
|
248
|
+
* if (result.success && result.value) {
|
|
249
|
+
* console.log('User:', result.value.name);
|
|
250
|
+
* } else {
|
|
251
|
+
* console.log('Profile not found or cache error');
|
|
252
|
+
* }
|
|
253
|
+
*
|
|
254
|
+
* // Get product list
|
|
255
|
+
* const products = await cache.get<Product[]>('products:featured');
|
|
256
|
+
* if (products.success && products.value) {
|
|
257
|
+
* products.value.forEach(product => {
|
|
258
|
+
* console.log(product.name, product.price);
|
|
259
|
+
* });
|
|
260
|
+
* }
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
get<T extends object>(key: string): Promise<DatabaseResult<T | null>>;
|
|
264
|
+
/**
|
|
265
|
+
* Sets a value in cache with optional TTL.
|
|
266
|
+
* Automatically handles JSON serialization.
|
|
267
|
+
*
|
|
268
|
+
* @param key Cache key
|
|
269
|
+
* @param value Value to cache
|
|
270
|
+
* @param ttl Time to live in seconds (uses default if not specified)
|
|
271
|
+
* @returns DatabaseResult indicating operation success
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```typescript
|
|
275
|
+
* // Cache with default TTL
|
|
276
|
+
* await cache.set('user:123', { id: 123, name: 'John' });
|
|
277
|
+
*
|
|
278
|
+
* // Cache with custom TTL (5 minutes)
|
|
279
|
+
* await cache.set('session:abc123', sessionData, 300);
|
|
280
|
+
*
|
|
281
|
+
* // Cache with long TTL for static data
|
|
282
|
+
* await cache.set('config:app-settings', appSettings, 86400); // 24 hours
|
|
283
|
+
*
|
|
284
|
+
* // Cache with short TTL for frequently changing data
|
|
285
|
+
* await cache.set('metrics:realtime', realtimeData, 60); // 1 minute
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
set<T extends object>(key: string, value: T, ttl?: number): Promise<DatabaseResult<null>>;
|
|
289
|
+
/**
|
|
290
|
+
* Deletes a value from cache.
|
|
291
|
+
*
|
|
292
|
+
* @param key Cache key
|
|
293
|
+
* @returns DatabaseResult indicating operation success
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```typescript
|
|
297
|
+
* // Delete specific cache entry
|
|
298
|
+
* await cache.del('user:123');
|
|
299
|
+
*
|
|
300
|
+
* // Delete session on logout
|
|
301
|
+
* await cache.del(`session:${sessionId}`);
|
|
302
|
+
*
|
|
303
|
+
* // Delete cached configuration
|
|
304
|
+
* await cache.del('config:feature-flags');
|
|
305
|
+
* ```
|
|
306
|
+
*/
|
|
307
|
+
del(key: string): Promise<DatabaseResult<null>>;
|
|
308
|
+
/**
|
|
309
|
+
* Invalidates all cache entries matching a pattern.
|
|
310
|
+
* Useful for clearing related cache entries when data changes.
|
|
311
|
+
*
|
|
312
|
+
* @param pattern Redis key pattern (e.g., 'users:*')
|
|
313
|
+
* @returns DatabaseResult indicating operation success
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* ```typescript
|
|
317
|
+
* // Invalidate all user-related caches
|
|
318
|
+
* await cache.invalidatePattern('users:*');
|
|
319
|
+
*
|
|
320
|
+
* // Invalidate all caches for a specific category
|
|
321
|
+
* await cache.invalidatePattern('products:category:electronics:*');
|
|
322
|
+
*
|
|
323
|
+
* // Invalidate all session caches
|
|
324
|
+
* await cache.invalidatePattern('session:*');
|
|
325
|
+
*
|
|
326
|
+
* // Invalidate all caches for a tenant
|
|
327
|
+
* await cache.invalidatePattern(`tenant:${tenantId}:*`);
|
|
328
|
+
*
|
|
329
|
+
* // Invalidate all analytics caches
|
|
330
|
+
* await cache.invalidatePattern('analytics:*');
|
|
331
|
+
* ```
|
|
332
|
+
*/
|
|
333
|
+
invalidatePattern(pattern: string): Promise<DatabaseResult<null>>;
|
|
334
|
+
/**
|
|
335
|
+
* Generates a cache key for database queries.
|
|
336
|
+
* Creates consistent, URL-safe keys that include table, operation, and parameters.
|
|
337
|
+
*
|
|
338
|
+
* @param table Database table name
|
|
339
|
+
* @param operation Database operation type
|
|
340
|
+
* @param params Query parameters object
|
|
341
|
+
* @returns Generated cache key
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```typescript
|
|
345
|
+
* // Simple key generation
|
|
346
|
+
* const key = cache.generateKey('users', 'findById', { id: '123' });
|
|
347
|
+
* // Returns: 'db:users:findById:eyJpYXJhbTAiOiIxMjMifQ=='
|
|
348
|
+
*
|
|
349
|
+
* // Complex query key
|
|
350
|
+
* const complexKey = cache.generateKey('products', 'findMany', {
|
|
351
|
+
* filter: { field: 'category', operator: 'eq', value: 'electronics' },
|
|
352
|
+
* sort: [{ field: 'price', direction: 'asc' }],
|
|
353
|
+
* pagination: { limit: 20, offset: 0 }
|
|
354
|
+
* });
|
|
355
|
+
*
|
|
356
|
+
* // User-specific key
|
|
357
|
+
* const userKey = cache.generateKey('orders', 'findMany', {
|
|
358
|
+
* filter: { field: 'userId', operator: 'eq', value: '123' }
|
|
359
|
+
* });
|
|
360
|
+
* ```
|
|
361
|
+
*/
|
|
362
|
+
generateKey(table: string, operation: string, params: Record<string, string | number | boolean | null>): string;
|
|
363
|
+
/**
|
|
364
|
+
* Performs a health check on the Redis connection.
|
|
365
|
+
* Useful for monitoring and ensuring cache availability.
|
|
366
|
+
*
|
|
367
|
+
* @returns DatabaseResult with boolean indicating if Redis is healthy
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* ```typescript
|
|
371
|
+
* // Check Redis health
|
|
372
|
+
* const health = await cache.healthCheck();
|
|
373
|
+
* if (health.success && health.value) {
|
|
374
|
+
* console.log('Redis is healthy');
|
|
375
|
+
* } else {
|
|
376
|
+
* console.log('Redis health check failed:', health.error?.message);
|
|
377
|
+
* // Implement fallback logic or alerting
|
|
378
|
+
* }
|
|
379
|
+
*
|
|
380
|
+
* // Use in health check endpoint
|
|
381
|
+
* app.get('/health', async (req, res) => {
|
|
382
|
+
* const dbHealth = await db.healthCheck();
|
|
383
|
+
* const cacheHealth = await cache.healthCheck();
|
|
384
|
+
*
|
|
385
|
+
* res.json({
|
|
386
|
+
* database: dbHealth.success && dbHealth.value,
|
|
387
|
+
* cache: cacheHealth.success && cacheHealth.value,
|
|
388
|
+
* timestamp: new Date()
|
|
389
|
+
* });
|
|
390
|
+
* });
|
|
391
|
+
* ```
|
|
392
|
+
*/
|
|
393
|
+
healthCheck(): Promise<DatabaseResult<boolean>>;
|
|
394
|
+
/**
|
|
395
|
+
* Closes the Redis connection gracefully.
|
|
396
|
+
* Should be called during application shutdown.
|
|
397
|
+
*
|
|
398
|
+
* @example
|
|
399
|
+
* ```typescript
|
|
400
|
+
* // In your application shutdown logic
|
|
401
|
+
* async function shutdown() {
|
|
402
|
+
* console.log('Shutting down cache...');
|
|
403
|
+
* await cache.close();
|
|
404
|
+
* console.log('Cache connection closed');
|
|
405
|
+
*
|
|
406
|
+
* // Close other connections...
|
|
407
|
+
* process.exit(0);
|
|
408
|
+
* }
|
|
409
|
+
*
|
|
410
|
+
* // Handle graceful shutdown
|
|
411
|
+
* process.on('SIGTERM', shutdown);
|
|
412
|
+
* process.on('SIGINT', shutdown);
|
|
413
|
+
* ```
|
|
414
|
+
*/
|
|
415
|
+
close(): Promise<void>;
|
|
416
|
+
}
|
|
417
|
+
//# sourceMappingURL=RedisCache.d.ts.map
|