ts-prorm-orm 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/CHANGELOG.md +1111 -0
  2. package/LICENSE +21 -0
  3. package/README.md +573 -0
  4. package/dist/audit/history-query.js +180 -0
  5. package/dist/audit/index.js +23 -0
  6. package/dist/audit/logger.js +236 -0
  7. package/dist/cache/cache-manager.js +84 -0
  8. package/dist/cache/index.js +16 -0
  9. package/dist/cache/redis-cluster-cache.js +557 -0
  10. package/dist/cli.js +2200 -0
  11. package/dist/compliance/audit-trail.js +68 -0
  12. package/dist/compliance/backup-verification.js +685 -0
  13. package/dist/compliance/breach-detector.js +505 -0
  14. package/dist/compliance/consent-record.js +227 -0
  15. package/dist/compliance/consent-versioning.js +331 -0
  16. package/dist/compliance/cross-border-log.js +530 -0
  17. package/dist/compliance/data-classifier.js +258 -0
  18. package/dist/compliance/data-lineage.js +565 -0
  19. package/dist/compliance/data-masker.js +303 -0
  20. package/dist/compliance/data-portability.js +265 -0
  21. package/dist/compliance/data-retention.js +195 -0
  22. package/dist/compliance/dsar-workflow.js +342 -0
  23. package/dist/compliance/field-encryption.js +223 -0
  24. package/dist/compliance/immutable-record.js +148 -0
  25. package/dist/compliance/index.js +260 -0
  26. package/dist/compliance/privacy-impact-assessment.js +364 -0
  27. package/dist/compliance/pseudonymization.js +269 -0
  28. package/dist/compliance/query-firewall.js +1182 -0
  29. package/dist/compliance/rate-limiter.js +580 -0
  30. package/dist/compliance/right-to-erasure.js +117 -0
  31. package/dist/compliance/row-level-security.js +246 -0
  32. package/dist/compliance/security-decorator.js +574 -0
  33. package/dist/compliance/security-monitor.js +525 -0
  34. package/dist/compliance/sensitive-data-discovery.js +476 -0
  35. package/dist/compliance/session-isolation.js +472 -0
  36. package/dist/compliance/tls-enforcer.js +108 -0
  37. package/dist/compliance/worm-storage.js +712 -0
  38. package/dist/connection-manager.js +198 -0
  39. package/dist/connection-pool.js +519 -0
  40. package/dist/decorators/audit.js +136 -0
  41. package/dist/decorators/belongs-to-many.js +115 -0
  42. package/dist/decorators/belongs-to.js +115 -0
  43. package/dist/decorators/check.js +435 -0
  44. package/dist/decorators/collate.js +329 -0
  45. package/dist/decorators/comment.js +205 -0
  46. package/dist/decorators/database-settings.js +236 -0
  47. package/dist/decorators/default.js +244 -0
  48. package/dist/decorators/encryption.js +235 -0
  49. package/dist/decorators/engine.js +97 -0
  50. package/dist/decorators/fk-constraints.js +594 -0
  51. package/dist/decorators/foreign-table.js +136 -0
  52. package/dist/decorators/generated.js +274 -0
  53. package/dist/decorators/has-many.js +127 -0
  54. package/dist/decorators/has-one.js +116 -0
  55. package/dist/decorators/hstore.js +129 -0
  56. package/dist/decorators/index.js +355 -0
  57. package/dist/decorators/json-column.js +83 -0
  58. package/dist/decorators/jsonb.js +101 -0
  59. package/dist/decorators/orm-decorators.js +425 -0
  60. package/dist/decorators/permissions.js +294 -0
  61. package/dist/decorators/procedure.js +210 -0
  62. package/dist/decorators/query-options.js +556 -0
  63. package/dist/decorators/range.js +167 -0
  64. package/dist/decorators/set-column.js +83 -0
  65. package/dist/decorators/spatial.js +114 -0
  66. package/dist/decorators/storage.js +580 -0
  67. package/dist/decorators/timezone.js +512 -0
  68. package/dist/decorators/trigger.js +90 -0
  69. package/dist/decorators/uuid.js +135 -0
  70. package/dist/decorators/view.js +258 -0
  71. package/dist/diagrams/chen-diagram.js +354 -0
  72. package/dist/diagrams/class-diagram.js +384 -0
  73. package/dist/diagrams/dependency-diagram.js +432 -0
  74. package/dist/diagrams/er-diagram.js +605 -0
  75. package/dist/diagrams/flow-diagram.js +394 -0
  76. package/dist/diagrams/gantt-diagram.js +411 -0
  77. package/dist/diagrams/index-diagram.js +353 -0
  78. package/dist/diagrams/index.js +184 -0
  79. package/dist/diagrams/migration-diagram.js +316 -0
  80. package/dist/diagrams/model-diagram.js +616 -0
  81. package/dist/diagrams/package-diagram.js +376 -0
  82. package/dist/diagrams/palette.js +85 -0
  83. package/dist/diagrams/relational-diagram.js +455 -0
  84. package/dist/diagrams/schemadoc-diagram.js +309 -0
  85. package/dist/diagrams/sequence-diagram.js +307 -0
  86. package/dist/diagrams/state-diagram.js +344 -0
  87. package/dist/diagrams/svg-dom.js +111 -0
  88. package/dist/diagrams/tree-diagram.js +250 -0
  89. package/dist/dialects/clickhouse/index.js +1742 -0
  90. package/dist/dialects/cockroachdb/index.js +4677 -0
  91. package/dist/dialects/cratedb/index.js +441 -0
  92. package/dist/dialects/databricks/index.js +517 -0
  93. package/dist/dialects/db2/index.js +2225 -0
  94. package/dist/dialects/dialect.js +720 -0
  95. package/dist/dialects/duckdb/index.js +2014 -0
  96. package/dist/dialects/exasol/index.js +357 -0
  97. package/dist/dialects/firebird/index.js +495 -0
  98. package/dist/dialects/greenplum/index.js +457 -0
  99. package/dist/dialects/hana/index.js +1741 -0
  100. package/dist/dialects/mariadb/index.js +3590 -0
  101. package/dist/dialects/mssql/index.js +2296 -0
  102. package/dist/dialects/mysql/index.js +4058 -0
  103. package/dist/dialects/oracle/index.js +2999 -0
  104. package/dist/dialects/postgres/index.js +5319 -0
  105. package/dist/dialects/query-stream-helper.js +152 -0
  106. package/dist/dialects/questdb/index.js +433 -0
  107. package/dist/dialects/redshift/index.js +2277 -0
  108. package/dist/dialects/singlestore/index.js +354 -0
  109. package/dist/dialects/snowflake/index.js +2082 -0
  110. package/dist/dialects/spanner/index.js +1768 -0
  111. package/dist/dialects/sqlite/index.js +3382 -0
  112. package/dist/dialects/tidb/index.js +377 -0
  113. package/dist/dialects/timescaledb/index.js +164 -0
  114. package/dist/dialects/trino/index.js +420 -0
  115. package/dist/dialects/turso/index.js +227 -0
  116. package/dist/dialects/vertica/index.js +317 -0
  117. package/dist/dialects/yugabytedb/index.js +424 -0
  118. package/dist/errors/index.js +472 -0
  119. package/dist/errors/utils.js +340 -0
  120. package/dist/errors.js +21 -0
  121. package/dist/extensions/catalog/cloud-warehouse-features.js +207 -0
  122. package/dist/extensions/catalog/mssql-features.js +147 -0
  123. package/dist/extensions/catalog/mysql-mariadb-plugins.js +229 -0
  124. package/dist/extensions/catalog/oracle-db2-features.js +196 -0
  125. package/dist/extensions/catalog/postgres-extensions.js +516 -0
  126. package/dist/extensions/index.js +71 -0
  127. package/dist/extensions/types.js +13 -0
  128. package/dist/foreign-data.js +173 -0
  129. package/dist/hooks/hooks-manager.js +350 -0
  130. package/dist/hooks/index.js +37 -0
  131. package/dist/index.js +463 -0
  132. package/dist/logging.js +335 -0
  133. package/dist/migrations/index.js +40 -0
  134. package/dist/migrations/migration.js +196 -0
  135. package/dist/migrations/migrator.js +411 -0
  136. package/dist/migrations/prormmigration.js +275 -0
  137. package/dist/migrations/query-interface.js +435 -0
  138. package/dist/migrations/seeder.js +353 -0
  139. package/dist/models/associations.js +852 -0
  140. package/dist/models/constraints.js +288 -0
  141. package/dist/models/data-types.js +2518 -0
  142. package/dist/models/decorators.js +445 -0
  143. package/dist/models/index.js +33 -0
  144. package/dist/models/indexes.js +531 -0
  145. package/dist/models/methods.js +382 -0
  146. package/dist/models/model-manager.js +103 -0
  147. package/dist/models/model.js +5349 -0
  148. package/dist/models/operators.js +67 -0
  149. package/dist/models/scopes.js +189 -0
  150. package/dist/models/typescript-types.js +26 -0
  151. package/dist/nosql/aerospike/index.js +205 -0
  152. package/dist/nosql/allegrograph/index.js +169 -0
  153. package/dist/nosql/arangodb/index.js +364 -0
  154. package/dist/nosql/azure-blob/index.js +206 -0
  155. package/dist/nosql/beanstalkd/index.js +231 -0
  156. package/dist/nosql/beequeue/index.js +210 -0
  157. package/dist/nosql/bigchaindb/index.js +195 -0
  158. package/dist/nosql/bigtable/index.js +224 -0
  159. package/dist/nosql/blazegraph/index.js +173 -0
  160. package/dist/nosql/bullmq/index.js +191 -0
  161. package/dist/nosql/cassandra/index.js +174 -0
  162. package/dist/nosql/chroma/index.js +190 -0
  163. package/dist/nosql/cloudflare-kv/index.js +220 -0
  164. package/dist/nosql/coherence/index.js +200 -0
  165. package/dist/nosql/cosmosdb/index.js +157 -0
  166. package/dist/nosql/couchbase/index.js +213 -0
  167. package/dist/nosql/dax/index.js +212 -0
  168. package/dist/nosql/deno-kv/index.js +206 -0
  169. package/dist/nosql/dgraph/index.js +171 -0
  170. package/dist/nosql/doris/index.js +169 -0
  171. package/dist/nosql/druid/index.js +162 -0
  172. package/dist/nosql/dynamodb/index.js +937 -0
  173. package/dist/nosql/elasticsearch/index.js +377 -0
  174. package/dist/nosql/etcd/index.js +502 -0
  175. package/dist/nosql/eventhubs/index.js +213 -0
  176. package/dist/nosql/eventstore/index.js +254 -0
  177. package/dist/nosql/faunadb/index.js +188 -0
  178. package/dist/nosql/firestore/index.js +177 -0
  179. package/dist/nosql/fluree/index.js +148 -0
  180. package/dist/nosql/fuseki/index.js +170 -0
  181. package/dist/nosql/gcs/index.js +172 -0
  182. package/dist/nosql/gearman/index.js +160 -0
  183. package/dist/nosql/geode/index.js +196 -0
  184. package/dist/nosql/graphdb/index.js +169 -0
  185. package/dist/nosql/graylog/index.js +188 -0
  186. package/dist/nosql/gridgain/index.js +171 -0
  187. package/dist/nosql/hazelcast/index.js +162 -0
  188. package/dist/nosql/hbase/index.js +230 -0
  189. package/dist/nosql/ignite/index.js +173 -0
  190. package/dist/nosql/immudb/index.js +184 -0
  191. package/dist/nosql/index.js +232 -0
  192. package/dist/nosql/infinispan/index.js +200 -0
  193. package/dist/nosql/influxdb/index.js +0 -0
  194. package/dist/nosql/kafka/index.js +234 -0
  195. package/dist/nosql/keyspaces/index.js +189 -0
  196. package/dist/nosql/kinesis/index.js +253 -0
  197. package/dist/nosql/leveldb/index.js +153 -0
  198. package/dist/nosql/lmdb/index.js +160 -0
  199. package/dist/nosql/loki/index.js +201 -0
  200. package/dist/nosql/marklogic/index.js +204 -0
  201. package/dist/nosql/materialize/index.js +145 -0
  202. package/dist/nosql/meilisearch/index.js +154 -0
  203. package/dist/nosql/memcached/index.js +223 -0
  204. package/dist/nosql/milvus/index.js +410 -0
  205. package/dist/nosql/minio/index.js +265 -0
  206. package/dist/nosql/momento/index.js +179 -0
  207. package/dist/nosql/mongodb/index.js +461 -0
  208. package/dist/nosql/nats/index.js +247 -0
  209. package/dist/nosql/nedb/index.js +164 -0
  210. package/dist/nosql/neo4j/index.js +450 -0
  211. package/dist/nosql/neptune/index.js +470 -0
  212. package/dist/nosql/nsq/index.js +200 -0
  213. package/dist/nosql/opensearch/index.js +186 -0
  214. package/dist/nosql/orientdb/index.js +175 -0
  215. package/dist/nosql/papertrail/index.js +200 -0
  216. package/dist/nosql/pinecone/index.js +0 -0
  217. package/dist/nosql/pinot/index.js +133 -0
  218. package/dist/nosql/pouchdb/index.js +172 -0
  219. package/dist/nosql/prometheus/index.js +174 -0
  220. package/dist/nosql/provendb/index.js +147 -0
  221. package/dist/nosql/pubsub/index.js +187 -0
  222. package/dist/nosql/pulsar/index.js +232 -0
  223. package/dist/nosql/qdrant/index.js +295 -0
  224. package/dist/nosql/qldb/index.js +192 -0
  225. package/dist/nosql/r2/index.js +281 -0
  226. package/dist/nosql/rabbitmq/index.js +237 -0
  227. package/dist/nosql/ravendb/index.js +175 -0
  228. package/dist/nosql/redis/index.js +607 -0
  229. package/dist/nosql/redpanda/index.js +237 -0
  230. package/dist/nosql/resque/index.js +203 -0
  231. package/dist/nosql/rethinkdb/index.js +232 -0
  232. package/dist/nosql/rocksdb/index.js +152 -0
  233. package/dist/nosql/rockset/index.js +126 -0
  234. package/dist/nosql/s3/index.js +298 -0
  235. package/dist/nosql/scylladb/index.js +178 -0
  236. package/dist/nosql/signoz/index.js +227 -0
  237. package/dist/nosql/sns/index.js +201 -0
  238. package/dist/nosql/solr/index.js +231 -0
  239. package/dist/nosql/splunk/index.js +227 -0
  240. package/dist/nosql/sqs/index.js +246 -0
  241. package/dist/nosql/stardog/index.js +169 -0
  242. package/dist/nosql/starrocks/index.js +170 -0
  243. package/dist/nosql/store.js +2 -0
  244. package/dist/nosql/sumologic/index.js +213 -0
  245. package/dist/nosql/surrealdb/index.js +179 -0
  246. package/dist/nosql/terminusdb/index.js +151 -0
  247. package/dist/nosql/tigergraph/index.js +469 -0
  248. package/dist/nosql/typesense/index.js +148 -0
  249. package/dist/nosql/unqlite/index.js +157 -0
  250. package/dist/nosql/upstash/index.js +167 -0
  251. package/dist/nosql/vercel-kv/index.js +166 -0
  252. package/dist/nosql/victoriametrics/index.js +213 -0
  253. package/dist/nosql/virtuoso/index.js +169 -0
  254. package/dist/nosql/weaviate/index.js +276 -0
  255. package/dist/operators/index.js +108 -0
  256. package/dist/operators.js +2690 -0
  257. package/dist/prisma-migrate/index.js +38 -0
  258. package/dist/prisma-migrate/migration-generator.js +125 -0
  259. package/dist/prisma-migrate/model-generator.js +172 -0
  260. package/dist/prisma-migrate/relations.js +100 -0
  261. package/dist/prisma-migrate/schema-parser.js +167 -0
  262. package/dist/prisma-migrate/type-mapper.js +40 -0
  263. package/dist/prorm.js +6832 -0
  264. package/dist/query-builders/cte-builder.js +80 -0
  265. package/dist/query-builders/functions/aggregate.js +390 -0
  266. package/dist/query-builders/functions/conditional.js +503 -0
  267. package/dist/query-builders/functions/datetime.js +695 -0
  268. package/dist/query-builders/functions/fulltext.js +439 -0
  269. package/dist/query-builders/functions/index.js +93 -0
  270. package/dist/query-builders/functions/json.js +427 -0
  271. package/dist/query-builders/functions/math.js +399 -0
  272. package/dist/query-builders/functions/string.js +518 -0
  273. package/dist/query-builders/functions/window.js +328 -0
  274. package/dist/query-builders/include-builder.js +323 -0
  275. package/dist/query-builders/index-expression-builder.js +242 -0
  276. package/dist/query-builders/index.js +161 -0
  277. package/dist/query-builders/insert-builder.js +164 -0
  278. package/dist/query-builders/model-helpers.js +38 -0
  279. package/dist/query-builders/order-limit-builder.js +239 -0
  280. package/dist/query-builders/sql-compiler.js +2040 -0
  281. package/dist/query-builders/subquery-builder.js +152 -0
  282. package/dist/query-builders/update-builder.js +182 -0
  283. package/dist/query-builders/view-builder.js +218 -0
  284. package/dist/query-builders/where-builder.js +1532 -0
  285. package/dist/query-interface.js +622 -0
  286. package/dist/query-optimizers/batch-optimizer.js +426 -0
  287. package/dist/query-optimizers/explain-plans.js +415 -0
  288. package/dist/query-optimizers/index.js +51 -0
  289. package/dist/query-optimizers/prepared-statement-cache.js +423 -0
  290. package/dist/query-optimizers/query-hints.js +438 -0
  291. package/dist/query-optimizers/query-optimizer.js +278 -0
  292. package/dist/query-optimizers/slow-query-logger.js +271 -0
  293. package/dist/replica-manager.js +507 -0
  294. package/dist/schema/index.js +15 -0
  295. package/dist/schema/migration-generator.js +374 -0
  296. package/dist/schema/schema-differ.js +549 -0
  297. package/dist/schema/types.js +6 -0
  298. package/dist/sql-constants.js +300 -0
  299. package/dist/sqlite-advanced.js +1047 -0
  300. package/dist/streams/index.js +12 -0
  301. package/dist/streams/transforms.js +178 -0
  302. package/dist/transaction.js +456 -0
  303. package/dist/types/index.js +180 -0
  304. package/dist/user-management.js +127 -0
  305. package/dist/utils/date.js +300 -0
  306. package/dist/utils/index.js +1079 -0
  307. package/dist/utils/string.js +161 -0
  308. package/dist/validators/index.js +19 -0
  309. package/dist/validators/validator.js +911 -0
  310. package/package.json +190 -0
