@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.
Files changed (118) hide show
  1. package/README.md +169 -0
  2. package/dist/adapters/drizzle/DrizzleAdapter.d.ts +269 -0
  3. package/dist/adapters/drizzle/DrizzleAdapter.d.ts.map +1 -0
  4. package/dist/adapters/index.d.ts +20 -0
  5. package/dist/adapters/index.d.ts.map +1 -0
  6. package/dist/adapters/sql/SQLAdapter.d.ts +282 -0
  7. package/dist/adapters/sql/SQLAdapter.d.ts.map +1 -0
  8. package/dist/adapters/supabase/SupabaseAdapter.d.ts +305 -0
  9. package/dist/adapters/supabase/SupabaseAdapter.d.ts.map +1 -0
  10. package/dist/advanced/backup/BackupService.d.ts +159 -0
  11. package/dist/advanced/backup/BackupService.d.ts.map +1 -0
  12. package/dist/advanced/backup/index.d.ts +2 -0
  13. package/dist/advanced/backup/index.d.ts.map +1 -0
  14. package/dist/advanced/caching/CacheEvict.decorator.d.ts +3 -0
  15. package/dist/advanced/caching/CacheEvict.decorator.d.ts.map +1 -0
  16. package/dist/advanced/caching/Cacheable.decorator.d.ts +99 -0
  17. package/dist/advanced/caching/Cacheable.decorator.d.ts.map +1 -0
  18. package/dist/advanced/caching/RedisCache.d.ts +417 -0
  19. package/dist/advanced/caching/RedisCache.d.ts.map +1 -0
  20. package/dist/advanced/caching/index.d.ts +4 -0
  21. package/dist/advanced/caching/index.d.ts.map +1 -0
  22. package/dist/advanced/connection-pool/DynamicPool.d.ts +234 -0
  23. package/dist/advanced/connection-pool/DynamicPool.d.ts.map +1 -0
  24. package/dist/advanced/connection-pool/index.d.ts +2 -0
  25. package/dist/advanced/connection-pool/index.d.ts.map +1 -0
  26. package/dist/advanced/index.d.ts +8 -0
  27. package/dist/advanced/index.d.ts.map +1 -0
  28. package/dist/advanced/monitoring/AlertManager.d.ts +72 -0
  29. package/dist/advanced/monitoring/AlertManager.d.ts.map +1 -0
  30. package/dist/advanced/monitoring/MetricsCollector.d.ts +81 -0
  31. package/dist/advanced/monitoring/MetricsCollector.d.ts.map +1 -0
  32. package/dist/advanced/monitoring/index.d.ts +3 -0
  33. package/dist/advanced/monitoring/index.d.ts.map +1 -0
  34. package/dist/advanced/multi-tenancy/TenantContext.d.ts +52 -0
  35. package/dist/advanced/multi-tenancy/TenantContext.d.ts.map +1 -0
  36. package/dist/advanced/multi-tenancy/TenantRepository.d.ts +292 -0
  37. package/dist/advanced/multi-tenancy/TenantRepository.d.ts.map +1 -0
  38. package/dist/advanced/multi-tenancy/index.d.ts +3 -0
  39. package/dist/advanced/multi-tenancy/index.d.ts.map +1 -0
  40. package/dist/advanced/read-replica/ReadReplicaAdapter.d.ts +516 -0
  41. package/dist/advanced/read-replica/ReadReplicaAdapter.d.ts.map +1 -0
  42. package/dist/advanced/read-replica/ReadReplicaManager.d.ts +68 -0
  43. package/dist/advanced/read-replica/ReadReplicaManager.d.ts.map +1 -0
  44. package/dist/advanced/read-replica/UseReplica.decorator.d.ts +24 -0
  45. package/dist/advanced/read-replica/UseReplica.decorator.d.ts.map +1 -0
  46. package/dist/advanced/read-replica/index.d.ts +3 -0
  47. package/dist/advanced/read-replica/index.d.ts.map +1 -0
  48. package/dist/advanced/sharding/ShardKey.d.ts +80 -0
  49. package/dist/advanced/sharding/ShardKey.d.ts.map +1 -0
  50. package/dist/advanced/sharding/ShardRouter.d.ts +66 -0
  51. package/dist/advanced/sharding/ShardRouter.d.ts.map +1 -0
  52. package/dist/advanced/sharding/index.d.ts +3 -0
  53. package/dist/advanced/sharding/index.d.ts.map +1 -0
  54. package/dist/builder/query/index.d.ts +7 -0
  55. package/dist/builder/query/index.d.ts.map +1 -0
  56. package/dist/builder/query/orm.d.ts +22 -0
  57. package/dist/builder/query/orm.d.ts.map +1 -0
  58. package/dist/builder/query/sql.d.ts +29 -0
  59. package/dist/builder/query/sql.d.ts.map +1 -0
  60. package/dist/extensions/AuditExtension.d.ts +468 -0
  61. package/dist/extensions/AuditExtension.d.ts.map +1 -0
  62. package/dist/extensions/CachingAdapter.d.ts +451 -0
  63. package/dist/extensions/CachingAdapter.d.ts.map +1 -0
  64. package/dist/extensions/EncryptionExtension.d.ts +95 -0
  65. package/dist/extensions/EncryptionExtension.d.ts.map +1 -0
  66. package/dist/extensions/ReadReplicaAdapter.d.ts +32 -0
  67. package/dist/extensions/ReadReplicaAdapter.d.ts.map +1 -0
  68. package/dist/extensions/SoftDeleteExtension.d.ts +430 -0
  69. package/dist/extensions/SoftDeleteExtension.d.ts.map +1 -0
  70. package/dist/extensions/index.d.ts +79 -0
  71. package/dist/extensions/index.d.ts.map +1 -0
  72. package/dist/factory/AdapterFactory.d.ts +111 -0
  73. package/dist/factory/AdapterFactory.d.ts.map +1 -0
  74. package/dist/factory/createDatabaseService.d.ts +121 -0
  75. package/dist/factory/createDatabaseService.d.ts.map +1 -0
  76. package/dist/index.cjs +8518 -0
  77. package/dist/index.cjs.map +1 -0
  78. package/dist/index.d.ts +19 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.mjs +8480 -0
  81. package/dist/index.mjs.map +1 -0
  82. package/dist/repository/BaseRepository.d.ts +209 -0
  83. package/dist/repository/BaseRepository.d.ts.map +1 -0
  84. package/dist/repository/index.d.ts +80 -0
  85. package/dist/repository/index.d.ts.map +1 -0
  86. package/dist/security/index.cjs +118 -0
  87. package/dist/security/index.cjs.map +1 -0
  88. package/dist/security/index.d.ts +3 -0
  89. package/dist/security/index.d.ts.map +1 -0
  90. package/dist/security/index.mjs +114 -0
  91. package/dist/security/index.mjs.map +1 -0
  92. package/dist/security/sanitizers/html.sanitizer.d.ts +31 -0
  93. package/dist/security/sanitizers/html.sanitizer.d.ts.map +1 -0
  94. package/dist/security/serializers/DataValidation.d.ts +34 -0
  95. package/dist/security/serializers/DataValidation.d.ts.map +1 -0
  96. package/dist/service/DatabaseService.d.ts +136 -0
  97. package/dist/service/DatabaseService.d.ts.map +1 -0
  98. package/dist/service/EventEmitter.d.ts +110 -0
  99. package/dist/service/EventEmitter.d.ts.map +1 -0
  100. package/dist/service/HealthManager.d.ts +166 -0
  101. package/dist/service/HealthManager.d.ts.map +1 -0
  102. package/dist/utils/ConfigMerger.d.ts +227 -0
  103. package/dist/utils/ConfigMerger.d.ts.map +1 -0
  104. package/dist/utils/databaseResultHelpers.d.ts +98 -0
  105. package/dist/utils/databaseResultHelpers.d.ts.map +1 -0
  106. package/dist/utils/index.d.ts +7 -0
  107. package/dist/utils/index.d.ts.map +1 -0
  108. package/dist/utils/normalizeDetails.d.ts +111 -0
  109. package/dist/utils/normalizeDetails.d.ts.map +1 -0
  110. package/dist/utils/pagination.d.ts +77 -0
  111. package/dist/utils/pagination.d.ts.map +1 -0
  112. package/dist/utils/regex.d.ts +199 -0
  113. package/dist/utils/regex.d.ts.map +1 -0
  114. package/dist/utils/typeGuards.d.ts +57 -0
  115. package/dist/utils/typeGuards.d.ts.map +1 -0
  116. package/dist/utils/validation.d.ts +146 -0
  117. package/dist/utils/validation.d.ts.map +1 -0
  118. package/package.json +156 -0
