ts-prorm-orm 1.1.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 (310) hide show
  1. package/CHANGELOG.md +1111 -0
  2. package/LICENSE +21 -0
  3. package/README.md +573 -0
  4. package/dist/audit/history-query.js +180 -0
  5. package/dist/audit/index.js +23 -0
  6. package/dist/audit/logger.js +236 -0
  7. package/dist/cache/cache-manager.js +84 -0
  8. package/dist/cache/index.js +16 -0
  9. package/dist/cache/redis-cluster-cache.js +557 -0
  10. package/dist/cli.js +2200 -0
  11. package/dist/compliance/audit-trail.js +68 -0
  12. package/dist/compliance/backup-verification.js +685 -0
  13. package/dist/compliance/breach-detector.js +505 -0
  14. package/dist/compliance/consent-record.js +227 -0
  15. package/dist/compliance/consent-versioning.js +331 -0
  16. package/dist/compliance/cross-border-log.js +530 -0
  17. package/dist/compliance/data-classifier.js +258 -0
  18. package/dist/compliance/data-lineage.js +565 -0
  19. package/dist/compliance/data-masker.js +303 -0
  20. package/dist/compliance/data-portability.js +265 -0
  21. package/dist/compliance/data-retention.js +195 -0
  22. package/dist/compliance/dsar-workflow.js +342 -0
  23. package/dist/compliance/field-encryption.js +223 -0
  24. package/dist/compliance/immutable-record.js +148 -0
  25. package/dist/compliance/index.js +260 -0
  26. package/dist/compliance/privacy-impact-assessment.js +364 -0
  27. package/dist/compliance/pseudonymization.js +269 -0
  28. package/dist/compliance/query-firewall.js +1182 -0
  29. package/dist/compliance/rate-limiter.js +580 -0
  30. package/dist/compliance/right-to-erasure.js +117 -0
  31. package/dist/compliance/row-level-security.js +246 -0
  32. package/dist/compliance/security-decorator.js +574 -0
  33. package/dist/compliance/security-monitor.js +525 -0
  34. package/dist/compliance/sensitive-data-discovery.js +476 -0
  35. package/dist/compliance/session-isolation.js +472 -0
  36. package/dist/compliance/tls-enforcer.js +108 -0
  37. package/dist/compliance/worm-storage.js +712 -0
  38. package/dist/connection-manager.js +198 -0
  39. package/dist/connection-pool.js +519 -0
  40. package/dist/decorators/audit.js +136 -0
  41. package/dist/decorators/belongs-to-many.js +115 -0
  42. package/dist/decorators/belongs-to.js +115 -0
  43. package/dist/decorators/check.js +435 -0
  44. package/dist/decorators/collate.js +329 -0
  45. package/dist/decorators/comment.js +205 -0
  46. package/dist/decorators/database-settings.js +236 -0
  47. package/dist/decorators/default.js +244 -0
  48. package/dist/decorators/encryption.js +235 -0
  49. package/dist/decorators/engine.js +97 -0
  50. package/dist/decorators/fk-constraints.js +594 -0
  51. package/dist/decorators/foreign-table.js +136 -0
  52. package/dist/decorators/generated.js +274 -0
  53. package/dist/decorators/has-many.js +127 -0
  54. package/dist/decorators/has-one.js +116 -0
  55. package/dist/decorators/hstore.js +129 -0
  56. package/dist/decorators/index.js +355 -0
  57. package/dist/decorators/json-column.js +83 -0
  58. package/dist/decorators/jsonb.js +101 -0
  59. package/dist/decorators/orm-decorators.js +425 -0
  60. package/dist/decorators/permissions.js +294 -0
  61. package/dist/decorators/procedure.js +210 -0
  62. package/dist/decorators/query-options.js +556 -0
  63. package/dist/decorators/range.js +167 -0
  64. package/dist/decorators/set-column.js +83 -0
  65. package/dist/decorators/spatial.js +114 -0
  66. package/dist/decorators/storage.js +580 -0
  67. package/dist/decorators/timezone.js +512 -0
  68. package/dist/decorators/trigger.js +90 -0
  69. package/dist/decorators/uuid.js +135 -0
  70. package/dist/decorators/view.js +258 -0
  71. package/dist/diagrams/chen-diagram.js +354 -0
  72. package/dist/diagrams/class-diagram.js +384 -0
  73. package/dist/diagrams/dependency-diagram.js +432 -0
  74. package/dist/diagrams/er-diagram.js +605 -0
  75. package/dist/diagrams/flow-diagram.js +394 -0
  76. package/dist/diagrams/gantt-diagram.js +411 -0
  77. package/dist/diagrams/index-diagram.js +353 -0
  78. package/dist/diagrams/index.js +184 -0
  79. package/dist/diagrams/migration-diagram.js +316 -0
  80. package/dist/diagrams/model-diagram.js +616 -0
  81. package/dist/diagrams/package-diagram.js +376 -0
  82. package/dist/diagrams/palette.js +85 -0
  83. package/dist/diagrams/relational-diagram.js +455 -0
  84. package/dist/diagrams/schemadoc-diagram.js +309 -0
  85. package/dist/diagrams/sequence-diagram.js +307 -0
  86. package/dist/diagrams/state-diagram.js +344 -0
  87. package/dist/diagrams/svg-dom.js +111 -0
  88. package/dist/diagrams/tree-diagram.js +250 -0
  89. package/dist/dialects/clickhouse/index.js +1742 -0
  90. package/dist/dialects/cockroachdb/index.js +4677 -0
  91. package/dist/dialects/cratedb/index.js +441 -0
  92. package/dist/dialects/databricks/index.js +517 -0
  93. package/dist/dialects/db2/index.js +2225 -0
  94. package/dist/dialects/dialect.js +720 -0
  95. package/dist/dialects/duckdb/index.js +2014 -0
  96. package/dist/dialects/exasol/index.js +357 -0
  97. package/dist/dialects/firebird/index.js +495 -0
  98. package/dist/dialects/greenplum/index.js +457 -0
  99. package/dist/dialects/hana/index.js +1741 -0
  100. package/dist/dialects/mariadb/index.js +3590 -0
  101. package/dist/dialects/mssql/index.js +2296 -0
  102. package/dist/dialects/mysql/index.js +4058 -0
  103. package/dist/dialects/oracle/index.js +2999 -0
  104. package/dist/dialects/postgres/index.js +5319 -0
  105. package/dist/dialects/query-stream-helper.js +152 -0
  106. package/dist/dialects/questdb/index.js +433 -0
  107. package/dist/dialects/redshift/index.js +2277 -0
  108. package/dist/dialects/singlestore/index.js +354 -0
  109. package/dist/dialects/snowflake/index.js +2082 -0
  110. package/dist/dialects/spanner/index.js +1768 -0
  111. package/dist/dialects/sqlite/index.js +3382 -0
  112. package/dist/dialects/tidb/index.js +377 -0
  113. package/dist/dialects/timescaledb/index.js +164 -0
  114. package/dist/dialects/trino/index.js +420 -0
  115. package/dist/dialects/turso/index.js +227 -0
  116. package/dist/dialects/vertica/index.js +317 -0
  117. package/dist/dialects/yugabytedb/index.js +424 -0
  118. package/dist/errors/index.js +472 -0
  119. package/dist/errors/utils.js +340 -0
  120. package/dist/errors.js +21 -0
  121. package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
  122. package/dist/extensions/catalog/mssql-features.js +147 -0
  123. package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
  124. package/dist/extensions/catalog/oracle-db2-features.js +196 -0
  125. package/dist/extensions/catalog/postgres-extensions.js +516 -0
  126. package/dist/extensions/index.js +71 -0
  127. package/dist/extensions/types.js +13 -0
  128. package/dist/foreign-data.js +173 -0
  129. package/dist/hooks/hooks-manager.js +350 -0
  130. package/dist/hooks/index.js +37 -0
  131. package/dist/index.js +463 -0
  132. package/dist/logging.js +335 -0
  133. package/dist/migrations/index.js +40 -0
  134. package/dist/migrations/migration.js +196 -0
  135. package/dist/migrations/migrator.js +411 -0
  136. package/dist/migrations/prormmigration.js +275 -0
  137. package/dist/migrations/query-interface.js +435 -0
  138. package/dist/migrations/seeder.js +353 -0
  139. package/dist/models/associations.js +852 -0
  140. package/dist/models/constraints.js +288 -0
  141. package/dist/models/data-types.js +2518 -0
  142. package/dist/models/decorators.js +445 -0
  143. package/dist/models/index.js +33 -0
  144. package/dist/models/indexes.js +531 -0
  145. package/dist/models/methods.js +382 -0
  146. package/dist/models/model-manager.js +103 -0
  147. package/dist/models/model.js +5349 -0
  148. package/dist/models/operators.js +67 -0
  149. package/dist/models/scopes.js +189 -0
  150. package/dist/models/typescript-types.js +26 -0
  151. package/dist/nosql/aerospike/index.js +205 -0
  152. package/dist/nosql/allegrograph/index.js +169 -0
  153. package/dist/nosql/arangodb/index.js +364 -0
  154. package/dist/nosql/azure-blob/index.js +206 -0
  155. package/dist/nosql/beanstalkd/index.js +231 -0
  156. package/dist/nosql/beequeue/index.js +210 -0
  157. package/dist/nosql/bigchaindb/index.js +195 -0
  158. package/dist/nosql/bigtable/index.js +224 -0
  159. package/dist/nosql/blazegraph/index.js +173 -0
  160. package/dist/nosql/bullmq/index.js +191 -0
  161. package/dist/nosql/cassandra/index.js +174 -0
  162. package/dist/nosql/chroma/index.js +190 -0
  163. package/dist/nosql/cloudflare-kv/index.js +220 -0
  164. package/dist/nosql/coherence/index.js +200 -0
  165. package/dist/nosql/cosmosdb/index.js +157 -0
  166. package/dist/nosql/couchbase/index.js +213 -0
  167. package/dist/nosql/dax/index.js +212 -0
  168. package/dist/nosql/deno-kv/index.js +206 -0
  169. package/dist/nosql/dgraph/index.js +171 -0
  170. package/dist/nosql/doris/index.js +169 -0
  171. package/dist/nosql/druid/index.js +162 -0
  172. package/dist/nosql/dynamodb/index.js +937 -0
  173. package/dist/nosql/elasticsearch/index.js +377 -0
  174. package/dist/nosql/etcd/index.js +502 -0
  175. package/dist/nosql/eventhubs/index.js +213 -0
  176. package/dist/nosql/eventstore/index.js +254 -0
  177. package/dist/nosql/faunadb/index.js +188 -0
  178. package/dist/nosql/firestore/index.js +177 -0
  179. package/dist/nosql/fluree/index.js +148 -0
  180. package/dist/nosql/fuseki/index.js +170 -0
  181. package/dist/nosql/gcs/index.js +172 -0
  182. package/dist/nosql/gearman/index.js +160 -0
  183. package/dist/nosql/geode/index.js +196 -0
  184. package/dist/nosql/graphdb/index.js +169 -0
  185. package/dist/nosql/graylog/index.js +188 -0
  186. package/dist/nosql/gridgain/index.js +171 -0
  187. package/dist/nosql/hazelcast/index.js +162 -0
  188. package/dist/nosql/hbase/index.js +230 -0
  189. package/dist/nosql/ignite/index.js +173 -0
  190. package/dist/nosql/immudb/index.js +184 -0
  191. package/dist/nosql/index.js +232 -0
  192. package/dist/nosql/infinispan/index.js +200 -0
  193. package/dist/nosql/influxdb/index.js +0 -0
  194. package/dist/nosql/kafka/index.js +234 -0
  195. package/dist/nosql/keyspaces/index.js +189 -0
  196. package/dist/nosql/kinesis/index.js +253 -0
  197. package/dist/nosql/leveldb/index.js +153 -0
  198. package/dist/nosql/lmdb/index.js +160 -0
  199. package/dist/nosql/loki/index.js +201 -0
  200. package/dist/nosql/marklogic/index.js +204 -0
  201. package/dist/nosql/materialize/index.js +145 -0
  202. package/dist/nosql/meilisearch/index.js +154 -0
  203. package/dist/nosql/memcached/index.js +223 -0
  204. package/dist/nosql/milvus/index.js +410 -0
  205. package/dist/nosql/minio/index.js +265 -0
  206. package/dist/nosql/momento/index.js +179 -0
  207. package/dist/nosql/mongodb/index.js +461 -0
  208. package/dist/nosql/nats/index.js +247 -0
  209. package/dist/nosql/nedb/index.js +164 -0
  210. package/dist/nosql/neo4j/index.js +450 -0
  211. package/dist/nosql/neptune/index.js +470 -0
  212. package/dist/nosql/nsq/index.js +200 -0
  213. package/dist/nosql/opensearch/index.js +186 -0
  214. package/dist/nosql/orientdb/index.js +175 -0
  215. package/dist/nosql/papertrail/index.js +200 -0
  216. package/dist/nosql/pinecone/index.js +0 -0
  217. package/dist/nosql/pinot/index.js +133 -0
  218. package/dist/nosql/pouchdb/index.js +172 -0
  219. package/dist/nosql/prometheus/index.js +174 -0
  220. package/dist/nosql/provendb/index.js +147 -0
  221. package/dist/nosql/pubsub/index.js +187 -0
  222. package/dist/nosql/pulsar/index.js +232 -0
  223. package/dist/nosql/qdrant/index.js +295 -0
  224. package/dist/nosql/qldb/index.js +192 -0
  225. package/dist/nosql/r2/index.js +281 -0
  226. package/dist/nosql/rabbitmq/index.js +237 -0
  227. package/dist/nosql/ravendb/index.js +175 -0
  228. package/dist/nosql/redis/index.js +607 -0
  229. package/dist/nosql/redpanda/index.js +237 -0
  230. package/dist/nosql/resque/index.js +203 -0
  231. package/dist/nosql/rethinkdb/index.js +232 -0
  232. package/dist/nosql/rocksdb/index.js +152 -0
  233. package/dist/nosql/rockset/index.js +126 -0
  234. package/dist/nosql/s3/index.js +298 -0
  235. package/dist/nosql/scylladb/index.js +178 -0
  236. package/dist/nosql/signoz/index.js +227 -0
  237. package/dist/nosql/sns/index.js +201 -0
  238. package/dist/nosql/solr/index.js +231 -0
  239. package/dist/nosql/splunk/index.js +227 -0
  240. package/dist/nosql/sqs/index.js +246 -0
  241. package/dist/nosql/stardog/index.js +169 -0
  242. package/dist/nosql/starrocks/index.js +170 -0
  243. package/dist/nosql/store.js +2 -0
  244. package/dist/nosql/sumologic/index.js +213 -0
  245. package/dist/nosql/surrealdb/index.js +179 -0
  246. package/dist/nosql/terminusdb/index.js +151 -0
  247. package/dist/nosql/tigergraph/index.js +469 -0
  248. package/dist/nosql/typesense/index.js +148 -0
  249. package/dist/nosql/unqlite/index.js +157 -0
  250. package/dist/nosql/upstash/index.js +167 -0
  251. package/dist/nosql/vercel-kv/index.js +166 -0
  252. package/dist/nosql/victoriametrics/index.js +213 -0
  253. package/dist/nosql/virtuoso/index.js +169 -0
  254. package/dist/nosql/weaviate/index.js +276 -0
  255. package/dist/operators/index.js +108 -0
  256. package/dist/operators.js +2690 -0
  257. package/dist/prisma-migrate/index.js +38 -0
  258. package/dist/prisma-migrate/migration-generator.js +125 -0
  259. package/dist/prisma-migrate/model-generator.js +172 -0
  260. package/dist/prisma-migrate/relations.js +100 -0
  261. package/dist/prisma-migrate/schema-parser.js +167 -0
  262. package/dist/prisma-migrate/type-mapper.js +40 -0
  263. package/dist/prorm.js +6832 -0
  264. package/dist/query-builders/cte-builder.js +80 -0
  265. package/dist/query-builders/functions/aggregate.js +390 -0
  266. package/dist/query-builders/functions/conditional.js +503 -0
  267. package/dist/query-builders/functions/datetime.js +695 -0
  268. package/dist/query-builders/functions/fulltext.js +439 -0
  269. package/dist/query-builders/functions/index.js +93 -0
  270. package/dist/query-builders/functions/json.js +427 -0
  271. package/dist/query-builders/functions/math.js +399 -0
  272. package/dist/query-builders/functions/string.js +518 -0
  273. package/dist/query-builders/functions/window.js +328 -0
  274. package/dist/query-builders/include-builder.js +323 -0
  275. package/dist/query-builders/index-expression-builder.js +242 -0
  276. package/dist/query-builders/index.js +161 -0
  277. package/dist/query-builders/insert-builder.js +164 -0
  278. package/dist/query-builders/model-helpers.js +38 -0
  279. package/dist/query-builders/order-limit-builder.js +239 -0
  280. package/dist/query-builders/sql-compiler.js +2040 -0
  281. package/dist/query-builders/subquery-builder.js +152 -0
  282. package/dist/query-builders/update-builder.js +182 -0
  283. package/dist/query-builders/view-builder.js +218 -0
  284. package/dist/query-builders/where-builder.js +1532 -0
  285. package/dist/query-interface.js +622 -0
  286. package/dist/query-optimizers/batch-optimizer.js +426 -0
  287. package/dist/query-optimizers/explain-plans.js +415 -0
  288. package/dist/query-optimizers/index.js +51 -0
  289. package/dist/query-optimizers/prepared-statement-cache.js +423 -0
  290. package/dist/query-optimizers/query-hints.js +438 -0
  291. package/dist/query-optimizers/query-optimizer.js +278 -0
  292. package/dist/query-optimizers/slow-query-logger.js +271 -0
  293. package/dist/replica-manager.js +507 -0
  294. package/dist/schema/index.js +15 -0
  295. package/dist/schema/migration-generator.js +374 -0
  296. package/dist/schema/schema-differ.js +549 -0
  297. package/dist/schema/types.js +6 -0
  298. package/dist/sql-constants.js +300 -0
  299. package/dist/sqlite-advanced.js +1047 -0
  300. package/dist/streams/index.js +12 -0
  301. package/dist/streams/transforms.js +178 -0
  302. package/dist/transaction.js +456 -0
  303. package/dist/types/index.js +180 -0
  304. package/dist/user-management.js +127 -0
  305. package/dist/utils/date.js +300 -0
  306. package/dist/utils/index.js +1079 -0
  307. package/dist/utils/string.js +161 -0
  308. package/dist/validators/index.js +19 -0
  309. package/dist/validators/validator.js +911 -0
  310. package/package.json +190 -0
