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,549 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Schema Differ
|
|
4
|
+
* Compares model definitions against database schema to detect changes
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.SchemaDiffer = void 0;
|
|
8
|
+
exports.createSchemaDiffer = createSchemaDiffer;
|
|
9
|
+
/**
|
|
10
|
+
* SchemaDiffer compares model definitions against database schema
|
|
11
|
+
*/
|
|
12
|
+
class SchemaDiffer {
|
|
13
|
+
constructor(dialect, options = {}) {
|
|
14
|
+
this.dialect = dialect;
|
|
15
|
+
this.options = {
|
|
16
|
+
compareIndexes: true,
|
|
17
|
+
compareConstraints: true,
|
|
18
|
+
compareForeignKeys: true,
|
|
19
|
+
serializeColumnType: (type) => this.serializeDataType(type),
|
|
20
|
+
...options,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Compare a model against its database table
|
|
25
|
+
*/
|
|
26
|
+
async diffModel(model) {
|
|
27
|
+
const tableName = model.tableName || model.name;
|
|
28
|
+
const schemaName = model.schema;
|
|
29
|
+
// Get model definition
|
|
30
|
+
const modelColumns = this.extractColumnDefinitions(model);
|
|
31
|
+
const modelIndexes = this.extractIndexDefinitions(model);
|
|
32
|
+
const modelConstraints = this.extractConstraintDefinitions(model);
|
|
33
|
+
const modelForeignKeys = this.extractForeignKeyDefinitions(model);
|
|
34
|
+
// Get database definition
|
|
35
|
+
const dbColumns = await this.getDatabaseColumns(tableName, schemaName);
|
|
36
|
+
const dbIndexes = this.options.compareIndexes
|
|
37
|
+
? await this.getDatabaseIndexes(tableName, schemaName)
|
|
38
|
+
: [];
|
|
39
|
+
const dbConstraints = this.options.compareConstraints
|
|
40
|
+
? await this.getDatabaseConstraints(tableName, schemaName)
|
|
41
|
+
: [];
|
|
42
|
+
const dbForeignKeys = this.options.compareForeignKeys
|
|
43
|
+
? await this.getDatabaseForeignKeys(tableName, schemaName)
|
|
44
|
+
: [];
|
|
45
|
+
// Compute changes
|
|
46
|
+
const columnChanges = this.getColumnChanges(modelColumns, dbColumns);
|
|
47
|
+
const indexChanges = this.getIndexChanges(modelIndexes, dbIndexes);
|
|
48
|
+
const constraintChanges = this.getConstraintChanges(modelConstraints, dbConstraints);
|
|
49
|
+
const foreignKeyChanges = this.getForeignKeyChanges(modelForeignKeys, dbForeignKeys);
|
|
50
|
+
const hasChanges = columnChanges.length > 0 ||
|
|
51
|
+
indexChanges.length > 0 ||
|
|
52
|
+
constraintChanges.length > 0 ||
|
|
53
|
+
foreignKeyChanges.length > 0;
|
|
54
|
+
return {
|
|
55
|
+
modelName: model.name,
|
|
56
|
+
tableName,
|
|
57
|
+
schemaName,
|
|
58
|
+
changes: {
|
|
59
|
+
columns: columnChanges,
|
|
60
|
+
indexes: indexChanges,
|
|
61
|
+
constraints: constraintChanges,
|
|
62
|
+
foreignKeys: foreignKeyChanges,
|
|
63
|
+
},
|
|
64
|
+
hasChanges,
|
|
65
|
+
generatedAt: new Date(),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Diff all models registered with Prorm
|
|
70
|
+
*/
|
|
71
|
+
async diffAll() {
|
|
72
|
+
const prorm = this.dialect.prorm;
|
|
73
|
+
if (!prorm) {
|
|
74
|
+
throw new Error('Dialect is not associated with a Prorm instance');
|
|
75
|
+
}
|
|
76
|
+
const models = prorm.models || {};
|
|
77
|
+
const diffs = [];
|
|
78
|
+
for (const model of Object.values(models)) {
|
|
79
|
+
if (model && model.name) {
|
|
80
|
+
const diff = await this.diffModel(model);
|
|
81
|
+
if (diff.hasChanges) {
|
|
82
|
+
diffs.push(diff);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return diffs;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get column changes between model and database
|
|
90
|
+
*/
|
|
91
|
+
getColumnChanges(modelColumns, dbColumns) {
|
|
92
|
+
const changes = [];
|
|
93
|
+
const dbColumnMap = new Map(dbColumns.map((c) => [c.name, c]));
|
|
94
|
+
const modelColumnMap = new Map(modelColumns.map((c) => [c.name, c]));
|
|
95
|
+
// Check for new or modified columns
|
|
96
|
+
for (const modelCol of modelColumns) {
|
|
97
|
+
const dbCol = dbColumnMap.get(modelCol.name);
|
|
98
|
+
if (!dbCol) {
|
|
99
|
+
// New column
|
|
100
|
+
changes.push({
|
|
101
|
+
type: 'column',
|
|
102
|
+
changeType: 'create',
|
|
103
|
+
columnName: modelCol.name,
|
|
104
|
+
modelDefinition: modelCol,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
// Check for modifications
|
|
109
|
+
const changedProps = this.compareColumnDefinitions(modelCol, dbCol);
|
|
110
|
+
if (changedProps.length > 0) {
|
|
111
|
+
changes.push({
|
|
112
|
+
type: 'column',
|
|
113
|
+
changeType: 'modify',
|
|
114
|
+
columnName: modelCol.name,
|
|
115
|
+
modelDefinition: modelCol,
|
|
116
|
+
databaseDefinition: dbCol,
|
|
117
|
+
changedProperties: changedProps,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Check for deleted columns
|
|
123
|
+
for (const dbCol of dbColumns) {
|
|
124
|
+
if (!modelColumnMap.has(dbCol.name)) {
|
|
125
|
+
changes.push({
|
|
126
|
+
type: 'column',
|
|
127
|
+
changeType: 'delete',
|
|
128
|
+
columnName: dbCol.name,
|
|
129
|
+
databaseDefinition: dbCol,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return changes;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get index changes between model and database
|
|
137
|
+
*/
|
|
138
|
+
getIndexChanges(modelIndexes, dbIndexes) {
|
|
139
|
+
const changes = [];
|
|
140
|
+
const dbIndexMap = new Map(dbIndexes.map((i) => [i.name, i]));
|
|
141
|
+
const modelIndexMap = new Map(modelIndexes.map((i) => [i.name, i]));
|
|
142
|
+
// Check for new or modified indexes
|
|
143
|
+
for (const modelIdx of modelIndexes) {
|
|
144
|
+
const dbIdx = dbIndexMap.get(modelIdx.name);
|
|
145
|
+
if (!dbIdx) {
|
|
146
|
+
changes.push({
|
|
147
|
+
type: 'index',
|
|
148
|
+
changeType: 'create',
|
|
149
|
+
indexName: modelIdx.name,
|
|
150
|
+
modelDefinition: modelIdx,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
const changedProps = this.compareIndexDefinitions(modelIdx, dbIdx);
|
|
155
|
+
if (changedProps.length > 0) {
|
|
156
|
+
changes.push({
|
|
157
|
+
type: 'index',
|
|
158
|
+
changeType: 'modify',
|
|
159
|
+
indexName: modelIdx.name,
|
|
160
|
+
modelDefinition: modelIdx,
|
|
161
|
+
databaseDefinition: dbIdx,
|
|
162
|
+
changedProperties: changedProps,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Check for deleted indexes
|
|
168
|
+
for (const dbIdx of dbIndexes) {
|
|
169
|
+
if (!modelIndexMap.has(dbIdx.name) && !dbIdx.primary) {
|
|
170
|
+
changes.push({
|
|
171
|
+
type: 'index',
|
|
172
|
+
changeType: 'delete',
|
|
173
|
+
indexName: dbIdx.name,
|
|
174
|
+
databaseDefinition: dbIdx,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return changes;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get constraint changes between model and database
|
|
182
|
+
*/
|
|
183
|
+
getConstraintChanges(modelConstraints, dbConstraints) {
|
|
184
|
+
const changes = [];
|
|
185
|
+
const dbConstraintMap = new Map(dbConstraints.map((c) => [c.name, c]));
|
|
186
|
+
const modelConstraintMap = new Map(modelConstraints.map((c) => [c.name, c]));
|
|
187
|
+
// Check for new or modified constraints
|
|
188
|
+
for (const modelCon of modelConstraints) {
|
|
189
|
+
const dbCon = dbConstraintMap.get(modelCon.name);
|
|
190
|
+
if (!dbCon) {
|
|
191
|
+
changes.push({
|
|
192
|
+
type: 'constraint',
|
|
193
|
+
changeType: 'create',
|
|
194
|
+
constraintName: modelCon.name,
|
|
195
|
+
constraintType: modelCon.type,
|
|
196
|
+
modelDefinition: modelCon,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
const changedProps = this.compareConstraintDefinitions(modelCon, dbCon);
|
|
201
|
+
if (changedProps.length > 0) {
|
|
202
|
+
changes.push({
|
|
203
|
+
type: 'constraint',
|
|
204
|
+
changeType: 'modify',
|
|
205
|
+
constraintName: modelCon.name,
|
|
206
|
+
constraintType: modelCon.type,
|
|
207
|
+
modelDefinition: modelCon,
|
|
208
|
+
databaseDefinition: dbCon,
|
|
209
|
+
changedProperties: changedProps,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Check for deleted constraints
|
|
215
|
+
for (const dbCon of dbConstraints) {
|
|
216
|
+
if (!modelConstraintMap.has(dbCon.name)) {
|
|
217
|
+
changes.push({
|
|
218
|
+
type: 'constraint',
|
|
219
|
+
changeType: 'delete',
|
|
220
|
+
constraintName: dbCon.name,
|
|
221
|
+
constraintType: dbCon.type,
|
|
222
|
+
databaseDefinition: dbCon,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return changes;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get foreign key changes between model and database
|
|
230
|
+
*/
|
|
231
|
+
getForeignKeyChanges(modelFKs, dbFKs) {
|
|
232
|
+
const changes = [];
|
|
233
|
+
const dbFKMap = new Map(dbFKs.map((f) => [f.name, f]));
|
|
234
|
+
const modelFKMap = new Map(modelFKs.map((f) => [f.name, f]));
|
|
235
|
+
// Check for new or modified foreign keys
|
|
236
|
+
for (const modelFK of modelFKs) {
|
|
237
|
+
const dbFK = dbFKMap.get(modelFK.name);
|
|
238
|
+
if (!dbFK) {
|
|
239
|
+
changes.push({
|
|
240
|
+
type: 'foreignKey',
|
|
241
|
+
changeType: 'create',
|
|
242
|
+
constraintName: modelFK.name,
|
|
243
|
+
modelDefinition: modelFK,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
const changedProps = this.compareForeignKeyDefinitions(modelFK, dbFK);
|
|
248
|
+
if (changedProps.length > 0) {
|
|
249
|
+
changes.push({
|
|
250
|
+
type: 'foreignKey',
|
|
251
|
+
changeType: 'modify',
|
|
252
|
+
constraintName: modelFK.name,
|
|
253
|
+
modelDefinition: modelFK,
|
|
254
|
+
databaseDefinition: dbFK,
|
|
255
|
+
changedProperties: changedProps,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// Check for deleted foreign keys
|
|
261
|
+
for (const dbFK of dbFKs) {
|
|
262
|
+
if (!modelFKMap.has(dbFK.name)) {
|
|
263
|
+
changes.push({
|
|
264
|
+
type: 'foreignKey',
|
|
265
|
+
changeType: 'delete',
|
|
266
|
+
constraintName: dbFK.name,
|
|
267
|
+
databaseDefinition: dbFK,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return changes;
|
|
272
|
+
}
|
|
273
|
+
// ==================== Private Helper Methods ====================
|
|
274
|
+
/**
|
|
275
|
+
* Extract column definitions from model
|
|
276
|
+
*/
|
|
277
|
+
extractColumnDefinitions(model) {
|
|
278
|
+
const rawAttributes = model.rawAttributes || {};
|
|
279
|
+
const columns = [];
|
|
280
|
+
for (const [attrName, attr] of Object.entries(rawAttributes)) {
|
|
281
|
+
const columnName = attr.field || attrName;
|
|
282
|
+
columns.push({
|
|
283
|
+
name: columnName,
|
|
284
|
+
type: attr.type,
|
|
285
|
+
typeString: this.serializeDataType(attr.type),
|
|
286
|
+
allowNull: attr.allowNull ?? true,
|
|
287
|
+
defaultValue: attr.defaultValue,
|
|
288
|
+
primaryKey: attr.primaryKey ?? false,
|
|
289
|
+
autoIncrement: attr.autoIncrement ?? false,
|
|
290
|
+
unique: (typeof attr.unique === 'object' ? false : attr.unique) ?? false,
|
|
291
|
+
references: attr.references
|
|
292
|
+
? {
|
|
293
|
+
model: typeof attr.references.model === 'string'
|
|
294
|
+
? attr.references.model
|
|
295
|
+
: attr.references.model.tableName || attr.references.model.name,
|
|
296
|
+
key: attr.references.key || 'id',
|
|
297
|
+
deferrable: attr.references.deferrable,
|
|
298
|
+
onDelete: attr.references.onDelete,
|
|
299
|
+
onUpdate: attr.references.onUpdate,
|
|
300
|
+
}
|
|
301
|
+
: undefined,
|
|
302
|
+
comment: attr.comment,
|
|
303
|
+
field: attr.field,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
return columns;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Extract index definitions from model
|
|
310
|
+
*/
|
|
311
|
+
extractIndexDefinitions(model) {
|
|
312
|
+
const indexes = model.indexes || [];
|
|
313
|
+
return indexes.map((idx) => ({
|
|
314
|
+
name: idx.name,
|
|
315
|
+
unique: idx.unique ?? false,
|
|
316
|
+
fields: idx.fields?.map((f) => (typeof f === 'string' ? f : f.attribute)) || [],
|
|
317
|
+
}));
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Extract constraint definitions from model
|
|
321
|
+
*/
|
|
322
|
+
extractConstraintDefinitions(model) {
|
|
323
|
+
const constraints = [];
|
|
324
|
+
const rawAttributes = model.rawAttributes || {};
|
|
325
|
+
// Extract primary key
|
|
326
|
+
const pkFields = [];
|
|
327
|
+
for (const [attrName, attr] of Object.entries(rawAttributes)) {
|
|
328
|
+
if (attr.primaryKey) {
|
|
329
|
+
pkFields.push(attr.field || attrName);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (pkFields.length > 0) {
|
|
333
|
+
constraints.push({
|
|
334
|
+
name: `${model.tableName || model.name}_pkey`,
|
|
335
|
+
type: 'PRIMARY KEY',
|
|
336
|
+
fields: pkFields,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
// Extract unique constraints from attributes
|
|
340
|
+
for (const [attrName, attr] of Object.entries(rawAttributes)) {
|
|
341
|
+
if (attr.unique && typeof attr.unique === 'string') {
|
|
342
|
+
constraints.push({
|
|
343
|
+
name: attr.unique,
|
|
344
|
+
type: 'UNIQUE',
|
|
345
|
+
fields: [attr.field || attrName],
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return constraints;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Extract foreign key definitions from model
|
|
353
|
+
*/
|
|
354
|
+
extractForeignKeyDefinitions(model) {
|
|
355
|
+
const foreignKeys = [];
|
|
356
|
+
const rawAttributes = model.rawAttributes || {};
|
|
357
|
+
for (const [attrName, attr] of Object.entries(rawAttributes)) {
|
|
358
|
+
if (attr.references) {
|
|
359
|
+
const fieldName = attr.field || attrName;
|
|
360
|
+
const refModel = attr.references.model;
|
|
361
|
+
const refTable = typeof refModel === 'string' ? refModel : refModel.tableName || refModel.name;
|
|
362
|
+
foreignKeys.push({
|
|
363
|
+
name: `${model.tableName || model.name}_${fieldName}_fkey`,
|
|
364
|
+
fields: [fieldName],
|
|
365
|
+
references: {
|
|
366
|
+
table: refTable,
|
|
367
|
+
fields: [attr.references.key || 'id'],
|
|
368
|
+
},
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return foreignKeys;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Get database column information
|
|
376
|
+
*/
|
|
377
|
+
async getDatabaseColumns(tableName, schemaName) {
|
|
378
|
+
try {
|
|
379
|
+
const tableDesc = await this.dialect.describeTable(tableName);
|
|
380
|
+
return Object.entries(tableDesc).map(([name, col]) => ({
|
|
381
|
+
name,
|
|
382
|
+
type: col.type,
|
|
383
|
+
allowNull: col.allowNull,
|
|
384
|
+
defaultValue: col.defaultValue,
|
|
385
|
+
primaryKey: col.primaryKey,
|
|
386
|
+
autoIncrement: col.autoIncrement,
|
|
387
|
+
}));
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
// Table doesn't exist
|
|
391
|
+
return [];
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Get database index information
|
|
396
|
+
*/
|
|
397
|
+
async getDatabaseIndexes(tableName, _schemaName) {
|
|
398
|
+
try {
|
|
399
|
+
const indexes = await this.dialect.showIndexes(tableName);
|
|
400
|
+
return indexes.map((idx) => ({
|
|
401
|
+
name: idx.name,
|
|
402
|
+
unique: idx.unique ?? false,
|
|
403
|
+
type: idx.type,
|
|
404
|
+
fields: idx.fields?.map((f) => f.attribute || f.name || f) || [],
|
|
405
|
+
primary: idx.primary ?? false,
|
|
406
|
+
}));
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
return [];
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Get database constraint information
|
|
414
|
+
*/
|
|
415
|
+
async getDatabaseConstraints(tableName, _schemaName) {
|
|
416
|
+
try {
|
|
417
|
+
const constraints = await this.dialect.showConstraints(tableName);
|
|
418
|
+
return constraints.map((con) => ({
|
|
419
|
+
name: con.name,
|
|
420
|
+
type: con.type,
|
|
421
|
+
fields: con.fields,
|
|
422
|
+
check: con.check,
|
|
423
|
+
}));
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
return [];
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Get database foreign key information
|
|
431
|
+
*/
|
|
432
|
+
async getDatabaseForeignKeys(tableName, _schemaName) {
|
|
433
|
+
try {
|
|
434
|
+
const constraints = await this.dialect.showConstraints(tableName);
|
|
435
|
+
return constraints
|
|
436
|
+
.filter((con) => con.type === 'FOREIGN KEY')
|
|
437
|
+
.map((con) => ({
|
|
438
|
+
name: con.name,
|
|
439
|
+
fields: con.fields || [],
|
|
440
|
+
references: con.references || { table: '', fields: [] },
|
|
441
|
+
onDelete: con.onDelete,
|
|
442
|
+
onUpdate: con.onUpdate,
|
|
443
|
+
}));
|
|
444
|
+
}
|
|
445
|
+
catch {
|
|
446
|
+
return [];
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Serialize DataType to string for comparison
|
|
451
|
+
*/
|
|
452
|
+
serializeDataType(type) {
|
|
453
|
+
if (!type)
|
|
454
|
+
return '';
|
|
455
|
+
if (typeof type === 'string')
|
|
456
|
+
return type;
|
|
457
|
+
const typeKey = type.key;
|
|
458
|
+
const typeArgs = type.values || [];
|
|
459
|
+
if (typeKey && typeArgs.length > 0) {
|
|
460
|
+
return `${typeKey.toUpperCase()}(${typeArgs.join(', ')})`;
|
|
461
|
+
}
|
|
462
|
+
return typeKey?.toUpperCase() || String(type);
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Compare column definitions and return list of changed properties
|
|
466
|
+
*/
|
|
467
|
+
compareColumnDefinitions(modelCol, dbCol) {
|
|
468
|
+
const changed = [];
|
|
469
|
+
// Compare types (simple comparison)
|
|
470
|
+
if (this.normalizeType(modelCol.typeString) !== this.normalizeType(dbCol.type)) {
|
|
471
|
+
changed.push('type');
|
|
472
|
+
}
|
|
473
|
+
// Compare nullability
|
|
474
|
+
if (modelCol.allowNull !== dbCol.allowNull) {
|
|
475
|
+
changed.push('allowNull');
|
|
476
|
+
}
|
|
477
|
+
// Compare default values
|
|
478
|
+
if (JSON.stringify(modelCol.defaultValue) !== JSON.stringify(dbCol.defaultValue)) {
|
|
479
|
+
changed.push('defaultValue');
|
|
480
|
+
}
|
|
481
|
+
// Compare primary key
|
|
482
|
+
if (modelCol.primaryKey !== dbCol.primaryKey) {
|
|
483
|
+
changed.push('primaryKey');
|
|
484
|
+
}
|
|
485
|
+
// Compare auto increment
|
|
486
|
+
if (modelCol.autoIncrement !== dbCol.autoIncrement) {
|
|
487
|
+
changed.push('autoIncrement');
|
|
488
|
+
}
|
|
489
|
+
return changed;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Compare index definitions and return list of changed properties
|
|
493
|
+
*/
|
|
494
|
+
compareIndexDefinitions(modelIdx, dbIdx) {
|
|
495
|
+
const changed = [];
|
|
496
|
+
if (modelIdx.unique !== dbIdx.unique) {
|
|
497
|
+
changed.push('unique');
|
|
498
|
+
}
|
|
499
|
+
const modelFields = [...modelIdx.fields].sort().join(',');
|
|
500
|
+
const dbFields = [...dbIdx.fields].sort().join(',');
|
|
501
|
+
if (modelFields !== dbFields) {
|
|
502
|
+
changed.push('fields');
|
|
503
|
+
}
|
|
504
|
+
return changed;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Compare constraint definitions and return list of changed properties
|
|
508
|
+
*/
|
|
509
|
+
compareConstraintDefinitions(modelCon, dbCon) {
|
|
510
|
+
const changed = [];
|
|
511
|
+
if (modelCon.type !== dbCon.type) {
|
|
512
|
+
changed.push('type');
|
|
513
|
+
}
|
|
514
|
+
const modelFields = [...(modelCon.fields || [])].sort().join(',');
|
|
515
|
+
const dbFields = [...(dbCon.fields || [])].sort().join(',');
|
|
516
|
+
if (modelFields !== dbFields) {
|
|
517
|
+
changed.push('fields');
|
|
518
|
+
}
|
|
519
|
+
return changed;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Compare foreign key definitions and return list of changed properties
|
|
523
|
+
*/
|
|
524
|
+
compareForeignKeyDefinitions(modelFK, dbFK) {
|
|
525
|
+
const changed = [];
|
|
526
|
+
if (modelFK.references.table !== (dbFK.references?.table || '')) {
|
|
527
|
+
changed.push('references.table');
|
|
528
|
+
}
|
|
529
|
+
const modelRefFields = [...modelFK.references.fields].sort().join(',');
|
|
530
|
+
const dbRefFields = [...(dbFK.references?.fields || [])].sort().join(',');
|
|
531
|
+
if (modelRefFields !== dbRefFields) {
|
|
532
|
+
changed.push('references.fields');
|
|
533
|
+
}
|
|
534
|
+
return changed;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Normalize type string for comparison
|
|
538
|
+
*/
|
|
539
|
+
normalizeType(typeStr) {
|
|
540
|
+
return typeStr.toUpperCase().replace(/\s+/g, ' ').trim();
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
exports.SchemaDiffer = SchemaDiffer;
|
|
544
|
+
/**
|
|
545
|
+
* Create a SchemaDiffer instance
|
|
546
|
+
*/
|
|
547
|
+
function createSchemaDiffer(dialect, options) {
|
|
548
|
+
return new SchemaDiffer(dialect, options);
|
|
549
|
+
}
|