@@ -0,0 +1,516 @@
1
+ import type { DatabaseAdapterType, DatabaseResult, DrizzleAdapterConfig, Filter, DatabaseHealthStatus, PaginatedResult, QueryOptions, Transaction } from "@plyaz/types/db";
2
+ /**
3
+ * Database adapter that provides read replica support with automatic read/write splitting.
4
+ * Routes SELECT queries to read replicas and write operations to the primary database.
5
+ * Implements load balancing across replicas and automatic failover to primary.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const config = {
10
+ * connectionString: 'postgres://primary:5432/db',
11
+ * replicas: [
12
+ * { connectionString: 'postgres://replica1:5432/db' },
13
+ * { connectionString: 'postgres://replica2:5432/db' }
14
+ * ]
15
+ * };
16
+ *
17
+ * const adapter = new ReadReplicaAdapter(config);
18
+ * await adapter.initialize();
19
+ *
20
+ * // This will be routed to a replica
21
+ * const users = await adapter.findMany('users');
22
+ *
23
+ * // This will be routed to primary
24
+ * await adapter.create('users', { name: 'John' });
25
+ * ```
26
+ */
27
+ export declare class ReadReplicaAdapter implements DatabaseAdapterType {
28
+ private primaryAdapter;
29
+ private replicaManager;
30
+ private replicas;
31
+ private currentReplicaIndex;
32
+ /**
33
+ * Creates a new ReadReplicaAdapter instance.
34
+ *
35
+ * **RESPONSIBILITY:** Sets up primary adapter and replica manager for read/write splitting
36
+ *
37
+ * @param config Configuration for primary and replica databases
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * const adapter = new ReadReplicaAdapter({
42
+ * connectionString: 'postgres://primary:5432/db',
43
+ * replicas: [
44
+ * { connectionString: 'postgres://replica1:5432/db' },
45
+ * { connectionString: 'postgres://replica2:5432/db' }
46
+ * ]
47
+ * });
48
+ * ```
49
+ */
50
+ constructor(config: DrizzleAdapterConfig & {
51
+ replicas: DrizzleAdapterConfig[];
52
+ });
53
+ /**
54
+ * Initializes the adapter and all replicas.
55
+ *
56
+ * **RESPONSIBILITY:** Establishes connections to primary and all replica databases
57
+ * **BEHAVIOR:** Fails if primary initialization fails, continues if replicas fail
58
+ *
59
+ * @returns Promise resolving to initialization result
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * const adapter = new ReadReplicaAdapter(config);
64
+ * const result = await adapter.initialize();
65
+ *
66
+ * if (result.success) {
67
+ * console.log('All databases initialized successfully');
68
+ * } else {
69
+ * console.error('Initialization failed:', result.error);
70
+ * }
71
+ * ```
72
+ */
73
+ initialize(): Promise<DatabaseResult<void>>;
74
+ /**
75
+ * Establishes connections to primary and all replicas.
76
+ *
77
+ * **RESPONSIBILITY:** Opens database connections for all configured databases
78
+ * **BEHAVIOR:** Throws error if any connection fails
79
+ *
80
+ * @throws {BaseError} When connection to any database fails
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * try {
85
+ * await adapter.connect();
86
+ * console.log('All connections established');
87
+ * } catch (error) {
88
+ * console.error('Connection failed:', error.message);
89
+ * }
90
+ * ```
91
+ */
92
+ connect(): Promise<void>;
93
+ /**
94
+ * Closes connections to primary and all replicas.
95
+ *
96
+ * **RESPONSIBILITY:** Gracefully closes all database connections
97
+ * **BEHAVIOR:** Attempts to close all connections even if some fail
98
+ *
99
+ * @throws {BaseError} When disconnection from any database fails
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * try {
104
+ * await adapter.disconnect();
105
+ * console.log('All connections closed');
106
+ * } catch (error) {
107
+ * console.error('Disconnection failed:', error.message);
108
+ * }
109
+ * ```
110
+ */
111
+ disconnect(): Promise<void>;
112
+ /**
113
+ * Gets the underlying primary database client.
114
+ *
115
+ * **RESPONSIBILITY:** Provides access to the primary database client for advanced operations
116
+ * **USE CASE:** When you need direct access to database-specific features
117
+ *
118
+ * @returns Primary database client
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * // Get PostgreSQL client for advanced operations
123
+ * const pgClient = adapter.getClient<pg.Client>();
124
+ *
125
+ * // Use client for database-specific operations
126
+ * const result = await pgClient.query('SELECT version()');
127
+ * ```
128
+ */
129
+ getClient<TClient extends object>(): TClient;
130
+ /**
131
+ * Executes a raw SQL query with automatic read/write routing.
132
+ *
133
+ * **ROUTING LOGIC:**
134
+ * - SELECT queries → Read replicas (with failover to primary)
135
+ * - INSERT/UPDATE/DELETE → Primary database only
136
+ *
137
+ * **LOAD BALANCING:** Round-robin across healthy replicas
138
+ * **FAILOVER:** Automatic fallback to primary if all replicas fail
139
+ *
140
+ * @param sql SQL query string
141
+ * @param params Query parameters
142
+ * @returns Query result rows
143
+ *
144
+ * @throws {BaseError} When SQL is invalid or execution fails
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * // Read query - routed to replica
149
+ * const users = await adapter.query(
150
+ * 'SELECT * FROM users WHERE status = $1',
151
+ * ['active']
152
+ * );
153
+ *
154
+ * // Write query - routed to primary
155
+ * await adapter.query(
156
+ * 'INSERT INTO users (name, email) VALUES ($1, $2)',
157
+ * ['John Doe', 'john@example.com']
158
+ * );
159
+ * ```
160
+ */
161
+ /**
162
+ * Validates SQL query string.
163
+ * @private
164
+ * @param sql SQL query to validate
165
+ * @throws {BaseError} When SQL is not a valid string
166
+ */
167
+ private validateSql;
168
+ /**
169
+ * Executes query on a read replica with load balancing.
170
+ * @private
171
+ * @param sql SQL query string
172
+ * @param params Query parameters
173
+ * @returns Query result
174
+ */
175
+ private executeOnReplica;
176
+ /**
177
+ * Tries other replicas or falls back to primary on failure.
178
+ * @private
179
+ * @param sql SQL query string
180
+ * @param params Query parameters
181
+ * @returns Query result
182
+ */
183
+ private tryOtherReplicasOrPrimary;
184
+ query<T>(sql: string, params?: T[]): Promise<T[]>;
185
+ /**
186
+ * Registers a table with primary and all replicas.
187
+ *
188
+ * **RESPONSIBILITY:** Ensures table schema is available on all database connections
189
+ * **BEHAVIOR:** Registers with primary and all replica adapters
190
+ *
191
+ * @param name Logical table name
192
+ * @param table Table schema
193
+ * @param idColumn Optional ID column name
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * // Register user table with all adapters
198
+ * adapter.registerTable('users', userTableSchema, 'id');
199
+ *
200
+ * // Now all operations on 'users' table will work
201
+ * const user = await adapter.findById('users', '123');
202
+ * ```
203
+ */
204
+ registerTable<TTable, TIdColumn>(name: string, table: TTable, idColumn?: TIdColumn): void;
205
+ /**
206
+ * Finds a record by ID, routing to a replica.
207
+ *
208
+ * **ROUTING:** Always uses read replica (with failover to primary)
209
+ * **PERFORMANCE:** Reduces load on primary database
210
+ *
211
+ * @param table Table name
212
+ * @param id Record ID
213
+ * @returns Found record or null
214
+ *
215
+ * @example
216
+ * ```typescript
217
+ * // This query goes to a replica
218
+ * const result = await adapter.findById('users', 'user-123');
219
+ *
220
+ * if (result.success && result.value) {
221
+ * console.log('User found:', result.value.name);
222
+ * } else {
223
+ * console.log('User not found');
224
+ * }
225
+ * ```
226
+ */
227
+ findById<T>(table: string, id: string): Promise<DatabaseResult<T | null>>;
228
+ /**
229
+ * Finds multiple records with filtering and pagination, routing to a replica.
230
+ *
231
+ * **ROUTING:** Always uses read replica (with failover to primary)
232
+ * **PERFORMANCE:** Ideal for heavy read workloads
233
+ *
234
+ * @param table Table name
235
+ * @param options Query options
236
+ * @returns Paginated result
237
+ *
238
+ * @example
239
+ * ```typescript
240
+ * // This query goes to a replica
241
+ * const result = await adapter.findMany('users', {
242
+ * filter: { field: 'status', operator: 'eq', value: 'active' },
243
+ * pagination: { page: 1, limit: 10 },
244
+ * sort: { field: 'name', direction: 'asc' }
245
+ * });
246
+ *
247
+ * console.log('Found users:', result.value?.data.length);
248
+ * ```
249
+ */
250
+ findMany<T>(table: string, options?: QueryOptions): Promise<DatabaseResult<PaginatedResult<T>>>;
251
+ /**
252
+ * Creates a new record, routing to primary.
253
+ *
254
+ * **ROUTING:** Always uses primary database
255
+ * **CONSISTENCY:** Ensures immediate consistency for writes
256
+ *
257
+ * @param table Table name
258
+ * @param data Record data
259
+ * @returns Created record
260
+ *
261
+ * @example
262
+ * ```typescript
263
+ * // This operation goes to primary
264
+ * const result = await adapter.create('users', {
265
+ * name: 'John Doe',
266
+ * email: 'john@example.com',
267
+ * status: 'active'
268
+ * });
269
+ *
270
+ * if (result.success) {
271
+ * console.log('User created:', result.value.id);
272
+ * }
273
+ * ```
274
+ */
275
+ create<T>(table: string, data: T): Promise<DatabaseResult<T>>;
276
+ /**
277
+ * Updates an existing record, routing to primary.
278
+ *
279
+ * **ROUTING:** Always uses primary database
280
+ * **CONSISTENCY:** Ensures immediate consistency for updates
281
+ *
282
+ * @param table Table name
283
+ * @param id Record ID
284
+ * @param data Partial record data
285
+ * @returns Updated record
286
+ *
287
+ * @example
288
+ * ```typescript
289
+ * // This operation goes to primary
290
+ * const result = await adapter.update('users', 'user-123', {
291
+ * name: 'Jane Doe',
292
+ * status: 'inactive'
293
+ * });
294
+ *
295
+ * if (result.success) {
296
+ * console.log('User updated:', result.value.name);
297
+ * }
298
+ * ```
299
+ */
300
+ update<T>(table: string, id: string, data: Partial<T>): Promise<DatabaseResult<T>>;
301
+ /**
302
+ * Deletes a record, routing to primary.
303
+ *
304
+ * **ROUTING:** Always uses primary database
305
+ * **CONSISTENCY:** Ensures immediate consistency for deletions
306
+ *
307
+ * @param table Table name
308
+ * @param id Record ID
309
+ * @returns Deletion result
310
+ *
311
+ * @example
312
+ * ```typescript
313
+ * // This operation goes to primary
314
+ * const result = await adapter.delete('users', 'user-123');
315
+ *
316
+ * if (result.success) {
317
+ * console.log('User deleted successfully');
318
+ * } else {
319
+ * console.error('Delete failed:', result.error?.message);
320
+ * }
321
+ * ```
322
+ */
323
+ delete(table: string, id: string): Promise<DatabaseResult<void>>;
324
+ /**
325
+ * Executes a transaction on the primary database.
326
+ *
327
+ * **ROUTING:** Always uses primary database (transactions require consistency)
328
+ * **ACID:** Provides full ACID transaction guarantees
329
+ *
330
+ * @param callback Transaction callback
331
+ * @returns Transaction result
332
+ *
333
+ * @example
334
+ * ```typescript
335
+ * // Transaction always goes to primary
336
+ * const result = await adapter.transaction(async (trx) => {
337
+ * const user = await trx.create('users', { name: 'John' });
338
+ * await trx.create('profiles', { userId: user.id, bio: 'Hello' });
339
+ * return user;
340
+ * });
341
+ *
342
+ * if (result.success) {
343
+ * console.log('Transaction completed:', result.value.id);
344
+ * }
345
+ * ```
346
+ */
347
+ transaction<T>(callback: (trx: Transaction) => Promise<T>): Promise<DatabaseResult<T>>;
348
+ /**
349
+ * Checks if a record exists, routing to a replica.
350
+ *
351
+ * **ROUTING:** Uses read replica (with failover to primary)
352
+ * **PERFORMANCE:** Efficient existence check without full record retrieval
353
+ *
354
+ * @param table Table name
355
+ * @param id Record ID
356
+ * @returns Existence result
357
+ *
358
+ * @example
359
+ * ```typescript
360
+ * // This check goes to a replica
361
+ * const result = await adapter.exists('users', 'user-123');
362
+ *
363
+ * if (result.success && result.value) {
364
+ * console.log('User exists');
365
+ * } else {
366
+ * console.log('User does not exist');
367
+ * }
368
+ * ```
369
+ */
370
+ exists(table: string, id: string): Promise<DatabaseResult<boolean>>;
371
+ /**
372
+ * Counts records matching a filter, routing to a replica.
373
+ *
374
+ * **ROUTING:** Uses read replica (with failover to primary)
375
+ * **PERFORMANCE:** Efficient counting without data transfer
376
+ *
377
+ * @param table Table name
378
+ * @param filter Filter conditions
379
+ * @returns Count result
380
+ *
381
+ * @example
382
+ * ```typescript
383
+ * // This count goes to a replica
384
+ * const result = await adapter.count('users', {
385
+ * field: 'status',
386
+ * operator: 'eq',
387
+ * value: 'active'
388
+ * });
389
+ *
390
+ * if (result.success) {
391
+ * console.log('Active users:', result.value);
392
+ * }
393
+ * ```
394
+ */
395
+ count(table: string, filter?: Filter): Promise<DatabaseResult<number>>;
396
+ /**
397
+ * Performs health checks on primary and all replicas.
398
+ *
399
+ * **RESPONSIBILITY:** Monitors health of entire database cluster
400
+ * **BEHAVIOR:** Returns healthy only if primary and at least one replica are healthy
401
+ *
402
+ * @returns Combined health status
403
+ *
404
+ * @example
405
+ * ```typescript
406
+ * const result = await adapter.healthCheck();
407
+ *
408
+ * if (result.success && result.value?.isHealthy) {
409
+ * console.log('Cluster is healthy');
410
+ * console.log('Response time:', result.value.responseTime, 'ms');
411
+ * } else {
412
+ * console.error('Cluster health issues detected');
413
+ * }
414
+ * ```
415
+ */
416
+ healthCheck(): Promise<DatabaseResult<DatabaseHealthStatus>>;
417
+ /**
418
+ * Determines if a SQL operation is a write operation.
419
+ *
420
+ * **LOGIC:** Checks for INSERT, UPDATE, DELETE, CREATE, DROP, ALTER keywords
421
+ * **ROUTING:** Write operations go to primary, reads go to replicas
422
+ *
423
+ * @private
424
+ * @param sql SQL query string
425
+ * @returns True if operation is a write operation
426
+ *
427
+ * @example
428
+ * ```typescript
429
+ * // These return true (write operations)
430
+ * this.isWriteOperation('INSERT INTO users...') // true
431
+ * this.isWriteOperation('UPDATE users SET...') // true
432
+ * this.isWriteOperation('DELETE FROM users...') // true
433
+ *
434
+ * // These return false (read operations)
435
+ * this.isWriteOperation('SELECT * FROM users') // false
436
+ * this.isWriteOperation('SELECT COUNT(*) FROM users') // false
437
+ * ```
438
+ */
439
+ private isWriteOperation;
440
+ /**
441
+ * Routes a read operation to a healthy replica with load balancing.
442
+ *
443
+ * **RESPONSIBILITY:** Executes operation on replica with automatic failover
444
+ * **LOAD BALANCING:** Uses round-robin selection across healthy replicas
445
+ * **FAILOVER:** Automatically tries handleReplicaError on failure
446
+ *
447
+ * @private
448
+ * @param operation Function to execute on replica adapter
449
+ * @returns Operation result
450
+ *
451
+ * @example
452
+ * ```typescript
453
+ * // Internal usage for read operations
454
+ * const result = await this.routeToReplica(adapter =>
455
+ * adapter.findById('users', 'user-123')
456
+ * );
457
+ *
458
+ * // Automatically handles:
459
+ * // 1. Selects healthy replica using round-robin
460
+ * // 2. Executes operation on selected replica
461
+ * // 3. Falls back to handleReplicaError on failure
462
+ * ```
463
+ */
464
+ private routeToReplica;
465
+ /**
466
+ * Handles replica errors by trying other replicas or falling back to primary.
467
+ *
468
+ * **RESPONSIBILITY:** Implements failover strategy when replica operations fail
469
+ * **STRATEGY:** Try all remaining replicas, then fallback to primary
470
+ * **RESILIENCE:** Ensures operation completes even if all replicas fail
471
+ *
472
+ * @private
473
+ * @param operation Function to execute on adapter
474
+ * @returns Operation result
475
+ *
476
+ * @example
477
+ * ```typescript
478
+ * // Internal usage when replica fails
479
+ * const result = await this.handleReplicaError(adapter =>
480
+ * adapter.findMany('users', options)
481
+ * );
482
+ *
483
+ * // Failover sequence:
484
+ * // 1. Try each remaining healthy replica
485
+ * // 2. If all replicas fail, use primary adapter
486
+ * // 3. Return result from successful operation
487
+ * ```
488
+ */
489
+ private handleReplicaError;
490
+ /**
491
+ * Gets healthy replicas by checking their status.
492
+ *
493
+ * **RESPONSIBILITY:** Filters replicas based on health status
494
+ * **CURRENT:** Returns all replicas (health checking not implemented)
495
+ * **FUTURE:** Should implement actual health status checking
496
+ *
497
+ * @private
498
+ * @returns Array of healthy replica adapters
499
+ *
500
+ * @example
501
+ * ```typescript
502
+ * // Internal usage
503
+ * const healthyReplicas = this.getHealthyReplicas();
504
+ *
505
+ * if (healthyReplicas.length > 0) {
506
+ * // Use replica for read operation
507
+ * const replica = healthyReplicas[index % healthyReplicas.length];
508
+ * } else {
509
+ * // No healthy replicas, fallback to primary
510
+ * return this.primaryAdapter.operation();
511
+ * }
512
+ * ```
513
+ */
514
+ private getHealthyReplicas;
515
+ }
516
+ //# sourceMappingURL=ReadReplicaAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReadReplicaAdapter.d.ts","sourceRoot":"","sources":["../../../src/advanced/read-replica/ReadReplicaAdapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { DrizzleAdapter } from "@adapters/drizzle/DrizzleAdapter";
2
+ import type { DatabaseResult, DrizzleAdapterConfig, DatabaseHealthStatus } from "@plyaz/types/db";
3
+ /**
4
+ * Manages read replica connections and health monitoring.
5
+ * Provides load balancing and failover capabilities across multiple replicas.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const configs = [
10
+ * { connectionString: 'postgres://replica1:5432/db' },
11
+ * { connectionString: 'postgres://replica2:5432/db' }
12
+ * ];
13
+ *
14
+ * const manager = new ReadReplicaManager(configs);
15
+ * await manager.initialize();
16
+ *
17
+ * const healthyReplicas = manager.getHealthyReplicas();
18
+ * const health = await manager.healthCheck();
19
+ * ```
20
+ */
21
+ export declare class ReadReplicaManager {
22
+ private replicaConfigs;
23
+ private replicas;
24
+ private replicaHealth;
25
+ /**
26
+ * Creates a new ReadReplicaManager instance.
27
+ * @param replicaConfigs Array of replica configurations
28
+ */
29
+ constructor(replicaConfigs: DrizzleAdapterConfig[]);
30
+ /**
31
+ * Initializes all replicas and checks their health.
32
+ * @returns Initialization result
33
+ */
34
+ initialize(): Promise<DatabaseResult<void>>;
35
+ /**
36
+ * Establishes connections to all replicas.
37
+ */
38
+ connect(): Promise<void>;
39
+ /**
40
+ * Closes connections to all replicas.
41
+ */
42
+ disconnect(): Promise<void>;
43
+ /**
44
+ * Registers a table with all replicas.
45
+ * @param name Logical table name
46
+ * @param table Table schema
47
+ * @param idColumn Optional ID column name
48
+ */
49
+ registerTable<TTable, TIdColumn>(name: string, table: TTable, idColumn?: TIdColumn): void;
50
+ /**
51
+ * Performs health checks on all replicas.
52
+ * @returns Combined health status
53
+ */
54
+ healthCheck(): Promise<DatabaseResult<DatabaseHealthStatus>>;
55
+ /**
56
+ * Gets all currently healthy replicas.
57
+ * @returns Array of healthy replica adapters
58
+ */
59
+ getHealthyReplicas(): DrizzleAdapter[];
60
+ /**
61
+ * Checks the health of a specific replica.
62
+ * @param replica Replica adapter to check
63
+ * @param index Replica index
64
+ * @returns Health check result
65
+ */
66
+ private checkReplicaHealth;
67
+ }
68
+ //# sourceMappingURL=ReadReplicaManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReadReplicaManager.d.ts","sourceRoot":"","sources":["../../../src/advanced/read-replica/ReadReplicaManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAGlE,OAAO,KAAK,EACV,cAAc,EACd,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,iBAAiB,CAAC;AACzB;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,kBAAkB;IAQjB,OAAO,CAAC,cAAc;IAPlC,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,aAAa,CAAmC;IAExD;;;OAGG;gBACiB,cAAc,EAAE,oBAAoB,EAAE;IAE1D;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IA0CjD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAI9B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;;;;OAKG;IACH,aAAa,CAAC,MAAM,EAAE,SAAS,EAC7B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,SAAS,GACnB,IAAI;IAMP;;;OAGG;IACG,WAAW,IAAI,OAAO,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC;IAuClE;;;OAGG;IACH,kBAAkB,IAAI,cAAc,EAAE;IAItC;;;;;OAKG;YACW,kBAAkB;CAwBjC"}
@@ -0,0 +1,24 @@
1
+ import type { UseReplicaOptions } from "@plyaz/types";
2
+ export declare const USE_REPLICA_KEY = "use_replica";
3
+ /**
4
+ * Decorator to specify replica usage for database operations.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * class UserService {
9
+ * @UseReplica({ strategy: ReplicaStrategy.REPLICA })
10
+ * async getUsers() {
11
+ * // This will use a read replica
12
+ * return this.db.findMany('users');
13
+ * }
14
+ *
15
+ * @UseReplica({ strategy: ReplicaStrategy.PRIMARY })
16
+ * async createUser(user: User) {
17
+ * // This will use primary
18
+ * return this.db.create('users', user);
19
+ * }
20
+ * }
21
+ * ```
22
+ */
23
+ export declare function UseReplica(options?: UseReplicaOptions): MethodDecorator;
24
+ //# sourceMappingURL=UseReplica.decorator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UseReplica.decorator.d.ts","sourceRoot":"","sources":["../../../src/advanced/read-replica/UseReplica.decorator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,eAAe,CAI3E"}
@@ -0,0 +1,3 @@
1
+ export { ReadReplicaAdapter } from "./ReadReplicaAdapter";
2
+ export { UseReplica } from "./UseReplica.decorator";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/advanced/read-replica/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC"}