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,455 @@
1
+ "use strict";
2
+ /**
3
+ * RelationalDiagram — renders a relational schema as entity boxes with their
4
+ * columns and draws connectors between related tables using proper crow's-foot
5
+ * cardinality notation.
6
+ *
7
+ * Each entity is a box listing its columns; primary-key columns are marked and
8
+ * underlined, foreign-key columns are marked. Relationship connectors terminate
9
+ * with crow's-foot endpoints:
10
+ * - "one" → a small perpendicular tick (single bar)
11
+ * - "many" → the three-pronged crow's foot
12
+ * - "optional" → a small circle just outside the endpoint (zero cardinality)
13
+ *
14
+ * Supported relationship types: one-to-one, one-to-many, many-to-one,
15
+ * many-to-many. Entities are laid out on a grid and connectors are routed
16
+ * between the nearest entity edges.
17
+ *
18
+ * Everything is built against a real DOM document via the shared `SvgDocument`
19
+ * / `El` builder — never by concatenating markup strings — and the viewBox is
20
+ * auto-sized to the content. Both `theme` and `color` change real fill/stroke
21
+ * values in the output (via `resolveTheme` / `resolveAccent`).
22
+ *
23
+ * Usage:
24
+ * const rel = new RelationalDiagram({
25
+ * title: 'Shop Schema',
26
+ * entities: [ …RelEntity ],
27
+ * relationships: [ …RelRelationship ],
28
+ * });
29
+ * rel.save('./diagrams/schema.svg');
30
+ * // or: const svg = rel.generate();
31
+ */
32
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
33
+ if (k2 === undefined) k2 = k;
34
+ var desc = Object.getOwnPropertyDescriptor(m, k);
35
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
36
+ desc = { enumerable: true, get: function() { return m[k]; } };
37
+ }
38
+ Object.defineProperty(o, k2, desc);
39
+ }) : (function(o, m, k, k2) {
40
+ if (k2 === undefined) k2 = k;
41
+ o[k2] = m[k];
42
+ }));
43
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
44
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
45
+ }) : function(o, v) {
46
+ o["default"] = v;
47
+ });
48
+ var __importStar = (this && this.__importStar) || (function () {
49
+ var ownKeys = function(o) {
50
+ ownKeys = Object.getOwnPropertyNames || function (o) {
51
+ var ar = [];
52
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
53
+ return ar;
54
+ };
55
+ return ownKeys(o);
56
+ };
57
+ return function (mod) {
58
+ if (mod && mod.__esModule) return mod;
59
+ var result = {};
60
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
61
+ __setModuleDefault(result, mod);
62
+ return result;
63
+ };
64
+ })();
65
+ Object.defineProperty(exports, "__esModule", { value: true });
66
+ exports.RelationalDiagram = void 0;
67
+ const fs = __importStar(require("fs"));
68
+ const path = __importStar(require("path"));
69
+ const palette_1 = require("./palette");
70
+ const svg_dom_1 = require("./svg-dom");
71
+ // ─── Main class ──────────────────────────────────────────────────────────────
72
+ class RelationalDiagram {
73
+ constructor(options) {
74
+ this.opts = {
75
+ entities: options.entities,
76
+ relationships: options.relationships ?? [],
77
+ title: options.title ?? 'Relational Schema',
78
+ theme: options.theme ?? 'light',
79
+ color: options.color ?? '',
80
+ columns: options.columns ?? 3,
81
+ };
82
+ }
83
+ // ── Box height for an entity ─────────────────────────────────────────────
84
+ boxHeight(entity) {
85
+ const h = RelationalDiagram.HDR_H + entity.columns.length * RelationalDiagram.ROW_H + 8;
86
+ return Math.max(h, RelationalDiagram.BOX_MIN_H);
87
+ }
88
+ // ── Grid layout ──────────────────────────────────────────────────────────
89
+ computeLayout() {
90
+ const { entities, columns } = this.opts;
91
+ const W = RelationalDiagram.BOX_W;
92
+ const MARGIN = RelationalDiagram.MARGIN;
93
+ const BANNER = RelationalDiagram.BANNER_H;
94
+ const H_GAP = RelationalDiagram.H_GAP;
95
+ const V_GAP = RelationalDiagram.V_GAP;
96
+ // Precompute per-row max height so rows never overlap.
97
+ const rowHeights = [];
98
+ let curRowMax = 0;
99
+ entities.forEach((e, i) => {
100
+ curRowMax = Math.max(curRowMax, this.boxHeight(e));
101
+ if ((i + 1) % columns === 0 || i === entities.length - 1) {
102
+ rowHeights.push(curRowMax);
103
+ curRowMax = 0;
104
+ }
105
+ });
106
+ const layout = [];
107
+ let col = 0;
108
+ let row = 0;
109
+ let rowTop = BANNER + MARGIN;
110
+ entities.forEach((entity) => {
111
+ const h = this.boxHeight(entity);
112
+ const x = MARGIN + col * (W + H_GAP);
113
+ const y = rowTop + (rowHeights[row] - h) / 2;
114
+ layout.push({ entity, x, y, w: W, h });
115
+ col++;
116
+ if (col >= columns) {
117
+ col = 0;
118
+ rowTop += rowHeights[row] + V_GAP;
119
+ row++;
120
+ }
121
+ });
122
+ return layout;
123
+ }
124
+ // ── Render a single entity box ───────────────────────────────────────────
125
+ renderBox(doc, svg, box, idx) {
126
+ const { entity, x, y, w, h } = box;
127
+ const t = (0, palette_1.resolveTheme)(this.opts.theme);
128
+ const palettes = (0, palette_1.rotatedPalettes)(this.opts.color);
129
+ const accent = palettes[idx % palettes.length];
130
+ const HDR = RelationalDiagram.HDR_H;
131
+ const ROW = RelationalDiagram.ROW_H;
132
+ const R = 8;
133
+ const uid = entity.name.replace(/\W/g, '') + idx;
134
+ // Header gradient (accent-driven → responds to `color`).
135
+ const gradId = doc.linearGradient(`relhg${uid}`, [
136
+ [0, accent.from],
137
+ [100, accent.mid],
138
+ ]);
139
+ // Shell / shadow.
140
+ svg.child('rect', {
141
+ x: x - 1,
142
+ y: y - 1,
143
+ width: w + 2,
144
+ height: h + 2,
145
+ rx: R + 1,
146
+ fill: t.border,
147
+ });
148
+ // Surface.
149
+ svg.child('rect', { x, y, width: w, height: h, rx: R, fill: t.cardBg });
150
+ // Header band (rounded top, flattened bottom).
151
+ svg.child('rect', { x, y, width: w, height: HDR, rx: R, fill: `url(#${gradId})` });
152
+ svg.child('rect', { x, y: y + HDR - R, width: w, height: R, fill: `url(#${gradId})` });
153
+ svg
154
+ .child('text', {
155
+ x: x + w / 2,
156
+ y: y + 26,
157
+ 'font-family': 'system-ui,-apple-system,sans-serif',
158
+ 'font-size': 16,
159
+ 'font-weight': 800,
160
+ fill: '#FFFFFF',
161
+ 'text-anchor': 'middle',
162
+ })
163
+ .text(entity.name);
164
+ // Column rows.
165
+ entity.columns.forEach((colDef, ci) => {
166
+ const ry = y + HDR + ci * ROW;
167
+ const midY = ry + ROW / 2;
168
+ const textY = midY + 4;
169
+ const isPK = !!colDef.primaryKey;
170
+ const isFK = !!colDef.foreignKey;
171
+ const rowBg = ci % 2 === 0 ? t.cardBg : t.rowAlt;
172
+ svg.child('rect', { x, y: ry, width: w, height: ROW, fill: rowBg });
173
+ // Key marker.
174
+ const markX = x + 14;
175
+ if (isPK) {
176
+ svg.child('circle', { cx: markX, cy: midY, r: 4, fill: '#F59E0B' });
177
+ }
178
+ else if (isFK) {
179
+ svg.child('circle', {
180
+ cx: markX,
181
+ cy: midY,
182
+ r: 4,
183
+ fill: 'none',
184
+ stroke: '#3B82F6',
185
+ 'stroke-width': 1.6,
186
+ });
187
+ }
188
+ else {
189
+ svg.child('circle', { cx: markX, cy: midY, r: 2.5, fill: t.textSecondary });
190
+ }
191
+ // Column name (PK underlined, PK/FK colored+bold).
192
+ const nameColor = isPK ? '#B45309' : isFK ? '#2563EB' : t.textPrimary;
193
+ const nameWeight = isPK ? 700 : isFK ? 600 : 400;
194
+ const nameX = x + 28;
195
+ svg
196
+ .child('text', {
197
+ x: nameX,
198
+ y: textY,
199
+ 'font-family': "'SF Mono','Fira Code',monospace",
200
+ 'font-size': 11,
201
+ 'font-weight': nameWeight,
202
+ 'text-decoration': isPK ? 'underline' : undefined,
203
+ fill: nameColor,
204
+ })
205
+ .text(colDef.name);
206
+ // Type (right-aligned).
207
+ if (colDef.type) {
208
+ svg
209
+ .child('text', {
210
+ x: x + w - 10,
211
+ y: textY,
212
+ 'font-family': "'SF Mono',monospace",
213
+ 'font-size': 10,
214
+ 'font-weight': 500,
215
+ fill: t.textSecondary,
216
+ 'text-anchor': 'end',
217
+ })
218
+ .text(colDef.type);
219
+ }
220
+ // PK/FK tag near the name.
221
+ if (isPK || isFK) {
222
+ svg
223
+ .child('text', {
224
+ x: nameX,
225
+ y: ry + ROW - 4,
226
+ 'font-family': 'monospace',
227
+ 'font-size': 7,
228
+ 'font-weight': 700,
229
+ fill: isPK ? '#B45309' : '#2563EB',
230
+ })
231
+ .text(isPK ? 'PK' : 'FK');
232
+ }
233
+ // Row separator.
234
+ svg.child('line', {
235
+ x1: x,
236
+ y1: ry + ROW,
237
+ x2: x + w,
238
+ y2: ry + ROW,
239
+ stroke: t.border,
240
+ 'stroke-width': 0.5,
241
+ });
242
+ });
243
+ }
244
+ // ── Pick the connection point on the nearest edges of two boxes ──────────
245
+ edgePoint(box, side) {
246
+ switch (side) {
247
+ case 'left':
248
+ return { x: box.x, y: box.y + box.h / 2 };
249
+ case 'right':
250
+ return { x: box.x + box.w, y: box.y + box.h / 2 };
251
+ case 'top':
252
+ return { x: box.x + box.w / 2, y: box.y };
253
+ case 'bottom':
254
+ return { x: box.x + box.w / 2, y: box.y + box.h };
255
+ }
256
+ }
257
+ chooseSides(a, b) {
258
+ const aMidX = a.x + a.w / 2;
259
+ const bMidX = b.x + b.w / 2;
260
+ const aMidY = a.y + a.h / 2;
261
+ const bMidY = b.y + b.h / 2;
262
+ // If mostly stacked vertically, exit top/bottom.
263
+ if (Math.abs(aMidX - bMidX) < a.w / 2 && Math.abs(aMidY - bMidY) > a.h) {
264
+ return b.y >= a.y ? ['bottom', 'top'] : ['top', 'bottom'];
265
+ }
266
+ return bMidX >= aMidX ? ['right', 'left'] : ['left', 'right'];
267
+ }
268
+ // ── Crow's-foot "many" endpoint (three prongs + arc bar) ────────────────
269
+ crowFoot(parent, x, y, side, color) {
270
+ // Symbol points AWAY from the box, back along the connector.
271
+ const reach = 13;
272
+ const spread = 7;
273
+ let ex, ey, perp;
274
+ if (side === 'left' || side === 'right') {
275
+ const sign = side === 'right' ? 1 : -1;
276
+ ex = x + sign * reach;
277
+ ey = y;
278
+ perp = [
279
+ [ex, y - spread],
280
+ [ex, y + spread],
281
+ ];
282
+ }
283
+ else {
284
+ const sign = side === 'bottom' ? 1 : -1;
285
+ ex = x;
286
+ ey = y + sign * reach;
287
+ perp = [
288
+ [x - spread, ey],
289
+ [x + spread, ey],
290
+ ];
291
+ }
292
+ // Three prongs converging at the box edge.
293
+ parent.child('line', { x1: x, y1: y, x2: perp[0][0], y2: perp[0][1], stroke: color, 'stroke-width': 1.6 });
294
+ parent.child('line', { x1: x, y1: y, x2: ex, y2: ey, stroke: color, 'stroke-width': 1.6 });
295
+ parent.child('line', { x1: x, y1: y, x2: perp[1][0], y2: perp[1][1], stroke: color, 'stroke-width': 1.6 });
296
+ // Connecting bar across the prongs.
297
+ parent.child('line', {
298
+ x1: perp[0][0],
299
+ y1: perp[0][1],
300
+ x2: perp[1][0],
301
+ y2: perp[1][1],
302
+ stroke: color,
303
+ 'stroke-width': 1.4,
304
+ });
305
+ }
306
+ // ── "One" endpoint (single perpendicular tick) ───────────────────────────
307
+ oneBar(parent, x, y, side, color) {
308
+ const gap = 11;
309
+ const ht = 7;
310
+ if (side === 'left' || side === 'right') {
311
+ const bx = side === 'right' ? x + gap : x - gap;
312
+ parent.child('line', { x1: bx, y1: y - ht, x2: bx, y2: y + ht, stroke: color, 'stroke-width': 1.8 });
313
+ }
314
+ else {
315
+ const by = side === 'bottom' ? y + gap : y - gap;
316
+ parent.child('line', { x1: x - ht, y1: by, x2: x + ht, y2: by, stroke: color, 'stroke-width': 1.8 });
317
+ }
318
+ }
319
+ // ── Draw one relationship connector with crow's-foot ends ────────────────
320
+ renderRelationship(svg, rel, byName, color) {
321
+ const a = byName.get(rel.from);
322
+ const b = byName.get(rel.to);
323
+ if (!a || !b)
324
+ return;
325
+ const [sideA, sideB] = this.chooseSides(a, b);
326
+ const p = this.edgePoint(a, sideA);
327
+ const q = this.edgePoint(b, sideB);
328
+ const group = svg.child('g', { 'data-rel': `${rel.from}-${rel.to}` });
329
+ // Connector path (bezier for horizontal exits, gentle curve for vertical).
330
+ const horizontal = sideA === 'left' || sideA === 'right';
331
+ let d;
332
+ if (horizontal) {
333
+ const off = Math.max(Math.abs(q.x - p.x) * 0.5, 50);
334
+ const c1x = sideA === 'right' ? p.x + off : p.x - off;
335
+ const c2x = sideB === 'left' ? q.x - off : q.x + off;
336
+ d = `M ${p.x} ${p.y} C ${c1x} ${p.y}, ${c2x} ${q.y}, ${q.x} ${q.y}`;
337
+ }
338
+ else {
339
+ const off = Math.max(Math.abs(q.y - p.y) * 0.5, 50);
340
+ const c1y = sideA === 'bottom' ? p.y + off : p.y - off;
341
+ const c2y = sideB === 'top' ? q.y - off : q.y + off;
342
+ d = `M ${p.x} ${p.y} C ${p.x} ${c1y}, ${q.x} ${c2y}, ${q.x} ${q.y}`;
343
+ }
344
+ group.child('path', {
345
+ d,
346
+ fill: 'none',
347
+ stroke: color,
348
+ 'stroke-width': 1.8,
349
+ opacity: 0.85,
350
+ });
351
+ // Cardinality endpoints.
352
+ const manyAtFrom = rel.type === 'many-to-one' || rel.type === 'many-to-many';
353
+ const manyAtTo = rel.type === 'one-to-many' || rel.type === 'many-to-many';
354
+ if (manyAtFrom)
355
+ this.crowFoot(group, p.x, p.y, sideA, color);
356
+ else
357
+ this.oneBar(group, p.x, p.y, sideA, color);
358
+ if (manyAtTo)
359
+ this.crowFoot(group, q.x, q.y, sideB, color);
360
+ else
361
+ this.oneBar(group, q.x, q.y, sideB, color);
362
+ // Midpoint label.
363
+ const label = rel.label ?? rel.type;
364
+ const mx = (p.x + q.x) / 2;
365
+ const my = (p.y + q.y) / 2;
366
+ const lw = label.length * 6.5 + 14;
367
+ group.child('rect', {
368
+ x: mx - lw / 2,
369
+ y: my - 10,
370
+ width: lw,
371
+ height: 18,
372
+ rx: 5,
373
+ fill: (0, palette_1.resolveTheme)(this.opts.theme).cardBg,
374
+ stroke: color,
375
+ 'stroke-width': 1,
376
+ opacity: 0.95,
377
+ });
378
+ group
379
+ .child('text', {
380
+ x: mx,
381
+ y: my + 3,
382
+ 'font-family': 'system-ui,sans-serif',
383
+ 'font-size': 9,
384
+ 'font-weight': 600,
385
+ fill: color,
386
+ 'text-anchor': 'middle',
387
+ })
388
+ .text(label);
389
+ }
390
+ // ── Generate full SVG ────────────────────────────────────────────────────
391
+ generate() {
392
+ const { title, relationships } = this.opts;
393
+ const t = (0, palette_1.resolveTheme)(this.opts.theme);
394
+ const accent = (0, palette_1.resolveAccent)(this.opts.color);
395
+ const MARGIN = RelationalDiagram.MARGIN;
396
+ const BANNER = RelationalDiagram.BANNER_H;
397
+ const layout = this.computeLayout();
398
+ const byName = new Map();
399
+ layout.forEach((b) => byName.set(b.entity.name, b));
400
+ // Auto-size canvas.
401
+ const maxX = layout.length ? Math.max(...layout.map((b) => b.x + b.w)) : MARGIN;
402
+ const maxY = layout.length ? Math.max(...layout.map((b) => b.y + b.h)) : BANNER;
403
+ const totalW = maxX + MARGIN;
404
+ const totalH = maxY + MARGIN;
405
+ const doc = new svg_dom_1.SvgDocument(totalW, totalH);
406
+ const svg = doc.root;
407
+ // Canvas background (theme-driven → responds to `theme`).
408
+ svg.child('rect', { width: totalW, height: totalH, fill: t.canvasBg });
409
+ // Banner (accent-driven fill so `color` shows here too).
410
+ const bannerGrad = doc.linearGradient('relBanner', [
411
+ [0, accent.from],
412
+ [100, accent.mid],
413
+ ], { x2: 1, y2: 0 });
414
+ svg.child('rect', { width: totalW, height: BANNER, fill: `url(#${bannerGrad})` });
415
+ svg
416
+ .child('text', {
417
+ x: 24,
418
+ y: 38,
419
+ 'font-family': 'system-ui,-apple-system,sans-serif',
420
+ 'font-size': 22,
421
+ 'font-weight': 800,
422
+ fill: '#FFFFFF',
423
+ })
424
+ .text(title);
425
+ // Relationship connectors (drawn under the boxes).
426
+ const relColor = accent.mid;
427
+ relationships.forEach((rel) => this.renderRelationship(svg, rel, byName, relColor));
428
+ // Entity boxes on top.
429
+ layout.forEach((box, i) => this.renderBox(doc, svg, box, i));
430
+ return doc.toString('Generated by ts-prorm-orm RelationalDiagram');
431
+ }
432
+ /**
433
+ * Write the SVG to a file, creating parent directories as needed.
434
+ * Returns the resolved absolute path.
435
+ */
436
+ save(outputPath) {
437
+ const resolved = path.resolve(outputPath);
438
+ const dir = path.dirname(resolved);
439
+ if (!fs.existsSync(dir))
440
+ fs.mkdirSync(dir, { recursive: true });
441
+ fs.writeFileSync(resolved, this.generate(), 'utf-8');
442
+ return resolved;
443
+ }
444
+ }
445
+ exports.RelationalDiagram = RelationalDiagram;
446
+ // Entity box geometry (px)
447
+ RelationalDiagram.BOX_W = 240;
448
+ RelationalDiagram.HDR_H = 40;
449
+ RelationalDiagram.ROW_H = 26;
450
+ RelationalDiagram.BOX_MIN_H = 80;
451
+ // Chrome
452
+ RelationalDiagram.BANNER_H = 60;
453
+ RelationalDiagram.MARGIN = 56;
454
+ RelationalDiagram.H_GAP = 130;
455
+ RelationalDiagram.V_GAP = 90;