@@ -0,0 +1,557 @@
1
+ "use strict";
2
+ /**
3
+ * Redis Cluster Cache Backend
4
+ *
5
+ * Implements CacheBackend using ioredis cluster with L1 (in-memory) and L2 (Redis cluster) caching.
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.RedisClusterCache = void 0;
42
+ exports.createRedisClusterCache = createRedisClusterCache;
43
+ const ioredis_1 = __importStar(require("ioredis"));
44
+ const cache_manager_1 = require("./cache-manager");
45
+ /**
46
+ * LRU Map implementation for L1 cache
47
+ */
48
+ class LRUCache {
49
+ constructor(maxSize = 1000, ttl = 60000) {
50
+ this.cache = new Map();
51
+ this.maxSize = maxSize;
52
+ this.ttl = ttl;
53
+ }
54
+ get(key) {
55
+ const value = this.cache.get(key);
56
+ if (value === undefined) {
57
+ return undefined;
58
+ }
59
+ // Move to end (most recently used)
60
+ this.cache.delete(key);
61
+ this.cache.set(key, value);
62
+ return value;
63
+ }
64
+ set(key, value) {
65
+ // If key exists, delete it first to update order
66
+ if (this.cache.has(key)) {
67
+ this.cache.delete(key);
68
+ }
69
+ // If at capacity, remove oldest (first) entry
70
+ if (this.cache.size >= this.maxSize) {
71
+ const firstKey = this.cache.keys().next().value;
72
+ if (firstKey) {
73
+ this.cache.delete(firstKey);
74
+ }
75
+ }
76
+ this.cache.set(key, value);
77
+ }
78
+ delete(key) {
79
+ return this.cache.delete(key);
80
+ }
81
+ clear() {
82
+ this.cache.clear();
83
+ }
84
+ keys() {
85
+ return Array.from(this.cache.keys());
86
+ }
87
+ size() {
88
+ return this.cache.size;
89
+ }
90
+ has(key) {
91
+ return this.cache.has(key);
92
+ }
93
+ }
94
+ /**
95
+ * Redis Cluster Cache implementation with L1/L2 support
96
+ */
97
+ class RedisClusterCache extends cache_manager_1.AbstractCacheManager {
98
+ // Use 'options' from parent class, cast for extended options
99
+ get clusterOptions() {
100
+ return this.options;
101
+ }
102
+ constructor(options = {}) {
103
+ super(options);
104
+ this.redisCluster = null;
105
+ this.redisReplicas = [];
106
+ this.connected = false;
107
+ this.l1Cache = new LRUCache(options.l1?.maxEntries ?? 1000, (options.l1?.ttl ?? 60) * 1000);
108
+ this.initializeCluster();
109
+ }
110
+ /**
111
+ * Initialize Redis cluster connection
112
+ */
113
+ initializeCluster() {
114
+ const opts = this.clusterOptions;
115
+ if (!opts.clusterNodes || opts.clusterNodes.length === 0) {
116
+ console.warn('RedisClusterCache: No cluster nodes provided, running in L1-only mode');
117
+ return;
118
+ }
119
+ const clusterNodes = opts.clusterNodes.map(node => ({
120
+ host: node.host,
121
+ port: node.port,
122
+ password: node.password,
123
+ tls: node.tls,
124
+ }));
125
+ const clusterOptions = {
126
+ maxRedirections: 3,
127
+ enableReadyCheck: true,
128
+ enableOfflineQueue: true,
129
+ lazyConnect: false,
130
+ redisOptions: {
131
+ password: this.options.clusterOptions?.password,
132
+ tls: this.options.clusterOptions?.tls ? {} : undefined,
133
+ connectTimeout: this.options.connectTimeout ?? 10000,
134
+ commandTimeout: this.options.commandTimeout ?? 5000,
135
+ db: this.options.db ?? 0,
136
+ },
137
+ };
138
+ // Add retry strategy
139
+ const toClusterRetryStrategy = (fn) => (times) => {
140
+ const result = fn(times);
141
+ return result instanceof Error ? null : result;
142
+ };
143
+ if (this.options.retryStrategy) {
144
+ clusterOptions.clusterRetryStrategy = toClusterRetryStrategy(this.options.retryStrategy);
145
+ }
146
+ else {
147
+ clusterOptions.clusterRetryStrategy = (times) => {
148
+ if (times > 10) {
149
+ return null; // Stop retrying
150
+ }
151
+ return Math.min(times * 200, 3000); // Max 3 seconds
152
+ };
153
+ }
154
+ this.redisCluster = new ioredis_1.Cluster(clusterNodes, clusterOptions);
155
+ this.redisCluster.on('connect', () => {
156
+ this.connected = true;
157
+ console.log('RedisClusterCache: Connected to cluster');
158
+ });
159
+ this.redisCluster.on('error', (err) => {
160
+ console.error('RedisClusterCache: Cluster error', err.message);
161
+ this.connected = false;
162
+ });
163
+ this.redisCluster.on('close', () => {
164
+ this.connected = false;
165
+ });
166
+ // Initialize read replicas if enabled
167
+ if (this.options.readFromReplicas && this.options.clusterOptions?.enableReadFromReplicas) {
168
+ this.initializeReplicas();
169
+ }
170
+ }
171
+ /**
172
+ * Initialize read replicas for read-from-replicas functionality
173
+ */
174
+ initializeReplicas() {
175
+ if (!this.options.clusterOptions?.replicaNodes || this.options.clusterOptions.replicaNodes.length === 0) {
176
+ return;
177
+ }
178
+ for (const node of this.options.clusterOptions.replicaNodes) {
179
+ const redis = new ioredis_1.default({
180
+ host: node.host,
181
+ port: node.port,
182
+ password: node.password,
183
+ tls: node.tls ? {} : undefined,
184
+ db: this.options.db ?? 0,
185
+ connectTimeout: this.options.connectTimeout ?? 10000,
186
+ commandTimeout: this.options.commandTimeout ?? 5000,
187
+ lazyConnect: false,
188
+ });
189
+ redis.on('error', (err) => {
190
+ console.error('RedisClusterCache: Replica error', err.message);
191
+ });
192
+ this.redisReplicas.push(redis);
193
+ }
194
+ }
195
+ /**
196
+ * Get a value from cache, checking L1 first then L2
197
+ */
198
+ async get(key) {
199
+ const fullKey = this.buildKey(key);
200
+ // Try L1 cache first
201
+ if (this.options.l1?.enabled !== false) {
202
+ const l1Value = this.l1Cache.get(fullKey);
203
+ if (l1Value !== undefined) {
204
+ this.stats.hits++;
205
+ this.stats.l1Hits++;
206
+ return l1Value;
207
+ }
208
+ }
209
+ // If L2 is disabled, return null
210
+ if (this.options.l2?.enabled === false) {
211
+ this.stats.misses++;
212
+ return null;
213
+ }
214
+ // Try L2 (Redis cluster)
215
+ try {
216
+ const redis = this.getRedisClient();
217
+ if (redis) {
218
+ const l2Value = await redis.get(fullKey);
219
+ if (l2Value !== null) {
220
+ this.stats.hits++;
221
+ this.stats.l2Hits++;
222
+ // Update L1 cache
223
+ if (this.options.l1?.enabled !== false) {
224
+ this.l1Cache.set(fullKey, l2Value);
225
+ }
226
+ return l2Value;
227
+ }
228
+ }
229
+ }
230
+ catch (error) {
231
+ console.error('RedisClusterCache: Error getting from L2', error);
232
+ }
233
+ this.stats.misses++;
234
+ return null;
235
+ }
236
+ /**
237
+ * Set a value in cache (both L1 and L2)
238
+ */
239
+ async set(key, value, ttl) {
240
+ const fullKey = this.buildKey(key);
241
+ const l2Ttl = ttl ?? this.options.l2?.defaultTtl ?? 3600;
242
+ // Always set in L1
243
+ if (this.options.l1?.enabled !== false) {
244
+ this.l1Cache.set(fullKey, value);
245
+ }
246
+ // Set in L2 if enabled
247
+ if (this.options.l2?.enabled !== false) {
248
+ try {
249
+ const redis = this.getRedisClient();
250
+ if (redis) {
251
+ await redis.setex(fullKey, l2Ttl, value);
252
+ return true;
253
+ }
254
+ }
255
+ catch (error) {
256
+ console.error('RedisClusterCache: Error setting in L2', error);
257
+ return false;
258
+ }
259
+ }
260
+ return true;
261
+ }
262
+ /**
263
+ * Delete a key from cache (both L1 and L2)
264
+ */
265
+ async del(key) {
266
+ const fullKey = this.buildKey(key);
267
+ // Delete from L1
268
+ if (this.options.l1?.enabled !== false) {
269
+ this.l1Cache.delete(fullKey);
270
+ }
271
+ // Delete from L2 if enabled
272
+ if (this.options.l2?.enabled !== false) {
273
+ try {
274
+ const redis = this.getRedisClient();
275
+ if (redis) {
276
+ await redis.del(fullKey);
277
+ return true;
278
+ }
279
+ }
280
+ catch (error) {
281
+ console.error('RedisClusterCache: Error deleting from L2', error);
282
+ return false;
283
+ }
284
+ }
285
+ return true;
286
+ }
287
+ /**
288
+ * Check if a key exists in cache
289
+ */
290
+ async exists(key) {
291
+ const fullKey = this.buildKey(key);
292
+ // Check L1 first
293
+ if (this.options.l1?.enabled !== false) {
294
+ if (this.l1Cache.has(fullKey)) {
295
+ return true;
296
+ }
297
+ }
298
+ // Check L2 if enabled
299
+ if (this.options.l2?.enabled !== false) {
300
+ try {
301
+ const redis = this.getRedisClient();
302
+ if (redis) {
303
+ const result = await redis.exists(fullKey);
304
+ return result === 1;
305
+ }
306
+ }
307
+ catch (error) {
308
+ console.error('RedisClusterCache: Error checking existence in L2', error);
309
+ }
310
+ }
311
+ return false;
312
+ }
313
+ /**
314
+ * Invalidate all keys matching a pattern
315
+ */
316
+ async invalidatePattern(pattern) {
317
+ const fullPattern = this.buildKey(pattern);
318
+ let invalidated = 0;
319
+ // Clear matching keys from L1
320
+ if (this.options.l1?.enabled !== false) {
321
+ const l1Keys = this.l1Cache.keys();
322
+ const regex = this.patternToRegex(fullPattern);
323
+ for (const key of l1Keys) {
324
+ if (regex.test(key)) {
325
+ this.l1Cache.delete(key);
326
+ invalidated++;
327
+ }
328
+ }
329
+ }
330
+ // Clear matching keys from L2 if enabled
331
+ if (this.options.l2?.enabled !== false) {
332
+ try {
333
+ const redis = this.getRedisClient();
334
+ if (redis) {
335
+ const keys = await redis.keys(fullPattern);
336
+ if (keys.length > 0) {
337
+ await redis.del(...keys);
338
+ invalidated += keys.length;
339
+ }
340
+ }
341
+ }
342
+ catch (error) {
343
+ console.error('RedisClusterCache: Error invalidating pattern in L2', error);
344
+ }
345
+ }
346
+ return invalidated;
347
+ }
348
+ /**
349
+ * Clear all cache entries
350
+ */
351
+ async clear() {
352
+ // Clear L1
353
+ if (this.options.l1?.enabled !== false) {
354
+ this.l1Cache.clear();
355
+ }
356
+ // Clear L2 if enabled
357
+ if (this.options.l2?.enabled !== false) {
358
+ try {
359
+ const redis = this.getRedisClient();
360
+ if (redis) {
361
+ const keys = await redis.keys(this.buildKey('*'));
362
+ if (keys.length > 0) {
363
+ await redis.del(...keys);
364
+ }
365
+ }
366
+ }
367
+ catch (error) {
368
+ console.error('RedisClusterCache: Error clearing L2', error);
369
+ return false;
370
+ }
371
+ }
372
+ this.resetStats();
373
+ return true;
374
+ }
375
+ /**
376
+ * Get multiple keys at once
377
+ */
378
+ async mget(keys) {
379
+ const fullKeys = keys.map(k => this.buildKey(k));
380
+ const results = new Array(keys.length);
381
+ // Separate keys into L1 and L2
382
+ const l1Results = new Map();
383
+ const l2Keys = [];
384
+ if (this.options.l1?.enabled !== false) {
385
+ for (let i = 0; i < fullKeys.length; i++) {
386
+ const value = this.l1Cache.get(fullKeys[i]);
387
+ if (value !== undefined) {
388
+ results[i] = value;
389
+ this.stats.hits++;
390
+ this.stats.l1Hits++;
391
+ }
392
+ else {
393
+ l2Keys.push(fullKeys[i]);
394
+ }
395
+ }
396
+ }
397
+ else {
398
+ l2Keys.push(...fullKeys);
399
+ }
400
+ // Get remaining from L2
401
+ if (l2Keys.length > 0 && this.options.l2?.enabled !== false) {
402
+ try {
403
+ const redis = this.getRedisClient();
404
+ if (redis) {
405
+ const l2Results = await redis.mget(...l2Keys);
406
+ for (let i = 0; i < l2Keys.length; i++) {
407
+ const fullKey = l2Keys[i];
408
+ const originalIndex = fullKeys.indexOf(fullKey);
409
+ if (l2Results[i] !== null) {
410
+ results[originalIndex] = l2Results[i];
411
+ this.stats.hits++;
412
+ this.stats.l2Hits++;
413
+ // Update L1 cache
414
+ if (this.options.l1?.enabled !== false) {
415
+ this.l1Cache.set(fullKey, l2Results[i]);
416
+ }
417
+ }
418
+ else {
419
+ this.stats.misses++;
420
+ }
421
+ }
422
+ }
423
+ }
424
+ catch (error) {
425
+ console.error('RedisClusterCache: Error in mget L2', error);
426
+ }
427
+ }
428
+ return results;
429
+ }
430
+ /**
431
+ * Set multiple keys at once
432
+ */
433
+ async mset(entries) {
434
+ // Set in L1
435
+ if (this.options.l1?.enabled !== false) {
436
+ for (const entry of entries) {
437
+ this.l1Cache.set(this.buildKey(entry.key), entry.value);
438
+ }
439
+ }
440
+ // Set in L2 if enabled
441
+ if (this.options.l2?.enabled !== false) {
442
+ try {
443
+ const redis = this.getRedisClient();
444
+ if (redis) {
445
+ const pipeline = redis.pipeline();
446
+ for (const entry of entries) {
447
+ const fullKey = this.buildKey(entry.key);
448
+ const l2Ttl = entry.ttl ?? this.options.l2?.defaultTtl ?? 3600;
449
+ pipeline.setex(fullKey, l2Ttl, entry.value);
450
+ }
451
+ await pipeline.exec();
452
+ return true;
453
+ }
454
+ }
455
+ catch (error) {
456
+ console.error('RedisClusterCache: Error in mset L2', error);
457
+ return false;
458
+ }
459
+ }
460
+ return true;
461
+ }
462
+ /**
463
+ * Get the appropriate Redis client (master or replica)
464
+ */
465
+ getRedisClient() {
466
+ if (!this.redisCluster) {
467
+ return null;
468
+ }
469
+ // Use replica if enabled and available
470
+ if (this.options.readFromReplicas && this.redisReplicas.length > 0) {
471
+ const randomIndex = Math.floor(Math.random() * this.redisReplicas.length);
472
+ return this.redisReplicas[randomIndex];
473
+ }
474
+ return this.redisCluster;
475
+ }
476
+ /**
477
+ * Get cache statistics
478
+ */
479
+ getStats() {
480
+ return {
481
+ ...super.getStats(),
482
+ keys: this.l1Cache.size(),
483
+ };
484
+ }
485
+ /**
486
+ * Close all Redis connections
487
+ */
488
+ async disconnect() {
489
+ // Close replica connections
490
+ for (const replica of this.redisReplicas) {
491
+ try {
492
+ await replica.quit();
493
+ }
494
+ catch (error) {
495
+ console.error('RedisClusterCache: Error closing replica', error);
496
+ }
497
+ }
498
+ this.redisReplicas = [];
499
+ // Close cluster connection
500
+ if (this.redisCluster) {
501
+ try {
502
+ await this.redisCluster.quit();
503
+ }
504
+ catch (error) {
505
+ console.error('RedisClusterCache: Error closing cluster', error);
506
+ }
507
+ this.redisCluster = null;
508
+ }
509
+ this.connected = false;
510
+ console.log('RedisClusterCache: Disconnected');
511
+ }
512
+ /**
513
+ * Check if cache backend is connected
514
+ */
515
+ isConnected() {
516
+ return this.connected && this.redisCluster !== null;
517
+ }
518
+ /**
519
+ * Get the underlying Redis cluster instance
520
+ */
521
+ getRedisCluster() {
522
+ return this.redisCluster;
523
+ }
524
+ /**
525
+ * Get all replica connections
526
+ */
527
+ getReplicas() {
528
+ return this.redisReplicas;
529
+ }
530
+ /**
531
+ * Manually invalidate L1 cache (useful for testing)
532
+ */
533
+ clearL1() {
534
+ this.l1Cache.clear();
535
+ }
536
+ /**
537
+ * Convert glob pattern to regex
538
+ */
539
+ patternToRegex(pattern) {
540
+ const escaped = pattern
541
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
542
+ .replace(/\*/g, '.*')
543
+ .replace(/\?/g, '.');
544
+ return new RegExp(`^${escaped}$`);
545
+ }
546
+ }
547
+ exports.RedisClusterCache = RedisClusterCache;
548
+ /**
549
+ * Create a RedisClusterCache instance with simplified options
550
+ */
551
+ function createRedisClusterCache(nodes, options = {}) {
552
+ return new RedisClusterCache({
553
+ ...options,
554
+ clusterNodes: nodes,
555
+ });
556
+ }
557
+ exports.default = RedisClusterCache;