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.
- package/CHANGELOG.md +1111 -0
- package/LICENSE +21 -0
- package/README.md +573 -0
- package/dist/audit/history-query.js +180 -0
- package/dist/audit/index.js +23 -0
- package/dist/audit/logger.js +236 -0
- package/dist/cache/cache-manager.js +84 -0
- package/dist/cache/index.js +16 -0
- package/dist/cache/redis-cluster-cache.js +557 -0
- package/dist/cli.js +2200 -0
- package/dist/compliance/audit-trail.js +68 -0
- package/dist/compliance/backup-verification.js +685 -0
- package/dist/compliance/breach-detector.js +505 -0
- package/dist/compliance/consent-record.js +227 -0
- package/dist/compliance/consent-versioning.js +331 -0
- package/dist/compliance/cross-border-log.js +530 -0
- package/dist/compliance/data-classifier.js +258 -0
- package/dist/compliance/data-lineage.js +565 -0
- package/dist/compliance/data-masker.js +303 -0
- package/dist/compliance/data-portability.js +265 -0
- package/dist/compliance/data-retention.js +195 -0
- package/dist/compliance/dsar-workflow.js +342 -0
- package/dist/compliance/field-encryption.js +223 -0
- package/dist/compliance/immutable-record.js +148 -0
- package/dist/compliance/index.js +260 -0
- package/dist/compliance/privacy-impact-assessment.js +364 -0
- package/dist/compliance/pseudonymization.js +269 -0
- package/dist/compliance/query-firewall.js +1182 -0
- package/dist/compliance/rate-limiter.js +580 -0
- package/dist/compliance/right-to-erasure.js +117 -0
- package/dist/compliance/row-level-security.js +246 -0
- package/dist/compliance/security-decorator.js +574 -0
- package/dist/compliance/security-monitor.js +525 -0
- package/dist/compliance/sensitive-data-discovery.js +476 -0
- package/dist/compliance/session-isolation.js +472 -0
- package/dist/compliance/tls-enforcer.js +108 -0
- package/dist/compliance/worm-storage.js +712 -0
- package/dist/connection-manager.js +198 -0
- package/dist/connection-pool.js +519 -0
- package/dist/decorators/audit.js +136 -0
- package/dist/decorators/belongs-to-many.js +115 -0
- package/dist/decorators/belongs-to.js +115 -0
- package/dist/decorators/check.js +435 -0
- package/dist/decorators/collate.js +329 -0
- package/dist/decorators/comment.js +205 -0
- package/dist/decorators/database-settings.js +236 -0
- package/dist/decorators/default.js +244 -0
- package/dist/decorators/encryption.js +235 -0
- package/dist/decorators/engine.js +97 -0
- package/dist/decorators/fk-constraints.js +594 -0
- package/dist/decorators/foreign-table.js +136 -0
- package/dist/decorators/generated.js +274 -0
- package/dist/decorators/has-many.js +127 -0
- package/dist/decorators/has-one.js +116 -0
- package/dist/decorators/hstore.js +129 -0
- package/dist/decorators/index.js +355 -0
- package/dist/decorators/json-column.js +83 -0
- package/dist/decorators/jsonb.js +101 -0
- package/dist/decorators/orm-decorators.js +425 -0
- package/dist/decorators/permissions.js +294 -0
- package/dist/decorators/procedure.js +210 -0
- package/dist/decorators/query-options.js +556 -0
- package/dist/decorators/range.js +167 -0
- package/dist/decorators/set-column.js +83 -0
- package/dist/decorators/spatial.js +114 -0
- package/dist/decorators/storage.js +580 -0
- package/dist/decorators/timezone.js +512 -0
- package/dist/decorators/trigger.js +90 -0
- package/dist/decorators/uuid.js +135 -0
- package/dist/decorators/view.js +258 -0
- package/dist/diagrams/chen-diagram.js +354 -0
- package/dist/diagrams/class-diagram.js +384 -0
- package/dist/diagrams/dependency-diagram.js +432 -0
- package/dist/diagrams/er-diagram.js +605 -0
- package/dist/diagrams/flow-diagram.js +394 -0
- package/dist/diagrams/gantt-diagram.js +411 -0
- package/dist/diagrams/index-diagram.js +353 -0
- package/dist/diagrams/index.js +184 -0
- package/dist/diagrams/migration-diagram.js +316 -0
- package/dist/diagrams/model-diagram.js +616 -0
- package/dist/diagrams/package-diagram.js +376 -0
- package/dist/diagrams/palette.js +85 -0
- package/dist/diagrams/relational-diagram.js +455 -0
- package/dist/diagrams/schemadoc-diagram.js +309 -0
- package/dist/diagrams/sequence-diagram.js +307 -0
- package/dist/diagrams/state-diagram.js +344 -0
- package/dist/diagrams/svg-dom.js +111 -0
- package/dist/diagrams/tree-diagram.js +250 -0
- package/dist/dialects/clickhouse/index.js +1742 -0
- package/dist/dialects/cockroachdb/index.js +4677 -0
- package/dist/dialects/cratedb/index.js +441 -0
- package/dist/dialects/databricks/index.js +517 -0
- package/dist/dialects/db2/index.js +2225 -0
- package/dist/dialects/dialect.js +720 -0
- package/dist/dialects/duckdb/index.js +2014 -0
- package/dist/dialects/exasol/index.js +357 -0
- package/dist/dialects/firebird/index.js +495 -0
- package/dist/dialects/greenplum/index.js +457 -0
- package/dist/dialects/hana/index.js +1741 -0
- package/dist/dialects/mariadb/index.js +3590 -0
- package/dist/dialects/mssql/index.js +2296 -0
- package/dist/dialects/mysql/index.js +4058 -0
- package/dist/dialects/oracle/index.js +2999 -0
- package/dist/dialects/postgres/index.js +5319 -0
- package/dist/dialects/query-stream-helper.js +152 -0
- package/dist/dialects/questdb/index.js +433 -0
- package/dist/dialects/redshift/index.js +2277 -0
- package/dist/dialects/singlestore/index.js +354 -0
- package/dist/dialects/snowflake/index.js +2082 -0
- package/dist/dialects/spanner/index.js +1768 -0
- package/dist/dialects/sqlite/index.js +3382 -0
- package/dist/dialects/tidb/index.js +377 -0
- package/dist/dialects/timescaledb/index.js +164 -0
- package/dist/dialects/trino/index.js +420 -0
- package/dist/dialects/turso/index.js +227 -0
- package/dist/dialects/vertica/index.js +317 -0
- package/dist/dialects/yugabytedb/index.js +424 -0
- package/dist/errors/index.js +472 -0
- package/dist/errors/utils.js +340 -0
- package/dist/errors.js +21 -0
- package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
- package/dist/extensions/catalog/mssql-features.js +147 -0
- package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
- package/dist/extensions/catalog/oracle-db2-features.js +196 -0
- package/dist/extensions/catalog/postgres-extensions.js +516 -0
- package/dist/extensions/index.js +71 -0
- package/dist/extensions/types.js +13 -0
- package/dist/foreign-data.js +173 -0
- package/dist/hooks/hooks-manager.js +350 -0
- package/dist/hooks/index.js +37 -0
- package/dist/index.js +463 -0
- package/dist/logging.js +335 -0
- package/dist/migrations/index.js +40 -0
- package/dist/migrations/migration.js +196 -0
- package/dist/migrations/migrator.js +411 -0
- package/dist/migrations/prormmigration.js +275 -0
- package/dist/migrations/query-interface.js +435 -0
- package/dist/migrations/seeder.js +353 -0
- package/dist/models/associations.js +852 -0
- package/dist/models/constraints.js +288 -0
- package/dist/models/data-types.js +2518 -0
- package/dist/models/decorators.js +445 -0
- package/dist/models/index.js +33 -0
- package/dist/models/indexes.js +531 -0
- package/dist/models/methods.js +382 -0
- package/dist/models/model-manager.js +103 -0
- package/dist/models/model.js +5349 -0
- package/dist/models/operators.js +67 -0
- package/dist/models/scopes.js +189 -0
- package/dist/models/typescript-types.js +26 -0
- package/dist/nosql/aerospike/index.js +205 -0
- package/dist/nosql/allegrograph/index.js +169 -0
- package/dist/nosql/arangodb/index.js +364 -0
- package/dist/nosql/azure-blob/index.js +206 -0
- package/dist/nosql/beanstalkd/index.js +231 -0
- package/dist/nosql/beequeue/index.js +210 -0
- package/dist/nosql/bigchaindb/index.js +195 -0
- package/dist/nosql/bigtable/index.js +224 -0
- package/dist/nosql/blazegraph/index.js +173 -0
- package/dist/nosql/bullmq/index.js +191 -0
- package/dist/nosql/cassandra/index.js +174 -0
- package/dist/nosql/chroma/index.js +190 -0
- package/dist/nosql/cloudflare-kv/index.js +220 -0
- package/dist/nosql/coherence/index.js +200 -0
- package/dist/nosql/cosmosdb/index.js +157 -0
- package/dist/nosql/couchbase/index.js +213 -0
- package/dist/nosql/dax/index.js +212 -0
- package/dist/nosql/deno-kv/index.js +206 -0
- package/dist/nosql/dgraph/index.js +171 -0
- package/dist/nosql/doris/index.js +169 -0
- package/dist/nosql/druid/index.js +162 -0
- package/dist/nosql/dynamodb/index.js +937 -0
- package/dist/nosql/elasticsearch/index.js +377 -0
- package/dist/nosql/etcd/index.js +502 -0
- package/dist/nosql/eventhubs/index.js +213 -0
- package/dist/nosql/eventstore/index.js +254 -0
- package/dist/nosql/faunadb/index.js +188 -0
- package/dist/nosql/firestore/index.js +177 -0
- package/dist/nosql/fluree/index.js +148 -0
- package/dist/nosql/fuseki/index.js +170 -0
- package/dist/nosql/gcs/index.js +172 -0
- package/dist/nosql/gearman/index.js +160 -0
- package/dist/nosql/geode/index.js +196 -0
- package/dist/nosql/graphdb/index.js +169 -0
- package/dist/nosql/graylog/index.js +188 -0
- package/dist/nosql/gridgain/index.js +171 -0
- package/dist/nosql/hazelcast/index.js +162 -0
- package/dist/nosql/hbase/index.js +230 -0
- package/dist/nosql/ignite/index.js +173 -0
- package/dist/nosql/immudb/index.js +184 -0
- package/dist/nosql/index.js +232 -0
- package/dist/nosql/infinispan/index.js +200 -0
- package/dist/nosql/influxdb/index.js +0 -0
- package/dist/nosql/kafka/index.js +234 -0
- package/dist/nosql/keyspaces/index.js +189 -0
- package/dist/nosql/kinesis/index.js +253 -0
- package/dist/nosql/leveldb/index.js +153 -0
- package/dist/nosql/lmdb/index.js +160 -0
- package/dist/nosql/loki/index.js +201 -0
- package/dist/nosql/marklogic/index.js +204 -0
- package/dist/nosql/materialize/index.js +145 -0
- package/dist/nosql/meilisearch/index.js +154 -0
- package/dist/nosql/memcached/index.js +223 -0
- package/dist/nosql/milvus/index.js +410 -0
- package/dist/nosql/minio/index.js +265 -0
- package/dist/nosql/momento/index.js +179 -0
- package/dist/nosql/mongodb/index.js +461 -0
- package/dist/nosql/nats/index.js +247 -0
- package/dist/nosql/nedb/index.js +164 -0
- package/dist/nosql/neo4j/index.js +450 -0
- package/dist/nosql/neptune/index.js +470 -0
- package/dist/nosql/nsq/index.js +200 -0
- package/dist/nosql/opensearch/index.js +186 -0
- package/dist/nosql/orientdb/index.js +175 -0
- package/dist/nosql/papertrail/index.js +200 -0
- package/dist/nosql/pinecone/index.js +0 -0
- package/dist/nosql/pinot/index.js +133 -0
- package/dist/nosql/pouchdb/index.js +172 -0
- package/dist/nosql/prometheus/index.js +174 -0
- package/dist/nosql/provendb/index.js +147 -0
- package/dist/nosql/pubsub/index.js +187 -0
- package/dist/nosql/pulsar/index.js +232 -0
- package/dist/nosql/qdrant/index.js +295 -0
- package/dist/nosql/qldb/index.js +192 -0
- package/dist/nosql/r2/index.js +281 -0
- package/dist/nosql/rabbitmq/index.js +237 -0
- package/dist/nosql/ravendb/index.js +175 -0
- package/dist/nosql/redis/index.js +607 -0
- package/dist/nosql/redpanda/index.js +237 -0
- package/dist/nosql/resque/index.js +203 -0
- package/dist/nosql/rethinkdb/index.js +232 -0
- package/dist/nosql/rocksdb/index.js +152 -0
- package/dist/nosql/rockset/index.js +126 -0
- package/dist/nosql/s3/index.js +298 -0
- package/dist/nosql/scylladb/index.js +178 -0
- package/dist/nosql/signoz/index.js +227 -0
- package/dist/nosql/sns/index.js +201 -0
- package/dist/nosql/solr/index.js +231 -0
- package/dist/nosql/splunk/index.js +227 -0
- package/dist/nosql/sqs/index.js +246 -0
- package/dist/nosql/stardog/index.js +169 -0
- package/dist/nosql/starrocks/index.js +170 -0
- package/dist/nosql/store.js +2 -0
- package/dist/nosql/sumologic/index.js +213 -0
- package/dist/nosql/surrealdb/index.js +179 -0
- package/dist/nosql/terminusdb/index.js +151 -0
- package/dist/nosql/tigergraph/index.js +469 -0
- package/dist/nosql/typesense/index.js +148 -0
- package/dist/nosql/unqlite/index.js +157 -0
- package/dist/nosql/upstash/index.js +167 -0
- package/dist/nosql/vercel-kv/index.js +166 -0
- package/dist/nosql/victoriametrics/index.js +213 -0
- package/dist/nosql/virtuoso/index.js +169 -0
- package/dist/nosql/weaviate/index.js +276 -0
- package/dist/operators/index.js +108 -0
- package/dist/operators.js +2690 -0
- package/dist/prisma-migrate/index.js +38 -0
- package/dist/prisma-migrate/migration-generator.js +125 -0
- package/dist/prisma-migrate/model-generator.js +172 -0
- package/dist/prisma-migrate/relations.js +100 -0
- package/dist/prisma-migrate/schema-parser.js +167 -0
- package/dist/prisma-migrate/type-mapper.js +40 -0
- package/dist/prorm.js +6832 -0
- package/dist/query-builders/cte-builder.js +80 -0
- package/dist/query-builders/functions/aggregate.js +390 -0
- package/dist/query-builders/functions/conditional.js +503 -0
- package/dist/query-builders/functions/datetime.js +695 -0
- package/dist/query-builders/functions/fulltext.js +439 -0
- package/dist/query-builders/functions/index.js +93 -0
- package/dist/query-builders/functions/json.js +427 -0
- package/dist/query-builders/functions/math.js +399 -0
- package/dist/query-builders/functions/string.js +518 -0
- package/dist/query-builders/functions/window.js +328 -0
- package/dist/query-builders/include-builder.js +323 -0
- package/dist/query-builders/index-expression-builder.js +242 -0
- package/dist/query-builders/index.js +161 -0
- package/dist/query-builders/insert-builder.js +164 -0
- package/dist/query-builders/model-helpers.js +38 -0
- package/dist/query-builders/order-limit-builder.js +239 -0
- package/dist/query-builders/sql-compiler.js +2040 -0
- package/dist/query-builders/subquery-builder.js +152 -0
- package/dist/query-builders/update-builder.js +182 -0
- package/dist/query-builders/view-builder.js +218 -0
- package/dist/query-builders/where-builder.js +1532 -0
- package/dist/query-interface.js +622 -0
- package/dist/query-optimizers/batch-optimizer.js +426 -0
- package/dist/query-optimizers/explain-plans.js +415 -0
- package/dist/query-optimizers/index.js +51 -0
- package/dist/query-optimizers/prepared-statement-cache.js +423 -0
- package/dist/query-optimizers/query-hints.js +438 -0
- package/dist/query-optimizers/query-optimizer.js +278 -0
- package/dist/query-optimizers/slow-query-logger.js +271 -0
- package/dist/replica-manager.js +507 -0
- package/dist/schema/index.js +15 -0
- package/dist/schema/migration-generator.js +374 -0
- package/dist/schema/schema-differ.js +549 -0
- package/dist/schema/types.js +6 -0
- package/dist/sql-constants.js +300 -0
- package/dist/sqlite-advanced.js +1047 -0
- package/dist/streams/index.js +12 -0
- package/dist/streams/transforms.js +178 -0
- package/dist/transaction.js +456 -0
- package/dist/types/index.js +180 -0
- package/dist/user-management.js +127 -0
- package/dist/utils/date.js +300 -0
- package/dist/utils/index.js +1079 -0
- package/dist/utils/string.js +161 -0
- package/dist/validators/index.js +19 -0
- package/dist/validators/validator.js +911 -0
- package/package.json +190 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MigrationDiagram — generates an SVG showing database schema changes.
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Shows tables with their columns (before/after or just new state)
|
|
7
|
+
* - Color-coded change indicators: green (added), red (removed), yellow (modified)
|
|
8
|
+
* - Migration metadata header with timestamp and description
|
|
9
|
+
* - Support for multiple migration steps
|
|
10
|
+
* - Compact field rows with type badges
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* const diag = new MigrationDiagram({
|
|
14
|
+
* title: 'User Migration',
|
|
15
|
+
* description: 'Add email verification fields',
|
|
16
|
+
* changes: [
|
|
17
|
+
* { table: 'users', type: 'modify', changes: [...] },
|
|
18
|
+
* { table: 'sessions', type: 'add', changes: [...] },
|
|
19
|
+
* ]
|
|
20
|
+
* });
|
|
21
|
+
* diag.save('./diagrams/migration.svg');
|
|
22
|
+
*/
|
|
23
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
26
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
27
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
28
|
+
}
|
|
29
|
+
Object.defineProperty(o, k2, desc);
|
|
30
|
+
}) : (function(o, m, k, k2) {
|
|
31
|
+
if (k2 === undefined) k2 = k;
|
|
32
|
+
o[k2] = m[k];
|
|
33
|
+
}));
|
|
34
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
35
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
36
|
+
}) : function(o, v) {
|
|
37
|
+
o["default"] = v;
|
|
38
|
+
});
|
|
39
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
40
|
+
var ownKeys = function(o) {
|
|
41
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
42
|
+
var ar = [];
|
|
43
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
44
|
+
return ar;
|
|
45
|
+
};
|
|
46
|
+
return ownKeys(o);
|
|
47
|
+
};
|
|
48
|
+
return function (mod) {
|
|
49
|
+
if (mod && mod.__esModule) return mod;
|
|
50
|
+
var result = {};
|
|
51
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
52
|
+
__setModuleDefault(result, mod);
|
|
53
|
+
return result;
|
|
54
|
+
};
|
|
55
|
+
})();
|
|
56
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
57
|
+
exports.MigrationDiagram = void 0;
|
|
58
|
+
const fs = __importStar(require("fs"));
|
|
59
|
+
const path = __importStar(require("path"));
|
|
60
|
+
// ─── Constants ─────────────────────────────────────────────────────────────
|
|
61
|
+
const CHANGE_COLORS = {
|
|
62
|
+
add: { header: '#065F46', mid: '#059669', light: '#D1FAE5', text: '#065F46', icon: '#059669' },
|
|
63
|
+
remove: { header: '#7F1D1D', mid: '#DC2626', light: '#FEE2E2', text: '#7F1D1D', icon: '#DC2626' },
|
|
64
|
+
modify: { header: '#92400E', mid: '#D97706', light: '#FEF3C7', text: '#92400E', icon: '#D97706' },
|
|
65
|
+
};
|
|
66
|
+
const TABLE_COLORS = [
|
|
67
|
+
{ header: '#1E3A8A', mid: '#2563EB', light: '#DBEAFE', text: '#1E3A8A' },
|
|
68
|
+
{ header: '#5B21B6', mid: '#7C3AED', light: '#EDE9FE', text: '#5B21B6' },
|
|
69
|
+
{ header: '#065F46', mid: '#059669', light: '#D1FAE5', text: '#065F46' },
|
|
70
|
+
{ header: '#92400E', mid: '#D97706', light: '#FEF3C7', text: '#92400E' },
|
|
71
|
+
{ header: '#831843', mid: '#DB2777', light: '#FCE7F3', text: '#831843' },
|
|
72
|
+
{ header: '#0C4A6E', mid: '#0284C7', light: '#E0F2FE', text: '#0C4A6E' },
|
|
73
|
+
];
|
|
74
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
75
|
+
function xmlEsc(s) {
|
|
76
|
+
return String(s ?? '')
|
|
77
|
+
.replace(/&/g, '&')
|
|
78
|
+
.replace(/</g, '<')
|
|
79
|
+
.replace(/>/g, '>')
|
|
80
|
+
.replace(/"/g, '"');
|
|
81
|
+
}
|
|
82
|
+
function typeBadgeColor(type) {
|
|
83
|
+
const t = type.toUpperCase();
|
|
84
|
+
if (/STRING|VARCHAR|CHAR|TEXT/i.test(t))
|
|
85
|
+
return { text: '#059669', bg: '#D1FAE5' };
|
|
86
|
+
if (/INT|BIGINT|SMALLINT|FLOAT|DOUBLE|DECIMAL/i.test(t))
|
|
87
|
+
return { text: '#7C3AED', bg: '#EDE9FE' };
|
|
88
|
+
if (/DATE|TIME|TIMESTAMP/i.test(t))
|
|
89
|
+
return { text: '#EA580C', bg: '#FFEDD5' };
|
|
90
|
+
if (/BOOL/i.test(t))
|
|
91
|
+
return { text: '#DB2777', bg: '#FCE7F3' };
|
|
92
|
+
if (/UUID/i.test(t))
|
|
93
|
+
return { text: '#0891B2', bg: '#CFFAFE' };
|
|
94
|
+
if (/JSON/i.test(t))
|
|
95
|
+
return { text: '#4F46E5', bg: '#E0E7FF' };
|
|
96
|
+
return { text: '#475569', bg: '#F1F5F9' };
|
|
97
|
+
}
|
|
98
|
+
// ─── Main class ────────────────────────────────────────────────────────────
|
|
99
|
+
class MigrationDiagram {
|
|
100
|
+
constructor(options) {
|
|
101
|
+
this.opts = {
|
|
102
|
+
title: options.title ?? 'Database Migration',
|
|
103
|
+
description: options.description ?? '',
|
|
104
|
+
timestamp: options.timestamp ?? new Date().toISOString(),
|
|
105
|
+
changes: options.changes ?? [],
|
|
106
|
+
theme: options.theme ?? 'light',
|
|
107
|
+
color: options.color ?? 'blue',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// ── Compute layout positions ─────────────────────────────────────────
|
|
111
|
+
computeLayout() {
|
|
112
|
+
const layout = [];
|
|
113
|
+
let y = this.opts.changes.length > 0 ? MigrationDiagram.BANNER_H + MigrationDiagram.MARGIN : 0;
|
|
114
|
+
let maxW = 0;
|
|
115
|
+
this.opts.changes.forEach((change, idx) => {
|
|
116
|
+
const rowCount = Math.max((change.changes ?? []).length, 1);
|
|
117
|
+
const h = MigrationDiagram.BOX_HDR + rowCount * MigrationDiagram.BOX_ROW + MigrationDiagram.FOOT_H;
|
|
118
|
+
const x = MigrationDiagram.MARGIN;
|
|
119
|
+
layout.push({
|
|
120
|
+
change,
|
|
121
|
+
x,
|
|
122
|
+
y,
|
|
123
|
+
w: MigrationDiagram.BOX_W,
|
|
124
|
+
h,
|
|
125
|
+
colorIdx: idx % TABLE_COLORS.length,
|
|
126
|
+
});
|
|
127
|
+
maxW = Math.max(maxW, MigrationDiagram.BOX_W);
|
|
128
|
+
y += h + MigrationDiagram.V_GAP;
|
|
129
|
+
});
|
|
130
|
+
return layout;
|
|
131
|
+
}
|
|
132
|
+
// ── Render banner ────────────────────────────────────────────────────
|
|
133
|
+
renderBanner(totalW) {
|
|
134
|
+
const H = MigrationDiagram.BANNER_H;
|
|
135
|
+
const { title, description, timestamp } = this.opts;
|
|
136
|
+
return `
|
|
137
|
+
<!-- ═══ BANNER ═══ -->
|
|
138
|
+
<defs>
|
|
139
|
+
<linearGradient id="migBanner" x1="0" y1="0" x2="1" y2="0"
|
|
140
|
+
gradientUnits="objectBoundingBox">
|
|
141
|
+
<stop offset="0%" stop-color="#7C3AED"/>
|
|
142
|
+
<stop offset="100%" stop-color="#A855F7"/>
|
|
143
|
+
</linearGradient>
|
|
144
|
+
<filter id="migBannerSh" x="-5%" y="-5%" width="110%" height="120%">
|
|
145
|
+
<feDropShadow dx="0" dy="4" stdDeviation="8" flood-color="#7C3AED30"/>
|
|
146
|
+
</filter>
|
|
147
|
+
</defs>
|
|
148
|
+
<rect width="${totalW}" height="${H}" fill="url(#migBanner)" filter="url(#migBannerSh)"/>
|
|
149
|
+
|
|
150
|
+
<!-- Database icon (SVG) -->
|
|
151
|
+
<g transform="translate(30, 24)">
|
|
152
|
+
<ellipse cx="14" cy="8" rx="12" ry="4" fill="white" opacity="0.3"/>
|
|
153
|
+
<path d="M2 12v12c0 2.2 5.4 4 12 4s12-1.8 12-4V12" fill="white" opacity="0.9"/>
|
|
154
|
+
<path d="M2 16c0 2.2 5.4 4 12 4s12-1.8 12-4" fill="none" stroke="white" stroke-width="1.5" opacity="0.5"/>
|
|
155
|
+
<path d="M2 20c0 2.2 5.4 4 12 4s12-1.8 12-4" fill="none" stroke="white" stroke-width="1.5" opacity="0.3"/>
|
|
156
|
+
</g>
|
|
157
|
+
|
|
158
|
+
<text x="58" y="36" font-family="system-ui" font-size="22" font-weight="800" fill="white">${xmlEsc(title)}</text>
|
|
159
|
+
<text x="58" y="54" font-family="system-ui" font-size="12" fill="rgba(255,255,255,0.75)">${xmlEsc(description)}</text>
|
|
160
|
+
<text x="${totalW - 30}" y="54" font-family="'SF Mono',monospace" font-size="11" fill="rgba(255,255,255,0.6)" text-anchor="end">${timestamp}</text>
|
|
161
|
+
|
|
162
|
+
<!-- Migration tag -->
|
|
163
|
+
<rect x="${totalW - 130}" y="20" width="100" height="26" rx="13" fill="rgba(255,255,255,0.15)"/>
|
|
164
|
+
<text x="${totalW - 80}" y="38" font-family="'SF Mono',monospace" font-size="11" font-weight="700" fill="white" text-anchor="middle">MIGRATION</text>`;
|
|
165
|
+
}
|
|
166
|
+
// ── Render a table change box ─────────────────────────────────────────
|
|
167
|
+
renderChangeBox(item) {
|
|
168
|
+
const { change, x, y, w, h, colorIdx } = item;
|
|
169
|
+
// Fallback color for unknown/undefined change types so `colors.header` etc.
|
|
170
|
+
// never throw.
|
|
171
|
+
const colors = CHANGE_COLORS[change.type] ?? {
|
|
172
|
+
header: '#334155',
|
|
173
|
+
mid: '#475569',
|
|
174
|
+
light: '#E2E8F0',
|
|
175
|
+
text: '#334155',
|
|
176
|
+
icon: '#475569',
|
|
177
|
+
};
|
|
178
|
+
const R = 10;
|
|
179
|
+
// Sanitize the table name for use in an SVG element id (must be a valid,
|
|
180
|
+
// unique NCName) and escape it wherever it lands in markup/comments.
|
|
181
|
+
const safeId = String(change.table ?? 'table').replace(/\W/g, '') + colorIdx;
|
|
182
|
+
const changes = change.changes ?? [];
|
|
183
|
+
let out = `\n <!-- Change: ${xmlEsc(change.table)} (${xmlEsc(change.type)}) -->`;
|
|
184
|
+
// Shadow
|
|
185
|
+
out += `\n <defs>
|
|
186
|
+
<filter id="migSh${safeId}" x="-8%" y="-8%" width="116%" height="130%">
|
|
187
|
+
<feDropShadow dx="0" dy="3" stdDeviation="5" flood-color="#00000015"/>
|
|
188
|
+
</filter>
|
|
189
|
+
</defs>`;
|
|
190
|
+
// Box background
|
|
191
|
+
out += `\n <rect x="${x}" y="${y}" width="${w}" height="${h}" rx="${R}" fill="white" filter="url(#migSh${safeId})"/>`;
|
|
192
|
+
// Header with change type indicator
|
|
193
|
+
out += `\n <rect x="${x}" y="${y}" width="${w}" height="${MigrationDiagram.BOX_HDR}" rx="${R}" fill="${colors.header}"/>`;
|
|
194
|
+
// Change type badge
|
|
195
|
+
out += `\n <rect x="${x + 12}" y="${y + 10}" width="56" height="22" rx="6" fill="${colors.light}"/>`;
|
|
196
|
+
out += `\n <text x="${x + 40}" y="${y + 25}" font-family="'SF Mono',monospace" font-size="10" font-weight="700" fill="${colors.text}" text-anchor="middle">${xmlEsc(String(change.type ?? '').toUpperCase())}</text>`;
|
|
197
|
+
// Table name
|
|
198
|
+
out += `\n <text x="${x + 80}" y="${y + 27}" font-family="system-ui" font-size="15" font-weight="700" fill="white">${xmlEsc(change.table)}</text>`;
|
|
199
|
+
// Column changes
|
|
200
|
+
changes.forEach((col, i) => {
|
|
201
|
+
const fy = y + MigrationDiagram.BOX_HDR + i * MigrationDiagram.BOX_ROW;
|
|
202
|
+
const rowBg = i % 2 === 0 ? '#FFFFFF' : '#F9FAFB';
|
|
203
|
+
const tc = typeBadgeColor(col.type);
|
|
204
|
+
out += `\n <rect x="${x}" y="${fy}" width="${w}" height="${MigrationDiagram.BOX_ROW}" fill="${rowBg}"/>`;
|
|
205
|
+
// Change indicator stripe
|
|
206
|
+
const stripeColor = col.action === 'add' ? '#059669' : col.action === 'remove' ? '#DC2626' : '#D97706';
|
|
207
|
+
out += `\n <rect x="${x}" y="${fy}" width="4" height="${MigrationDiagram.BOX_ROW}" fill="${stripeColor}"/>`;
|
|
208
|
+
// Action icon (SVG)
|
|
209
|
+
const ix = x + 16;
|
|
210
|
+
const iy = fy + MigrationDiagram.BOX_ROW / 2;
|
|
211
|
+
if (col.action === 'add') {
|
|
212
|
+
out += `\n <circle cx="${ix}" cy="${iy}" r="6" fill="${stripeColor}"/>
|
|
213
|
+
<path d="M${ix - 3} ${iy}v6M${ix} ${iy - 3}h6" stroke="white" stroke-width="2" fill="none"/>`;
|
|
214
|
+
}
|
|
215
|
+
else if (col.action === 'remove') {
|
|
216
|
+
out += `\n <circle cx="${ix}" cy="${iy}" r="6" fill="${stripeColor}"/>
|
|
217
|
+
<path d="M${ix - 3} ${iy}h6" stroke="white" stroke-width="2" fill="none"/>`;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
out += `\n <circle cx="${ix}" cy="${iy}" r="6" fill="${stripeColor}"/>
|
|
221
|
+
<path d="M${ix - 3} ${iy}h6" stroke="white" stroke-width="2" fill="none"/>
|
|
222
|
+
<path d="M${ix} ${iy - 3}v6" stroke="white" stroke-width="2" fill="none"/>`;
|
|
223
|
+
}
|
|
224
|
+
// Column name
|
|
225
|
+
const nameX = x + 36;
|
|
226
|
+
const nameW = col.action === 'modify' && col.oldType ? '600' : '500';
|
|
227
|
+
out += `\n <text x="${nameX}" y="${iy + 4}" font-family="'SF Mono',monospace" font-size="12" font-weight="${nameW}" fill="#1E293B">${xmlEsc(col.name)}</text>`;
|
|
228
|
+
// Type badge
|
|
229
|
+
if (col.action === 'modify' && col.oldType) {
|
|
230
|
+
// Show old → new type
|
|
231
|
+
out += `\n <text x="${x + w - 10}" y="${iy + 4}" font-family="'SF Mono',monospace" font-size="9" fill="#94A3B8" text-anchor="end">${xmlEsc(col.oldType)} → ${xmlEsc(col.type)}</text>`;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
const tbW = col.type.length * 6 + 12;
|
|
235
|
+
out += `\n <rect x="${x + w - tbW - 8}" y="${fy + 6}" width="${tbW}" height="16" rx="4" fill="${tc.bg}"/>`;
|
|
236
|
+
out += `\n <text x="${x + w - tbW / 2 - 8}" y="${fy + 18}" font-family="'SF Mono',monospace" font-size="9" font-weight="600" fill="${tc.text}" text-anchor="middle">${xmlEsc(col.type.slice(0, 12))}</text>`;
|
|
237
|
+
}
|
|
238
|
+
// Row separator
|
|
239
|
+
out += `\n <line x1="${x}" y1="${fy + MigrationDiagram.BOX_ROW}" x2="${x + w}" y2="${fy + MigrationDiagram.BOX_ROW}" stroke="#E2E8F0"/>`;
|
|
240
|
+
});
|
|
241
|
+
// Footer
|
|
242
|
+
const footY = y + MigrationDiagram.BOX_HDR + changes.length * MigrationDiagram.BOX_ROW;
|
|
243
|
+
out += `\n <rect x="${x}" y="${footY}" width="${w}" height="${MigrationDiagram.FOOT_H}" fill="${colors.light}" rx="0 0 ${R} ${R}"/>`;
|
|
244
|
+
out += `\n <text x="${x + 12}" y="${footY + 18}" font-family="system-ui" font-size="10" fill="${colors.text}" font-weight="600">${changes.length} change${changes.length !== 1 ? 's' : ''}</text>`;
|
|
245
|
+
return out;
|
|
246
|
+
}
|
|
247
|
+
// ── Render legend ────────────────────────────────────────────────────
|
|
248
|
+
renderLegend(x, y) {
|
|
249
|
+
const items = [
|
|
250
|
+
{ label: 'Added', color: '#059669', bg: '#D1FAE5' },
|
|
251
|
+
{ label: 'Removed', color: '#DC2626', bg: '#FEE2E2' },
|
|
252
|
+
{ label: 'Modified', color: '#D97706', bg: '#FEF3C7' },
|
|
253
|
+
];
|
|
254
|
+
let out = `\n <!-- LEGEND -->`;
|
|
255
|
+
items.forEach((item, i) => {
|
|
256
|
+
const ix = x + i * 110;
|
|
257
|
+
out += `\n <rect x="${ix}" y="${y}" width="90" height="28" rx="6" fill="${item.bg}"/>`;
|
|
258
|
+
out += `\n <circle cx="${ix + 16}" cy="${y + 14}" r="6" fill="${item.color}"/>`;
|
|
259
|
+
out += `\n <text x="${ix + 30}" y="${y + 18}" font-family="system-ui" font-size="11" font-weight="600" fill="${item.color}">${item.label}</text>`;
|
|
260
|
+
});
|
|
261
|
+
return out;
|
|
262
|
+
}
|
|
263
|
+
// ── Generate full SVG ────────────────────────────────────────────────
|
|
264
|
+
generate() {
|
|
265
|
+
const { changes } = this.opts;
|
|
266
|
+
const MARGIN = MigrationDiagram.MARGIN;
|
|
267
|
+
const BANNER = MigrationDiagram.BANNER_H;
|
|
268
|
+
const layout = this.computeLayout();
|
|
269
|
+
// Calculate dimensions
|
|
270
|
+
let totalW = MigrationDiagram.BOX_W + 2 * MARGIN + 100;
|
|
271
|
+
let totalH = BANNER + MARGIN;
|
|
272
|
+
if (layout.length > 0) {
|
|
273
|
+
const lastItem = layout[layout.length - 1];
|
|
274
|
+
totalH = lastItem.y + lastItem.h + MARGIN + 50;
|
|
275
|
+
}
|
|
276
|
+
const svg = [
|
|
277
|
+
`<?xml version="1.0" encoding="UTF-8"?>`,
|
|
278
|
+
`<!-- Generated by ts-prorm-orm MigrationDiagram -->`,
|
|
279
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="${totalW}" height="${totalH}" viewBox="0 0 ${totalW} ${totalH}">`,
|
|
280
|
+
` <rect width="${totalW}" height="${totalH}" fill="#F8FAFC"/>`,
|
|
281
|
+
];
|
|
282
|
+
// Banner
|
|
283
|
+
svg.push(this.renderBanner(totalW));
|
|
284
|
+
// Change boxes
|
|
285
|
+
layout.forEach((item) => {
|
|
286
|
+
svg.push(this.renderChangeBox(item));
|
|
287
|
+
});
|
|
288
|
+
// Legend
|
|
289
|
+
if (layout.length > 0) {
|
|
290
|
+
svg.push(this.renderLegend(MARGIN, totalH - 50));
|
|
291
|
+
}
|
|
292
|
+
svg.push(`</svg>`);
|
|
293
|
+
return svg.join('\n');
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Write the SVG to a file.
|
|
297
|
+
*/
|
|
298
|
+
save(outputPath) {
|
|
299
|
+
const resolved = path.resolve(outputPath);
|
|
300
|
+
const dir = path.dirname(resolved);
|
|
301
|
+
if (!fs.existsSync(dir))
|
|
302
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
303
|
+
const svg = this.generate();
|
|
304
|
+
fs.writeFileSync(resolved, svg, 'utf-8');
|
|
305
|
+
return resolved;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
exports.MigrationDiagram = MigrationDiagram;
|
|
309
|
+
// Layout constants
|
|
310
|
+
MigrationDiagram.BOX_W = 320;
|
|
311
|
+
MigrationDiagram.BOX_HDR = 42;
|
|
312
|
+
MigrationDiagram.BOX_ROW = 28;
|
|
313
|
+
MigrationDiagram.FOOT_H = 28;
|
|
314
|
+
MigrationDiagram.MARGIN = 40;
|
|
315
|
+
MigrationDiagram.BANNER_H = 80;
|
|
316
|
+
MigrationDiagram.V_GAP = 50;
|