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,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* UUID Decorator for the ORM
|
|
4
|
+
*
|
|
5
|
+
* Provides PostgreSQL UUID type support with automatic extension management.
|
|
6
|
+
* Requires: CREATE EXTENSION IF NOT EXISTS "uuid-ossp"
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
*
|
|
10
|
+
* // Auto-generate UUID using gen_random_uuid() (PostgreSQL 13+)
|
|
11
|
+
* @UUID()
|
|
12
|
+
* id: string;
|
|
13
|
+
*
|
|
14
|
+
* // Use uuid_generate_v4() (requires uuid-ossp extension)
|
|
15
|
+
* @UUID({ defaultValue: 'uuid_generate_v4' })
|
|
16
|
+
* id: string;
|
|
17
|
+
*
|
|
18
|
+
* // With custom default
|
|
19
|
+
* @UUID({ defaultValue: 'gen_random_uuid' })
|
|
20
|
+
* id: string;
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.UUID = UUID;
|
|
24
|
+
exports.getUUIDMetadata = getUUIDMetadata;
|
|
25
|
+
exports.getAllUUIDMetadata = getAllUUIDMetadata;
|
|
26
|
+
exports.isUUIDColumn = isUUIDColumn;
|
|
27
|
+
exports.clearUUIDMetadata = clearUUIDMetadata;
|
|
28
|
+
exports.getUUIDExtensionSQL = getUUIDExtensionSQL;
|
|
29
|
+
exports.buildUUIDDefaultSQL = buildUUIDDefaultSQL;
|
|
30
|
+
// ==================== Registry ====================
|
|
31
|
+
const uuidMetadataMap = new Map();
|
|
32
|
+
/**
|
|
33
|
+
* UUID decorator for PostgreSQL UUID columns
|
|
34
|
+
*
|
|
35
|
+
* @param options - Optional UUID column options
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* // Auto-generate UUID
|
|
39
|
+
* class User extends Model {
|
|
40
|
+
* @UUID()
|
|
41
|
+
* id: string;
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* // With specific default
|
|
45
|
+
* class User extends Model {
|
|
46
|
+
* @UUID({ defaultValue: 'uuid_generate_v4' })
|
|
47
|
+
* id: string;
|
|
48
|
+
* }
|
|
49
|
+
*/
|
|
50
|
+
function UUID(options) {
|
|
51
|
+
return function (target, propertyKey) {
|
|
52
|
+
const decoratorOptions = {
|
|
53
|
+
allowNull: false,
|
|
54
|
+
defaultValue: 'gen_random_uuid',
|
|
55
|
+
...options,
|
|
56
|
+
};
|
|
57
|
+
// Get or create metadata map for this class
|
|
58
|
+
if (!uuidMetadataMap.has(target.constructor)) {
|
|
59
|
+
uuidMetadataMap.set(target.constructor, new Map());
|
|
60
|
+
}
|
|
61
|
+
const metadataMap = uuidMetadataMap.get(target.constructor);
|
|
62
|
+
// Store metadata
|
|
63
|
+
metadataMap.set(propertyKey, {
|
|
64
|
+
options: decoratorOptions,
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get UUID metadata for a property
|
|
70
|
+
*
|
|
71
|
+
* @param target - The target class
|
|
72
|
+
* @param propertyKey - The property name
|
|
73
|
+
* @returns UUID metadata or undefined if not found
|
|
74
|
+
*/
|
|
75
|
+
function getUUIDMetadata(target, propertyKey) {
|
|
76
|
+
const metadataMap = uuidMetadataMap.get(target.constructor);
|
|
77
|
+
if (!metadataMap) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
return metadataMap.get(propertyKey);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get all UUID metadata for a class
|
|
84
|
+
*
|
|
85
|
+
* @param target - The target class
|
|
86
|
+
* @returns Map of property names to UUID metadata
|
|
87
|
+
*/
|
|
88
|
+
function getAllUUIDMetadata(target) {
|
|
89
|
+
return uuidMetadataMap.get(target.constructor) || new Map();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Check if a property is a UUID column
|
|
93
|
+
*
|
|
94
|
+
* @param target - The target class
|
|
95
|
+
* @param propertyKey - The property name
|
|
96
|
+
* @returns True if the property is a UUID column
|
|
97
|
+
*/
|
|
98
|
+
function isUUIDColumn(target, propertyKey) {
|
|
99
|
+
const metadata = getUUIDMetadata(target, propertyKey);
|
|
100
|
+
return metadata !== undefined;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Clear UUID metadata (useful for testing)
|
|
104
|
+
*/
|
|
105
|
+
function clearUUIDMetadata() {
|
|
106
|
+
uuidMetadataMap.clear();
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get the SQL to create the UUID extension
|
|
110
|
+
*
|
|
111
|
+
* @returns SQL to create the uuid-ossp extension
|
|
112
|
+
*/
|
|
113
|
+
function getUUIDExtensionSQL() {
|
|
114
|
+
return 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp"';
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Build the default value SQL for UUID
|
|
118
|
+
*
|
|
119
|
+
* @param options - UUID decorator options
|
|
120
|
+
* @returns SQL for the default value
|
|
121
|
+
*/
|
|
122
|
+
function buildUUIDDefaultSQL(options) {
|
|
123
|
+
if (!options.defaultValue) {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
switch (options.defaultValue) {
|
|
127
|
+
case 'gen_random_uuid':
|
|
128
|
+
return 'gen_random_uuid()';
|
|
129
|
+
case 'uuid_generate_v4':
|
|
130
|
+
return 'uuid_generate_v4()';
|
|
131
|
+
default:
|
|
132
|
+
// Custom SQL expression
|
|
133
|
+
return options.defaultValue;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @View class decorator — annotate a Model class so it maps to a database view
|
|
4
|
+
* instead of a base table. The ORM stores the view definition and can generate
|
|
5
|
+
* the CREATE VIEW DDL for you.
|
|
6
|
+
*
|
|
7
|
+
* Example:
|
|
8
|
+
*
|
|
9
|
+
* @View({
|
|
10
|
+
* name: 'active_users_view',
|
|
11
|
+
* query: `
|
|
12
|
+
* SELECT id, name, email, created_at
|
|
13
|
+
* FROM users
|
|
14
|
+
* WHERE status = 'active'
|
|
15
|
+
* `,
|
|
16
|
+
* replace: true,
|
|
17
|
+
* })
|
|
18
|
+
* class ActiveUser extends Model<ActiveUserAttributes> {
|
|
19
|
+
* declare id: number;
|
|
20
|
+
* declare name: string;
|
|
21
|
+
* declare email: string;
|
|
22
|
+
* declare createdAt: Date;
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* // After Model.init() — generate and create the view:
|
|
26
|
+
* const sql = ViewRegistry.getSQL(ActiveUser);
|
|
27
|
+
* await prorm.query(sql);
|
|
28
|
+
*
|
|
29
|
+
* // Or let the ORM create it automatically:
|
|
30
|
+
* await ViewRegistry.createView(prorm, ActiveUser);
|
|
31
|
+
*
|
|
32
|
+
* // Query it just like a normal model:
|
|
33
|
+
* const users = await ActiveUser.findAll({ where: { name: 'Alice' } });
|
|
34
|
+
*/
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.MaterializedViewRegistry = exports.ViewRegistry = void 0;
|
|
37
|
+
exports.getViewOptions = getViewOptions;
|
|
38
|
+
exports.View = View;
|
|
39
|
+
exports.getMaterializedViewOptions = getMaterializedViewOptions;
|
|
40
|
+
exports.MaterializedView = MaterializedView;
|
|
41
|
+
// ==================== Registry ====================
|
|
42
|
+
const VIEW_OPTIONS_KEY = '__orm_view_options__';
|
|
43
|
+
/**
|
|
44
|
+
* Read the @View options attached to a class.
|
|
45
|
+
* Returns undefined if the class has no @View decorator.
|
|
46
|
+
*/
|
|
47
|
+
function getViewOptions(target) {
|
|
48
|
+
return target[VIEW_OPTIONS_KEY];
|
|
49
|
+
}
|
|
50
|
+
// ==================== Decorator ====================
|
|
51
|
+
/**
|
|
52
|
+
* Mark a Model subclass as a database view.
|
|
53
|
+
*
|
|
54
|
+
* - Sets the `tableName` option to the view name so findAll() etc. work correctly.
|
|
55
|
+
* - Registers view metadata so the ORM can generate CREATE VIEW DDL.
|
|
56
|
+
*
|
|
57
|
+
* @View({ name: 'active_users_view', query: 'SELECT ...' })
|
|
58
|
+
* class ActiveUser extends Model { ... }
|
|
59
|
+
*/
|
|
60
|
+
function View(options) {
|
|
61
|
+
return function (target) {
|
|
62
|
+
// Resolve view name — default: class name converted to snake_case
|
|
63
|
+
const name = options.name ?? toSnakeCase(target.name);
|
|
64
|
+
const resolved = {
|
|
65
|
+
dialect: 'mysql',
|
|
66
|
+
replace: false,
|
|
67
|
+
...options,
|
|
68
|
+
name,
|
|
69
|
+
};
|
|
70
|
+
target[VIEW_OPTIONS_KEY] = resolved;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// ==================== SQL Generation ====================
|
|
74
|
+
function qualifiedName(name, schema, dialect) {
|
|
75
|
+
if (!schema)
|
|
76
|
+
return dialect === 'postgres' ? `"${name}"` : `\`${name}\``;
|
|
77
|
+
return dialect === 'postgres' ? `"${schema}"."${name}"` : `\`${schema}\`.\`${name}\``;
|
|
78
|
+
}
|
|
79
|
+
function buildViewSQL(opts) {
|
|
80
|
+
const query = opts.queryFn ? opts.queryFn() : opts.query;
|
|
81
|
+
if (!query)
|
|
82
|
+
throw new Error('[ORM] @View requires either a `query` or `queryFn` option.');
|
|
83
|
+
const dialect = opts.dialect ?? 'mysql';
|
|
84
|
+
const name = qualifiedName(opts.name, opts.schema, dialect);
|
|
85
|
+
const materialized = opts.materialized ? 'MATERIALIZED ' : '';
|
|
86
|
+
const orReplace = opts.replace && !opts.materialized ? 'OR REPLACE ' : '';
|
|
87
|
+
if (dialect === 'postgres') {
|
|
88
|
+
let sql = `CREATE ${orReplace}${materialized}VIEW ${name} AS\n${query.trim()}`;
|
|
89
|
+
if (opts.checkOption && !opts.materialized) {
|
|
90
|
+
const check = opts.checkOption === true ? 'CASCADED' : opts.checkOption;
|
|
91
|
+
sql += `\nWITH ${check} CHECK OPTION`;
|
|
92
|
+
}
|
|
93
|
+
return sql;
|
|
94
|
+
}
|
|
95
|
+
// MySQL / MariaDB / SQLite
|
|
96
|
+
return `CREATE ${orReplace}VIEW ${name} AS\n${query.trim()}`;
|
|
97
|
+
}
|
|
98
|
+
// ==================== Public Registry API ====================
|
|
99
|
+
exports.ViewRegistry = {
|
|
100
|
+
/**
|
|
101
|
+
* Generate the CREATE VIEW SQL for a @View-annotated class.
|
|
102
|
+
*/
|
|
103
|
+
getSQL(target, dialectOverride) {
|
|
104
|
+
const opts = getViewOptions(target);
|
|
105
|
+
if (!opts)
|
|
106
|
+
throw new Error(`[ORM] Class "${target.name}" does not have a @View decorator.`);
|
|
107
|
+
return buildViewSQL({ ...opts, ...(dialectOverride ? { dialect: dialectOverride } : {}) });
|
|
108
|
+
},
|
|
109
|
+
/**
|
|
110
|
+
* Execute the CREATE VIEW statement for a @View-annotated model class.
|
|
111
|
+
*/
|
|
112
|
+
async createView(prorm, target, dialectOverride) {
|
|
113
|
+
const sql = exports.ViewRegistry.getSQL(target, dialectOverride);
|
|
114
|
+
await prorm.query(sql);
|
|
115
|
+
},
|
|
116
|
+
/**
|
|
117
|
+
* Drop the view for a @View-annotated class.
|
|
118
|
+
* @param ifExists - Emit IF EXISTS (default: true)
|
|
119
|
+
*/
|
|
120
|
+
async dropView(prorm, target, ifExists = true) {
|
|
121
|
+
const opts = getViewOptions(target);
|
|
122
|
+
if (!opts)
|
|
123
|
+
throw new Error(`[ORM] Class "${target.name}" does not have a @View decorator.`);
|
|
124
|
+
const dialect = opts.dialect ?? 'mysql';
|
|
125
|
+
const name = qualifiedName(opts.name, opts.schema, dialect);
|
|
126
|
+
const ifExistsClause = ifExists ? 'IF EXISTS ' : '';
|
|
127
|
+
const materialized = opts.materialized ? 'MATERIALIZED ' : '';
|
|
128
|
+
await prorm.query(`DROP ${materialized}VIEW ${ifExistsClause}${name}`);
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
const MATERIALIZED_VIEW_OPTIONS_KEY = '__orm_materialized_view_options__';
|
|
132
|
+
/**
|
|
133
|
+
* Read the @MaterializedView options attached to a class.
|
|
134
|
+
* Returns undefined if the class has no @MaterializedView decorator.
|
|
135
|
+
*/
|
|
136
|
+
function getMaterializedViewOptions(target) {
|
|
137
|
+
return target[MATERIALIZED_VIEW_OPTIONS_KEY];
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Mark a Model subclass as a database materialized view.
|
|
141
|
+
*
|
|
142
|
+
* - Sets the `tableName` option to the view name so findAll() etc. work correctly.
|
|
143
|
+
* - Registers materialized view metadata so the ORM can generate CREATE MATERIALIZED VIEW DDL.
|
|
144
|
+
* - Adds a `refresh()` static method for refreshing the view data.
|
|
145
|
+
*
|
|
146
|
+
* @MaterializedView({
|
|
147
|
+
* name: 'user_stats_view',
|
|
148
|
+
* query: `
|
|
149
|
+
* SELECT user_id, COUNT(*) as order_count
|
|
150
|
+
* FROM orders
|
|
151
|
+
* GROUP BY user_id
|
|
152
|
+
* `,
|
|
153
|
+
* uniqueIndex: 'user_stats_view_user_id_key',
|
|
154
|
+
* })
|
|
155
|
+
* class UserStats extends Model<UserStatsAttributes> {
|
|
156
|
+
* declare userId: number;
|
|
157
|
+
* declare orderCount: number;
|
|
158
|
+
* }
|
|
159
|
+
*
|
|
160
|
+
* // After Model.init() — generate and create the materialized view:
|
|
161
|
+
* const sql = MaterializedViewRegistry.getSQL(UserStats);
|
|
162
|
+
* await prorm.query(sql);
|
|
163
|
+
*
|
|
164
|
+
* // Or let the ORM create it automatically:
|
|
165
|
+
* await MaterializedViewRegistry.createMaterializedView(prorm, UserStats);
|
|
166
|
+
*
|
|
167
|
+
* // Query it just like a normal model:
|
|
168
|
+
* const stats = await UserStats.findAll();
|
|
169
|
+
*
|
|
170
|
+
* // Refresh the materialized view:
|
|
171
|
+
* await UserStats.refresh();
|
|
172
|
+
* // Or concurrently (requires unique index):
|
|
173
|
+
* await UserStats.refresh({ concurrently: true });
|
|
174
|
+
*/
|
|
175
|
+
function MaterializedView(options) {
|
|
176
|
+
return function (target) {
|
|
177
|
+
// Resolve view name — default: class name converted to snake_case
|
|
178
|
+
const name = options.name ?? toSnakeCase(target.name);
|
|
179
|
+
const resolved = {
|
|
180
|
+
refreshStrategy: 'ON DEMAND',
|
|
181
|
+
withData: true,
|
|
182
|
+
replace: false,
|
|
183
|
+
ifNotExists: false,
|
|
184
|
+
...options,
|
|
185
|
+
name,
|
|
186
|
+
};
|
|
187
|
+
target[MATERIALIZED_VIEW_OPTIONS_KEY] = resolved;
|
|
188
|
+
// Mark as materialized view for type checking
|
|
189
|
+
target.isMaterializedView = true;
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
// ==================== SQL Generation for Materialized Views ====================
|
|
193
|
+
function buildMaterializedViewSQL(opts) {
|
|
194
|
+
const query = opts.queryFn ? opts.queryFn() : opts.query;
|
|
195
|
+
if (!query)
|
|
196
|
+
throw new Error('[ORM] @MaterializedView requires either a `query` or `queryFn` option.');
|
|
197
|
+
const name = qualifiedName(opts.name, opts.schema, 'postgres');
|
|
198
|
+
let sql = 'CREATE MATERIALIZED VIEW';
|
|
199
|
+
if (opts.replace) {
|
|
200
|
+
sql = 'CREATE OR REPLACE MATERIALIZED VIEW';
|
|
201
|
+
}
|
|
202
|
+
else if (opts.ifNotExists) {
|
|
203
|
+
sql = 'CREATE MATERIALIZED VIEW IF NOT EXISTS';
|
|
204
|
+
}
|
|
205
|
+
sql += ` ${name} AS\n${query.trim()}`;
|
|
206
|
+
if (!opts.withData) {
|
|
207
|
+
sql += ' WITH NO DATA';
|
|
208
|
+
}
|
|
209
|
+
return sql;
|
|
210
|
+
}
|
|
211
|
+
// ==================== Materialized View Registry ====================
|
|
212
|
+
exports.MaterializedViewRegistry = {
|
|
213
|
+
/**
|
|
214
|
+
* Generate the CREATE MATERIALIZED VIEW SQL for a @MaterializedView-annotated class.
|
|
215
|
+
*/
|
|
216
|
+
getSQL(target, dialectOverride) {
|
|
217
|
+
const opts = getMaterializedViewOptions(target);
|
|
218
|
+
if (!opts)
|
|
219
|
+
throw new Error(`[ORM] Class "${target.name}" does not have a @MaterializedView decorator.`);
|
|
220
|
+
return buildMaterializedViewSQL({
|
|
221
|
+
...opts,
|
|
222
|
+
...(dialectOverride ? { schema: dialectOverride } : {}),
|
|
223
|
+
});
|
|
224
|
+
},
|
|
225
|
+
/**
|
|
226
|
+
* Execute the CREATE MATERIALIZED VIEW statement for a @MaterializedView-annotated model class.
|
|
227
|
+
*/
|
|
228
|
+
async createMaterializedView(prorm, target, dialectOverride) {
|
|
229
|
+
const sql = exports.MaterializedViewRegistry.getSQL(target, dialectOverride);
|
|
230
|
+
await prorm.query(sql);
|
|
231
|
+
// Create unique index if provided (required for CONCURRENTLY refresh)
|
|
232
|
+
const opts = getMaterializedViewOptions(target);
|
|
233
|
+
if (opts?.uniqueIndex) {
|
|
234
|
+
const name = qualifiedName(opts.name, opts.schema, 'postgres');
|
|
235
|
+
const indexSql = `CREATE UNIQUE INDEX ${opts.uniqueIndex} ON ${name} (${opts.uniqueIndex.replace(/_key$/, '')})`;
|
|
236
|
+
await prorm.query(indexSql);
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
/**
|
|
240
|
+
* Drop the materialized view for a @MaterializedView-annotated class.
|
|
241
|
+
* @param ifExists - Emit IF EXISTS (default: true)
|
|
242
|
+
*/
|
|
243
|
+
async dropMaterializedView(prorm, target, ifExists = true) {
|
|
244
|
+
const opts = getMaterializedViewOptions(target);
|
|
245
|
+
if (!opts)
|
|
246
|
+
throw new Error(`[ORM] Class "${target.name}" does not have a @MaterializedView decorator.`);
|
|
247
|
+
const name = qualifiedName(opts.name, opts.schema, 'postgres');
|
|
248
|
+
const ifExistsClause = ifExists ? 'IF EXISTS ' : '';
|
|
249
|
+
await prorm.query(`DROP MATERIALIZED VIEW ${ifExistsClause}${name}`);
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
// ==================== Internal Helpers ====================
|
|
253
|
+
function toSnakeCase(str) {
|
|
254
|
+
return str
|
|
255
|
+
.replace(/([A-Z])/g, '_$1')
|
|
256
|
+
.toLowerCase()
|
|
257
|
+
.replace(/^_/, '');
|
|
258
|
+
}
|