@spinajs/orm 2.0.480 → 2.0.482

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 (228) hide show
  1. package/README.md +72 -3
  2. package/lib/cjs/bootstrap.js +10 -0
  3. package/lib/cjs/bootstrap.js.map +1 -1
  4. package/lib/cjs/builders.d.ts +115 -11
  5. package/lib/cjs/builders.d.ts.map +1 -1
  6. package/lib/cjs/builders.js +342 -283
  7. package/lib/cjs/builders.js.map +1 -1
  8. package/lib/cjs/converters.d.ts +9 -2
  9. package/lib/cjs/converters.d.ts.map +1 -1
  10. package/lib/cjs/converters.js +48 -8
  11. package/lib/cjs/converters.js.map +1 -1
  12. package/lib/cjs/decorators.d.ts +26 -3
  13. package/lib/cjs/decorators.d.ts.map +1 -1
  14. package/lib/cjs/decorators.js +95 -42
  15. package/lib/cjs/decorators.js.map +1 -1
  16. package/lib/cjs/dehydrators.js +1 -1
  17. package/lib/cjs/dehydrators.js.map +1 -1
  18. package/lib/cjs/descriptor.d.ts +1 -0
  19. package/lib/cjs/descriptor.d.ts.map +1 -1
  20. package/lib/cjs/descriptor.js +16 -40
  21. package/lib/cjs/descriptor.js.map +1 -1
  22. package/lib/cjs/driver.d.ts +136 -7
  23. package/lib/cjs/driver.d.ts.map +1 -1
  24. package/lib/cjs/driver.js +279 -0
  25. package/lib/cjs/driver.js.map +1 -1
  26. package/lib/cjs/existsRelationHandlers.d.ts +29 -0
  27. package/lib/cjs/existsRelationHandlers.d.ts.map +1 -0
  28. package/lib/cjs/existsRelationHandlers.js +104 -0
  29. package/lib/cjs/existsRelationHandlers.js.map +1 -0
  30. package/lib/cjs/fp.d.ts.map +1 -1
  31. package/lib/cjs/fp.js +10 -15
  32. package/lib/cjs/fp.js.map +1 -1
  33. package/lib/cjs/hydrators.d.ts.map +1 -1
  34. package/lib/cjs/hydrators.js +29 -2
  35. package/lib/cjs/hydrators.js.map +1 -1
  36. package/lib/cjs/identity-map.d.ts +60 -0
  37. package/lib/cjs/identity-map.d.ts.map +1 -0
  38. package/lib/cjs/identity-map.js +135 -0
  39. package/lib/cjs/identity-map.js.map +1 -0
  40. package/lib/cjs/index.d.ts +12 -0
  41. package/lib/cjs/index.d.ts.map +1 -1
  42. package/lib/cjs/index.js +12 -0
  43. package/lib/cjs/index.js.map +1 -1
  44. package/lib/cjs/interfaces.d.ts +295 -9
  45. package/lib/cjs/interfaces.d.ts.map +1 -1
  46. package/lib/cjs/interfaces.js +54 -1
  47. package/lib/cjs/interfaces.js.map +1 -1
  48. package/lib/cjs/metadata.d.ts.map +1 -1
  49. package/lib/cjs/metadata.js +4 -1
  50. package/lib/cjs/metadata.js.map +1 -1
  51. package/lib/cjs/metrics.d.ts +53 -0
  52. package/lib/cjs/metrics.d.ts.map +1 -0
  53. package/lib/cjs/metrics.js +82 -0
  54. package/lib/cjs/metrics.js.map +1 -0
  55. package/lib/cjs/middlewares.d.ts +13 -1
  56. package/lib/cjs/middlewares.d.ts.map +1 -1
  57. package/lib/cjs/middlewares.js +55 -15
  58. package/lib/cjs/middlewares.js.map +1 -1
  59. package/lib/cjs/model.d.ts +129 -13
  60. package/lib/cjs/model.d.ts.map +1 -1
  61. package/lib/cjs/model.js +449 -93
  62. package/lib/cjs/model.js.map +1 -1
  63. package/lib/cjs/orm.d.ts.map +1 -1
  64. package/lib/cjs/orm.js +12 -3
  65. package/lib/cjs/orm.js.map +1 -1
  66. package/lib/cjs/orphan.d.ts +27 -0
  67. package/lib/cjs/orphan.d.ts.map +1 -0
  68. package/lib/cjs/orphan.js +55 -0
  69. package/lib/cjs/orphan.js.map +1 -0
  70. package/lib/cjs/primary-keys.d.ts +60 -0
  71. package/lib/cjs/primary-keys.d.ts.map +1 -0
  72. package/lib/cjs/primary-keys.js +243 -0
  73. package/lib/cjs/primary-keys.js.map +1 -0
  74. package/lib/cjs/relation-objects.d.ts +101 -9
  75. package/lib/cjs/relation-objects.d.ts.map +1 -1
  76. package/lib/cjs/relation-objects.js +194 -43
  77. package/lib/cjs/relation-objects.js.map +1 -1
  78. package/lib/cjs/relations.d.ts +7 -1
  79. package/lib/cjs/relations.d.ts.map +1 -1
  80. package/lib/cjs/relations.js +16 -1
  81. package/lib/cjs/relations.js.map +1 -1
  82. package/lib/cjs/resilience.d.ts +50 -0
  83. package/lib/cjs/resilience.d.ts.map +1 -0
  84. package/lib/cjs/resilience.js +70 -0
  85. package/lib/cjs/resilience.js.map +1 -0
  86. package/lib/cjs/snapshot.d.ts +58 -0
  87. package/lib/cjs/snapshot.d.ts.map +1 -0
  88. package/lib/cjs/snapshot.js +125 -0
  89. package/lib/cjs/snapshot.js.map +1 -0
  90. package/lib/cjs/statements.d.ts +11 -1
  91. package/lib/cjs/statements.d.ts.map +1 -1
  92. package/lib/cjs/statements.js +13 -2
  93. package/lib/cjs/statements.js.map +1 -1
  94. package/lib/cjs/subject-builder.d.ts +79 -0
  95. package/lib/cjs/subject-builder.d.ts.map +1 -0
  96. package/lib/cjs/subject-builder.js +296 -0
  97. package/lib/cjs/subject-builder.js.map +1 -0
  98. package/lib/cjs/subject-executor.d.ts +122 -0
  99. package/lib/cjs/subject-executor.d.ts.map +1 -0
  100. package/lib/cjs/subject-executor.js +319 -0
  101. package/lib/cjs/subject-executor.js.map +1 -0
  102. package/lib/cjs/subject-sorter.d.ts +70 -0
  103. package/lib/cjs/subject-sorter.d.ts.map +1 -0
  104. package/lib/cjs/subject-sorter.js +173 -0
  105. package/lib/cjs/subject-sorter.js.map +1 -0
  106. package/lib/cjs/subject.d.ts +100 -0
  107. package/lib/cjs/subject.d.ts.map +1 -0
  108. package/lib/cjs/subject.js +89 -0
  109. package/lib/cjs/subject.js.map +1 -0
  110. package/lib/cjs/unit-of-work.d.ts +52 -0
  111. package/lib/cjs/unit-of-work.d.ts.map +1 -0
  112. package/lib/cjs/unit-of-work.js +170 -0
  113. package/lib/cjs/unit-of-work.js.map +1 -0
  114. package/lib/mjs/bootstrap.js +10 -0
  115. package/lib/mjs/bootstrap.js.map +1 -1
  116. package/lib/mjs/builders.d.ts +115 -11
  117. package/lib/mjs/builders.d.ts.map +1 -1
  118. package/lib/mjs/builders.js +344 -285
  119. package/lib/mjs/builders.js.map +1 -1
  120. package/lib/mjs/converters.d.ts +9 -2
  121. package/lib/mjs/converters.d.ts.map +1 -1
  122. package/lib/mjs/converters.js +48 -8
  123. package/lib/mjs/converters.js.map +1 -1
  124. package/lib/mjs/decorators.d.ts +26 -3
  125. package/lib/mjs/decorators.d.ts.map +1 -1
  126. package/lib/mjs/decorators.js +96 -44
  127. package/lib/mjs/decorators.js.map +1 -1
  128. package/lib/mjs/dehydrators.js +1 -1
  129. package/lib/mjs/dehydrators.js.map +1 -1
  130. package/lib/mjs/descriptor.d.ts +1 -0
  131. package/lib/mjs/descriptor.d.ts.map +1 -1
  132. package/lib/mjs/descriptor.js +17 -39
  133. package/lib/mjs/descriptor.js.map +1 -1
  134. package/lib/mjs/driver.d.ts +136 -7
  135. package/lib/mjs/driver.d.ts.map +1 -1
  136. package/lib/mjs/driver.js +279 -0
  137. package/lib/mjs/driver.js.map +1 -1
  138. package/lib/mjs/existsRelationHandlers.d.ts +29 -0
  139. package/lib/mjs/existsRelationHandlers.d.ts.map +1 -0
  140. package/lib/mjs/existsRelationHandlers.js +100 -0
  141. package/lib/mjs/existsRelationHandlers.js.map +1 -0
  142. package/lib/mjs/fp.d.ts.map +1 -1
  143. package/lib/mjs/fp.js +10 -15
  144. package/lib/mjs/fp.js.map +1 -1
  145. package/lib/mjs/hydrators.d.ts.map +1 -1
  146. package/lib/mjs/hydrators.js +29 -2
  147. package/lib/mjs/hydrators.js.map +1 -1
  148. package/lib/mjs/identity-map.d.ts +60 -0
  149. package/lib/mjs/identity-map.d.ts.map +1 -0
  150. package/lib/mjs/identity-map.js +130 -0
  151. package/lib/mjs/identity-map.js.map +1 -0
  152. package/lib/mjs/index.d.ts +12 -0
  153. package/lib/mjs/index.d.ts.map +1 -1
  154. package/lib/mjs/index.js +12 -0
  155. package/lib/mjs/index.js.map +1 -1
  156. package/lib/mjs/interfaces.d.ts +295 -9
  157. package/lib/mjs/interfaces.d.ts.map +1 -1
  158. package/lib/mjs/interfaces.js +53 -0
  159. package/lib/mjs/interfaces.js.map +1 -1
  160. package/lib/mjs/metadata.d.ts.map +1 -1
  161. package/lib/mjs/metadata.js +4 -1
  162. package/lib/mjs/metadata.js.map +1 -1
  163. package/lib/mjs/metrics.d.ts +53 -0
  164. package/lib/mjs/metrics.d.ts.map +1 -0
  165. package/lib/mjs/metrics.js +76 -0
  166. package/lib/mjs/metrics.js.map +1 -0
  167. package/lib/mjs/middlewares.d.ts +13 -1
  168. package/lib/mjs/middlewares.d.ts.map +1 -1
  169. package/lib/mjs/middlewares.js +55 -15
  170. package/lib/mjs/middlewares.js.map +1 -1
  171. package/lib/mjs/model.d.ts +129 -13
  172. package/lib/mjs/model.d.ts.map +1 -1
  173. package/lib/mjs/model.js +451 -95
  174. package/lib/mjs/model.js.map +1 -1
  175. package/lib/mjs/orm.d.ts.map +1 -1
  176. package/lib/mjs/orm.js +12 -3
  177. package/lib/mjs/orm.js.map +1 -1
  178. package/lib/mjs/orphan.d.ts +27 -0
  179. package/lib/mjs/orphan.d.ts.map +1 -0
  180. package/lib/mjs/orphan.js +52 -0
  181. package/lib/mjs/orphan.js.map +1 -0
  182. package/lib/mjs/primary-keys.d.ts +60 -0
  183. package/lib/mjs/primary-keys.d.ts.map +1 -0
  184. package/lib/mjs/primary-keys.js +223 -0
  185. package/lib/mjs/primary-keys.js.map +1 -0
  186. package/lib/mjs/relation-objects.d.ts +101 -9
  187. package/lib/mjs/relation-objects.d.ts.map +1 -1
  188. package/lib/mjs/relation-objects.js +194 -43
  189. package/lib/mjs/relation-objects.js.map +1 -1
  190. package/lib/mjs/relations.d.ts +7 -1
  191. package/lib/mjs/relations.d.ts.map +1 -1
  192. package/lib/mjs/relations.js +16 -1
  193. package/lib/mjs/relations.js.map +1 -1
  194. package/lib/mjs/resilience.d.ts +50 -0
  195. package/lib/mjs/resilience.d.ts.map +1 -0
  196. package/lib/mjs/resilience.js +64 -0
  197. package/lib/mjs/resilience.js.map +1 -0
  198. package/lib/mjs/snapshot.d.ts +58 -0
  199. package/lib/mjs/snapshot.d.ts.map +1 -0
  200. package/lib/mjs/snapshot.js +115 -0
  201. package/lib/mjs/snapshot.js.map +1 -0
  202. package/lib/mjs/statements.d.ts +11 -1
  203. package/lib/mjs/statements.d.ts.map +1 -1
  204. package/lib/mjs/statements.js +14 -3
  205. package/lib/mjs/statements.js.map +1 -1
  206. package/lib/mjs/subject-builder.d.ts +79 -0
  207. package/lib/mjs/subject-builder.d.ts.map +1 -0
  208. package/lib/mjs/subject-builder.js +292 -0
  209. package/lib/mjs/subject-builder.js.map +1 -0
  210. package/lib/mjs/subject-executor.d.ts +122 -0
  211. package/lib/mjs/subject-executor.d.ts.map +1 -0
  212. package/lib/mjs/subject-executor.js +312 -0
  213. package/lib/mjs/subject-executor.js.map +1 -0
  214. package/lib/mjs/subject-sorter.d.ts +70 -0
  215. package/lib/mjs/subject-sorter.d.ts.map +1 -0
  216. package/lib/mjs/subject-sorter.js +168 -0
  217. package/lib/mjs/subject-sorter.js.map +1 -0
  218. package/lib/mjs/subject.d.ts +100 -0
  219. package/lib/mjs/subject.d.ts.map +1 -0
  220. package/lib/mjs/subject.js +84 -0
  221. package/lib/mjs/subject.js.map +1 -0
  222. package/lib/mjs/unit-of-work.d.ts +52 -0
  223. package/lib/mjs/unit-of-work.d.ts.map +1 -0
  224. package/lib/mjs/unit-of-work.js +166 -0
  225. package/lib/mjs/unit-of-work.js.map +1 -0
  226. package/lib/tsconfig.cjs.tsbuildinfo +1 -1
  227. package/lib/tsconfig.mjs.tsbuildinfo +1 -1
  228. package/package.json +9 -7
