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,507 @@
1
+ "use strict";
2
+ /**
3
+ * Replica Manager for handling read replicas with lag detection
4
+ * Supports multiple database dialects with dialect-specific lag detection queries
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.ReplicaManager = exports.ReplicaRoutingStrategy = void 0;
41
+ const events_1 = require("events");
42
+ /**
43
+ * Routing strategy for selecting a replica.
44
+ *
45
+ * Companion enum to the `RoutingStrategy` string-literal union below.
46
+ * Use either `ReplicaRoutingStrategy.RoundRobin` or the raw string
47
+ * `'round-robin'` (and so on) — both are accepted wherever a
48
+ * `RoutingStrategy` is expected.
49
+ */
50
+ var ReplicaRoutingStrategy;
51
+ (function (ReplicaRoutingStrategy) {
52
+ ReplicaRoutingStrategy["RoundRobin"] = "round-robin";
53
+ ReplicaRoutingStrategy["LeastConnections"] = "least-connections";
54
+ ReplicaRoutingStrategy["LowestLag"] = "lowest-lag";
55
+ })(ReplicaRoutingStrategy || (exports.ReplicaRoutingStrategy = ReplicaRoutingStrategy = {}));
56
+ /**
57
+ * Replica connection pool wrapper
58
+ */
59
+ class ReplicaPool {
60
+ constructor(config) {
61
+ this.name = config.name;
62
+ this.config = config;
63
+ }
64
+ async initialize(dialectModule) {
65
+ this.dialectModule = dialectModule;
66
+ // Create dialect and pool based on the replica's configured dialect
67
+ // (not the replica's *name*, which is an arbitrary label a caller could
68
+ // set to anything - e.g. a Postgres replica named "read-1" was previously
69
+ // silently treated as an unsupported dialect).
70
+ const dialectName = this.config.dialect.toLowerCase();
71
+ if (dialectName.includes('mysql') || dialectName.includes('mariadb')) {
72
+ const mysql = await Promise.resolve().then(() => __importStar(require('mysql2/promise')));
73
+ this.pool = mysql.createPool({
74
+ host: this.config.host,
75
+ port: this.config.port,
76
+ user: this.config.username,
77
+ password: this.config.password,
78
+ database: this.config.database,
79
+ waitForConnections: true,
80
+ connectionLimit: this.config.pool?.max || 10,
81
+ queueLimit: 0,
82
+ });
83
+ }
84
+ else if (dialectName.includes('postgres')) {
85
+ const { Pool } = await Promise.resolve().then(() => __importStar(require('pg')));
86
+ this.pool = new Pool({
87
+ host: this.config.host,
88
+ port: this.config.port,
89
+ user: this.config.username,
90
+ password: this.config.password,
91
+ database: this.config.database,
92
+ max: this.config.pool?.max || 10,
93
+ });
94
+ }
95
+ }
96
+ getPool() {
97
+ return this.pool;
98
+ }
99
+ getName() {
100
+ return this.name;
101
+ }
102
+ getDialect() {
103
+ return this.config.dialect;
104
+ }
105
+ async getConnection() {
106
+ if (!this.pool) {
107
+ throw new Error(`Pool not initialized for replica ${this.name}`);
108
+ }
109
+ if (this.config.dialect.toLowerCase().includes('mysql') || this.config.dialect.toLowerCase().includes('mariadb')) {
110
+ return this.pool.getConnection();
111
+ }
112
+ else if (this.config.dialect.toLowerCase().includes('postgres')) {
113
+ return this.pool.connect();
114
+ }
115
+ throw new Error(`Unsupported dialect for replica ${this.name}`);
116
+ }
117
+ async releaseConnection(connection) {
118
+ if (!this.pool)
119
+ return;
120
+ if (this.config.dialect.toLowerCase().includes('mysql') || this.config.dialect.toLowerCase().includes('mariadb')) {
121
+ connection.release();
122
+ }
123
+ else if (this.config.dialect.toLowerCase().includes('postgres')) {
124
+ connection.release();
125
+ }
126
+ }
127
+ async close() {
128
+ if (this.pool) {
129
+ await this.pool.end();
130
+ this.pool = null;
131
+ }
132
+ }
133
+ async query(sql, options) {
134
+ const connection = await this.getConnection();
135
+ try {
136
+ if (this.config.dialect.toLowerCase().includes('mysql') || this.config.dialect.toLowerCase().includes('mariadb')) {
137
+ const [rows] = await connection.query(sql);
138
+ return { rows };
139
+ }
140
+ else if (this.config.dialect.toLowerCase().includes('postgres')) {
141
+ const result = await connection.query(sql);
142
+ return { rows: result.rows };
143
+ }
144
+ throw new Error(`Unsupported dialect for replica ${this.name}`);
145
+ }
146
+ finally {
147
+ this.releaseConnection(connection);
148
+ }
149
+ }
150
+ }
151
+ /**
152
+ * ReplicaManager class for managing read replicas with lag detection
153
+ */
154
+ class ReplicaManager extends events_1.EventEmitter {
155
+ /**
156
+ * Create a new ReplicaManager
157
+ */
158
+ constructor(options) {
159
+ super();
160
+ this.replicas = new Map();
161
+ this.replicaStats = new Map();
162
+ this.roundRobinIndex = 0;
163
+ this.monitorInterval = null;
164
+ this.masterConfig = null;
165
+ this.lagDetectionConfig = {
166
+ enabled: options?.lagDetection?.enabled ?? true,
167
+ interval: options?.lagDetection?.interval ?? 5000,
168
+ timeout: options?.lagDetection?.timeout ?? 5000,
169
+ maxAcceptableLag: options?.lagDetection?.maxAcceptableLag ?? 2000,
170
+ maxFailures: options?.lagDetection?.maxFailures ?? 3,
171
+ };
172
+ this.routingStrategy = options?.defaultRoutingStrategy ?? 'round-robin';
173
+ this.masterConfig = options?.master ?? null;
174
+ }
175
+ /**
176
+ * Add a replica to the manager
177
+ */
178
+ async addReplica(config) {
179
+ if (this.replicas.has(config.name)) {
180
+ throw new Error(`Replica with name ${config.name} already exists`);
181
+ }
182
+ const pool = new ReplicaPool(config);
183
+ pool.initialize({});
184
+ this.replicas.set(config.name, pool);
185
+ // Initialize status
186
+ this.replicaStats.set(config.name, {
187
+ name: config.name,
188
+ healthy: false,
189
+ lag: null,
190
+ activeConnections: 0,
191
+ lastCheck: new Date(),
192
+ });
193
+ this.emit('replica:added', config.name);
194
+ }
195
+ /**
196
+ * Remove a replica from the manager
197
+ */
198
+ async removeReplica(name) {
199
+ const pool = this.replicas.get(name);
200
+ if (!pool) {
201
+ throw new Error(`Replica ${name} not found`);
202
+ }
203
+ await pool.close();
204
+ this.replicas.delete(name);
205
+ this.replicaStats.delete(name);
206
+ this.emit('replica:removed', name);
207
+ }
208
+ /**
209
+ * Get a replica by name
210
+ */
211
+ getReplica(name) {
212
+ return this.replicas.get(name);
213
+ }
214
+ /**
215
+ * Get all replica names
216
+ */
217
+ getReplicaNames() {
218
+ return Array.from(this.replicas.keys());
219
+ }
220
+ /**
221
+ * Check replication lag for a specific replica
222
+ * Uses dialect-specific queries for lag detection
223
+ */
224
+ async checkLag(name) {
225
+ const pool = this.replicas.get(name);
226
+ if (!pool) {
227
+ throw new Error(`Replica ${name} not found`);
228
+ }
229
+ const replicaDialect = pool.getDialect().toLowerCase();
230
+ let lagQuery;
231
+ let lag = null;
232
+ try {
233
+ // Determine the lag detection query based on the replica's configured
234
+ // dialect (not its arbitrary display name - see the ReplicaPool fix
235
+ // above for why name-based dialect guessing is unreliable).
236
+ if (replicaDialect.includes('mysql') || replicaDialect.includes('mariadb')) {
237
+ // MySQL/MariaDB: Use SHOW SLAVE STATUS to get Seconds_Behind_Master
238
+ lagQuery = 'SHOW SLAVE STATUS';
239
+ const result = await pool.query(lagQuery);
240
+ if (result.rows && result.rows.length > 0) {
241
+ const slaveStatus = result.rows[0];
242
+ const secondsBehind = slaveStatus.Seconds_Behind_Master;
243
+ lag = secondsBehind !== null && secondsBehind !== undefined
244
+ ? Number(secondsBehind) * 1000 // Convert seconds to milliseconds
245
+ : null;
246
+ }
247
+ }
248
+ else if (replicaDialect.includes('postgres')) {
249
+ // PostgreSQL: Use pg_last_xact_replay_timestamp()
250
+ lagQuery = "SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp())) * 1000 AS lag";
251
+ const result = await pool.query(lagQuery);
252
+ if (result.rows && result.rows.length > 0) {
253
+ lag = result.rows[0]?.lag ? Math.round(Number(result.rows[0].lag)) : null;
254
+ }
255
+ }
256
+ else {
257
+ // For other dialects, return null (not supported)
258
+ console.warn(`Lag detection not supported for dialect: ${replicaDialect}`);
259
+ return null;
260
+ }
261
+ // Update stats
262
+ const stats = this.replicaStats.get(name);
263
+ if (stats) {
264
+ stats.lag = lag;
265
+ stats.lastCheck = new Date();
266
+ stats.error = undefined;
267
+ }
268
+ if (lag !== null) {
269
+ this.emit('replica:lag-detected', name, lag);
270
+ }
271
+ return lag;
272
+ }
273
+ catch (error) {
274
+ // Update stats with error
275
+ const stats = this.replicaStats.get(name);
276
+ if (stats) {
277
+ stats.lag = null;
278
+ stats.lastCheck = new Date();
279
+ stats.error = error instanceof Error ? error.message : 'Unknown error';
280
+ }
281
+ throw error;
282
+ }
283
+ }
284
+ /**
285
+ * Start the lag monitoring loop
286
+ */
287
+ startLagMonitor() {
288
+ if (this.monitorInterval) {
289
+ console.warn('Lag monitor already running');
290
+ return;
291
+ }
292
+ const checkAllLags = async () => {
293
+ for (const name of Array.from(this.replicas.keys())) {
294
+ try {
295
+ const lag = await this.checkLag(name);
296
+ const stats = this.replicaStats.get(name);
297
+ if (stats) {
298
+ const wasHealthy = stats.healthy;
299
+ stats.healthy = lag !== null && lag <= this.lagDetectionConfig.maxAcceptableLag;
300
+ if (!wasHealthy && stats.healthy) {
301
+ this.emit('replica:healthy', name, stats);
302
+ }
303
+ else if (wasHealthy && !stats.healthy) {
304
+ this.emit('replica:unhealthy', name, stats);
305
+ }
306
+ }
307
+ // Check if all replicas are unhealthy
308
+ const allStats = Array.from(this.replicaStats.values());
309
+ const allUnhealthy = allStats.every(s => !s.healthy);
310
+ if (allUnhealthy && this.replicas.size > 0) {
311
+ this.emit('all-replicas-unhealthy');
312
+ }
313
+ }
314
+ catch (error) {
315
+ console.error(`Error checking lag for replica ${name}:`, error);
316
+ // A failed lag check means we can't confirm this replica is caught
317
+ // up - and if the connection itself is down, it can't serve reads
318
+ // either. Mark it unhealthy rather than silently leaving stale
319
+ // (possibly "healthy") stats in place, which would keep routing
320
+ // reads to a replica that's actually unreachable.
321
+ const stats = this.replicaStats.get(name);
322
+ if (stats) {
323
+ const wasHealthy = stats.healthy;
324
+ stats.healthy = false;
325
+ stats.lastCheck = new Date();
326
+ stats.error = error instanceof Error ? error.message : 'Unknown error';
327
+ if (wasHealthy) {
328
+ this.emit('replica:unhealthy', name, stats);
329
+ }
330
+ }
331
+ const allStats = Array.from(this.replicaStats.values());
332
+ if (allStats.length > 0 && allStats.every((s) => !s.healthy) && this.replicas.size > 0) {
333
+ this.emit('all-replicas-unhealthy');
334
+ }
335
+ }
336
+ }
337
+ };
338
+ // Run initial check
339
+ checkAllLags();
340
+ // Set up interval
341
+ this.monitorInterval = setInterval(checkAllLags, this.lagDetectionConfig.interval);
342
+ this.emit('monitor:started');
343
+ }
344
+ /**
345
+ * Stop the lag monitoring loop
346
+ */
347
+ stopLagMonitor() {
348
+ if (this.monitorInterval) {
349
+ clearInterval(this.monitorInterval);
350
+ this.monitorInterval = null;
351
+ this.emit('monitor:stopped');
352
+ }
353
+ }
354
+ /**
355
+ * Get statistics for all replicas
356
+ */
357
+ getReplicaStats() {
358
+ return new Map(this.replicaStats);
359
+ }
360
+ /**
361
+ * Get statistics for a specific replica
362
+ */
363
+ getReplicaStat(name) {
364
+ return this.replicaStats.get(name);
365
+ }
366
+ /**
367
+ * Set the routing strategy
368
+ */
369
+ setRoutingStrategy(strategy) {
370
+ this.routingStrategy = strategy;
371
+ }
372
+ /**
373
+ * Get the current routing strategy
374
+ */
375
+ getRoutingStrategy() {
376
+ return this.routingStrategy;
377
+ }
378
+ /**
379
+ * Select a replica based on the current routing strategy
380
+ */
381
+ async selectReplica() {
382
+ if (this.replicas.size === 0) {
383
+ throw new Error('No replicas available');
384
+ }
385
+ const names = Array.from(this.replicas.keys());
386
+ let selectedName;
387
+ // Round-robin should still skip known-unhealthy replicas where possible -
388
+ // previously it cycled through every name unconditionally, so an
389
+ // unhealthy replica still received its turn in rotation. Fall back to
390
+ // the full name list only if there are no healthy replicas at all (e.g.
391
+ // before the first lag-check cycle has run), so selection never throws.
392
+ const healthyNames = names.filter((name) => this.replicaStats.get(name)?.healthy !== false);
393
+ const roundRobinPool = healthyNames.length > 0 ? healthyNames : names;
394
+ switch (this.routingStrategy) {
395
+ case 'round-robin':
396
+ selectedName = roundRobinPool[this.roundRobinIndex % roundRobinPool.length];
397
+ this.roundRobinIndex++;
398
+ break;
399
+ case 'least-connections':
400
+ let minConnections = Infinity;
401
+ for (const name of names) {
402
+ const stats = this.replicaStats.get(name);
403
+ if (stats && stats.healthy && stats.activeConnections < minConnections) {
404
+ minConnections = stats.activeConnections;
405
+ selectedName = name;
406
+ }
407
+ }
408
+ if (!selectedName) {
409
+ // Fallback to round-robin if all have same connections or none are healthy
410
+ selectedName = roundRobinPool[this.roundRobinIndex % roundRobinPool.length];
411
+ this.roundRobinIndex++;
412
+ }
413
+ break;
414
+ case 'lowest-lag':
415
+ let minLag = Infinity;
416
+ for (const name of names) {
417
+ const stats = this.replicaStats.get(name);
418
+ if (stats && stats.healthy && stats.lag !== null && stats.lag < minLag) {
419
+ minLag = stats.lag;
420
+ selectedName = name;
421
+ }
422
+ }
423
+ if (!selectedName) {
424
+ // Fallback to round-robin if all have same lag or none are healthy
425
+ selectedName = roundRobinPool[this.roundRobinIndex % roundRobinPool.length];
426
+ this.roundRobinIndex++;
427
+ }
428
+ break;
429
+ default:
430
+ selectedName = roundRobinPool[this.roundRobinIndex % roundRobinPool.length];
431
+ this.roundRobinIndex++;
432
+ }
433
+ const pool = this.replicas.get(selectedName);
434
+ // Update active connections
435
+ const stats = this.replicaStats.get(selectedName);
436
+ if (stats) {
437
+ stats.activeConnections++;
438
+ }
439
+ this.emit('replica:selected', selectedName);
440
+ return { name: selectedName, pool };
441
+ }
442
+ /**
443
+ * Execute a query on a replica (auto-selects replica based on routing strategy)
444
+ */
445
+ async queryReplica(sql, options) {
446
+ const { name, pool } = await this.selectReplica();
447
+ const result = await pool.query(sql, options);
448
+ // Decrease active connections after query completes
449
+ const stats = this.replicaStats.get(name);
450
+ if (stats && stats.activeConnections > 0) {
451
+ stats.activeConnections--;
452
+ }
453
+ return result;
454
+ }
455
+ /**
456
+ * Get healthy replicas
457
+ */
458
+ getHealthyReplicas() {
459
+ const healthy = [];
460
+ for (const [name, stats] of Array.from(this.replicaStats.entries())) {
461
+ if (stats.healthy) {
462
+ healthy.push(name);
463
+ }
464
+ }
465
+ return healthy;
466
+ }
467
+ /**
468
+ * Get replica count
469
+ */
470
+ getReplicaCount() {
471
+ return this.replicas.size;
472
+ }
473
+ /**
474
+ * Check if replication is enabled
475
+ */
476
+ isReplicationEnabled() {
477
+ return this.replicas.size > 0;
478
+ }
479
+ /**
480
+ * Set lag detection configuration
481
+ */
482
+ setLagDetectionConfig(config) {
483
+ this.lagDetectionConfig = {
484
+ ...this.lagDetectionConfig,
485
+ ...config,
486
+ };
487
+ }
488
+ /**
489
+ * Get lag detection configuration
490
+ */
491
+ getLagDetectionConfig() {
492
+ return { ...this.lagDetectionConfig };
493
+ }
494
+ /**
495
+ * Close all replica connections
496
+ */
497
+ async close() {
498
+ this.stopLagMonitor();
499
+ for (const pool of Array.from(this.replicas.values())) {
500
+ await pool.close();
501
+ }
502
+ this.replicas.clear();
503
+ this.replicaStats.clear();
504
+ }
505
+ }
506
+ exports.ReplicaManager = ReplicaManager;
507
+ exports.default = ReplicaManager;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ /**
3
+ * Schema Module - Automated schema diffing and migration generation
4
+ * Exports classes and functions for comparing model definitions against database schema
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createMigrationGenerator = exports.MigrationGenerator = exports.createSchemaDiffer = exports.SchemaDiffer = void 0;
8
+ // Re-export SchemaDiffer
9
+ var schema_differ_1 = require("./schema-differ");
10
+ Object.defineProperty(exports, "SchemaDiffer", { enumerable: true, get: function () { return schema_differ_1.SchemaDiffer; } });
11
+ Object.defineProperty(exports, "createSchemaDiffer", { enumerable: true, get: function () { return schema_differ_1.createSchemaDiffer; } });
12
+ // Re-export MigrationGenerator
13
+ var migration_generator_1 = require("./migration-generator");
14
+ Object.defineProperty(exports, "MigrationGenerator", { enumerable: true, get: function () { return migration_generator_1.MigrationGenerator; } });
15
+ Object.defineProperty(exports, "createMigrationGenerator", { enumerable: true, get: function () { return migration_generator_1.createMigrationGenerator; } });