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,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @Audit class decorator — automatically record model lifecycle events to an
|
|
4
|
+
* in-memory audit log.
|
|
5
|
+
*
|
|
6
|
+
* When applied to a model class the decorator registers beforeCreate,
|
|
7
|
+
* beforeUpdate, and beforeDestroy hooks (via ModelClass.addHook) that append
|
|
8
|
+
* structured entries to a per-class log.
|
|
9
|
+
*
|
|
10
|
+
* Example:
|
|
11
|
+
*
|
|
12
|
+
* @Audit({ tableName: 'audit_log', trackFields: ['name', 'email'] })
|
|
13
|
+
* class User extends Model { ... }
|
|
14
|
+
*
|
|
15
|
+
* // After create/update/destroy hooks fire:
|
|
16
|
+
* const log = getAuditLog(User);
|
|
17
|
+
* clearAuditLog(User);
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.getAuditLog = getAuditLog;
|
|
21
|
+
exports.clearAuditLog = clearAuditLog;
|
|
22
|
+
exports.Audit = Audit;
|
|
23
|
+
exports.getAuditOptions = getAuditOptions;
|
|
24
|
+
// ==================== In-memory storage ====================
|
|
25
|
+
const auditLogs = new Map();
|
|
26
|
+
function getLog(target) {
|
|
27
|
+
if (!auditLogs.has(target)) {
|
|
28
|
+
auditLogs.set(target, []);
|
|
29
|
+
}
|
|
30
|
+
return auditLogs.get(target);
|
|
31
|
+
}
|
|
32
|
+
/** Return all audit log entries accumulated for a model class. */
|
|
33
|
+
function getAuditLog(target) {
|
|
34
|
+
return getLog(target);
|
|
35
|
+
}
|
|
36
|
+
/** Clear all audit log entries for a model class. */
|
|
37
|
+
function clearAuditLog(target) {
|
|
38
|
+
auditLogs.set(target, []);
|
|
39
|
+
}
|
|
40
|
+
// ==================== Internal helpers ====================
|
|
41
|
+
function extractValues(instance, fields) {
|
|
42
|
+
const raw = typeof instance.toJSON === 'function'
|
|
43
|
+
? instance.toJSON()
|
|
44
|
+
: typeof instance.dataValues === 'object' && instance.dataValues !== null
|
|
45
|
+
? { ...instance.dataValues }
|
|
46
|
+
: { ...instance };
|
|
47
|
+
if (!fields || fields.length === 0)
|
|
48
|
+
return raw;
|
|
49
|
+
const result = {};
|
|
50
|
+
for (const f of fields) {
|
|
51
|
+
if (Object.prototype.hasOwnProperty.call(raw, f)) {
|
|
52
|
+
result[f] = raw[f];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
function extractPreviousValues(instance, fields) {
|
|
58
|
+
// Prorm exposes _previousDataValues for changed fields
|
|
59
|
+
const prev = typeof instance._previousDataValues === 'object' && instance._previousDataValues !== null
|
|
60
|
+
? { ...instance._previousDataValues }
|
|
61
|
+
: extractValues(instance, fields);
|
|
62
|
+
if (!fields || fields.length === 0)
|
|
63
|
+
return prev;
|
|
64
|
+
const result = {};
|
|
65
|
+
for (const f of fields) {
|
|
66
|
+
if (Object.prototype.hasOwnProperty.call(prev, f)) {
|
|
67
|
+
result[f] = prev[f];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
// ==================== Decorator ====================
|
|
73
|
+
const AUDIT_OPTIONS_KEY = '__orm_audit_options__';
|
|
74
|
+
/**
|
|
75
|
+
* Mark a model class for automatic audit logging.
|
|
76
|
+
*
|
|
77
|
+
* Hooks are registered via `ModelClass.addHook` if the method exists, so this
|
|
78
|
+
* decorator is compatible with both Prorm-style models and plain mock classes
|
|
79
|
+
* that expose addHook manually in tests.
|
|
80
|
+
*/
|
|
81
|
+
function Audit(options = {}) {
|
|
82
|
+
return (target) => {
|
|
83
|
+
const auditTable = options.tableName ?? 'audit_log';
|
|
84
|
+
const trackFields = options.trackFields;
|
|
85
|
+
const userField = options.userField;
|
|
86
|
+
// Store options for introspection
|
|
87
|
+
target[AUDIT_OPTIONS_KEY] = { ...options, tableName: auditTable };
|
|
88
|
+
const log = getLog(target);
|
|
89
|
+
function getUser(instance) {
|
|
90
|
+
if (!userField)
|
|
91
|
+
return undefined;
|
|
92
|
+
return typeof instance.getDataValue === 'function'
|
|
93
|
+
? instance.getDataValue(userField)
|
|
94
|
+
: instance[userField];
|
|
95
|
+
}
|
|
96
|
+
const beforeCreate = (instance) => {
|
|
97
|
+
log.push({
|
|
98
|
+
action: 'CREATE',
|
|
99
|
+
model: auditTable,
|
|
100
|
+
newValues: extractValues(instance, trackFields),
|
|
101
|
+
user: getUser(instance),
|
|
102
|
+
timestamp: new Date(),
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
const beforeUpdate = (instance) => {
|
|
106
|
+
log.push({
|
|
107
|
+
action: 'UPDATE',
|
|
108
|
+
model: auditTable,
|
|
109
|
+
oldValues: extractPreviousValues(instance, trackFields),
|
|
110
|
+
newValues: extractValues(instance, trackFields),
|
|
111
|
+
user: getUser(instance),
|
|
112
|
+
timestamp: new Date(),
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
const beforeDestroy = (instance) => {
|
|
116
|
+
log.push({
|
|
117
|
+
action: 'DELETE',
|
|
118
|
+
model: auditTable,
|
|
119
|
+
oldValues: extractValues(instance, trackFields),
|
|
120
|
+
user: getUser(instance),
|
|
121
|
+
timestamp: new Date(),
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
if (typeof target.addHook === 'function') {
|
|
125
|
+
target.addHook('beforeCreate', 'orm:audit:create', beforeCreate);
|
|
126
|
+
target.addHook('beforeUpdate', 'orm:audit:update', beforeUpdate);
|
|
127
|
+
target.addHook('beforeDestroy', 'orm:audit:destroy', beforeDestroy);
|
|
128
|
+
}
|
|
129
|
+
// Also store hooks on the class so tests can invoke them directly
|
|
130
|
+
target.__auditHooks__ = { beforeCreate, beforeUpdate, beforeDestroy };
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/** Read the AuditOptions stored on a decorated class. */
|
|
134
|
+
function getAuditOptions(target) {
|
|
135
|
+
return target[AUDIT_OPTIONS_KEY];
|
|
136
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BelongsToMany decorator for the ORM.
|
|
4
|
+
*
|
|
5
|
+
* Defines a many-to-many relationship between models via a join table/model.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
*
|
|
9
|
+
* @BelongsToMany(() => Role, { through: 'user_roles' })
|
|
10
|
+
* roles: Role[];
|
|
11
|
+
*
|
|
12
|
+
* @BelongsToMany(() => Role, { through: UserRole, as: 'assignedRoles' })
|
|
13
|
+
* assignedRoles: Role[];
|
|
14
|
+
*
|
|
15
|
+
* // With options
|
|
16
|
+
* @BelongsToMany(() => Tag, {
|
|
17
|
+
* through: 'post_tags',
|
|
18
|
+
* foreignKey: 'post_id',
|
|
19
|
+
* otherKey: 'tag_id',
|
|
20
|
+
* onDelete: 'CASCADE'
|
|
21
|
+
* })
|
|
22
|
+
* tags: Tag[];
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.getBelongsToMany = getBelongsToMany;
|
|
26
|
+
exports.getAllBelongsToMany = getAllBelongsToMany;
|
|
27
|
+
exports.BelongsToMany = BelongsToMany;
|
|
28
|
+
exports.processBelongsToManyDecorators = processBelongsToManyDecorators;
|
|
29
|
+
// ==================== Metadata Storage ====================
|
|
30
|
+
const BELONGS_TO_MANY_KEY = '__orm_belongs_to_many__';
|
|
31
|
+
/**
|
|
32
|
+
* Get all @BelongsToMany annotations attached to a model constructor.
|
|
33
|
+
*/
|
|
34
|
+
function getBelongsToMany(target) {
|
|
35
|
+
return target[BELONGS_TO_MANY_KEY] || [];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get all belongsToMany associations including inherited ones.
|
|
39
|
+
*/
|
|
40
|
+
function getAllBelongsToMany(target) {
|
|
41
|
+
const associations = [];
|
|
42
|
+
let current = target;
|
|
43
|
+
while (current && current.prototype) {
|
|
44
|
+
const meta = getBelongsToMany(current);
|
|
45
|
+
associations.push(...meta);
|
|
46
|
+
current = Object.getPrototypeOf(current);
|
|
47
|
+
if (current === Object.prototype)
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
return associations;
|
|
51
|
+
}
|
|
52
|
+
// ==================== Decorator ====================
|
|
53
|
+
/**
|
|
54
|
+
* Define a many-to-many relationship.
|
|
55
|
+
*
|
|
56
|
+
* This decorator stores metadata on the model class that can be used
|
|
57
|
+
* by the ORM to establish the association at model initialization time.
|
|
58
|
+
*
|
|
59
|
+
* @param target - A function that returns the target model class
|
|
60
|
+
* @param options - Configuration for the association (through is required)
|
|
61
|
+
*/
|
|
62
|
+
function BelongsToMany(target, options) {
|
|
63
|
+
return function (prototype, propertyKey) {
|
|
64
|
+
const ModelClass = prototype.constructor;
|
|
65
|
+
if (!ModelClass[BELONGS_TO_MANY_KEY]) {
|
|
66
|
+
ModelClass[BELONGS_TO_MANY_KEY] = [];
|
|
67
|
+
}
|
|
68
|
+
ModelClass[BELONGS_TO_MANY_KEY].push({
|
|
69
|
+
target,
|
|
70
|
+
options: {
|
|
71
|
+
as: options.as || propertyKey.toString(),
|
|
72
|
+
through: options.through,
|
|
73
|
+
foreignKey: options.foreignKey,
|
|
74
|
+
otherKey: options.otherKey,
|
|
75
|
+
constraints: options.constraints,
|
|
76
|
+
onDelete: options.onDelete,
|
|
77
|
+
onUpdate: options.onUpdate,
|
|
78
|
+
targetKey: options.targetKey,
|
|
79
|
+
sourceKey: options.sourceKey,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Process @BelongsToMany decorators and create association configuration.
|
|
86
|
+
*
|
|
87
|
+
* Call this to get the raw association definitions from decorators.
|
|
88
|
+
*
|
|
89
|
+
* @param ModelClass - The model class with @BelongsToMany decorators
|
|
90
|
+
* @returns Array of association configurations
|
|
91
|
+
*/
|
|
92
|
+
function processBelongsToManyDecorators(ModelClass) {
|
|
93
|
+
const decorators = getAllBelongsToMany(ModelClass);
|
|
94
|
+
return decorators.map(({ target, options }) => {
|
|
95
|
+
const targetModel = target();
|
|
96
|
+
const foreignKey = typeof options.foreignKey === 'string'
|
|
97
|
+
? options.foreignKey
|
|
98
|
+
: options.foreignKey?.name
|
|
99
|
+
? options.foreignKey.name
|
|
100
|
+
: `${ModelClass.name}Id`;
|
|
101
|
+
return {
|
|
102
|
+
source: ModelClass,
|
|
103
|
+
target: targetModel,
|
|
104
|
+
foreignKey,
|
|
105
|
+
as: options.as || '',
|
|
106
|
+
options,
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
exports.default = {
|
|
111
|
+
BelongsToMany,
|
|
112
|
+
getBelongsToMany,
|
|
113
|
+
getAllBelongsToMany,
|
|
114
|
+
processBelongsToManyDecorators,
|
|
115
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BelongsTo decorator for the ORM.
|
|
4
|
+
*
|
|
5
|
+
* Defines a many-to-one (inverse of hasOne/hasMany) relationship between models.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
*
|
|
9
|
+
* @BelongsTo(() => User)
|
|
10
|
+
* user: User;
|
|
11
|
+
*
|
|
12
|
+
* @BelongsTo(() => User, { as: 'author' })
|
|
13
|
+
* author: User;
|
|
14
|
+
*
|
|
15
|
+
* // With options
|
|
16
|
+
* @BelongsTo(() => Category, {
|
|
17
|
+
* foreignKey: { name: 'category_id', allowNull: false },
|
|
18
|
+
* onDelete: 'CASCADE'
|
|
19
|
+
* })
|
|
20
|
+
* category: Category;
|
|
21
|
+
*
|
|
22
|
+
* // Self-referential
|
|
23
|
+
* @BelongsTo(() => User, { as: 'manager', foreignKey: 'manager_id' })
|
|
24
|
+
* manager: User;
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.getBelongsTo = getBelongsTo;
|
|
28
|
+
exports.getAllBelongsTo = getAllBelongsTo;
|
|
29
|
+
exports.BelongsTo = BelongsTo;
|
|
30
|
+
exports.processBelongsToDecorators = processBelongsToDecorators;
|
|
31
|
+
// ==================== Metadata Storage ====================
|
|
32
|
+
const BELONGS_TO_KEY = '__orm_belongs_to__';
|
|
33
|
+
/**
|
|
34
|
+
* Get all @BelongsTo annotations attached to a model constructor.
|
|
35
|
+
*/
|
|
36
|
+
function getBelongsTo(target) {
|
|
37
|
+
return target[BELONGS_TO_KEY] || [];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get all belongsTo associations including inherited ones.
|
|
41
|
+
*/
|
|
42
|
+
function getAllBelongsTo(target) {
|
|
43
|
+
const associations = [];
|
|
44
|
+
let current = target;
|
|
45
|
+
while (current && current.prototype) {
|
|
46
|
+
const meta = getBelongsTo(current);
|
|
47
|
+
associations.push(...meta);
|
|
48
|
+
current = Object.getPrototypeOf(current);
|
|
49
|
+
if (current === Object.prototype)
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
return associations;
|
|
53
|
+
}
|
|
54
|
+
// ==================== Decorator ====================
|
|
55
|
+
/**
|
|
56
|
+
* Define a many-to-one relationship.
|
|
57
|
+
*
|
|
58
|
+
* This decorator stores metadata on the model class that can be used
|
|
59
|
+
* by the ORM to establish the association at model initialization time.
|
|
60
|
+
*
|
|
61
|
+
* @param target - A function that returns the target model class
|
|
62
|
+
* @param options - Optional configuration for the association
|
|
63
|
+
*/
|
|
64
|
+
function BelongsTo(target, options = {}) {
|
|
65
|
+
return function (prototype, propertyKey) {
|
|
66
|
+
const ModelClass = prototype.constructor;
|
|
67
|
+
if (!ModelClass[BELONGS_TO_KEY]) {
|
|
68
|
+
ModelClass[BELONGS_TO_KEY] = [];
|
|
69
|
+
}
|
|
70
|
+
ModelClass[BELONGS_TO_KEY].push({
|
|
71
|
+
target,
|
|
72
|
+
options: {
|
|
73
|
+
as: options.as || propertyKey.toString(),
|
|
74
|
+
foreignKey: options.foreignKey,
|
|
75
|
+
constraints: options.constraints,
|
|
76
|
+
onDelete: options.onDelete,
|
|
77
|
+
onUpdate: options.onUpdate,
|
|
78
|
+
targetKey: options.targetKey,
|
|
79
|
+
sourceKey: options.sourceKey,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Process @BelongsTo decorators and create association configuration.
|
|
86
|
+
*
|
|
87
|
+
* Call this to get the raw association definitions from decorators.
|
|
88
|
+
*
|
|
89
|
+
* @param ModelClass - The model class with @BelongsTo decorators
|
|
90
|
+
* @returns Array of association configurations
|
|
91
|
+
*/
|
|
92
|
+
function processBelongsToDecorators(ModelClass) {
|
|
93
|
+
const decorators = getAllBelongsTo(ModelClass);
|
|
94
|
+
return decorators.map(({ target, options }) => {
|
|
95
|
+
const targetModel = target();
|
|
96
|
+
const foreignKey = typeof options.foreignKey === 'string'
|
|
97
|
+
? options.foreignKey
|
|
98
|
+
: options.foreignKey?.name
|
|
99
|
+
? options.foreignKey.name
|
|
100
|
+
: `${targetModel.name}Id`;
|
|
101
|
+
return {
|
|
102
|
+
source: ModelClass,
|
|
103
|
+
target: targetModel,
|
|
104
|
+
foreignKey,
|
|
105
|
+
as: options.as || '',
|
|
106
|
+
options,
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
exports.default = {
|
|
111
|
+
BelongsTo,
|
|
112
|
+
getBelongsTo,
|
|
113
|
+
getAllBelongsTo,
|
|
114
|
+
processBelongsToDecorators,
|
|
115
|
+
};
|