@getstrata/core 0.5.13 → 0.5.15
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/README.md +16 -6
- package/dist/bootstrap/contracts.d.ts +2 -0
- package/dist/bootstrap/httpKernel.d.ts +1 -2
- package/dist/core/admin/registry.d.ts +1 -0
- package/dist/core/auth/membershipService.d.ts +5 -1
- package/dist/core/database/baseRepository.d.ts +6 -1
- package/dist/core/database/connectionContext.d.ts +2 -1
- package/dist/core/database/defaultConnection.d.ts +6 -0
- package/dist/core/database/queryProxy.d.ts +3 -0
- package/dist/core/database/repositoryConnection.d.ts +3 -3
- package/dist/core/jobs/dispatchWebhookJob.d.ts +0 -1
- package/dist/core/security/safeFetch.d.ts +2 -0
- package/dist/core/security/safeUrl.d.ts +16 -1
- package/dist/core/storage/storage.d.ts +6 -3
- package/dist/core/tenant/tenantDatabaseScope.d.ts +2 -1
- package/dist/db/connection/index.d.ts +1 -1
- package/dist/entries/auth/accessControl.js +1 -113
- package/dist/entries/auth/authContext.js +1 -15
- package/dist/entries/auth/guard.js +1 -3044
- package/dist/entries/auth/membershipContext.js +1 -276
- package/dist/entries/auth/membershipScope.js +1 -390
- package/dist/entries/auth/membershipService.js +1 -480
- package/dist/entries/auth/policy.js +1 -134
- package/dist/entries/database.js +1 -2398
- package/dist/entries/http/csrfToken.js +0 -6
- package/dist/entries/http/middleware.js +1 -68
- package/dist/entries/http/requestMetaContext.js +1 -18
- package/dist/entries/http/webErrorResponse.js +94 -563
- package/dist/entries/http/webFormRequest.js +0 -131
- package/dist/entries/http.js +1 -4091
- package/dist/entries/jobs/dispatchWebhookJob.js +109 -102
- package/dist/entries/queue/createAppQueue.js +111 -631
- package/dist/entries/queue/jobRunner.js +0 -3
- package/dist/entries/queue/publicQueue.js +45 -546
- package/dist/entries/queue/queueMetrics.js +111 -631
- package/dist/entries/security/safeUrl.js +29 -0
- package/dist/entries/security/securityEvents.js +1 -41
- package/dist/entries/storage/storage.js +14 -4
- package/dist/entries/tenant/tenantContext.js +1 -30
- package/dist/entries/tenant/tenantMiddleware.js +1 -312
- package/dist/entries/tracing/traceContext.js +1 -15
- package/dist/entries/view.js +94 -563
- package/dist/framework/public-api.d.ts +36 -4
- package/dist/index.js +2270 -1666
- package/dist/modules/user/repository.d.ts +1 -0
- package/package.json +6 -5
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
var {RedisClient: RedisClient2 } = globalThis.Bun;
|
|
4
4
|
|
|
5
5
|
// ../../src/bootstrap/config.ts
|
|
6
|
-
var CORE_QUEUE_TOKEN = "core.queue";
|
|
7
|
-
var CORE_POLICY_GATE_TOKEN = "core.policyGate";
|
|
8
|
-
var CORE_AUTH_TOKEN = "core.auth";
|
|
9
6
|
var CORE_TOKEN_SERVICE_TOKEN = "core.tokenService";
|
|
10
7
|
var DEFAULT_QUEUE_DRIVER = "sync";
|
|
11
8
|
|
|
@@ -123,15 +120,9 @@ function getRequiredDependency(dependencies, key) {
|
|
|
123
120
|
}
|
|
124
121
|
return dependency;
|
|
125
122
|
}
|
|
126
|
-
function resolveService(dependencies, token) {
|
|
127
|
-
return dependencies.container.resolve(token);
|
|
128
|
-
}
|
|
129
123
|
|
|
130
124
|
// ../../src/bootstrap/applicationRegistry.ts
|
|
131
125
|
var activeContext;
|
|
132
|
-
function setActiveApplicationContext(context) {
|
|
133
|
-
activeContext = context;
|
|
134
|
-
}
|
|
135
126
|
function requireActiveApplicationContext() {
|
|
136
127
|
if (!activeContext) {
|
|
137
128
|
throw new Error("The application context has not been bootstrapped.");
|
|
@@ -141,24 +132,6 @@ function requireActiveApplicationContext() {
|
|
|
141
132
|
function resolveApplicationCache() {
|
|
142
133
|
return getRequiredDependency(requireActiveApplicationContext().dependencies, "cache");
|
|
143
134
|
}
|
|
144
|
-
function resolveApplicationQueue() {
|
|
145
|
-
return requireActiveApplicationContext().container.resolve(CORE_QUEUE_TOKEN);
|
|
146
|
-
}
|
|
147
|
-
function resolveApplicationAuth() {
|
|
148
|
-
return requireActiveApplicationContext().container.resolve(CORE_AUTH_TOKEN);
|
|
149
|
-
}
|
|
150
|
-
function resolveApplicationPolicyGate() {
|
|
151
|
-
return requireActiveApplicationContext().container.resolve(CORE_POLICY_GATE_TOKEN);
|
|
152
|
-
}
|
|
153
|
-
function resolveApplicationConfig() {
|
|
154
|
-
return requireActiveApplicationContext().config;
|
|
155
|
-
}
|
|
156
|
-
function resolveApplicationLogger() {
|
|
157
|
-
return appLogger;
|
|
158
|
-
}
|
|
159
|
-
function resolveApplicationDependencies() {
|
|
160
|
-
return requireActiveApplicationContext().dependencies;
|
|
161
|
-
}
|
|
162
135
|
|
|
163
136
|
// ../../src/core/jobs/dispatchWebhookJob.ts
|
|
164
137
|
import { createHmac } from "crypto";
|
|
@@ -172,75 +145,77 @@ var appConfig = {
|
|
|
172
145
|
apiPrefix: process.env.API_PREFIX ?? "/api/v1"
|
|
173
146
|
};
|
|
174
147
|
|
|
175
|
-
// ../../src/
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
|
|
179
|
-
}
|
|
180
|
-
var databaseConfig = {
|
|
181
|
-
url: process.env.DATABASE_URL ?? "",
|
|
182
|
-
poolMax: readInteger("DB_POOL_MAX", 10),
|
|
183
|
-
idleTimeoutSeconds: readInteger("DB_POOL_IDLE_TIMEOUT", 30),
|
|
184
|
-
maxLifetimeSeconds: readInteger("DB_POOL_MAX_LIFETIME", 3600),
|
|
185
|
-
connectionTimeoutSeconds: readInteger("DB_CONNECTION_TIMEOUT", 10)
|
|
148
|
+
// ../../src/core/database/boundConnection.ts
|
|
149
|
+
var boundConnectionHolder = {
|
|
150
|
+
connection: null
|
|
186
151
|
};
|
|
152
|
+
function getBoundDatabaseConnection() {
|
|
153
|
+
return boundConnectionHolder.connection;
|
|
154
|
+
}
|
|
187
155
|
|
|
188
156
|
// ../../src/core/database/connectionContext.ts
|
|
189
157
|
import { AsyncLocalStorage } from "async_hooks";
|
|
190
158
|
var activeConnection = new AsyncLocalStorage;
|
|
191
|
-
function runWithDatabaseConnection(connection, callback) {
|
|
192
|
-
return activeConnection.run(connection, callback);
|
|
193
|
-
}
|
|
194
159
|
function getActiveDatabaseConnection(fallback) {
|
|
195
160
|
return activeConnection.getStore() ?? fallback;
|
|
196
161
|
}
|
|
197
162
|
|
|
198
|
-
// ../../src/
|
|
199
|
-
var
|
|
200
|
-
function
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
163
|
+
// ../../src/core/database/queryProxy.ts
|
|
164
|
+
var POOL_CONNECTION_METHODS = new Set(["begin", "close", "connect"]);
|
|
165
|
+
function createDatabaseQueryProxy(pool) {
|
|
166
|
+
function resolveDatabase() {
|
|
167
|
+
return getActiveDatabaseConnection(pool);
|
|
168
|
+
}
|
|
169
|
+
function resolveDatabaseForProperty(property) {
|
|
170
|
+
if (typeof property === "string" && POOL_CONNECTION_METHODS.has(property)) {
|
|
171
|
+
return pool;
|
|
172
|
+
}
|
|
173
|
+
return resolveDatabase();
|
|
174
|
+
}
|
|
175
|
+
return new Proxy(function database() {}, {
|
|
176
|
+
apply(_target, _thisArg, args) {
|
|
177
|
+
return resolveDatabase()(...args);
|
|
178
|
+
},
|
|
179
|
+
get(_target, property) {
|
|
180
|
+
const connection = resolveDatabaseForProperty(property);
|
|
181
|
+
const value = connection[property];
|
|
182
|
+
return typeof value === "function" ? value.bind(connection) : value;
|
|
183
|
+
}
|
|
210
184
|
});
|
|
211
185
|
}
|
|
212
186
|
|
|
213
|
-
// ../../src/
|
|
214
|
-
var
|
|
187
|
+
// ../../src/core/database/defaultConnection.ts
|
|
188
|
+
var defaultPool = {
|
|
215
189
|
connection: null
|
|
216
190
|
};
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
var POOL_CONNECTION_METHODS = new Set(["begin", "close", "connect"]);
|
|
224
|
-
function resolveDatabase() {
|
|
225
|
-
return getActiveDatabaseConnection(getDatabase());
|
|
191
|
+
var defaultQuery = {
|
|
192
|
+
connection: null
|
|
193
|
+
};
|
|
194
|
+
function registerDefaultDatabasePool(connection) {
|
|
195
|
+
defaultPool.connection = connection;
|
|
196
|
+
defaultQuery.connection = createDatabaseQueryProxy(connection);
|
|
226
197
|
}
|
|
227
|
-
function
|
|
228
|
-
if (
|
|
229
|
-
|
|
198
|
+
function getDefaultDatabaseQuery() {
|
|
199
|
+
if (!defaultQuery.connection) {
|
|
200
|
+
throw new Error("Default database query handle is not registered. Call registerDefaultDatabasePool() during app bootstrap.");
|
|
230
201
|
}
|
|
231
|
-
return
|
|
202
|
+
return defaultQuery.connection;
|
|
232
203
|
}
|
|
233
|
-
|
|
204
|
+
|
|
205
|
+
// ../../src/core/database/repositoryConnection.ts
|
|
206
|
+
function resolveRepositoryConnection() {
|
|
207
|
+
return getBoundDatabaseConnection() ?? getDefaultDatabaseQuery();
|
|
208
|
+
}
|
|
209
|
+
var repositoryConnection = new Proxy(function repositoryConnection2() {}, {
|
|
234
210
|
apply(_target, _thisArg, args) {
|
|
235
|
-
return
|
|
211
|
+
return resolveRepositoryConnection()(...args);
|
|
236
212
|
},
|
|
237
213
|
get(_target, property) {
|
|
238
|
-
const connection =
|
|
214
|
+
const connection = resolveRepositoryConnection();
|
|
239
215
|
const value = connection[property];
|
|
240
216
|
return typeof value === "function" ? value.bind(connection) : value;
|
|
241
217
|
}
|
|
242
218
|
});
|
|
243
|
-
var connection_default = db;
|
|
244
219
|
|
|
245
220
|
// ../../src/core/queue/index.ts
|
|
246
221
|
class Job {
|
|
@@ -249,56 +224,8 @@ class Job {
|
|
|
249
224
|
priority;
|
|
250
225
|
}
|
|
251
226
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
await job.handle(payload);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
class AsyncQueue {
|
|
259
|
-
async dispatch(job, payload) {
|
|
260
|
-
setTimeout(() => {
|
|
261
|
-
job.handle(payload).catch((error) => {
|
|
262
|
-
console.error("[AsyncQueue] Job failed:", error);
|
|
263
|
-
});
|
|
264
|
-
}, 0);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
function createQueue(driver) {
|
|
268
|
-
return driver === "async" ? new AsyncQueue : new SyncQueue;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// ../../src/core/security/safeFetch.ts
|
|
272
|
-
var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
|
|
273
|
-
async function safeFetch(input, init = {}, options = {}) {
|
|
274
|
-
const timeoutMs = options.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;
|
|
275
|
-
const maxRedirects = options.maxRedirects ?? 0;
|
|
276
|
-
const controller = new AbortController;
|
|
277
|
-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
278
|
-
try {
|
|
279
|
-
let currentUrl = input;
|
|
280
|
-
let redirectCount = 0;
|
|
281
|
-
while (true) {
|
|
282
|
-
const response = await fetch(currentUrl, {
|
|
283
|
-
...init,
|
|
284
|
-
signal: controller.signal,
|
|
285
|
-
redirect: "manual"
|
|
286
|
-
});
|
|
287
|
-
if (response.status >= 300 && response.status < 400) {
|
|
288
|
-
const location = response.headers.get("location");
|
|
289
|
-
if (!location || redirectCount >= maxRedirects) {
|
|
290
|
-
return response;
|
|
291
|
-
}
|
|
292
|
-
currentUrl = new URL(location, currentUrl).toString();
|
|
293
|
-
redirectCount += 1;
|
|
294
|
-
continue;
|
|
295
|
-
}
|
|
296
|
-
return response;
|
|
297
|
-
}
|
|
298
|
-
} finally {
|
|
299
|
-
clearTimeout(timeout);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
227
|
+
// ../../src/core/security/safeUrl.ts
|
|
228
|
+
import { lookup as dnsLookupImpl } from "dns/promises";
|
|
302
229
|
|
|
303
230
|
// ../../src/core/errors/http.ts
|
|
304
231
|
class HttpError extends Error {
|
|
@@ -367,6 +294,7 @@ class PreconditionFailedError extends HttpError {
|
|
|
367
294
|
}
|
|
368
295
|
|
|
369
296
|
// ../../src/core/security/safeUrl.ts
|
|
297
|
+
var dnsLookup = dnsLookupImpl;
|
|
370
298
|
var BLOCKED_HOSTNAMES = new Set([
|
|
371
299
|
"localhost",
|
|
372
300
|
"127.0.0.1",
|
|
@@ -438,16 +366,68 @@ function assertSafeOutboundUrl(rawUrl, options = {}) {
|
|
|
438
366
|
}
|
|
439
367
|
return parsed;
|
|
440
368
|
}
|
|
369
|
+
function isBlockedIpAddress(address) {
|
|
370
|
+
return isBlockedHostname(address.trim().toLowerCase());
|
|
371
|
+
}
|
|
372
|
+
async function assertSafeOutboundUrlResolved(rawUrl, options = {}) {
|
|
373
|
+
const parsed = assertSafeOutboundUrl(rawUrl, options);
|
|
374
|
+
if (options.resolveDns === false) {
|
|
375
|
+
return parsed;
|
|
376
|
+
}
|
|
377
|
+
const hostname = parsed.hostname.trim().toLowerCase();
|
|
378
|
+
const results = await dnsLookup(hostname, { all: true, verbatim: true });
|
|
379
|
+
if (results.some((result) => isBlockedIpAddress(result.address))) {
|
|
380
|
+
throw new BadRequestError("Webhook URL targets a blocked host.");
|
|
381
|
+
}
|
|
382
|
+
return parsed;
|
|
383
|
+
}
|
|
384
|
+
function setDnsLookupForTests(lookupFn) {
|
|
385
|
+
dnsLookup = lookupFn;
|
|
386
|
+
}
|
|
387
|
+
function resetDnsLookupForTests() {
|
|
388
|
+
dnsLookup = dnsLookupImpl;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// ../../src/core/security/safeFetch.ts
|
|
392
|
+
var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
|
|
393
|
+
async function safeFetch(input, init = {}, options = {}) {
|
|
394
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;
|
|
395
|
+
const maxRedirects = options.maxRedirects ?? 0;
|
|
396
|
+
const resolveDns = options.resolveDns ?? appConfig.env === "production";
|
|
397
|
+
const urlOptions = { allowHttp: options.allowHttp, resolveDns };
|
|
398
|
+
const controller = new AbortController;
|
|
399
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
400
|
+
try {
|
|
401
|
+
let currentUrl = (await assertSafeOutboundUrlResolved(input, urlOptions)).toString();
|
|
402
|
+
let redirectCount = 0;
|
|
403
|
+
while (true) {
|
|
404
|
+
const response = await fetch(currentUrl, {
|
|
405
|
+
...init,
|
|
406
|
+
signal: controller.signal,
|
|
407
|
+
redirect: "manual"
|
|
408
|
+
});
|
|
409
|
+
if (response.status >= 300 && response.status < 400) {
|
|
410
|
+
const location = response.headers.get("location");
|
|
411
|
+
if (!location || redirectCount >= maxRedirects) {
|
|
412
|
+
return response;
|
|
413
|
+
}
|
|
414
|
+
currentUrl = (await assertSafeOutboundUrlResolved(new URL(location, currentUrl).toString(), urlOptions)).toString();
|
|
415
|
+
redirectCount += 1;
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
return response;
|
|
419
|
+
}
|
|
420
|
+
} finally {
|
|
421
|
+
clearTimeout(timeout);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
441
424
|
|
|
442
425
|
// ../../src/core/jobs/dispatchWebhookJob.ts
|
|
443
426
|
class DispatchWebhookJob extends Job {
|
|
444
|
-
constructor() {
|
|
445
|
-
super();
|
|
446
|
-
}
|
|
447
427
|
maxAttempts = 3;
|
|
448
428
|
backoffMs = 2000;
|
|
449
429
|
async handle(payload) {
|
|
450
|
-
const rows = await
|
|
430
|
+
const rows = await repositoryConnection`
|
|
451
431
|
SELECT id, url, secret
|
|
452
432
|
FROM webhook
|
|
453
433
|
WHERE id = ${payload.webhookId} AND active = TRUE
|
|
@@ -470,14 +450,14 @@ class DispatchWebhookJob extends Job {
|
|
|
470
450
|
"x-workhub-signature": signature
|
|
471
451
|
},
|
|
472
452
|
body
|
|
473
|
-
});
|
|
453
|
+
}, { allowHttp: appConfig.env !== "production" });
|
|
474
454
|
responseStatus = response.status;
|
|
475
455
|
if (!response.ok) {
|
|
476
456
|
throw new Error(`Webhook delivery failed with status ${response.status}.`);
|
|
477
457
|
}
|
|
478
458
|
} catch (error) {
|
|
479
459
|
errorMessage = error instanceof Error ? error.message : String(error);
|
|
480
|
-
await
|
|
460
|
+
await repositoryConnection`
|
|
481
461
|
INSERT INTO webhook_delivery (webhook_id, event, payload, response_status, error)
|
|
482
462
|
VALUES (
|
|
483
463
|
${webhook.id},
|
|
@@ -489,7 +469,7 @@ class DispatchWebhookJob extends Job {
|
|
|
489
469
|
`;
|
|
490
470
|
throw error instanceof Error ? error : new Error(errorMessage);
|
|
491
471
|
}
|
|
492
|
-
await
|
|
472
|
+
await repositoryConnection`
|
|
493
473
|
INSERT INTO webhook_delivery (webhook_id, event, payload, response_status)
|
|
494
474
|
VALUES (
|
|
495
475
|
${webhook.id},
|
|
@@ -748,14 +728,6 @@ function appendWhereParts(tableName, where, params) {
|
|
|
748
728
|
}
|
|
749
729
|
return clauses.join(" AND ");
|
|
750
730
|
}
|
|
751
|
-
function buildWhereClause(tableName, where = {}) {
|
|
752
|
-
const params = [];
|
|
753
|
-
const body = appendWhereParts(tableName, where, params);
|
|
754
|
-
return {
|
|
755
|
-
clause: body.length > 0 ? ` WHERE ${body}` : "",
|
|
756
|
-
params
|
|
757
|
-
};
|
|
758
|
-
}
|
|
759
731
|
function buildWhereNodeClause(tableName, node, params) {
|
|
760
732
|
if ("where" in node) {
|
|
761
733
|
return appendWhereParts(tableName, node.where, params);
|
|
@@ -1058,30 +1030,6 @@ function buildDeleteByIdQuery(table, id) {
|
|
|
1058
1030
|
}
|
|
1059
1031
|
|
|
1060
1032
|
// ../../src/core/database/relationships.ts
|
|
1061
|
-
function hasMany(definition) {
|
|
1062
|
-
return {
|
|
1063
|
-
type: "hasMany",
|
|
1064
|
-
...definition
|
|
1065
|
-
};
|
|
1066
|
-
}
|
|
1067
|
-
function hasOne(definition) {
|
|
1068
|
-
return {
|
|
1069
|
-
type: "hasOne",
|
|
1070
|
-
...definition
|
|
1071
|
-
};
|
|
1072
|
-
}
|
|
1073
|
-
function belongsTo(definition) {
|
|
1074
|
-
return {
|
|
1075
|
-
type: "belongsTo",
|
|
1076
|
-
...definition
|
|
1077
|
-
};
|
|
1078
|
-
}
|
|
1079
|
-
function belongsToMany(definition) {
|
|
1080
|
-
return {
|
|
1081
|
-
type: "belongsToMany",
|
|
1082
|
-
...definition
|
|
1083
|
-
};
|
|
1084
|
-
}
|
|
1085
1033
|
function indexHasManyRelation(parents, children, relation) {
|
|
1086
1034
|
const groups = new Map;
|
|
1087
1035
|
for (const parent of parents) {
|
|
@@ -1097,15 +1045,6 @@ function indexHasManyRelation(parents, children, relation) {
|
|
|
1097
1045
|
}
|
|
1098
1046
|
return groups;
|
|
1099
1047
|
}
|
|
1100
|
-
function indexHasOneRelation(parents, children, relation) {
|
|
1101
|
-
const grouped = indexHasManyRelation(parents, children, relation);
|
|
1102
|
-
const result = new Map;
|
|
1103
|
-
for (const parent of parents) {
|
|
1104
|
-
const matches = grouped.get(parent[relation.localKey]) ?? [];
|
|
1105
|
-
result.set(parent[relation.localKey], matches[0]);
|
|
1106
|
-
}
|
|
1107
|
-
return result;
|
|
1108
|
-
}
|
|
1109
1048
|
function indexBelongsToRelation(children, parents, relation) {
|
|
1110
1049
|
const parentsById = new Map;
|
|
1111
1050
|
for (const parent of parents) {
|
|
@@ -1121,45 +1060,6 @@ function indexBelongsToRelation(children, parents, relation) {
|
|
|
1121
1060
|
}
|
|
1122
1061
|
return result;
|
|
1123
1062
|
}
|
|
1124
|
-
function indexBelongsToManyRelation(parents, pivotRows, relatedRows, relation) {
|
|
1125
|
-
const relatedById = new Map;
|
|
1126
|
-
for (const related of relatedRows) {
|
|
1127
|
-
relatedById.set(related[relation.relatedKey], related);
|
|
1128
|
-
}
|
|
1129
|
-
const groups = new Map;
|
|
1130
|
-
for (const parent of parents) {
|
|
1131
|
-
groups.set(parent[relation.parentKey], []);
|
|
1132
|
-
}
|
|
1133
|
-
for (const pivot of pivotRows) {
|
|
1134
|
-
const parentId = pivot[relation.foreignPivotKey];
|
|
1135
|
-
const relatedId = pivot[relation.relatedPivotKey];
|
|
1136
|
-
const group = groups.get(parentId);
|
|
1137
|
-
const related = relatedById.get(relatedId);
|
|
1138
|
-
if (!group || !related) {
|
|
1139
|
-
continue;
|
|
1140
|
-
}
|
|
1141
|
-
group.push(related);
|
|
1142
|
-
}
|
|
1143
|
-
return groups;
|
|
1144
|
-
}
|
|
1145
|
-
function morphMany(definition) {
|
|
1146
|
-
return {
|
|
1147
|
-
type: "morphMany",
|
|
1148
|
-
...definition
|
|
1149
|
-
};
|
|
1150
|
-
}
|
|
1151
|
-
function morphOne(definition) {
|
|
1152
|
-
return {
|
|
1153
|
-
type: "morphOne",
|
|
1154
|
-
...definition
|
|
1155
|
-
};
|
|
1156
|
-
}
|
|
1157
|
-
function morphTo(definition) {
|
|
1158
|
-
return {
|
|
1159
|
-
type: "morphTo",
|
|
1160
|
-
...definition
|
|
1161
|
-
};
|
|
1162
|
-
}
|
|
1163
1063
|
function indexMorphManyRelation(parents, children, relation) {
|
|
1164
1064
|
const groups = new Map;
|
|
1165
1065
|
for (const parent of parents) {
|
|
@@ -1178,15 +1078,6 @@ function indexMorphManyRelation(parents, children, relation) {
|
|
|
1178
1078
|
}
|
|
1179
1079
|
return groups;
|
|
1180
1080
|
}
|
|
1181
|
-
function indexMorphOneRelation(parents, children, relation) {
|
|
1182
|
-
const grouped = indexMorphManyRelation(parents, children, relation);
|
|
1183
|
-
const result = new Map;
|
|
1184
|
-
for (const parent of parents) {
|
|
1185
|
-
const matches = grouped.get(parent[relation.localKey]) ?? [];
|
|
1186
|
-
result.set(parent[relation.localKey], matches[0]);
|
|
1187
|
-
}
|
|
1188
|
-
return result;
|
|
1189
|
-
}
|
|
1190
1081
|
function indexMorphToRelation(children, parentsByType, relation) {
|
|
1191
1082
|
const result = new Map;
|
|
1192
1083
|
for (const child of children) {
|
|
@@ -1203,29 +1094,6 @@ function indexMorphToRelation(children, parentsByType, relation) {
|
|
|
1203
1094
|
return result;
|
|
1204
1095
|
}
|
|
1205
1096
|
|
|
1206
|
-
// ../../src/core/database/boundConnection.ts
|
|
1207
|
-
var boundConnectionHolder = {
|
|
1208
|
-
connection: null
|
|
1209
|
-
};
|
|
1210
|
-
function bindDatabaseConnection(connection) {
|
|
1211
|
-
boundConnectionHolder.connection = connection;
|
|
1212
|
-
}
|
|
1213
|
-
function getBoundDatabaseConnection() {
|
|
1214
|
-
return boundConnectionHolder.connection;
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
// ../../src/core/database/repositoryConnection.ts
|
|
1218
|
-
function resolveRepositoryConnection() {
|
|
1219
|
-
return getBoundDatabaseConnection() ?? connection_default;
|
|
1220
|
-
}
|
|
1221
|
-
var repositoryConnection = new Proxy({}, {
|
|
1222
|
-
get(_target, property) {
|
|
1223
|
-
const connection = resolveRepositoryConnection();
|
|
1224
|
-
const value = connection[property];
|
|
1225
|
-
return typeof value === "function" ? value.bind(connection) : value;
|
|
1226
|
-
}
|
|
1227
|
-
});
|
|
1228
|
-
|
|
1229
1097
|
// ../../src/core/database/whereBuilder.ts
|
|
1230
1098
|
class WhereBuilder {
|
|
1231
1099
|
nodes = [];
|
|
@@ -1781,327 +1649,10 @@ class BaseRepository {
|
|
|
1781
1649
|
}
|
|
1782
1650
|
}
|
|
1783
1651
|
var baseRepository_default = BaseRepository;
|
|
1784
|
-
// ../../src/core/database/connection.ts
|
|
1785
|
-
function createDatabaseConnection2(source) {
|
|
1786
|
-
return {
|
|
1787
|
-
async unsafe(query, params = []) {
|
|
1788
|
-
return await source.unsafe(query, params);
|
|
1789
|
-
}
|
|
1790
|
-
};
|
|
1791
|
-
}
|
|
1792
1652
|
// ../../src/core/database/model.ts
|
|
1793
1653
|
var modelRepositories = new WeakMap;
|
|
1794
1654
|
var modelGlobalScopes = new WeakMap;
|
|
1795
1655
|
var modelBooted = new WeakSet;
|
|
1796
|
-
function resolveModelRepository(model) {
|
|
1797
|
-
const repository = modelRepositories.get(model);
|
|
1798
|
-
if (!repository) {
|
|
1799
|
-
throw new Error(`${model.name}.repository() is not implemented.`);
|
|
1800
|
-
}
|
|
1801
|
-
return repository;
|
|
1802
|
-
}
|
|
1803
|
-
function modelStatics(model) {
|
|
1804
|
-
return model;
|
|
1805
|
-
}
|
|
1806
|
-
function ensureBooted(model) {
|
|
1807
|
-
if (modelBooted.has(model)) {
|
|
1808
|
-
return;
|
|
1809
|
-
}
|
|
1810
|
-
modelBooted.add(model);
|
|
1811
|
-
const boot = model.boot;
|
|
1812
|
-
if (typeof boot === "function") {
|
|
1813
|
-
boot.call(model);
|
|
1814
|
-
}
|
|
1815
|
-
}
|
|
1816
|
-
function getGlobalScopes(model) {
|
|
1817
|
-
return modelGlobalScopes.get(model) ?? [];
|
|
1818
|
-
}
|
|
1819
|
-
function hydrateValue(value, cast) {
|
|
1820
|
-
if (value === null || value === undefined) {
|
|
1821
|
-
return value;
|
|
1822
|
-
}
|
|
1823
|
-
switch (cast) {
|
|
1824
|
-
case "date":
|
|
1825
|
-
case "datetime":
|
|
1826
|
-
return value instanceof Date ? value : new Date(String(value));
|
|
1827
|
-
case "json":
|
|
1828
|
-
return typeof value === "string" ? JSON.parse(value) : value;
|
|
1829
|
-
case "bool":
|
|
1830
|
-
case "boolean":
|
|
1831
|
-
return value === true || value === 1 || value === "1" || value === "true";
|
|
1832
|
-
default:
|
|
1833
|
-
return value;
|
|
1834
|
-
}
|
|
1835
|
-
}
|
|
1836
|
-
function dehydrateValue(value, cast) {
|
|
1837
|
-
if (value === null || value === undefined) {
|
|
1838
|
-
return value;
|
|
1839
|
-
}
|
|
1840
|
-
switch (cast) {
|
|
1841
|
-
case "date":
|
|
1842
|
-
case "datetime":
|
|
1843
|
-
return value instanceof Date ? value : new Date(String(value));
|
|
1844
|
-
case "json":
|
|
1845
|
-
return typeof value === "string" ? value : JSON.stringify(value);
|
|
1846
|
-
case "bool":
|
|
1847
|
-
case "boolean":
|
|
1848
|
-
return Boolean(value);
|
|
1849
|
-
default:
|
|
1850
|
-
return value;
|
|
1851
|
-
}
|
|
1852
|
-
}
|
|
1853
|
-
function filterMassAssignable(fillable, guarded, input) {
|
|
1854
|
-
const resolvedGuarded = guarded ?? true;
|
|
1855
|
-
if (fillable && fillable.length > 0) {
|
|
1856
|
-
const allowed = new Set(fillable);
|
|
1857
|
-
return Object.fromEntries(Object.entries(input).filter(([key]) => allowed.has(key)));
|
|
1858
|
-
}
|
|
1859
|
-
if (resolvedGuarded === true || resolvedGuarded.includes("*")) {
|
|
1860
|
-
return {};
|
|
1861
|
-
}
|
|
1862
|
-
const blocked = new Set(resolvedGuarded);
|
|
1863
|
-
return Object.fromEntries(Object.entries(input).filter(([key]) => !blocked.has(key)));
|
|
1864
|
-
}
|
|
1865
|
-
function applyCasts(values, casts, direction) {
|
|
1866
|
-
if (Object.keys(casts).length === 0) {
|
|
1867
|
-
return values;
|
|
1868
|
-
}
|
|
1869
|
-
const result = { ...values };
|
|
1870
|
-
const castFn = direction === "hydrate" ? hydrateValue : dehydrateValue;
|
|
1871
|
-
for (const [key, cast] of Object.entries(casts)) {
|
|
1872
|
-
if (key in result && cast) {
|
|
1873
|
-
result[key] = castFn(result[key], cast);
|
|
1874
|
-
}
|
|
1875
|
-
}
|
|
1876
|
-
return result;
|
|
1877
|
-
}
|
|
1878
|
-
function applyTimestampsOnCreate(columns, values, enabled) {
|
|
1879
|
-
if (!enabled) {
|
|
1880
|
-
return values;
|
|
1881
|
-
}
|
|
1882
|
-
const now = new Date;
|
|
1883
|
-
const result = { ...values };
|
|
1884
|
-
if (columns.includes("created_at")) {
|
|
1885
|
-
result.created_at = now;
|
|
1886
|
-
}
|
|
1887
|
-
if (columns.includes("updated_at")) {
|
|
1888
|
-
result.updated_at = now;
|
|
1889
|
-
}
|
|
1890
|
-
return result;
|
|
1891
|
-
}
|
|
1892
|
-
function applyTimestampsOnUpdate(columns, values, enabled) {
|
|
1893
|
-
if (!enabled) {
|
|
1894
|
-
return values;
|
|
1895
|
-
}
|
|
1896
|
-
const result = { ...values };
|
|
1897
|
-
if (columns.includes("updated_at")) {
|
|
1898
|
-
result.updated_at = new Date;
|
|
1899
|
-
}
|
|
1900
|
-
return result;
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
class Model {
|
|
1904
|
-
attributes;
|
|
1905
|
-
repository;
|
|
1906
|
-
static $fillable;
|
|
1907
|
-
static $guarded;
|
|
1908
|
-
static $casts = {};
|
|
1909
|
-
static $timestamps = true;
|
|
1910
|
-
_exists;
|
|
1911
|
-
constructor(attributes, repository, exists = true) {
|
|
1912
|
-
this.attributes = attributes;
|
|
1913
|
-
this.repository = repository;
|
|
1914
|
-
this._exists = exists;
|
|
1915
|
-
}
|
|
1916
|
-
get $exists() {
|
|
1917
|
-
return this._exists;
|
|
1918
|
-
}
|
|
1919
|
-
get(key) {
|
|
1920
|
-
return this.attributes[key];
|
|
1921
|
-
}
|
|
1922
|
-
get id() {
|
|
1923
|
-
return this.attributes[this.primaryKey()];
|
|
1924
|
-
}
|
|
1925
|
-
toObject() {
|
|
1926
|
-
return { ...this.attributes };
|
|
1927
|
-
}
|
|
1928
|
-
primaryKey() {
|
|
1929
|
-
throw new Error(`${this.constructor.name}.primaryKey() is not implemented.`);
|
|
1930
|
-
}
|
|
1931
|
-
static primaryKeyField() {
|
|
1932
|
-
return resolveModelRepository(this).getTable().primaryKey;
|
|
1933
|
-
}
|
|
1934
|
-
static hydrateAttributes(attributes) {
|
|
1935
|
-
const casts = modelStatics(this).$casts ?? {};
|
|
1936
|
-
return applyCasts(attributes, casts, "hydrate");
|
|
1937
|
-
}
|
|
1938
|
-
static dehydrateAttributes(attributes) {
|
|
1939
|
-
const casts = modelStatics(this).$casts ?? {};
|
|
1940
|
-
return applyCasts(attributes, casts, "dehydrate");
|
|
1941
|
-
}
|
|
1942
|
-
static fromRecord(record, repository, exists = true) {
|
|
1943
|
-
const statics = modelStatics(this);
|
|
1944
|
-
const hydrated = statics.hydrateAttributes(record);
|
|
1945
|
-
return new statics(hydrated, repository, exists);
|
|
1946
|
-
}
|
|
1947
|
-
static boot() {}
|
|
1948
|
-
static addGlobalScope(_name, scope) {
|
|
1949
|
-
ensureBooted(this);
|
|
1950
|
-
const existing = modelGlobalScopes.get(this) ?? [];
|
|
1951
|
-
modelGlobalScopes.set(this, [
|
|
1952
|
-
...existing,
|
|
1953
|
-
scope
|
|
1954
|
-
]);
|
|
1955
|
-
}
|
|
1956
|
-
static repository() {
|
|
1957
|
-
return resolveModelRepository(this);
|
|
1958
|
-
}
|
|
1959
|
-
static query() {
|
|
1960
|
-
ensureBooted(this);
|
|
1961
|
-
const repository = resolveModelRepository(this);
|
|
1962
|
-
let query = repository.query();
|
|
1963
|
-
for (const scope of getGlobalScopes(this)) {
|
|
1964
|
-
query = scope(query);
|
|
1965
|
-
}
|
|
1966
|
-
return query;
|
|
1967
|
-
}
|
|
1968
|
-
static async create(attributes) {
|
|
1969
|
-
const statics = modelStatics(this);
|
|
1970
|
-
ensureBooted(this);
|
|
1971
|
-
const repository = resolveModelRepository(this);
|
|
1972
|
-
const table = repository.getTable();
|
|
1973
|
-
const timestamps = statics.$timestamps ?? true;
|
|
1974
|
-
const assignable = filterMassAssignable(statics.$fillable, statics.$guarded, attributes);
|
|
1975
|
-
const withTimestamps = applyTimestampsOnCreate(table.columns, assignable, timestamps);
|
|
1976
|
-
const payload = statics.dehydrateAttributes(withTimestamps);
|
|
1977
|
-
const record = await repository.create(payload);
|
|
1978
|
-
return statics.fromRecord(record, repository, true);
|
|
1979
|
-
}
|
|
1980
|
-
static async find(id) {
|
|
1981
|
-
const statics = modelStatics(this);
|
|
1982
|
-
const repository = resolveModelRepository(this);
|
|
1983
|
-
const primaryKey = repository.getTable().primaryKey;
|
|
1984
|
-
const record = await Model.query.call(this).where({ [primaryKey]: id }).first();
|
|
1985
|
-
return record ? statics.fromRecord(record, repository, true) : null;
|
|
1986
|
-
}
|
|
1987
|
-
static async findOrFail(id, errorFactory) {
|
|
1988
|
-
const model = await Model.find.call(this, id);
|
|
1989
|
-
if (model) {
|
|
1990
|
-
return model;
|
|
1991
|
-
}
|
|
1992
|
-
throw errorFactory?.(id) ?? new NotFoundError(`${this.name} ${String(id)} not found.`);
|
|
1993
|
-
}
|
|
1994
|
-
static async all(options = {}) {
|
|
1995
|
-
const statics = modelStatics(this);
|
|
1996
|
-
const repository = resolveModelRepository(this);
|
|
1997
|
-
let query = Model.query.call(this);
|
|
1998
|
-
if (options.orderBy) {
|
|
1999
|
-
query = query.orderBy(options.orderBy);
|
|
2000
|
-
}
|
|
2001
|
-
if (options.limit !== undefined) {
|
|
2002
|
-
query = query.limit(options.limit);
|
|
2003
|
-
}
|
|
2004
|
-
const rows = await query.get();
|
|
2005
|
-
return rows.map((row) => statics.fromRecord(row, repository, true));
|
|
2006
|
-
}
|
|
2007
|
-
static async firstWhere(where, options = {}) {
|
|
2008
|
-
const statics = modelStatics(this);
|
|
2009
|
-
const repository = resolveModelRepository(this);
|
|
2010
|
-
let query = Model.query.call(this).where(where);
|
|
2011
|
-
if (options.orderBy) {
|
|
2012
|
-
query = query.orderBy(options.orderBy);
|
|
2013
|
-
}
|
|
2014
|
-
const record = await query.first();
|
|
2015
|
-
return record ? statics.fromRecord(record, repository, true) : null;
|
|
2016
|
-
}
|
|
2017
|
-
async save() {
|
|
2018
|
-
const ModelClass = modelStatics(this.constructor);
|
|
2019
|
-
const timestamps = ModelClass.$timestamps ?? true;
|
|
2020
|
-
const casts = ModelClass.$casts ?? {};
|
|
2021
|
-
const table = this.repository.getTable();
|
|
2022
|
-
if (this.$exists) {
|
|
2023
|
-
const changes = applyTimestampsOnUpdate(table.columns, applyCasts(this.attributes, casts, "dehydrate"), timestamps);
|
|
2024
|
-
const record2 = await this.repository.updateByIdOrThrow(this.id, changes);
|
|
2025
|
-
this.attributes = ModelClass.hydrateAttributes(record2);
|
|
2026
|
-
return this;
|
|
2027
|
-
}
|
|
2028
|
-
const assignable = filterMassAssignable(ModelClass.$fillable, ModelClass.$guarded, this.attributes);
|
|
2029
|
-
const withTimestamps = applyTimestampsOnCreate(table.columns, assignable, timestamps);
|
|
2030
|
-
const payload = ModelClass.dehydrateAttributes(withTimestamps);
|
|
2031
|
-
const record = await this.repository.create(payload);
|
|
2032
|
-
this.attributes = ModelClass.hydrateAttributes(record);
|
|
2033
|
-
this._exists = true;
|
|
2034
|
-
return this;
|
|
2035
|
-
}
|
|
2036
|
-
async update(changes) {
|
|
2037
|
-
const ModelClass = modelStatics(this.constructor);
|
|
2038
|
-
const assignable = filterMassAssignable(ModelClass.$fillable, ModelClass.$guarded, changes);
|
|
2039
|
-
Object.assign(this.attributes, assignable);
|
|
2040
|
-
return await this.save();
|
|
2041
|
-
}
|
|
2042
|
-
async delete() {
|
|
2043
|
-
if (resolveSoftDeleteColumn(this.repository.getTable())) {
|
|
2044
|
-
return await this.repository.deleteById(this.id);
|
|
2045
|
-
}
|
|
2046
|
-
return await this.repository.forceDeleteById(this.id);
|
|
2047
|
-
}
|
|
2048
|
-
async forceDelete() {
|
|
2049
|
-
return await this.repository.forceDeleteById(this.id);
|
|
2050
|
-
}
|
|
2051
|
-
async restore() {
|
|
2052
|
-
const ModelClass = modelStatics(this.constructor);
|
|
2053
|
-
const record = await this.repository.restoreById(this.id);
|
|
2054
|
-
if (!record) {
|
|
2055
|
-
return null;
|
|
2056
|
-
}
|
|
2057
|
-
this.attributes = ModelClass.hydrateAttributes(record);
|
|
2058
|
-
return this;
|
|
2059
|
-
}
|
|
2060
|
-
async loadHasMany(as, relation, childRepository, options = {}) {
|
|
2061
|
-
const grouped = await childRepository.withConnection(this.repository.getConnection()).loadHasManyForParents([this.attributes], relation, options);
|
|
2062
|
-
const loaded = grouped.get(this.attributes[relation.localKey]) ?? [];
|
|
2063
|
-
return Object.assign(this, { [as]: loaded });
|
|
2064
|
-
}
|
|
2065
|
-
async loadHasOne(as, relation, childRepository, options = {}) {
|
|
2066
|
-
const loaded = await this.loadHasMany(as, relation, childRepository, { ...options, limit: 1 });
|
|
2067
|
-
const value = loaded[as]?.[0];
|
|
2068
|
-
return Object.assign(this, { [as]: value });
|
|
2069
|
-
}
|
|
2070
|
-
async loadBelongsTo(as, relation, parentRepository, options = {}) {
|
|
2071
|
-
const grouped = await this.repository.loadBelongsToForParents([this.attributes], relation, parentRepository, options);
|
|
2072
|
-
const loaded = grouped.get(this.attributes[relation.foreignKey]);
|
|
2073
|
-
return Object.assign(this, { [as]: loaded });
|
|
2074
|
-
}
|
|
2075
|
-
async loadBelongsToMany(as, relation, relatedRepository, options = {}) {
|
|
2076
|
-
const connection = this.repository.getConnection();
|
|
2077
|
-
const parentId = this.attributes[relation.parentKey];
|
|
2078
|
-
const pivotRows = await connection.unsafe(`SELECT * FROM ${relation.pivotTable} WHERE ${String(relation.foreignPivotKey)} = $1`, [parentId]);
|
|
2079
|
-
if (pivotRows.length === 0) {
|
|
2080
|
-
return Object.assign(this, { [as]: [] });
|
|
2081
|
-
}
|
|
2082
|
-
const relatedIds = [
|
|
2083
|
-
...new Set(pivotRows.map((row) => row[relation.relatedPivotKey]))
|
|
2084
|
-
];
|
|
2085
|
-
const relatedRows = await relatedRepository.withConnection(connection).findAll({
|
|
2086
|
-
...options,
|
|
2087
|
-
where: {
|
|
2088
|
-
[relation.relatedKey]: relatedIds
|
|
2089
|
-
}
|
|
2090
|
-
});
|
|
2091
|
-
const grouped = indexBelongsToManyRelation([this.attributes], pivotRows, relatedRows, relation);
|
|
2092
|
-
const loaded = grouped.get(parentId) ?? [];
|
|
2093
|
-
return Object.assign(this, { [as]: loaded });
|
|
2094
|
-
}
|
|
2095
|
-
mergeAttributes(patch) {
|
|
2096
|
-
Object.assign(this.attributes, patch);
|
|
2097
|
-
return this;
|
|
2098
|
-
}
|
|
2099
|
-
}
|
|
2100
|
-
function registerModelRepository(model, repository) {
|
|
2101
|
-
modelRepositories.set(model, repository);
|
|
2102
|
-
ensureBooted(model);
|
|
2103
|
-
return model;
|
|
2104
|
-
}
|
|
2105
1656
|
// ../../src/core/database/schema/columnDefinition.ts
|
|
2106
1657
|
class ColumnDefinition {
|
|
2107
1658
|
name;
|
|
@@ -2323,45 +1874,6 @@ class Blueprint {
|
|
|
2323
1874
|
});
|
|
2324
1875
|
}
|
|
2325
1876
|
}
|
|
2326
|
-
// ../../src/core/database/schema/driver.ts
|
|
2327
|
-
function normalizeConnectionName(connection) {
|
|
2328
|
-
const normalized = connection.trim().toLowerCase();
|
|
2329
|
-
if (normalized === "pgsql" || normalized === "postgres" || normalized === "postgresql") {
|
|
2330
|
-
return "pgsql";
|
|
2331
|
-
}
|
|
2332
|
-
if (normalized === "mysql" || normalized === "mariadb") {
|
|
2333
|
-
return "mysql";
|
|
2334
|
-
}
|
|
2335
|
-
if (normalized === "sqlite") {
|
|
2336
|
-
return "sqlite";
|
|
2337
|
-
}
|
|
2338
|
-
throw new Error(`Unsupported DB_CONNECTION: ${connection}`);
|
|
2339
|
-
}
|
|
2340
|
-
function resolveDriverFromUrl(url) {
|
|
2341
|
-
const normalized = url.trim().toLowerCase();
|
|
2342
|
-
if (normalized.startsWith("postgres://") || normalized.startsWith("postgresql://") || normalized.startsWith("postgres:")) {
|
|
2343
|
-
return "pgsql";
|
|
2344
|
-
}
|
|
2345
|
-
if (normalized.startsWith("mysql://") || normalized.startsWith("mysql:")) {
|
|
2346
|
-
return "mysql";
|
|
2347
|
-
}
|
|
2348
|
-
if (normalized.startsWith("sqlite:")) {
|
|
2349
|
-
return "sqlite";
|
|
2350
|
-
}
|
|
2351
|
-
return null;
|
|
2352
|
-
}
|
|
2353
|
-
function resolveDatabaseDriver(options = {}) {
|
|
2354
|
-
const connection = options.connection ?? process.env.DB_CONNECTION;
|
|
2355
|
-
if (connection) {
|
|
2356
|
-
return normalizeConnectionName(connection);
|
|
2357
|
-
}
|
|
2358
|
-
const url = options.url ?? process.env.DATABASE_URL ?? "";
|
|
2359
|
-
const fromUrl = resolveDriverFromUrl(url);
|
|
2360
|
-
if (fromUrl) {
|
|
2361
|
-
return fromUrl;
|
|
2362
|
-
}
|
|
2363
|
-
return "pgsql";
|
|
2364
|
-
}
|
|
2365
1877
|
// ../../src/core/database/schema/errors.ts
|
|
2366
1878
|
class UnsupportedSchemaFeatureError extends Error {
|
|
2367
1879
|
constructor(feature, driver) {
|
|
@@ -2700,48 +2212,16 @@ class SchemaBuilder {
|
|
|
2700
2212
|
toSql() {
|
|
2701
2213
|
return [...this.#statements];
|
|
2702
2214
|
}
|
|
2703
|
-
async execute(
|
|
2215
|
+
async execute(db) {
|
|
2704
2216
|
for (const statement of this.#statements) {
|
|
2705
|
-
await
|
|
2217
|
+
await db.unsafe(statement);
|
|
2706
2218
|
}
|
|
2707
2219
|
}
|
|
2708
2220
|
}
|
|
2709
|
-
|
|
2710
|
-
class Schema {
|
|
2711
|
-
static builder(driver) {
|
|
2712
|
-
return new SchemaBuilder(driver ?? resolveDatabaseDriver());
|
|
2713
|
-
}
|
|
2714
|
-
static async run(db2, driver, callback) {
|
|
2715
|
-
const schema = Schema.builder(driver);
|
|
2716
|
-
await callback(schema);
|
|
2717
|
-
await schema.execute(db2);
|
|
2718
|
-
}
|
|
2719
|
-
}
|
|
2720
|
-
function createSchemaBuilder(db2, driver) {
|
|
2721
|
-
const builder = Schema.builder(driver);
|
|
2722
|
-
return Object.assign(builder, {
|
|
2723
|
-
async commit() {
|
|
2724
|
-
await builder.execute(db2);
|
|
2725
|
-
}
|
|
2726
|
-
});
|
|
2727
|
-
}
|
|
2728
2221
|
// ../../src/core/database/table.ts
|
|
2729
2222
|
function defineTable(definition) {
|
|
2730
2223
|
return definition;
|
|
2731
2224
|
}
|
|
2732
|
-
// ../../src/core/database/transaction.ts
|
|
2733
|
-
function supportsTransactions(connection) {
|
|
2734
|
-
return typeof connection.begin === "function";
|
|
2735
|
-
}
|
|
2736
|
-
async function runInTransaction(operation) {
|
|
2737
|
-
const pool = resolveRepositoryConnection();
|
|
2738
|
-
if (!supportsTransactions(pool)) {
|
|
2739
|
-
throw new Error("Active database connection does not support transactions. Bind a client with begin() via bindDatabaseConnection.");
|
|
2740
|
-
}
|
|
2741
|
-
return await pool.begin(async (transaction) => {
|
|
2742
|
-
return await operation(createDatabaseConnection2(transaction));
|
|
2743
|
-
});
|
|
2744
|
-
}
|
|
2745
2225
|
// ../../src/core/queue/failedJobTable.ts
|
|
2746
2226
|
var failedJobTable = defineTable({
|
|
2747
2227
|
name: "failed_job",
|