@@ -0,0 +1,512 @@
1
+ "use strict";
2
+ /**
3
+ * Timezone Decorator for the ORM
4
+ *
5
+ * Provides automatic timezone conversion for date/time columns.
6
+ * Supports column-level, table-level, and database-level timezone configuration.
7
+ *
8
+ * Usage:
9
+ *
10
+ * // Column-level timezone
11
+ * @Timezone('UTC') // Store as UTC, convert on read/write
12
+ * createdAt: Date;
13
+ *
14
+ * @Timezone('America/New_York') // Eastern time
15
+ * orderPlacedAt: Date;
16
+ *
17
+ * @Timezone('Europe/London') // British time
18
+ * updatedAt: Date;
19
+ *
20
+ * // Auto-detect from user context
21
+ * @Timezone({ from: 'user' })
22
+ * lastLoginAt: Date;
23
+ *
24
+ * // With format options
25
+ * @Timezone({
26
+ * zone: 'UTC',
27
+ * format: 'ISO', // 'ISO', 'DATE', 'DATETIME', 'TIMESTAMP'
28
+ * storeAs: 'utc' // 'utc', 'local', 'string'
29
+ * })
30
+ * timestamp: Date;
31
+ *
32
+ * // Table-level default timezone
33
+ * @Table({ timezone: 'America/Los_Angeles' })
34
+ * class WestCoastOrder extends Model {}
35
+ *
36
+ * // Database-level timezone setting
37
+ * @DatabaseSetting('timezone', 'UTC')
38
+ */
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.TimezoneEnum = void 0;
41
+ exports.setTimezoneContext = setTimezoneContext;
42
+ exports.getTimezoneContext = getTimezoneContext;
43
+ exports.clearTimezoneContext = clearTimezoneContext;
44
+ exports.resolveTimezoneFromContext = resolveTimezoneFromContext;
45
+ exports.getTimezoneFields = getTimezoneFields;
46
+ exports.getTimezoneForField = getTimezoneForField;
47
+ exports.getTableTimezone = getTableTimezone;
48
+ exports.getDefaultTimezone = getDefaultTimezone;
49
+ exports.convertToTimezone = convertToTimezone;
50
+ exports.convertFromTimezone = convertFromTimezone;
51
+ exports.formatDateTimezone = formatDateTimezone;
52
+ exports.parseDate = parseDate;
53
+ exports.convertOnRead = convertOnRead;
54
+ exports.convertOnWrite = convertOnWrite;
55
+ exports.Timezone = Timezone;
56
+ exports.applyTimezoneToQuery = applyTimezoneToQuery;
57
+ exports.convertWhereToTimezone = convertWhereToTimezone;
58
+ exports.getEffectiveTimezone = getEffectiveTimezone;
59
+ exports.getAllTimezoneFields = getAllTimezoneFields;
60
+ exports.convertInstanceOnRead = convertInstanceOnRead;
61
+ exports.convertInstanceOnWrite = convertInstanceOnWrite;
62
+ exports.applyTimezoneHooks = applyTimezoneHooks;
63
+ require("reflect-metadata");
64
+ // ==================== Constants ====================
65
+ /**
66
+ * Common timezone constants for easy reference
67
+ */
68
+ exports.TimezoneEnum = {
69
+ UTC: 'UTC',
70
+ US_EASTERN: 'America/New_York',
71
+ US_CENTRAL: 'America/Chicago',
72
+ US_MOUNTAIN: 'America/Denver',
73
+ US_PACIFIC: 'America/Los_Angeles',
74
+ EUROPE_LONDON: 'Europe/London',
75
+ EUROPE_PARIS: 'Europe/Paris',
76
+ EUROPE_BERLIN: 'Europe/Berlin',
77
+ ASIA_TOKYO: 'Asia/Tokyo',
78
+ ASIA_SHANGHAI: 'Asia/Shanghai',
79
+ ASIA_SINGAPORE: 'Asia/Singapore',
80
+ AUSTRALIA_SYDNEY: 'Australia/Sydney',
81
+ };
82
+ /**
83
+ * Metadata keys for storing timezone information
84
+ */
85
+ const TIMEZONE_FIELDS_KEY = '__orm_timezone_fields__';
86
+ const TABLE_TIMEZONE_KEY = '__orm_table_timezone__';
87
+ const DEFAULT_TIMEZONE_KEY = '__orm_default_timezone__';
88
+ // ==================== Context Management ====================
89
+ /**
90
+ * Current timezone context (thread-local storage for request scope)
91
+ */
92
+ let currentTimezoneContext = null;
93
+ /**
94
+ * Set timezone context for current request/operation
95
+ *
96
+ * @param context - The timezone context
97
+ */
98
+ function setTimezoneContext(context) {
99
+ currentTimezoneContext = context;
100
+ }
101
+ /**
102
+ * Get current timezone context
103
+ *
104
+ * @returns The current timezone context
105
+ */
106
+ function getTimezoneContext() {
107
+ return currentTimezoneContext;
108
+ }
109
+ /**
110
+ * Clear timezone context
111
+ */
112
+ function clearTimezoneContext() {
113
+ currentTimezoneContext = null;
114
+ }
115
+ /**
116
+ * Get timezone from context based on source configuration
117
+ *
118
+ * @param source - The timezone source configuration
119
+ * @returns The resolved timezone string
120
+ */
121
+ function resolveTimezoneFromContext(source) {
122
+ if (typeof source === 'string') {
123
+ return source;
124
+ }
125
+ if (typeof source === 'object' && 'from' in source) {
126
+ const ctx = currentTimezoneContext;
127
+ if (!ctx)
128
+ return undefined;
129
+ switch (source.from) {
130
+ case 'user':
131
+ return ctx.timezone;
132
+ case 'request':
133
+ case 'context':
134
+ return ctx.timezone || ctx.request?.timezone || ctx.timezone;
135
+ default:
136
+ return undefined;
137
+ }
138
+ }
139
+ return undefined;
140
+ }
141
+ // ==================== Metadata Storage ====================
142
+ /**
143
+ * Get all timezone field metadata from a model class
144
+ */
145
+ function getTimezoneFields(target) {
146
+ return target[TIMEZONE_FIELDS_KEY] || [];
147
+ }
148
+ /**
149
+ * Get timezone metadata for a specific field
150
+ */
151
+ function getTimezoneForField(target, field) {
152
+ const fields = getTimezoneFields(target);
153
+ return fields.find((f) => f.field === field);
154
+ }
155
+ /**
156
+ * Get table-level timezone configuration
157
+ */
158
+ function getTableTimezone(target) {
159
+ return target[TABLE_TIMEZONE_KEY];
160
+ }
161
+ /**
162
+ * Get default timezone from class
163
+ */
164
+ function getDefaultTimezone(target) {
165
+ return target[DEFAULT_TIMEZONE_KEY];
166
+ }
167
+ // ==================== Timezone Conversion ====================
168
+ /**
169
+ * Convert date to specified timezone
170
+ *
171
+ * @param date - The date to convert
172
+ * @param targetZone - Target timezone (e.g., 'America/New_York')
173
+ * @returns Date adjusted to target timezone
174
+ */
175
+ function convertToTimezone(date, targetZone) {
176
+ // Get offset for target timezone
177
+ const targetDate = new Date(date.toLocaleString('en-US', { timeZone: targetZone }));
178
+ const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }));
179
+ const offsetMs = targetDate.getTime() - utcDate.getTime();
180
+ const result = new Date(date.getTime() + offsetMs);
181
+ return result;
182
+ }
183
+ /**
184
+ * Convert date from specified timezone to UTC
185
+ *
186
+ * @param date - The date to convert
187
+ * @param sourceZone - Source timezone (e.g., 'America/New_York')
188
+ * @returns Date in UTC
189
+ */
190
+ function convertFromTimezone(date, sourceZone) {
191
+ // Create date as if it's in the source timezone
192
+ const str = date.toISOString();
193
+ const sourceDateStr = date.toLocaleString('en-US', { timeZone: sourceZone });
194
+ const sourceDate = new Date(sourceDateStr);
195
+ // Calculate the offset
196
+ const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }));
197
+ const offsetMs = sourceDate.getTime() - utcDate.getTime();
198
+ return new Date(date.getTime() - offsetMs);
199
+ }
200
+ /**
201
+ * Format date according to specified format
202
+ *
203
+ * @param date - The date to format
204
+ * @param format - The format type
205
+ * @returns Formatted date string or timestamp
206
+ */
207
+ function formatDateTimezone(date, format) {
208
+ switch (format) {
209
+ case 'ISO':
210
+ return date.toISOString();
211
+ case 'DATE':
212
+ return date.toISOString().split('T')[0];
213
+ case 'DATETIME':
214
+ return date.toISOString().replace('T', ' ').split('.')[0];
215
+ case 'TIMESTAMP':
216
+ return date.getTime();
217
+ default:
218
+ return date.toISOString();
219
+ }
220
+ }
221
+ /**
222
+ * Parse date from database storage format
223
+ *
224
+ * @param value - The value from database
225
+ * @param format - The expected format
226
+ * @returns Parsed Date object
227
+ */
228
+ function parseDate(value, format) {
229
+ if (value === null || value === undefined) {
230
+ return null;
231
+ }
232
+ if (value instanceof Date) {
233
+ return value;
234
+ }
235
+ if (typeof value === 'number') {
236
+ // Timestamp
237
+ return new Date(value);
238
+ }
239
+ if (typeof value === 'string') {
240
+ return new Date(value);
241
+ }
242
+ return null;
243
+ }
244
+ // ==================== Field-Level Operations ====================
245
+ /**
246
+ * Convert value when reading from database
247
+ *
248
+ * @param value - Raw value from database
249
+ * @param meta - Timezone metadata
250
+ * @returns Converted value
251
+ */
252
+ function convertOnRead(value, meta) {
253
+ if (!meta.convertOnRead) {
254
+ return value;
255
+ }
256
+ const date = parseDate(value, meta.format);
257
+ if (!date) {
258
+ return value;
259
+ }
260
+ // Resolve actual timezone
261
+ let targetZone;
262
+ if (typeof meta.zone === 'string') {
263
+ targetZone = meta.zone;
264
+ }
265
+ else {
266
+ targetZone = resolveTimezoneFromContext(meta.zone);
267
+ }
268
+ if (!targetZone) {
269
+ return value;
270
+ }
271
+ // Convert to target timezone
272
+ const converted = convertToTimezone(date, targetZone);
273
+ // Return in requested format
274
+ if (meta.storeAs === 'string') {
275
+ return formatDateTimezone(converted, meta.format);
276
+ }
277
+ return converted;
278
+ }
279
+ /**
280
+ * Convert value when writing to database
281
+ *
282
+ * @param value - Value from application
283
+ * @param meta - Timezone metadata
284
+ * @returns Value ready for database
285
+ */
286
+ function convertOnWrite(value, meta) {
287
+ if (!meta.convertOnWrite) {
288
+ return value;
289
+ }
290
+ if (value === null || value === undefined) {
291
+ return value;
292
+ }
293
+ const date = value instanceof Date ? value : new Date(value);
294
+ if (isNaN(date.getTime())) {
295
+ return value;
296
+ }
297
+ // Resolve source timezone
298
+ let sourceZone;
299
+ if (typeof meta.zone === 'string') {
300
+ sourceZone = meta.zone;
301
+ }
302
+ else {
303
+ sourceZone = resolveTimezoneFromContext(meta.zone);
304
+ }
305
+ // If storing as UTC, convert to UTC
306
+ if (meta.storeAs === 'utc') {
307
+ return date.toISOString();
308
+ }
309
+ // If storing as string with timezone info
310
+ if (meta.storeAs === 'string') {
311
+ return formatDateTimezone(date, meta.format);
312
+ }
313
+ // Store as local time
314
+ return date;
315
+ }
316
+ // ==================== Decorators ====================
317
+ /**
318
+ * Column-level timezone decorator
319
+ *
320
+ * @param options - Timezone options or timezone string
321
+ */
322
+ function Timezone(options = {}) {
323
+ return function (target, propertyKey) {
324
+ const field = propertyKey;
325
+ const column = typeof options === 'string' ? options : options.column || propertyKey;
326
+ const zone = typeof options === 'string' ? options : options.zone || 'UTC';
327
+ const format = typeof options === 'string' ? 'ISO' : options.format || 'ISO';
328
+ const storeAs = typeof options === 'string' ? 'utc' : options.storeAs || 'utc';
329
+ const convertOnRead = typeof options === 'string' ? true : (options.convertOnRead ?? true);
330
+ const convertOnWrite = typeof options === 'string' ? true : (options.convertOnWrite ?? true);
331
+ // Store on the prototype (class), not the instance
332
+ const Constructor = target.constructor;
333
+ if (!Constructor[TIMEZONE_FIELDS_KEY]) {
334
+ Constructor[TIMEZONE_FIELDS_KEY] = [];
335
+ }
336
+ Constructor[TIMEZONE_FIELDS_KEY].push({
337
+ field,
338
+ column,
339
+ zone,
340
+ format,
341
+ storeAs,
342
+ convertOnRead,
343
+ convertOnWrite,
344
+ });
345
+ };
346
+ }
347
+ // ==================== Query Helper ====================
348
+ /**
349
+ * Apply timezone conversion to query options
350
+ *
351
+ * @param queryOptions - Original query options
352
+ * @param targetTimezone - Target timezone for conversion
353
+ * @returns Modified query options with timezone
354
+ */
355
+ function applyTimezoneToQuery(queryOptions, targetTimezone) {
356
+ if (!queryOptions) {
357
+ return { timezone: targetTimezone };
358
+ }
359
+ return {
360
+ ...queryOptions,
361
+ timezone: targetTimezone,
362
+ };
363
+ }
364
+ /**
365
+ * Convert where clause dates to specified timezone
366
+ *
367
+ * @param where - Original where clause
368
+ * @param timezone - Target timezone
369
+ * @returns Modified where clause with timezone context
370
+ */
371
+ function convertWhereToTimezone(where, timezone) {
372
+ if (!where) {
373
+ return where;
374
+ }
375
+ // Process each key in the where clause
376
+ const result = {};
377
+ for (const [key, value] of Object.entries(where)) {
378
+ if (value instanceof Date) {
379
+ // Convert date to target timezone
380
+ result[key] = convertToTimezone(value, timezone);
381
+ }
382
+ else if (typeof value === 'object' && value !== null) {
383
+ // Recursively process nested objects
384
+ result[key] = convertWhereToTimezone(value, timezone);
385
+ }
386
+ else {
387
+ result[key] = value;
388
+ }
389
+ }
390
+ return result;
391
+ }
392
+ // ==================== Model-Level Helpers ====================
393
+ /**
394
+ * Get effective timezone for a field (column-level or table-level default)
395
+ *
396
+ * @param target - Model class
397
+ * @param field - Field name
398
+ * @returns Effective timezone or undefined
399
+ */
400
+ function getEffectiveTimezone(target, field) {
401
+ // Check column-level first
402
+ const fieldMeta = getTimezoneForField(target, field);
403
+ if (fieldMeta) {
404
+ if (typeof fieldMeta.zone === 'string') {
405
+ return fieldMeta.zone;
406
+ }
407
+ return resolveTimezoneFromContext(fieldMeta.zone);
408
+ }
409
+ // Fall back to table-level default
410
+ const tableOptions = getTableTimezone(target);
411
+ if (tableOptions?.timezone) {
412
+ return tableOptions.timezone;
413
+ }
414
+ // Fall back to global default
415
+ return getDefaultTimezone(target);
416
+ }
417
+ /**
418
+ * Get all timezone metadata for a model including table defaults
419
+ *
420
+ * @param target - Model class
421
+ * @returns Array of timezone field metadata
422
+ */
423
+ function getAllTimezoneFields(target) {
424
+ return getTimezoneFields(target);
425
+ }
426
+ /**
427
+ * Convert model instance field values based on timezone metadata
428
+ *
429
+ * @param instance - Model instance
430
+ * @param targetTimezone - Target timezone for conversion
431
+ * @returns Converted instance values
432
+ */
433
+ function convertInstanceOnRead(instance, targetTimezone) {
434
+ const ModelClass = instance.constructor;
435
+ const timezoneFields = getTimezoneFields(ModelClass);
436
+ if (timezoneFields.length === 0) {
437
+ return instance;
438
+ }
439
+ const result = {};
440
+ for (const [key, value] of Object.entries(instance.toJSON ? instance.toJSON() : instance)) {
441
+ const meta = timezoneFields.find((f) => f.field === key || f.column === key);
442
+ if (meta) {
443
+ result[key] = convertOnRead(value, {
444
+ ...meta,
445
+ zone: targetTimezone,
446
+ });
447
+ }
448
+ else {
449
+ result[key] = value;
450
+ }
451
+ }
452
+ return result;
453
+ }
454
+ /**
455
+ * Convert model instance field values before writing to database
456
+ *
457
+ * @param instance - Model instance
458
+ * @returns Converted values ready for database
459
+ */
460
+ function convertInstanceOnWrite(instance) {
461
+ const ModelClass = instance.constructor;
462
+ const timezoneFields = getTimezoneFields(ModelClass);
463
+ if (timezoneFields.length === 0) {
464
+ return instance;
465
+ }
466
+ const result = {};
467
+ const data = instance.getDataValue
468
+ ? (() => {
469
+ const data = {};
470
+ for (const f of timezoneFields) {
471
+ data[f.column] = instance.getDataValue(f.field);
472
+ }
473
+ return data;
474
+ })()
475
+ : instance;
476
+ for (const [key, value] of Object.entries(data)) {
477
+ const meta = timezoneFields.find((f) => f.field === key || f.column === key);
478
+ if (meta) {
479
+ const converted = convertOnWrite(value, meta);
480
+ result[meta.column] = converted;
481
+ }
482
+ else {
483
+ result[key] = value;
484
+ }
485
+ }
486
+ return result;
487
+ }
488
+ // ==================== Hook Registration ====================
489
+ /**
490
+ * Register hooks for automatic timezone conversion
491
+ * Call this after Model.init()
492
+ *
493
+ * @param ModelClass - The model class
494
+ */
495
+ function applyTimezoneHooks(ModelClass) {
496
+ const timezoneFields = getTimezoneFields(ModelClass);
497
+ if (timezoneFields.length === 0)
498
+ return;
499
+ // Before find hooks to set timezone context
500
+ if (typeof ModelClass.addHook === 'function') {
501
+ ModelClass.addHook('beforeFind', 'orm:timezone', async (instance) => {
502
+ // Set context based on query options if timezone specified
503
+ const timezone = instance._timezone || instance.timezone;
504
+ if (timezone) {
505
+ setTimezoneContext({ timezone });
506
+ }
507
+ });
508
+ ModelClass.addHook('afterFind', 'orm:timezone', async () => {
509
+ clearTimezoneContext();
510
+ });
511
+ }
512
+ }
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ /**
3
+ * @Trigger class decorator — declare a database trigger on a model class.
4
+ *
5
+ * Stores trigger metadata using plain class properties (no reflect-metadata
6
+ * dependency) consistent with the rest of this decorator suite.
7
+ *
8
+ * Example:
9
+ *
10
+ * @Trigger({
11
+ * name: 'trg_users_audit',
12
+ * timing: 'AFTER',
13
+ * event: 'INSERT',
14
+ * body: `INSERT INTO audit_log(action, ts) VALUES ('INSERT', NOW())`,
15
+ * forEach: 'ROW',
16
+ * })
17
+ * class User extends Model { ... }
18
+ *
19
+ * // Retrieve trigger definitions:
20
+ * const triggers = getTriggers(User);
21
+ *
22
+ * // Generate DDL:
23
+ * const sql = buildCreateTriggerSQL('users', triggers[0], 'mysql');
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.Trigger = Trigger;
27
+ exports.getTriggers = getTriggers;
28
+ exports.buildCreateTriggerSQL = buildCreateTriggerSQL;
29
+ // ==================== Metadata key ====================
30
+ const TRIGGERS_KEY = '__orm_triggers__';
31
+ // ==================== Decorator ====================
32
+ /**
33
+ * Attach a trigger definition to a model class.
34
+ * Multiple @Trigger decorators may be stacked on the same class.
35
+ */
36
+ function Trigger(options) {
37
+ return (target) => {
38
+ if (!target[TRIGGERS_KEY]) {
39
+ target[TRIGGERS_KEY] = [];
40
+ }
41
+ target[TRIGGERS_KEY] = [...target[TRIGGERS_KEY], options];
42
+ };
43
+ }
44
+ // ==================== Helpers ====================
45
+ /**
46
+ * Return all trigger definitions registered on a class.
47
+ */
48
+ function getTriggers(target) {
49
+ return target[TRIGGERS_KEY] || [];
50
+ }
51
+ /**
52
+ * Generate a CREATE TRIGGER DDL statement for the given dialect.
53
+ *
54
+ * Supported dialects: 'mysql' | 'mariadb' | 'postgres' | 'sqlite'
55
+ */
56
+ function buildCreateTriggerSQL(tableName, trigger, dialect) {
57
+ const forEach = trigger.forEach ?? 'ROW';
58
+ const name = trigger.name;
59
+ switch (dialect) {
60
+ case 'postgres': {
61
+ // PostgreSQL requires a trigger function; we embed the body in a
62
+ // DO-style anonymous block as a convention for metadata purposes.
63
+ const fnName = `${name}_fn`;
64
+ const createFn = `CREATE OR REPLACE FUNCTION ${fnName}()\n` +
65
+ `RETURNS TRIGGER LANGUAGE plpgsql AS $$\n` +
66
+ `BEGIN\n ${trigger.body}\n RETURN NEW;\nEND;\n$$`;
67
+ const createTrg = `CREATE TRIGGER ${name}\n` +
68
+ ` ${trigger.timing} ${trigger.event}\n` +
69
+ ` ON "${tableName}"\n` +
70
+ ` FOR EACH ${forEach}\n` +
71
+ ` EXECUTE FUNCTION ${fnName}()`;
72
+ return `${createFn};\n\n${createTrg}`;
73
+ }
74
+ case 'sqlite': {
75
+ // SQLite does not support FOR EACH STATEMENT; always ROW-level implicitly.
76
+ return (`CREATE TRIGGER IF NOT EXISTS ${name}\n` +
77
+ ` ${trigger.timing} ${trigger.event}\n` +
78
+ ` ON \`${tableName}\`\n` +
79
+ `BEGIN\n ${trigger.body};\nEND`);
80
+ }
81
+ // mysql / mariadb (default)
82
+ default: {
83
+ return (`CREATE TRIGGER \`${name}\`\n` +
84
+ ` ${trigger.timing} ${trigger.event}\n` +
85
+ ` ON \`${tableName}\`\n` +
86
+ ` FOR EACH ${forEach}\n` +
87
+ `BEGIN\n ${trigger.body};\nEND`);
88
+ }
89
+ }
90
+ }