package/lib/cjs/driver.js CHANGED
@@ -16,9 +16,20 @@ const interfaces_js_1 = require("./interfaces.js");
16
16
  const di_1 = require("@spinajs/di");
17
17
  const builders_js_1 = require("./builders.js");
18
18
  const converters_js_1 = require("./converters.js");
19
+ const exceptions_js_1 = require("./exceptions.js");
20
+ const async_hooks_1 = require("async_hooks");
21
+ const resilience_js_1 = require("./resilience.js");
22
+ const metrics_js_1 = require("./metrics.js");
19
23
  require("./hydrators.js");
20
24
  require("./dehydrators.js");
21
25
  class OrmDriver extends di_1.SyncService {
26
+ /**
27
+ * The transaction currently in scope on this async execution path, or `undefined` outside
28
+ * a transaction.
29
+ */
30
+ get CurrentTransaction() {
31
+ return this.TransactionStorage.getStore();
32
+ }
22
33
  constructor(options) {
23
34
  super();
24
35
  /**
@@ -30,6 +41,22 @@ class OrmDriver extends di_1.SyncService {
30
41
  Name: 'orm-driver',
31
42
  DefaultConnection: false,
32
43
  };
44
+ /**
45
+ * Ambient transaction context.
46
+ *
47
+ * Statements executed inside a `transaction()` callback must run on that transaction's
48
+ * connection. This lives on the abstract driver — rather than being a MySQL implementation
49
+ * detail, as it used to be — so the guarantee is part of the contract and every driver
50
+ * inherits it.
51
+ */
52
+ this.TransactionStorage = new async_hooks_1.AsyncLocalStorage();
53
+ /**
54
+ * Isolation levels this driver honours. Empty by default: a driver that declares nothing
55
+ * rejects every explicitly requested isolation level rather than quietly ignoring it.
56
+ */
57
+ this.SupportedIsolationLevels = [];
58
+ this._state = resilience_js_1.ConnectionState.Disconnected;
59
+ this._healthCheckTimer = null;
33
60
  this.Options = Object.assign(this.Options, options);
34
61
  }
35
62
  resolve() {
@@ -44,6 +71,207 @@ class OrmDriver extends di_1.SyncService {
44
71
  this.Container.register(converters_js_1.UuidConverter).as(converters_js_1.UuidConverter);
45
72
  this.Container.register(converters_js_1.UniversalValueConverter).as(converters_js_1.UniversalValueConverter);
46
73
  }
74
+ /**
75
+ * Effective pool settings: `Pool.*` when given, then the deprecated `PoolLimit` for `Max`,
76
+ * then the defaults. Resolved in one place so every driver agrees on what "unset" means.
77
+ */
78
+ resolvedPoolOptions() {
79
+ const pool = this.Options.Pool ?? {};
80
+ return {
81
+ Min: pool.Min ?? 0,
82
+ Max: pool.Max ?? this.Options.PoolLimit ?? 10,
83
+ IdleTimeout: pool.IdleTimeout ?? 30000,
84
+ AcquireTimeout: pool.AcquireTimeout ?? 10000,
85
+ };
86
+ }
87
+ /**
88
+ * Current connection lifecycle state.
89
+ */
90
+ get State() {
91
+ return this._state;
92
+ }
93
+ /**
94
+ * Records a state transition and logs it. Repeat transitions to the same state are ignored.
95
+ */
96
+ setState(state) {
97
+ if (this._state === state) {
98
+ return;
99
+ }
100
+ const previous = this._state;
101
+ this._state = state;
102
+ if (state === resilience_js_1.ConnectionState.Connected) {
103
+ this.Log.info(`connection ${this.Options.Name} is ${state} (was ${previous})`);
104
+ }
105
+ else if (state === resilience_js_1.ConnectionState.Degraded || state === resilience_js_1.ConnectionState.Disconnected) {
106
+ this.Log.warn(`connection ${this.Options.Name} is ${state} (was ${previous})`);
107
+ }
108
+ else {
109
+ this.Log.trace(`connection ${this.Options.Name} is ${state} (was ${previous})`);
110
+ }
111
+ }
112
+ /**
113
+ * Effective resilience settings with defaults applied.
114
+ */
115
+ resolvedResilienceOptions() {
116
+ const r = this.Options.Resilience ?? {};
117
+ return {
118
+ HealthCheckInterval: r.HealthCheckInterval ?? 30000,
119
+ MaxRetries: r.MaxRetries ?? 5,
120
+ RetryDelay: r.RetryDelay ?? 200,
121
+ MaxRetryDelay: r.MaxRetryDelay ?? 5000,
122
+ };
123
+ }
124
+ /**
125
+ * True when the error means the transport died rather than the statement being wrong.
126
+ * Drivers override to add dialect-specific codes.
127
+ */
128
+ isRetryableError(err) {
129
+ return (0, resilience_js_1.isRetryableErrorCode)(err);
130
+ }
131
+ /**
132
+ * Runs `operation`, and on a retryable transport failure reconnects and retries with bounded
133
+ * exponential backoff. Query errors propagate on the first attempt untouched.
134
+ */
135
+ async withReconnect(operation) {
136
+ const { MaxRetries, RetryDelay, MaxRetryDelay } = this.resolvedResilienceOptions();
137
+ let lastError;
138
+ for (let attempt = 0; attempt <= MaxRetries; attempt++) {
139
+ try {
140
+ const result = await operation();
141
+ this.setState(resilience_js_1.ConnectionState.Connected);
142
+ return result;
143
+ }
144
+ catch (err) {
145
+ if (!this.isRetryableError(err)) {
146
+ throw err;
147
+ }
148
+ lastError = err;
149
+ this.setState(resilience_js_1.ConnectionState.Degraded);
150
+ if (attempt === MaxRetries) {
151
+ break;
152
+ }
153
+ const wait = (0, resilience_js_1.backoffDelay)(attempt, RetryDelay, MaxRetryDelay);
154
+ this.Log.warn(`connection ${this.Options.Name} lost (${err.message}); reconnect attempt ${attempt + 1}/${MaxRetries} in ${wait}ms`);
155
+ await (0, resilience_js_1.delay)(wait);
156
+ try {
157
+ this.setState(resilience_js_1.ConnectionState.Connecting);
158
+ await this.connect();
159
+ }
160
+ catch (reconnectErr) {
161
+ this.Log.warn(`reconnect attempt ${attempt + 1} for ${this.Options.Name} failed: ${reconnectErr.message}`);
162
+ this.setState(resilience_js_1.ConnectionState.Degraded);
163
+ }
164
+ }
165
+ }
166
+ this.setState(resilience_js_1.ConnectionState.Disconnected);
167
+ throw lastError;
168
+ }
169
+ /**
170
+ * Starts the periodic health probe. Replaces the single startup `ping()` — a connection that
171
+ * was healthy at boot tells you nothing about a pool holding sockets to a database that has
172
+ * since restarted. No-op when `Resilience.HealthCheckInterval` is 0. Idempotent.
173
+ */
174
+ startHealthCheck() {
175
+ const { HealthCheckInterval } = this.resolvedResilienceOptions();
176
+ if (HealthCheckInterval <= 0 || this._healthCheckTimer !== null) {
177
+ return;
178
+ }
179
+ this._healthCheckTimer = setInterval(() => {
180
+ void this.runHealthCheck();
181
+ }, HealthCheckInterval);
182
+ // Never hold the process open just to probe a database.
183
+ if (typeof this._healthCheckTimer.unref === 'function') {
184
+ this._healthCheckTimer.unref();
185
+ }
186
+ }
187
+ /**
188
+ * Stops the periodic health probe. Idempotent.
189
+ */
190
+ stopHealthCheck() {
191
+ if (this._healthCheckTimer !== null) {
192
+ clearInterval(this._healthCheckTimer);
193
+ this._healthCheckTimer = null;
194
+ }
195
+ }
196
+ /**
197
+ * One health probe. A failed probe degrades the driver and attempts a single reconnect; it
198
+ * never throws, because it runs on a timer with no caller to receive the error.
199
+ */
200
+ async runHealthCheck() {
201
+ this.publishPoolMetrics();
202
+ let alive = false;
203
+ try {
204
+ alive = await this.ping();
205
+ }
206
+ catch {
207
+ alive = false;
208
+ }
209
+ if (alive) {
210
+ this.setState(resilience_js_1.ConnectionState.Connected);
211
+ return;
212
+ }
213
+ this.setState(resilience_js_1.ConnectionState.Degraded);
214
+ try {
215
+ // The driver stays DEGRADED even when reconnecting succeeds: a fresh handle is not
216
+ // evidence that queries work. Only the next successful probe promotes it back to
217
+ // Connected — drivers whose own connect() verifies the link ( mysql takes and releases
218
+ // a real connection ) set the state themselves.
219
+ await this.connect();
220
+ }
221
+ catch (err) {
222
+ this.Log.warn(`health check reconnect for ${this.Options.Name} failed: ${err.message}`);
223
+ }
224
+ }
225
+ /**
226
+ * Point-in-time pool state. The base implementation reports an empty pool; drivers that own a
227
+ * real pool override it. Must never throw — it runs on the health-check timer.
228
+ */
229
+ poolMetrics() {
230
+ return { Size: 0, InUse: 0, Waiting: 0 };
231
+ }
232
+ /**
233
+ * Pushes the current pool state and connection state to the shared `Metrics` registry from
234
+ * `@spinajs/telemetry-common`. Nothing has to be wired for this to work — `Metrics` owns a
235
+ * private registry and `@spinajs/telemetry`'s `/metrics` endpoint renders that same singleton.
236
+ */
237
+ publishPoolMetrics() {
238
+ try {
239
+ const metrics = (0, metrics_js_1.ormMetrics)();
240
+ if (!metrics) {
241
+ return;
242
+ }
243
+ const labels = { connection: this.Options.Name };
244
+ const pool = this.poolMetrics();
245
+ (0, metrics_js_1.ormGauge)(metrics, metrics_js_1.ORM_METRIC_KEY_POOL_SIZE).set(labels, pool.Size);
246
+ (0, metrics_js_1.ormGauge)(metrics, metrics_js_1.ORM_METRIC_KEY_POOL_IN_USE).set(labels, pool.InUse);
247
+ (0, metrics_js_1.ormGauge)(metrics, metrics_js_1.ORM_METRIC_KEY_POOL_WAITING).set(labels, pool.Waiting);
248
+ (0, metrics_js_1.ormGauge)(metrics, metrics_js_1.ORM_METRIC_KEY_CONNECTION_STATE).set(labels, this.State === resilience_js_1.ConnectionState.Connected ? 1 : 0);
249
+ }
250
+ catch (err) {
251
+ // Telemetry must never break a connection. This runs first on every health tick, so a
252
+ // registry that throws — or a driver built outside DI, as tooling and tests do — would
253
+ // otherwise stop the probe that follows it from ever running.
254
+ this.Log?.trace(`publishing pool metrics for ${this.Options.Name} failed: ${err.message}`);
255
+ }
256
+ }
257
+ /**
258
+ * Records one pool-acquire wait, in SECONDS ( prometheus convention ). Drivers that own a real
259
+ * pool call this from the acquire callback; keeping the prom-client objects behind this method
260
+ * is what stops every driver from needing to know about `@spinajs/telemetry-common`. Never
261
+ * throws, for the same reason `publishPoolMetrics` never throws.
262
+ */
263
+ observeAcquireSeconds(seconds) {
264
+ try {
265
+ const metrics = (0, metrics_js_1.ormMetrics)();
266
+ if (!metrics) {
267
+ return;
268
+ }
269
+ (0, metrics_js_1.ormHistogram)(metrics, metrics_js_1.ORM_METRIC_KEY_ACQUIRE_SECONDS).observe({ connection: this.Options.Name }, seconds);
270
+ }
271
+ catch (err) {
272
+ this.Log?.trace(`observing pool acquire time for ${this.Options.Name} failed: ${err.message}`);
273
+ }
274
+ }
47
275
  /**
48
276
  * Creates select query builder associated with this connection.
49
277
  * This can be used to execute raw queries to db without orm model layer
@@ -94,6 +322,57 @@ class OrmDriver extends di_1.SyncService {
94
322
  index() {
95
323
  return this.Container.resolve(builders_js_1.IndexQueryBuilder, [this]);
96
324
  }
325
+ /**
326
+ * Runs `cb` inside a transaction and owns its whole lifecycle: commits when the callback
327
+ * resolves, rolls back when it throws, and releases the connection exactly once either way.
328
+ * Resolves with whatever the callback returned.
329
+ *
330
+ * Statements issued inside the callback run on this transaction's connection automatically —
331
+ * the context is carried through `AsyncLocalStorage`, so nothing has to be threaded through
332
+ * by hand.
333
+ *
334
+ * Calling it again while a transaction is already in scope on this async path does **not**
335
+ * open a second, independent transaction: it takes a savepoint, so a failing nested block
336
+ * rolls back only its own work.
337
+ *
338
+ * @param cb - the transaction body
339
+ * @param options - optional isolation level, validated against {@link SupportedIsolationLevels}
340
+ */
341
+ async transaction(cb, options) {
342
+ if (options?.isolation && !this.SupportedIsolationLevels.includes(options.isolation)) {
343
+ throw new exceptions_js_1.OrmException(`isolation level ${options.isolation} not supported by driver ${this.Options.Driver}`);
344
+ }
345
+ const active = this.TransactionStorage.getStore();
346
+ // already inside a transaction — nest with a savepoint rather than opening a second one
347
+ if (active) {
348
+ const name = `sp_${++active.depth}`;
349
+ await this._savepoint(active, name);
350
+ try {
351
+ const result = await cb(this);
352
+ await this._releaseSavepoint(active, name);
353
+ return result;
354
+ }
355
+ catch (err) {
356
+ await this._rollbackToSavepoint(active, name);
357
+ throw err;
358
+ }
359
+ }
360
+ const ctx = await this._begin(options);
361
+ ctx.depth = 0;
362
+ try {
363
+ const result = await this.TransactionStorage.run(ctx, () => cb(this));
364
+ await this._commit(ctx);
365
+ return result;
366
+ }
367
+ catch (err) {
368
+ // swallow a rollback failure so it cannot mask whatever actually went wrong
369
+ await this._rollback(ctx).catch(() => undefined);
370
+ throw err;
371
+ }
372
+ finally {
373
+ await this._dispose(ctx);
374
+ }
375
+ }
97
376
  }
98
377
  exports.OrmDriver = OrmDriver;
99
378
  __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"driver.js","sourceRoot":"","sources":["../../src/driver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"driver.js","sourceRoot":"","sources":["../../src/driver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { IRelationDescriptor, ISelectQueryBuilder, RelationType } from './interfaces.js';
2
+ import type { WhereBuilder } from './builders.js';
3
+ import { WhereFunction } from './types.js';
4
+ /**
5
+ * Strategy that builds the EXISTS / NOT EXISTS clause for one relation type.
6
+ *
7
+ * Resolved via `Array.ofType(ExistsRelationHandler)` and dispatched by `rel.Type` from
8
+ * `WhereBuilder.buildExistsClause`. Implementations either:
9
+ * - mutate the outer builder directly and return `undefined` (eg. {@link RelationType.One}
10
+ * adds `WHERE FK IS NOT NULL` plus a right-join, no EXISTS sub-query is generated), or
11
+ * - return a correlated sub-query that the caller wraps in EXISTS/NOT EXISTS.
12
+ */
13
+ export declare abstract class ExistsRelationHandler {
14
+ abstract get Type(): RelationType;
15
+ abstract apply<R>(builder: WhereBuilder<any>, rel: IRelationDescriptor, relationName: string, callback?: WhereFunction<R>): ISelectQueryBuilder | undefined;
16
+ }
17
+ export declare class OneExistsRelationHandler extends ExistsRelationHandler {
18
+ get Type(): RelationType;
19
+ apply<R>(builder: WhereBuilder<any>, rel: IRelationDescriptor, _relationName: string, callback?: WhereFunction<R>): undefined;
20
+ }
21
+ export declare class ManyExistsRelationHandler extends ExistsRelationHandler {
22
+ get Type(): RelationType;
23
+ apply<R>(builder: WhereBuilder<any>, rel: IRelationDescriptor, _relationName: string, callback?: WhereFunction<R>): ISelectQueryBuilder;
24
+ }
25
+ export declare class ManyToManyExistsRelationHandler extends ExistsRelationHandler {
26
+ get Type(): RelationType;
27
+ apply<R>(builder: WhereBuilder<any>, rel: IRelationDescriptor, _relationName: string, callback?: WhereFunction<R>): ISelectQueryBuilder;
28
+ }
29
+ //# sourceMappingURL=existsRelationHandlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"existsRelationHandlers.d.ts","sourceRoot":"","sources":["../../src/existsRelationHandlers.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAgB,mBAAmB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEvG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;;;;GAQG;AACH,8BAAsB,qBAAqB;IACzC,aAAoB,IAAI,IAAI,YAAY,CAAC;aAEzB,KAAK,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,mBAAmB,GAAG,SAAS;CACnK;AAYD,qBACa,wBAAyB,SAAQ,qBAAqB;IACjE,IAAW,IAAI,IAAI,YAAY,CAE9B;IAEM,KAAK,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS;CAUrI;AAED,qBACa,yBAA0B,SAAQ,qBAAqB;IAClE,IAAW,IAAI,IAAI,YAAY,CAE9B;IAEM,KAAK,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,mBAAmB;CAmB/I;AAED,qBACa,+BAAgC,SAAQ,qBAAqB;IACxE,IAAW,IAAI,IAAI,YAAY,CAE9B;IAEM,KAAK,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,mBAAmB;CAuB/I"}
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.ManyToManyExistsRelationHandler = exports.ManyExistsRelationHandler = exports.OneExistsRelationHandler = exports.ExistsRelationHandler = void 0;
10
+ /* eslint-disable prettier/prettier */
11
+ const di_1 = require("@spinajs/di");
12
+ const util_1 = require("@spinajs/util");
13
+ const interfaces_js_1 = require("./interfaces.js");
14
+ const builders_js_1 = require("./builders.js");
15
+ /**
16
+ * Strategy that builds the EXISTS / NOT EXISTS clause for one relation type.
17
+ *
18
+ * Resolved via `Array.ofType(ExistsRelationHandler)` and dispatched by `rel.Type` from
19
+ * `WhereBuilder.buildExistsClause`. Implementations either:
20
+ * - mutate the outer builder directly and return `undefined` (eg. {@link RelationType.One}
21
+ * adds `WHERE FK IS NOT NULL` plus a right-join, no EXISTS sub-query is generated), or
22
+ * - return a correlated sub-query that the caller wraps in EXISTS/NOT EXISTS.
23
+ */
24
+ class ExistsRelationHandler {
25
+ }
26
+ exports.ExistsRelationHandler = ExistsRelationHandler;
27
+ /**
28
+ * Resolves the correlated source primary key column reference, eg. `` `users`.`Id` ``.
29
+ * Falls back to the source descriptor's `TableName` when neither the builder nor its parent
30
+ * has an alias set, matching the legacy behaviour of `whereExist` / `whereNotExists`.
31
+ */
32
+ function sourcePKeyRef(builder, tDesc) {
33
+ const sourceAlias = builder.TableAlias ?? tDesc.TableName;
34
+ return `\`${sourceAlias}\`.\`${tDesc.PrimaryKey[0]}\``;
35
+ }
36
+ let OneExistsRelationHandler = class OneExistsRelationHandler extends ExistsRelationHandler {
37
+ get Type() {
38
+ return interfaces_js_1.RelationType.One;
39
+ }
40
+ apply(builder, rel, _relationName, callback) {
41
+ builder.whereNotNull(rel.ForeignKey);
42
+ // simply use right join for condition check
43
+ if (callback) {
44
+ // TODO: cast fix
45
+ builder.rightJoin(rel.TargetModel, callback);
46
+ }
47
+ return undefined;
48
+ }
49
+ };
50
+ exports.OneExistsRelationHandler = OneExistsRelationHandler;
51
+ exports.OneExistsRelationHandler = OneExistsRelationHandler = __decorate([
52
+ (0, di_1.Injectable)(ExistsRelationHandler)
53
+ ], OneExistsRelationHandler);
54
+ let ManyExistsRelationHandler = class ManyExistsRelationHandler extends ExistsRelationHandler {
55
+ get Type() {
56
+ return interfaces_js_1.RelationType.Many;
57
+ }
58
+ apply(builder, rel, _relationName, callback) {
59
+ const tDesc = builder.Model.getModelDescriptor();
60
+ const tableName = rel.TargetModel.getModelDescriptor().TableName;
61
+ // set alias to avoid conflicts in case of multiple relations to same model and to make
62
+ // sure that relation query is correct even if source query has alias
63
+ const relQuery = rel.TargetModel.query().setAlias(`${tableName}_exists`);
64
+ relQuery.where(util_1.Lazy.oF(function () {
65
+ relQuery.where(new builders_js_1.RawQuery(`${rel.ForeignKey} = ${sourcePKeyRef(builder, tDesc)}`));
66
+ }));
67
+ if (callback) {
68
+ callback.apply(relQuery);
69
+ }
70
+ return relQuery;
71
+ }
72
+ };
73
+ exports.ManyExistsRelationHandler = ManyExistsRelationHandler;
74
+ exports.ManyExistsRelationHandler = ManyExistsRelationHandler = __decorate([
75
+ (0, di_1.Injectable)(ExistsRelationHandler)
76
+ ], ManyExistsRelationHandler);
77
+ let ManyToManyExistsRelationHandler = class ManyToManyExistsRelationHandler extends ExistsRelationHandler {
78
+ get Type() {
79
+ return interfaces_js_1.RelationType.ManyToMany;
80
+ }
81
+ apply(builder, rel, _relationName, callback) {
82
+ const tDesc = builder.Model.getModelDescriptor();
83
+ const junctionModel = rel.JunctionModel;
84
+ const junctionTableName = junctionModel.getModelDescriptor().TableName;
85
+ const relQuery = junctionModel.query().setAlias(`${junctionTableName}_exists`);
86
+ relQuery.where(util_1.Lazy.oF(function () {
87
+ relQuery.where(new builders_js_1.RawQuery(`${rel.JunctionModelSourceModelFKey_Name} = ${sourcePKeyRef(builder, tDesc)}`));
88
+ }));
89
+ if (callback) {
90
+ relQuery.rightJoin({
91
+ joinModel: rel.TargetModel,
92
+ joinTableForeignKey: rel.PrimaryKey,
93
+ sourceTablePrimaryKey: rel.JunctionModelTargetModelFKey_Name,
94
+ callback: callback,
95
+ });
96
+ }
97
+ return relQuery;
98
+ }
99
+ };
100
+ exports.ManyToManyExistsRelationHandler = ManyToManyExistsRelationHandler;
101
+ exports.ManyToManyExistsRelationHandler = ManyToManyExistsRelationHandler = __decorate([
102
+ (0, di_1.Injectable)(ExistsRelationHandler)
103
+ ], ManyToManyExistsRelationHandler);
104
+ //# sourceMappingURL=existsRelationHandlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"existsRelationHandlers.js","sourceRoot":"","sources":["../../src/existsRelationHandlers.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"fp.d.ts","sourceRoot":"","sources":["../../src/fp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAiB,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAIvC,oBAAY,WAAW;IACrB,kBAAkB,IAAA;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,sBAY1G;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAUvF;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,SAAS,EAAE,SAAS,CAAC,EAAE,eAAe,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAuB9G;AAED,wBAAgB,eAAe,CAAC,CAAC,SAAS,SAAS,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAU/E;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,SAAS,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAUvE"}
1
+ {"version":3,"file":"fp.d.ts","sourceRoot":"","sources":["../../src/fp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAiB,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAIvC,oBAAY,WAAW;IACrB,kBAAkB,IAAA;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,sBAY1G;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,SAAS,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAMvF;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,SAAS,EAAE,SAAS,CAAC,EAAE,eAAe,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAyB9G;AAED,wBAAgB,eAAe,CAAC,CAAC,SAAS,SAAS,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAK/E;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,SAAS,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAUvE"}
package/lib/cjs/fp.js CHANGED
@@ -43,12 +43,9 @@ function _get_entity(idOrEntity, c, fresh) {
43
43
  */
44
44
  function _update(data) {
45
45
  return (model) => {
46
- return model.update(data).then((res) => {
47
- if (res.LastInsertId <= 0 || res.RowsAffected <= 0) {
48
- return Promise.reject(new exceptions_1.ErrorCode(E_ORM_CODES.E_NO_ROWS_AFFECTED));
49
- }
50
- return model;
51
- });
46
+ // A clean model short-circuits to { RowsAffected: 0 } - that is a no-op success,
47
+ // not a failure, so we always resolve the model.
48
+ return model.update(data).then(() => model);
52
49
  };
53
50
  }
54
51
  /**
@@ -64,14 +61,16 @@ function _insert(behaviour) {
64
61
  return Promise.resolve(model);
65
62
  }
66
63
  return model[0].constructor.insert(model, behaviour).then((res) => {
67
- if (res.LastInsertId <= 0 || res.RowsAffected <= 0) {
64
+ // `uuid` and `assigned` primary keys report LastInsertId 0 on a successful insert, so
65
+ // only RowsAffected signals failure. See @Primary({ generated }) in the ORM docs.
66
+ if (res.RowsAffected <= 0) {
68
67
  return Promise.reject(new exceptions_1.ErrorCode(E_ORM_CODES.E_NO_ROWS_AFFECTED));
69
68
  }
70
69
  return model;
71
70
  });
72
71
  }
73
72
  return model.insert(behaviour).then((res) => {
74
- if (res.LastInsertId <= 0 || res.RowsAffected <= 0) {
73
+ if (res.RowsAffected <= 0) {
75
74
  return Promise.reject(new exceptions_1.ErrorCode(E_ORM_CODES.E_NO_ROWS_AFFECTED));
76
75
  }
77
76
  return model;
@@ -80,12 +79,8 @@ function _insert(behaviour) {
80
79
  }
81
80
  function _insertOrUpdate() {
82
81
  return (model) => {
83
- return model.insertOrUpdate().then((res) => {
84
- if (res.LastInsertId <= 0 || res.RowsAffected <= 0) {
85
- return Promise.reject(new exceptions_1.ErrorCode(E_ORM_CODES.E_NO_ROWS_AFFECTED));
86
- }
87
- return model;
88
- });
82
+ // insertOrUpdate on a clean model is a no-op success (RowsAffected 0) - resolve the model.
83
+ return model.insertOrUpdate().then(() => model);
89
84
  };
90
85
  }
91
86
  /**
@@ -97,7 +92,7 @@ function _insertOrUpdate() {
97
92
  function _delete() {
98
93
  return (model) => {
99
94
  return model.destroy().then((res) => {
100
- if (res.LastInsertId <= 0 || res.RowsAffected <= 0) {
95
+ if (res.RowsAffected <= 0) {
101
96
  return Promise.reject(new exceptions_1.ErrorCode(E_ORM_CODES.E_NO_ROWS_AFFECTED));
102
97
  }
103
98
  return model;
package/lib/cjs/fp.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"fp.js","sourceRoot":"","sources":["../../src/fp.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fp.js","sourceRoot":"","sources":["../../src/fp.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"hydrators.d.ts","sourceRoot":"","sources":["../../src/hydrators.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAIvC,8BAAsB,aAAa;aACjB,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI;CACxD;AAED,qBACa,kBAAmB,SAAQ,aAAa;IAC5C,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI;CAuBrD;AAED,qBACa,qBAAsB,SAAQ,aAAa;IAC/C,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI;CAYrD;AAED,qBACa,yBAA0B,SAAQ,aAAa;IACnD,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI;CA2BrD;AAED,qBACa,wBAAyB,SAAQ,aAAa;IAClD,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI;CAyBrD;AAED,qBACa,6BAA8B,SAAQ,aAAa;IACvD,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI;CAarD"}
1
+ {"version":3,"file":"hydrators.d.ts","sourceRoot":"","sources":["../../src/hydrators.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAIvC,8BAAsB,aAAa;aACjB,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI;CACxD;AAED,qBACa,kBAAmB,SAAQ,aAAa;IAC5C,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI;CAiCrD;AAED,qBACa,qBAAsB,SAAQ,aAAa;IAC/C,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI;CAYrD;AAED,qBACa,yBAA0B,SAAQ,aAAa;IACnD,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI;CA+BrD;AAED,qBACa,wBAAyB,SAAQ,aAAa;IAClD,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI;CAuCrD;AAED,qBACa,6BAA8B,SAAQ,aAAa;IACvD,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,GAAG,IAAI;CAarD"}
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.JunctionModelPropertyHydrator = exports.OneToOneRelationHydrator = exports.OneToManyRelationHydrator = exports.NonDbPropertyHydrator = exports.DbPropertyHydrator = exports.ModelHydrator = void 0;
10
10
  /* eslint-disable prettier/prettier */
11
11
  const interfaces_js_1 = require("./interfaces.js");
12
+ const model_js_1 = require("./model.js");
12
13
  const di_1 = require("@spinajs/di");
13
14
  const relation_objects_js_1 = require("./relation-objects.js");
14
15
  class ModelHydrator {
@@ -26,12 +27,22 @@ let DbPropertyHydrator = class DbPropertyHydrator extends ModelHydrator {
26
27
  keys.forEach((k) => {
27
28
  // skip if column is primary key & is null
28
29
  // we dont want to override pkey of target model
29
- if (k === descriptor.PrimaryKey && !values[k]) {
30
+ if (descriptor.PrimaryKey.includes(k) && (values[k] === null || values[k] === undefined)) {
30
31
  return;
31
32
  }
32
33
  const column = descriptor.Columns?.find((c) => c.Name === k);
33
34
  if (values[k] !== undefined) {
34
- target[k] = column?.Converter ? column.Converter.fromDB(values[k], values, descriptor.Converters.get(column.Name)?.Options) : values[k];
35
+ const incoming = values[k];
36
+ // A relation FK column may receive either a raw scalar id or an
37
+ // already-resolved model instance (eg. from a DTO @Relation field).
38
+ // When a model instance arrives, translate it to its primary key value
39
+ // so the FK column stores the id, not the object.
40
+ if (incoming instanceof model_js_1.ModelBase) {
41
+ target[k] = incoming.PrimaryKeyValue;
42
+ }
43
+ else {
44
+ target[k] = column?.Converter ? column.Converter.fromDB(incoming, values, descriptor.Converters.get(column.Name)?.Options) : incoming;
45
+ }
35
46
  }
36
47
  });
37
48
  }
@@ -76,7 +87,11 @@ let OneToManyRelationHydrator = class OneToManyRelationHydrator extends ModelHyd
76
87
  return tEntity;
77
88
  });
78
89
  const rel = new relation_objects_js_1.OneToManyRelationList(target, val, mapRel);
90
+ // Only reached under `values[key] != null`, i.e. only when the row actually carried
91
+ // relation data — so this never marks a relation the query did not ask for.
92
+ rel.Populated = true;
79
93
  entity[key] = rel;
94
+ target.snapshotRelation(key);
80
95
  delete target[val.ForeignKey];
81
96
  }
82
97
  }
@@ -98,6 +113,14 @@ let OneToOneRelationHydrator = class OneToOneRelationHydrator extends ModelHydra
98
113
  }
99
114
  if (values[key] != null) {
100
115
  const entity = target;
116
+ // Accept an already-resolved model instance passed under the relation
117
+ // name: attach it directly and translate its PK into the FK column,
118
+ // instead of trying to re-hydrate it from a plain data object.
119
+ if (values[key] instanceof model_js_1.ModelBase) {
120
+ entity[key] = new relation_objects_js_1.SingleRelation(target, val.TargetModel, val, values[key]);
121
+ target[val.ForeignKey] = values[key].PrimaryKeyValue;
122
+ continue;
123
+ }
101
124
  let tEntity = undefined;
102
125
  if (!Object.values(values[key]).every((x) => x === null)) {
103
126
  tEntity = !(0, di_1.isConstructor)(val.TargetModel) ? new (val.TargetModel())() : new val.TargetModel();
@@ -105,7 +128,11 @@ let OneToOneRelationHydrator = class OneToOneRelationHydrator extends ModelHydra
105
128
  tEntity['__relationKey__'] = key;
106
129
  }
107
130
  const rel = new relation_objects_js_1.SingleRelation(target, val.TargetModel, val, tEntity);
131
+ // Same guard as OneToManyRelationHydrator: `values[key] != null` means the query
132
+ // joined this relation in.
133
+ rel.Populated = true;
108
134
  entity[key] = rel;
135
+ target.snapshotRelation(key);
109
136
  }
110
137
  }
111
138
  }