@zintrust/core 0.1.21 → 0.1.23
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/bin/z.d.ts +1 -1
- package/bin/z.js +1 -1
- package/bin/zin.d.ts +1 -1
- package/bin/zin.js +1 -1
- package/bin/zintrust-main.d.ts +1 -1
- package/bin/zintrust-main.js +2 -2
- package/bin/zintrust-microservices.d.ts +1 -1
- package/bin/zintrust-microservices.js +1 -1
- package/bin/zintrust.d.ts +1 -1
- package/bin/zintrust.js +1 -1
- package/bin/zt.d.ts +1 -1
- package/bin/zt.js +1 -1
- package/package.json +2 -3
- package/public/index.html +3 -3
- package/routes/api.js +1 -1
- package/routes/health.d.ts +3 -4
- package/routes/health.d.ts.map +1 -1
- package/routes/health.js +3 -125
- package/src/boot/Application.d.ts.map +1 -1
- package/src/boot/Application.js +11 -22
- package/src/boot/bootstrap.d.ts +1 -1
- package/src/boot/bootstrap.js +48 -7
- package/src/builder/BundleOptimizer.d.ts +1 -1
- package/src/builder/BundleOptimizer.js +1 -1
- package/src/cache/drivers/KVRemoteDriver.d.ts +1 -1
- package/src/cache/drivers/KVRemoteDriver.js +1 -1
- package/src/cli/CLI.d.ts.map +1 -1
- package/src/cli/CLI.js +15 -1
- package/src/cli/ErrorHandler.js +3 -3
- package/src/cli/commands/AddCommand.d.ts +1 -1
- package/src/cli/commands/AddCommand.d.ts.map +1 -1
- package/src/cli/commands/AddCommand.js +1 -1
- package/src/cli/commands/DbSeedCommand.js +1 -1
- package/src/cli/commands/MakeMailTemplateCommand.js +2 -1
- package/src/cli/commands/MakeNotificationTemplateCommand.js +2 -1
- package/src/cli/commands/MigrateCommand.d.ts.map +1 -1
- package/src/cli/commands/MigrateCommand.js +1 -1
- package/src/cli/commands/MigrateWorkerCommand.d.ts +9 -0
- package/src/cli/commands/MigrateWorkerCommand.d.ts.map +1 -0
- package/src/cli/commands/MigrateWorkerCommand.js +182 -0
- package/src/cli/commands/NewCommand.d.ts +1 -1
- package/src/cli/commands/NewCommand.d.ts.map +1 -1
- package/src/cli/commands/NewCommand.js +21 -7
- package/src/cli/commands/PublishCommand.d.ts +5 -0
- package/src/cli/commands/PublishCommand.d.ts.map +1 -0
- package/src/cli/commands/PublishCommand.js +54 -0
- package/src/cli/commands/QACommand.js +4 -4
- package/src/cli/commands/ResourceControlCommand.d.ts +6 -0
- package/src/cli/commands/ResourceControlCommand.d.ts.map +1 -0
- package/src/cli/commands/ResourceControlCommand.js +43 -0
- package/src/cli/commands/SimulateCommand.d.ts +1 -1
- package/src/cli/commands/SimulateCommand.js +4 -4
- package/src/cli/commands/StartCommand.d.ts.map +1 -1
- package/src/cli/commands/StartCommand.js +19 -7
- package/src/cli/commands/UpgradeCommand.d.ts +1 -1
- package/src/cli/commands/UpgradeCommand.js +2 -2
- package/src/cli/commands/WorkerCommands.d.ts +17 -0
- package/src/cli/commands/WorkerCommands.d.ts.map +1 -0
- package/src/cli/commands/WorkerCommands.js +264 -0
- package/src/cli/commands/index.d.ts +2 -0
- package/src/cli/commands/index.d.ts.map +1 -1
- package/src/cli/commands/index.js +2 -0
- package/src/cli/config/ConfigSchema.d.ts +1 -1
- package/src/cli/config/ConfigSchema.d.ts.map +1 -1
- package/src/cli/config/ConfigSchema.js +4 -3
- package/src/cli/d1/D1SqlMigrations.d.ts.map +1 -1
- package/src/cli/d1/D1SqlMigrations.js +4 -3
- package/src/cli/scaffolding/ModelGenerator.d.ts +1 -1
- package/src/cli/scaffolding/ModelGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/ModelGenerator.js +10 -2
- package/src/cli/scaffolding/ProjectScaffolder.js +5 -5
- package/src/cli/scaffolding/RouteGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/RouteGenerator.js +21 -2
- package/src/cli/scaffolding/TemplateEngine.js +1 -1
- package/src/cli/utils/EnvFileLoader.d.ts.map +1 -1
- package/src/common/ExternalServiceUtils.d.ts +63 -0
- package/src/common/ExternalServiceUtils.d.ts.map +1 -0
- package/src/common/ExternalServiceUtils.js +116 -0
- package/src/common/HealthRoutes.d.ts +10 -0
- package/src/common/HealthRoutes.d.ts.map +1 -0
- package/src/common/HealthRoutes.js +114 -0
- package/src/config/SecretsManager.d.ts.map +1 -1
- package/src/config/SecretsManager.js +2 -1
- package/src/config/app.d.ts +2 -1
- package/src/config/app.d.ts.map +1 -1
- package/src/config/app.js +98 -52
- package/src/config/broadcast.d.ts.map +1 -1
- package/src/config/broadcast.js +2 -2
- package/src/config/cache.d.ts.map +1 -1
- package/src/config/cache.js +2 -2
- package/src/config/database.d.ts.map +1 -1
- package/src/config/database.js +24 -5
- package/src/config/env.d.ts +43 -1
- package/src/config/env.d.ts.map +1 -1
- package/src/config/env.js +68 -21
- package/src/config/index.d.ts +10 -1
- package/src/config/index.d.ts.map +1 -1
- package/src/config/index.js +1 -0
- package/src/config/mail.d.ts.map +1 -1
- package/src/config/mail.js +3 -3
- package/src/config/middleware.d.ts.map +1 -1
- package/src/config/middleware.js +1 -1
- package/src/config/notification.d.ts.map +1 -1
- package/src/config/notification.js +2 -2
- package/src/config/queue.d.ts +14 -0
- package/src/config/queue.d.ts.map +1 -1
- package/src/config/queue.js +61 -36
- package/src/config/security.js +2 -2
- package/src/config/storage.d.ts.map +1 -1
- package/src/config/storage.js +5 -5
- package/src/config/type.d.ts +122 -0
- package/src/config/type.d.ts.map +1 -1
- package/src/config/type.js +10 -1
- package/src/config/workers.d.ts +13 -0
- package/src/config/workers.d.ts.map +1 -0
- package/src/config/workers.js +173 -0
- package/src/database/Paginator.d.ts +37 -0
- package/src/database/Paginator.d.ts.map +1 -0
- package/src/database/Paginator.js +81 -0
- package/src/exceptions/ZintrustError.d.ts +5 -2
- package/src/exceptions/ZintrustError.d.ts.map +1 -1
- package/src/exceptions/ZintrustError.js +6 -2
- package/src/features/Auth.d.ts +1 -1
- package/src/features/Auth.d.ts.map +1 -1
- package/src/features/Auth.js +3 -2
- package/src/features/Queue.d.ts.map +1 -1
- package/src/features/Queue.js +0 -2
- package/src/index.d.ts +15 -5
- package/src/index.d.ts.map +1 -1
- package/src/index.js +24 -3
- package/src/microservices/MicroserviceBootstrap.d.ts.map +1 -1
- package/src/microservices/MicroserviceBootstrap.js +3 -1
- package/src/microservices/MicroserviceGenerator.js +4 -4
- package/src/microservices/MicroserviceManager.d.ts +1 -1
- package/src/microservices/MicroserviceManager.js +1 -1
- package/src/middleware/RateLimiter.d.ts.map +1 -1
- package/src/middleware/RateLimiter.js +4 -3
- package/src/migrations/MigrationLoader.d.ts +1 -1
- package/src/migrations/MigrationLoader.d.ts.map +1 -1
- package/src/migrations/Migrator.d.ts +3 -3
- package/src/migrations/Migrator.d.ts.map +1 -1
- package/src/migrations/Migrator.js +1 -1
- package/src/migrations/MigratorFactory.d.ts +1 -1
- package/src/migrations/MigratorFactory.d.ts.map +1 -1
- package/src/migrations/MigratorFactory.js +3 -3
- package/src/migrations/enum/index.d.ts +93 -0
- package/src/migrations/enum/index.d.ts.map +1 -0
- package/src/migrations/enum/index.js +92 -0
- package/src/migrations/schema/Blueprint.d.ts +1 -1
- package/src/migrations/schema/Blueprint.d.ts.map +1 -1
- package/src/migrations/schema/Blueprint.js +27 -25
- package/src/migrations/schema/Schema.d.ts +1 -1
- package/src/migrations/schema/Schema.d.ts.map +1 -1
- package/src/migrations/schema/Schema.js +4 -3
- package/src/migrations/schema/SchemaCompiler.d.ts +1 -1
- package/src/migrations/schema/SchemaCompiler.d.ts.map +1 -1
- package/src/migrations/schema/SchemaCompiler.js +99 -91
- package/src/migrations/schema/index.d.ts +4 -4
- package/src/migrations/schema/index.d.ts.map +1 -1
- package/src/migrations/schema/index.js +3 -3
- package/src/migrations/schema/types.d.ts +2 -1
- package/src/migrations/schema/types.d.ts.map +1 -1
- package/src/node-singletons/crypto.d.ts +1 -1
- package/src/node-singletons/crypto.d.ts.map +1 -1
- package/src/node-singletons/crypto.js +1 -1
- package/src/node-singletons/os.d.ts +10 -1
- package/src/node-singletons/os.d.ts.map +1 -1
- package/src/node-singletons/os.js +10 -1
- package/src/openapi/OpenApiGenerator.js +2 -2
- package/src/orm/ConnectionManager.d.ts +7 -5
- package/src/orm/ConnectionManager.d.ts.map +1 -1
- package/src/orm/ConnectionManager.js +249 -93
- package/src/orm/Database.d.ts +2 -1
- package/src/orm/Database.d.ts.map +1 -1
- package/src/orm/DatabaseAdapter.d.ts +3 -2
- package/src/orm/DatabaseAdapter.d.ts.map +1 -1
- package/src/orm/DatabaseAdapter.js +17 -0
- package/src/orm/Model.d.ts +8 -1
- package/src/orm/Model.d.ts.map +1 -1
- package/src/orm/Model.js +109 -26
- package/src/orm/QueryBuilder.d.ts +12 -2
- package/src/orm/QueryBuilder.d.ts.map +1 -1
- package/src/orm/QueryBuilder.js +438 -38
- package/src/orm/Relationships.d.ts +61 -1
- package/src/orm/Relationships.d.ts.map +1 -1
- package/src/orm/Relationships.js +190 -0
- package/src/orm/adapters/D1Adapter.d.ts.map +1 -1
- package/src/orm/adapters/D1Adapter.js +2 -1
- package/src/orm/adapters/D1RemoteAdapter.d.ts +1 -1
- package/src/orm/adapters/D1RemoteAdapter.d.ts.map +1 -1
- package/src/orm/adapters/D1RemoteAdapter.js +3 -2
- package/src/orm/adapters/MySQLAdapter.d.ts.map +1 -1
- package/src/orm/adapters/MySQLAdapter.js +2 -1
- package/src/orm/adapters/SQLServerAdapter.d.ts.map +1 -1
- package/src/orm/adapters/SQLServerAdapter.js +2 -1
- package/src/orm/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/src/orm/adapters/SQLiteAdapter.js +2 -1
- package/src/orm/migrations/MigrationStore.d.ts.map +1 -1
- package/src/performance/Optimizer.d.ts.map +1 -1
- package/src/performance/Optimizer.js +57 -18
- package/src/profiling/RequestProfiler.d.ts.map +1 -1
- package/src/profiling/RequestProfiler.js +3 -1
- package/src/routing/CoreRoutes.d.ts +1 -1
- package/src/routing/CoreRoutes.d.ts.map +1 -1
- package/src/routing/CoreRoutes.js +2 -116
- package/src/routing/error.d.ts.map +1 -1
- package/src/routing/error.js +3 -2
- package/src/routing/publicRoot.d.ts.map +1 -1
- package/src/routing/publicRoot.js +4 -2
- package/src/runtime/PluginAutoImports.d.ts.map +1 -1
- package/src/runtime/PluginAutoImports.js +20 -4
- package/src/runtime/PluginManager.d.ts.map +1 -1
- package/src/runtime/PluginManager.js +23 -6
- package/src/runtime/RuntimeAdapter.d.ts +3 -3
- package/src/runtime/RuntimeAdapter.d.ts.map +1 -1
- package/src/runtime/StartupConfigFileRegistry.d.ts +15 -13
- package/src/runtime/StartupConfigFileRegistry.d.ts.map +1 -1
- package/src/runtime/StartupConfigFileRegistry.js +12 -12
- package/src/runtime/adapters/CloudflareAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/CloudflareAdapter.js +1 -1
- package/src/runtime/adapters/DenoAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/DenoAdapter.js +1 -1
- package/src/runtime/adapters/FargateAdapter.d.ts +2 -2
- package/src/runtime/adapters/FargateAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/FargateAdapter.js +1 -1
- package/src/runtime/adapters/LambdaAdapter.d.ts +1 -1
- package/src/runtime/adapters/LambdaAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/LambdaAdapter.js +6 -4
- package/src/runtime/adapters/NodeServerAdapter.js +1 -1
- package/src/scripts/GenerateEnvArtifacts.js +1 -1
- package/src/security/SignedRequest.js +1 -1
- package/src/security/StartupSecretValidation.d.ts.map +1 -1
- package/src/security/StartupSecretValidation.js +7 -1
- package/src/start.d.ts.map +1 -1
- package/src/start.js +0 -2
- package/src/templates/features/Auth.ts.tpl +4 -4
- package/src/templates/project/basic/README.md.tpl +1 -1
- package/src/templates/project/basic/app/Middleware/index.ts.tpl +1 -1
- package/src/templates/project/basic/config/notification.ts.tpl +1 -1
- package/src/templates/project/basic/routes/api.ts.tpl +1 -3
- package/src/templates/project/basic/src/index.ts.tpl +1 -1
- package/src/templates/project/basic/src/zintrust.plugins.ts.tpl +1 -1
- package/src/templates/project/basic/template.json +1 -1
- package/src/toolkit/Secrets/index.d.ts.map +1 -1
- package/src/toolkit/Secrets/index.js +13 -9
- package/src/toolkit/Secrets/providers/AwsSecretsManager.d.ts.map +1 -1
- package/src/toolkit/Secrets/providers/AwsSecretsManager.js +20 -7
- package/src/toolkit/Secrets/providers/CloudflareKv.d.ts.map +1 -1
- package/src/toolkit/Secrets/providers/CloudflareKv.js +19 -6
- package/src/tools/http/Http.js +1 -1
- package/src/tools/mail/drivers/Ses.d.ts.map +1 -1
- package/src/tools/mail/drivers/Ses.js +5 -4
- package/src/tools/mail/templates/index.js +2 -2
- package/src/tools/notification/drivers/Termii.d.ts.map +1 -1
- package/src/tools/notification/drivers/Termii.js +6 -17
- package/src/tools/notification/testingHelpers.d.ts.map +1 -1
- package/src/tools/queue/Queue.d.ts.map +1 -1
- package/src/tools/queue/Queue.js +3 -5
- package/src/tools/queue/drivers/Redis.d.ts.map +1 -1
- package/src/tools/queue/drivers/Redis.js +7 -1
- package/src/tools/storage/drivers/S3.d.ts.map +1 -1
- package/src/tools/storage/drivers/S3.js +16 -3
- package/src/routes/health.d.ts +0 -2
- package/src/routes/health.d.ts.map +0 -1
- package/src/routes/health.js +0 -1
- package/src/runtime/RuntimeDetector.d.ts +0 -15
- package/src/runtime/RuntimeDetector.d.ts.map +0 -1
- package/src/runtime/RuntimeDetector.js +0 -271
- package/src/templates/project/basic/routes/health.ts.tpl +0 -143
- package/src/templates/project/basic/routes/metrics.ts.tpl +0 -22
- package/src/workers/BroadcastWorker.d.ts +0 -22
- package/src/workers/BroadcastWorker.d.ts.map +0 -1
- package/src/workers/BroadcastWorker.js +0 -24
- package/src/workers/NotificationWorker.d.ts +0 -22
- package/src/workers/NotificationWorker.d.ts.map +0 -1
- package/src/workers/NotificationWorker.js +0 -23
- package/src/workers/createQueueWorker.d.ts +0 -24
- package/src/workers/createQueueWorker.d.ts.map +0 -1
- package/src/workers/createQueueWorker.js +0 -114
package/src/orm/QueryBuilder.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* QueryBuilder - Type-Safe Query Builder
|
|
3
3
|
* Build queries without raw SQL
|
|
4
4
|
*/
|
|
5
|
+
import { createPaginator } from '../database/Paginator.js';
|
|
5
6
|
import { ErrorFactory } from '../exceptions/ZintrustError.js';
|
|
6
7
|
const getIdentifierQuote = (dialect) => {
|
|
7
8
|
const d = (dialect ?? '').toLowerCase();
|
|
@@ -286,6 +287,15 @@ const buildSelectQuery = (state) => {
|
|
|
286
287
|
const sql = `SELECT ${columns}${fromClause}${where.sql}${buildOrderByClause(state.orderByClauses, state.dialect)}${buildLimitOffsetClause(state.limitValue, state.offsetValue)}`;
|
|
287
288
|
return { sql, parameters: where.parameters };
|
|
288
289
|
};
|
|
290
|
+
const buildCountQuery = (state) => {
|
|
291
|
+
if (state.tableName.length > 0) {
|
|
292
|
+
assertSafeIdentifierPath(state.tableName, 'table name');
|
|
293
|
+
}
|
|
294
|
+
const fromClause = state.tableName.length > 0 ? ` FROM ${escapeIdentifier(state.tableName, state.dialect)}` : '';
|
|
295
|
+
const where = compileWhere(getEffectiveWhereConditions(state), state.dialect);
|
|
296
|
+
const sql = `SELECT COUNT(*) AS total${fromClause}${where.sql}`;
|
|
297
|
+
return { sql, parameters: where.parameters };
|
|
298
|
+
};
|
|
289
299
|
const applyWhereCondition = (state, column, operator, value) => {
|
|
290
300
|
const col = String(column).trim();
|
|
291
301
|
assertSafeIdentifierPath(col, 'where column');
|
|
@@ -397,6 +407,40 @@ async function executeGet(builder, db) {
|
|
|
397
407
|
throw ErrorFactory.createDatabaseError('Database instance not provided to QueryBuilder');
|
|
398
408
|
return (await db.query(builder.toSQL(), builder.getParameters(), builder.isReadOperation()));
|
|
399
409
|
}
|
|
410
|
+
const normalizePaginationValue = (value, label) => {
|
|
411
|
+
const n = Math.trunc(value);
|
|
412
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
413
|
+
throw ErrorFactory.createValidationError(`${label} must be a positive integer`);
|
|
414
|
+
}
|
|
415
|
+
return n;
|
|
416
|
+
};
|
|
417
|
+
async function executePaginate(builder, state, db, page, perPage, options) {
|
|
418
|
+
if (!db)
|
|
419
|
+
throw ErrorFactory.createDatabaseError('Database instance not provided to QueryBuilder');
|
|
420
|
+
const safePage = normalizePaginationValue(page, 'page');
|
|
421
|
+
const safePerPage = normalizePaginationValue(perPage, 'perPage');
|
|
422
|
+
const countQuery = buildCountQuery(state);
|
|
423
|
+
const countRows = (await db.query(countQuery.sql, countQuery.parameters, true));
|
|
424
|
+
const rawTotal = countRows.at(0)?.['total'];
|
|
425
|
+
const total = typeof rawTotal === 'bigint' ? Number(rawTotal) : Number(rawTotal ?? 0);
|
|
426
|
+
const sanitizedTotal = Number.isFinite(total) && total > 0 ? total : 0;
|
|
427
|
+
const offset = (safePage - 1) * safePerPage;
|
|
428
|
+
const prevLimit = state.limitValue;
|
|
429
|
+
const prevOffset = state.offsetValue;
|
|
430
|
+
state.limitValue = safePerPage;
|
|
431
|
+
state.offsetValue = offset;
|
|
432
|
+
const items = await executeGet(builder, db);
|
|
433
|
+
state.limitValue = prevLimit;
|
|
434
|
+
state.offsetValue = prevOffset;
|
|
435
|
+
return createPaginator({
|
|
436
|
+
items,
|
|
437
|
+
total: sanitizedTotal,
|
|
438
|
+
perPage: safePerPage,
|
|
439
|
+
currentPage: safePage,
|
|
440
|
+
baseUrl: options?.baseUrl,
|
|
441
|
+
query: options?.query,
|
|
442
|
+
});
|
|
443
|
+
}
|
|
400
444
|
/**
|
|
401
445
|
* Create the builder object
|
|
402
446
|
*/
|
|
@@ -505,57 +549,411 @@ function attachIntrospectionMethods(builder, state) {
|
|
|
505
549
|
builder.getParameters = () => buildSelectQuery(state).parameters;
|
|
506
550
|
// Internal method for eager loading distribution
|
|
507
551
|
builder.getEagerLoads = () => state.eagerLoads;
|
|
552
|
+
builder.getEagerLoadConstraints = () => state.eagerLoadConstraints;
|
|
553
|
+
builder.getEagerLoadCounts = () => state.eagerLoadCounts;
|
|
508
554
|
}
|
|
509
|
-
function attachReadExecutionMethods(builder, db) {
|
|
555
|
+
function attachReadExecutionMethods(builder, state, db) {
|
|
510
556
|
builder.first = async () => executeFirst(builder, db);
|
|
511
557
|
builder.firstOrFail = async (message) => executeFirstOrFail(builder, db, message);
|
|
512
558
|
builder.get = async () => executeGet(builder, db);
|
|
559
|
+
builder.paginate = async (page, perPage, options) => executePaginate(builder, state, db, page, perPage, options);
|
|
513
560
|
// raw just returns results without any hydration logic in callers
|
|
514
561
|
builder.raw = async () => executeGet(builder, db);
|
|
515
562
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
563
|
+
const isNonEmptyString = (value) => typeof value === 'string' && value.length > 0;
|
|
564
|
+
const isKeyValue = (value) => typeof value === 'string' || typeof value === 'number';
|
|
565
|
+
const getModelIds = (models, key) => models.map((model) => model.getAttribute(key)).filter(isKeyValue);
|
|
566
|
+
const applyConstraint = (query, constraint) => {
|
|
567
|
+
if (typeof constraint === 'function') {
|
|
568
|
+
return constraint(query) ?? query;
|
|
569
|
+
}
|
|
570
|
+
return query;
|
|
571
|
+
};
|
|
572
|
+
/**
|
|
573
|
+
* Load relationship counts for a collection of models
|
|
574
|
+
*/
|
|
575
|
+
async function loadCounts(models, relation, db) {
|
|
576
|
+
if (models.length === 0 || !db)
|
|
577
|
+
return;
|
|
578
|
+
const firstModel = models[0];
|
|
579
|
+
if (typeof firstModel[relation] !== 'function')
|
|
580
|
+
return;
|
|
581
|
+
const rel = firstModel[relation]();
|
|
582
|
+
if (rel === null || rel === undefined)
|
|
583
|
+
return;
|
|
584
|
+
const relType = rel.type;
|
|
585
|
+
// Only hasMany and belongsToMany support counts
|
|
586
|
+
if (relType !== 'hasMany' && relType !== 'belongsToMany') {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
const foreignKey = rel.foreignKey;
|
|
590
|
+
const localKey = rel.localKey;
|
|
591
|
+
const ids = getModelIds(models, localKey);
|
|
592
|
+
if (ids.length === 0)
|
|
593
|
+
return;
|
|
594
|
+
const dialect = typeof db.getType === 'function' ? db.getType() : undefined;
|
|
595
|
+
const queryCounts = async (sql, params) => {
|
|
596
|
+
const results = (await db.query(sql, params, true));
|
|
597
|
+
const map = new Map();
|
|
598
|
+
for (const row of results) {
|
|
599
|
+
let count;
|
|
600
|
+
if (typeof row.count === 'bigint') {
|
|
601
|
+
count = Number(row.count);
|
|
602
|
+
}
|
|
603
|
+
else if (typeof row.count === 'number') {
|
|
604
|
+
count = row.count;
|
|
605
|
+
}
|
|
606
|
+
else {
|
|
607
|
+
count = Number(row.count ?? 0);
|
|
608
|
+
}
|
|
609
|
+
map.set(row.key, count);
|
|
610
|
+
}
|
|
611
|
+
return map;
|
|
520
612
|
};
|
|
521
|
-
|
|
522
|
-
if (models.length === 0)
|
|
523
|
-
return;
|
|
524
|
-
// We assume the first model can give us the relationship definition
|
|
525
|
-
const firstModel = models[0];
|
|
526
|
-
if (typeof firstModel[relation] !== 'function')
|
|
527
|
-
return;
|
|
528
|
-
const rel = firstModel[relation]();
|
|
529
|
-
if (rel === null || rel === undefined)
|
|
530
|
-
return;
|
|
531
|
-
const related = rel.related;
|
|
532
|
-
if (related === null || related === undefined)
|
|
533
|
-
return;
|
|
534
|
-
const foreignKey = rel.foreignKey;
|
|
535
|
-
const localKey = rel.localKey;
|
|
536
|
-
const ids = models
|
|
537
|
-
.map((m) => m.getAttribute(localKey))
|
|
538
|
-
.filter((id) => id !== null && id !== undefined);
|
|
539
|
-
if (ids.length === 0)
|
|
540
|
-
return;
|
|
541
|
-
// Call query on the related model
|
|
542
|
-
const relatedModel = rel.related;
|
|
543
|
-
if (typeof relatedModel.query !== 'function')
|
|
544
|
-
return;
|
|
545
|
-
const relatedResults = await relatedModel.query().whereIn(foreignKey, ids).get();
|
|
546
|
-
// Map results back to models
|
|
613
|
+
const setCountsOnModels = (countMap) => {
|
|
547
614
|
for (const model of models) {
|
|
548
615
|
const modelId = model.getAttribute(localKey);
|
|
549
|
-
if (
|
|
550
|
-
const
|
|
551
|
-
model.
|
|
616
|
+
if (isKeyValue(modelId)) {
|
|
617
|
+
const count = countMap.get(modelId) ?? 0;
|
|
618
|
+
model.setAttribute(`${relation}_count`, count);
|
|
552
619
|
}
|
|
553
620
|
else {
|
|
554
|
-
|
|
555
|
-
model.setRelation(relation, found ?? null);
|
|
621
|
+
model.setAttribute(`${relation}_count`, 0);
|
|
556
622
|
}
|
|
557
623
|
}
|
|
558
624
|
};
|
|
625
|
+
if (relType === 'hasMany') {
|
|
626
|
+
const relatedModel = rel.related;
|
|
627
|
+
if (typeof relatedModel?.query !== 'function')
|
|
628
|
+
return;
|
|
629
|
+
const tempQuery = relatedModel.query();
|
|
630
|
+
const relatedTable = tempQuery.getTable();
|
|
631
|
+
const sql = `SELECT ${escapeIdentifier(foreignKey, dialect)} as key, COUNT(*) as count FROM ${escapeIdentifier(relatedTable, dialect)} WHERE ${escapeIdentifier(foreignKey, dialect)} IN (${ids.map(() => '?').join(',')}) GROUP BY ${escapeIdentifier(foreignKey, dialect)}`;
|
|
632
|
+
const countMap = await queryCounts(sql, ids);
|
|
633
|
+
setCountsOnModels(countMap);
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
// belongsToMany
|
|
637
|
+
const throughTable = rel.throughTable;
|
|
638
|
+
const relatedKey = rel.relatedKey;
|
|
639
|
+
if (!isNonEmptyString(throughTable) || !isNonEmptyString(relatedKey))
|
|
640
|
+
return;
|
|
641
|
+
const sql = `SELECT ${escapeIdentifier(foreignKey, dialect)} as key, COUNT(*) as count FROM ${escapeIdentifier(throughTable, dialect)} WHERE ${escapeIdentifier(foreignKey, dialect)} IN (${ids.map(() => '?').join(',')}) GROUP BY ${escapeIdentifier(foreignKey, dialect)}`;
|
|
642
|
+
const countMap = await queryCounts(sql, ids);
|
|
643
|
+
setCountsOnModels(countMap);
|
|
644
|
+
}
|
|
645
|
+
const getRelationFromModels = (models, relation) => {
|
|
646
|
+
const firstModel = models[0];
|
|
647
|
+
const relationFactory = firstModel?.[relation];
|
|
648
|
+
if (typeof relationFactory !== 'function')
|
|
649
|
+
return null;
|
|
650
|
+
const rel = relationFactory();
|
|
651
|
+
return rel ?? null;
|
|
652
|
+
};
|
|
653
|
+
const assignMorphToGroup = (modelsByType, type, model) => {
|
|
654
|
+
const existing = modelsByType.get(type);
|
|
655
|
+
if (existing) {
|
|
656
|
+
existing.push(model);
|
|
657
|
+
}
|
|
658
|
+
else {
|
|
659
|
+
modelsByType.set(type, [model]);
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
const getModelTable = (model) => {
|
|
663
|
+
const tableGetter = model.getTable;
|
|
664
|
+
if (typeof tableGetter !== 'function')
|
|
665
|
+
return null;
|
|
666
|
+
const table = tableGetter();
|
|
667
|
+
return isNonEmptyString(table) ? table : null;
|
|
668
|
+
};
|
|
669
|
+
const buildSingleMap = (results, key) => {
|
|
670
|
+
const map = new Map();
|
|
671
|
+
for (const result of results) {
|
|
672
|
+
const resultId = result.getAttribute(key);
|
|
673
|
+
if (isKeyValue(resultId)) {
|
|
674
|
+
map.set(resultId, result);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return map;
|
|
678
|
+
};
|
|
679
|
+
const buildBucketMap = (results, key) => {
|
|
680
|
+
const buckets = new Map();
|
|
681
|
+
for (const result of results) {
|
|
682
|
+
const resultId = result.getAttribute(key);
|
|
683
|
+
if (isKeyValue(resultId)) {
|
|
684
|
+
const existing = buckets.get(resultId) ?? [];
|
|
685
|
+
existing.push(result);
|
|
686
|
+
buckets.set(resultId, existing);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return buckets;
|
|
690
|
+
};
|
|
691
|
+
const setRelationsFromBuckets = (models, relation, localKey, buckets, isMany) => {
|
|
692
|
+
for (const model of models) {
|
|
693
|
+
const modelId = model.getAttribute(localKey);
|
|
694
|
+
if (!isKeyValue(modelId)) {
|
|
695
|
+
model.setRelation(relation, isMany ? [] : null);
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
const bucket = buckets.get(modelId) ?? [];
|
|
699
|
+
if (isMany) {
|
|
700
|
+
model.setRelation(relation, bucket);
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
model.setRelation(relation, bucket[0] ?? null);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
const buildParentToThroughIds = (throughResults, throughForeignKey, secondLocalKey) => {
|
|
708
|
+
const parentToThroughIds = new Map();
|
|
709
|
+
for (const throughItem of throughResults) {
|
|
710
|
+
const parentId = throughItem.getAttribute(throughForeignKey);
|
|
711
|
+
const throughId = throughItem.getAttribute(secondLocalKey);
|
|
712
|
+
if (isKeyValue(parentId) && isKeyValue(throughId)) {
|
|
713
|
+
const existing = parentToThroughIds.get(parentId) ?? [];
|
|
714
|
+
existing.push(throughId);
|
|
715
|
+
parentToThroughIds.set(parentId, existing);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return parentToThroughIds;
|
|
719
|
+
};
|
|
720
|
+
const collectThroughRelated = (throughIds, relatedBuckets) => {
|
|
721
|
+
const aggregated = [];
|
|
722
|
+
for (const throughId of throughIds) {
|
|
723
|
+
const bucket = relatedBuckets.get(throughId);
|
|
724
|
+
if (bucket !== undefined) {
|
|
725
|
+
aggregated.push(...bucket);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
return aggregated;
|
|
729
|
+
};
|
|
730
|
+
const setThroughRelations = (models, relation, localKey, parentToThroughIds, relatedBuckets, isMany) => {
|
|
731
|
+
for (const model of models) {
|
|
732
|
+
const modelId = model.getAttribute(localKey);
|
|
733
|
+
if (!isKeyValue(modelId)) {
|
|
734
|
+
model.setRelation(relation, isMany ? [] : null);
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
const throughIds = parentToThroughIds.get(modelId) ?? [];
|
|
738
|
+
if (throughIds.length === 0) {
|
|
739
|
+
model.setRelation(relation, isMany ? [] : null);
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
742
|
+
const aggregated = collectThroughRelated(throughIds, relatedBuckets);
|
|
743
|
+
if (isMany) {
|
|
744
|
+
model.setRelation(relation, aggregated);
|
|
745
|
+
}
|
|
746
|
+
else {
|
|
747
|
+
model.setRelation(relation, aggregated[0] ?? null);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
const buildMorphToGroups = (models, morphType) => {
|
|
752
|
+
const modelsByType = new Map();
|
|
753
|
+
for (const model of models) {
|
|
754
|
+
const type = model.getAttribute(morphType);
|
|
755
|
+
if (isNonEmptyString(type)) {
|
|
756
|
+
assignMorphToGroup(modelsByType, type, model);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return modelsByType;
|
|
760
|
+
};
|
|
761
|
+
const setMorphToRelations = (models, relation, morphId, relatedMap) => {
|
|
762
|
+
for (const model of models) {
|
|
763
|
+
const modelId = model.getAttribute(morphId);
|
|
764
|
+
if (isKeyValue(modelId)) {
|
|
765
|
+
model.setRelation(relation, relatedMap.get(modelId) ?? null);
|
|
766
|
+
}
|
|
767
|
+
else {
|
|
768
|
+
model.setRelation(relation, null);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
const loadMorphToGroup = async (relation, morphId, modelsOfType, relatedModel, constraint) => {
|
|
773
|
+
const ids = getModelIds(modelsOfType, morphId);
|
|
774
|
+
if (ids.length === 0)
|
|
775
|
+
return;
|
|
776
|
+
const relatedQuery = applyConstraint(relatedModel.query(), constraint);
|
|
777
|
+
const relatedResults = await relatedQuery.whereIn('id', ids).get();
|
|
778
|
+
const relatedMap = buildSingleMap(relatedResults, 'id');
|
|
779
|
+
setMorphToRelations(modelsOfType, relation, morphId, relatedMap);
|
|
780
|
+
};
|
|
781
|
+
const loadMorphToRelation = async (models, relation, rel, constraint) => {
|
|
782
|
+
if (rel.type !== 'morphTo')
|
|
783
|
+
return false;
|
|
784
|
+
const morphType = rel.morphType;
|
|
785
|
+
const morphId = rel.morphId;
|
|
786
|
+
const morphMap = rel.morphMap;
|
|
787
|
+
if (!isNonEmptyString(morphType) ||
|
|
788
|
+
!isNonEmptyString(morphId) ||
|
|
789
|
+
morphMap === null ||
|
|
790
|
+
morphMap === undefined) {
|
|
791
|
+
return true;
|
|
792
|
+
}
|
|
793
|
+
const modelsByType = buildMorphToGroups(models, morphType);
|
|
794
|
+
const tasks = [...modelsByType.entries()].map(async ([type, modelsOfType]) => {
|
|
795
|
+
const relatedModel = morphMap[type];
|
|
796
|
+
if (relatedModel === undefined || typeof relatedModel.query !== 'function') {
|
|
797
|
+
return Promise.resolve(); //NOSONAR
|
|
798
|
+
}
|
|
799
|
+
return loadMorphToGroup(relation, morphId, modelsOfType, relatedModel, constraint);
|
|
800
|
+
});
|
|
801
|
+
await Promise.all(tasks);
|
|
802
|
+
return true;
|
|
803
|
+
};
|
|
804
|
+
const prepareMorphOneMany = (models, rel, localKey, morphId, morphType) => {
|
|
805
|
+
if (!isNonEmptyString(morphType) || !isNonEmptyString(morphId) || !isNonEmptyString(localKey)) {
|
|
806
|
+
return { proceed: false };
|
|
807
|
+
}
|
|
808
|
+
const ids = getModelIds(models, localKey);
|
|
809
|
+
if (ids.length === 0)
|
|
810
|
+
return { proceed: false };
|
|
811
|
+
const relatedModel = rel.related;
|
|
812
|
+
if (typeof relatedModel.query !== 'function')
|
|
813
|
+
return { proceed: false };
|
|
814
|
+
const tableName = getModelTable(models[0]);
|
|
815
|
+
if (tableName === null)
|
|
816
|
+
return { proceed: false };
|
|
817
|
+
return { proceed: true, ids, relatedModel, tableName };
|
|
818
|
+
};
|
|
819
|
+
const loadMorphOneManyRelation = async (models, relation, rel, constraint) => {
|
|
820
|
+
if (rel.type !== 'morphOne' && rel.type !== 'morphMany')
|
|
821
|
+
return false;
|
|
822
|
+
const morphType = rel.morphType;
|
|
823
|
+
const morphId = rel.morphId;
|
|
824
|
+
const localKey = rel.localKey;
|
|
825
|
+
const prep = prepareMorphOneMany(models, rel, localKey, morphId, morphType);
|
|
826
|
+
if (!prep.proceed ||
|
|
827
|
+
prep.ids === undefined ||
|
|
828
|
+
prep.relatedModel === undefined ||
|
|
829
|
+
prep.tableName === undefined ||
|
|
830
|
+
!isNonEmptyString(morphType) ||
|
|
831
|
+
!isNonEmptyString(morphId) ||
|
|
832
|
+
!isNonEmptyString(localKey)) {
|
|
833
|
+
return true;
|
|
834
|
+
}
|
|
835
|
+
const ids = prep.ids;
|
|
836
|
+
const relatedModel = prep.relatedModel;
|
|
837
|
+
const tableName = prep.tableName;
|
|
838
|
+
const relatedQuery = applyConstraint(relatedModel.query(), constraint)
|
|
839
|
+
.where(morphType, '=', tableName)
|
|
840
|
+
.whereIn(morphId, ids);
|
|
841
|
+
const relatedResults = await relatedQuery.get();
|
|
842
|
+
const relatedBuckets = buildBucketMap(relatedResults, morphId);
|
|
843
|
+
const isMany = rel.type === 'morphMany';
|
|
844
|
+
setRelationsFromBuckets(models, relation, localKey, relatedBuckets, isMany);
|
|
845
|
+
return true;
|
|
846
|
+
};
|
|
847
|
+
const loadThroughRelation = async (models, relation, rel, constraint) => {
|
|
848
|
+
if (rel.type !== 'hasOneThrough' && rel.type !== 'hasManyThrough')
|
|
849
|
+
return false;
|
|
850
|
+
const through = rel.through;
|
|
851
|
+
const throughForeignKey = rel.throughForeignKey;
|
|
852
|
+
const secondLocalKey = rel.secondLocalKey;
|
|
853
|
+
const foreignKey = rel.foreignKey;
|
|
854
|
+
const localKey = rel.localKey;
|
|
855
|
+
if (through === undefined ||
|
|
856
|
+
through === null ||
|
|
857
|
+
!isNonEmptyString(throughForeignKey) ||
|
|
858
|
+
!isNonEmptyString(secondLocalKey) ||
|
|
859
|
+
!isNonEmptyString(foreignKey) ||
|
|
860
|
+
!isNonEmptyString(localKey)) {
|
|
861
|
+
return true;
|
|
862
|
+
}
|
|
863
|
+
const ids = getModelIds(models, localKey);
|
|
864
|
+
if (ids.length === 0)
|
|
865
|
+
return true;
|
|
866
|
+
const throughModel = through;
|
|
867
|
+
const relatedModel = rel.related;
|
|
868
|
+
if (typeof throughModel.getTable !== 'function' ||
|
|
869
|
+
typeof relatedModel.query !== 'function' ||
|
|
870
|
+
typeof relatedModel.getTable !== 'function') {
|
|
871
|
+
return true;
|
|
872
|
+
}
|
|
873
|
+
const throughTable = throughModel.getTable();
|
|
874
|
+
const relatedTable = relatedModel.getTable();
|
|
875
|
+
if (!isNonEmptyString(throughTable) || !isNonEmptyString(relatedTable))
|
|
876
|
+
return true;
|
|
877
|
+
let relatedQuery = relatedModel.query();
|
|
878
|
+
relatedQuery = applyConstraint(relatedQuery, constraint);
|
|
879
|
+
relatedQuery = relatedQuery
|
|
880
|
+
.join(throughTable, `${relatedTable}.${foreignKey} = ${throughTable}.${secondLocalKey}`)
|
|
881
|
+
.whereIn(`${throughTable}.${throughForeignKey}`, ids);
|
|
882
|
+
const relatedResults = await relatedQuery.get();
|
|
883
|
+
const throughQuery = throughModel.query().whereIn(throughForeignKey, ids);
|
|
884
|
+
const throughResults = await throughQuery.get();
|
|
885
|
+
const parentToThroughIds = buildParentToThroughIds(throughResults, throughForeignKey, secondLocalKey);
|
|
886
|
+
const relatedBuckets = buildBucketMap(relatedResults, foreignKey);
|
|
887
|
+
const isMany = rel.type === 'hasManyThrough';
|
|
888
|
+
setThroughRelations(models, relation, localKey, parentToThroughIds, relatedBuckets, isMany);
|
|
889
|
+
return true;
|
|
890
|
+
};
|
|
891
|
+
const loadStandardRelation = async (models, relation, rel, constraint) => {
|
|
892
|
+
const related = rel.related;
|
|
893
|
+
if (related === null || related === undefined)
|
|
894
|
+
return false;
|
|
895
|
+
const foreignKey = rel.foreignKey;
|
|
896
|
+
const localKey = rel.localKey;
|
|
897
|
+
if (!isNonEmptyString(foreignKey) || !isNonEmptyString(localKey))
|
|
898
|
+
return false;
|
|
899
|
+
const ids = getModelIds(models, localKey);
|
|
900
|
+
if (ids.length === 0)
|
|
901
|
+
return true;
|
|
902
|
+
const relatedModel = rel.related;
|
|
903
|
+
if (typeof relatedModel.query !== 'function')
|
|
904
|
+
return false;
|
|
905
|
+
const relatedQuery = applyConstraint(relatedModel.query(), constraint);
|
|
906
|
+
const relatedResults = await relatedQuery.whereIn(foreignKey, ids).get();
|
|
907
|
+
const relatedBuckets = buildBucketMap(relatedResults, foreignKey);
|
|
908
|
+
const isMany = rel.type === 'hasMany' || rel.type === 'belongsToMany';
|
|
909
|
+
setRelationsFromBuckets(models, relation, localKey, relatedBuckets, isMany);
|
|
910
|
+
return true;
|
|
911
|
+
};
|
|
912
|
+
const loadRelation = async (models, relation, constraint) => {
|
|
913
|
+
if (models.length === 0)
|
|
914
|
+
return;
|
|
915
|
+
const rel = getRelationFromModels(models, relation);
|
|
916
|
+
if (!rel)
|
|
917
|
+
return;
|
|
918
|
+
const type = rel.type;
|
|
919
|
+
if (type === 'morphTo') {
|
|
920
|
+
await loadMorphToRelation(models, relation, rel, constraint);
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
if (type === 'morphOne' || type === 'morphMany') {
|
|
924
|
+
await loadMorphOneManyRelation(models, relation, rel, constraint);
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
if (type === 'hasOneThrough' || type === 'hasManyThrough') {
|
|
928
|
+
await loadThroughRelation(models, relation, rel, constraint);
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
await loadStandardRelation(models, relation, rel, constraint);
|
|
932
|
+
};
|
|
933
|
+
function attachRelationshipMethods(builder, state, db) {
|
|
934
|
+
builder.with = (relation) => {
|
|
935
|
+
if (typeof relation === 'string') {
|
|
936
|
+
state.eagerLoads.push(relation);
|
|
937
|
+
return builder;
|
|
938
|
+
}
|
|
939
|
+
for (const [name, constraint] of Object.entries(relation)) {
|
|
940
|
+
if (state.eagerLoads.includes(name) === false) {
|
|
941
|
+
state.eagerLoads.push(name);
|
|
942
|
+
}
|
|
943
|
+
state.eagerLoadConstraints[name] = constraint;
|
|
944
|
+
}
|
|
945
|
+
return builder;
|
|
946
|
+
};
|
|
947
|
+
builder.withCount = (relation) => {
|
|
948
|
+
state.eagerLoadCounts.push(relation);
|
|
949
|
+
return builder;
|
|
950
|
+
};
|
|
951
|
+
builder.load = async (models, relation, constraint) => {
|
|
952
|
+
await loadRelation(models, relation, constraint);
|
|
953
|
+
};
|
|
954
|
+
builder.loadCount = async (models, relation) => {
|
|
955
|
+
await loadCounts(models, relation, db);
|
|
956
|
+
};
|
|
559
957
|
}
|
|
560
958
|
function attachWriteMethods(builder, state, db) {
|
|
561
959
|
const ensureDb = () => {
|
|
@@ -605,8 +1003,8 @@ function createBuilder(state, db) {
|
|
|
605
1003
|
attachSoftDeleteMethods(builder, state);
|
|
606
1004
|
attachJoinOrderPagingMethods(builder, state);
|
|
607
1005
|
attachIntrospectionMethods(builder, state);
|
|
608
|
-
attachReadExecutionMethods(builder, db);
|
|
609
|
-
attachRelationshipMethods(builder, state);
|
|
1006
|
+
attachReadExecutionMethods(builder, state, db);
|
|
1007
|
+
attachRelationshipMethods(builder, state, db);
|
|
610
1008
|
attachWriteMethods(builder, state, db);
|
|
611
1009
|
return builder;
|
|
612
1010
|
}
|
|
@@ -634,6 +1032,8 @@ export const QueryBuilder = Object.freeze({
|
|
|
634
1032
|
orderByClauses: [],
|
|
635
1033
|
joins: [],
|
|
636
1034
|
eagerLoads: [],
|
|
1035
|
+
eagerLoadConstraints: {},
|
|
1036
|
+
eagerLoadCounts: [],
|
|
637
1037
|
dialect: typeof database?.getType === 'function' ? database.getType() : undefined,
|
|
638
1038
|
};
|
|
639
1039
|
if (options.softDeleteColumn !== undefined && options.softDeleteColumn.trim().length > 0) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Define how models relate to each other
|
|
4
4
|
*/
|
|
5
5
|
import type { IModel, Model, ModelStatic } from './Model';
|
|
6
|
-
export type RelationshipType = 'hasOne' | 'hasMany' | 'belongsTo' | 'belongsToMany';
|
|
6
|
+
export type RelationshipType = 'hasOne' | 'hasMany' | 'belongsTo' | 'belongsToMany' | 'morphOne' | 'morphMany' | 'morphTo' | 'hasOneThrough' | 'hasManyThrough';
|
|
7
7
|
export interface Relation {
|
|
8
8
|
type: RelationshipType;
|
|
9
9
|
related: typeof Model;
|
|
@@ -19,6 +19,14 @@ export interface IRelationship {
|
|
|
19
19
|
localKey: string;
|
|
20
20
|
throughTable?: string;
|
|
21
21
|
relatedKey?: string;
|
|
22
|
+
morphType?: string;
|
|
23
|
+
morphId?: string;
|
|
24
|
+
morphName?: string;
|
|
25
|
+
morphMap?: Record<string, ModelStatic>;
|
|
26
|
+
through?: ModelStatic;
|
|
27
|
+
throughForeignKey?: string;
|
|
28
|
+
throughLocalKey?: string;
|
|
29
|
+
secondLocalKey?: string;
|
|
22
30
|
}
|
|
23
31
|
/**
|
|
24
32
|
* HasOne Relationship
|
|
@@ -56,4 +64,56 @@ export declare const BelongsTo: Readonly<{
|
|
|
56
64
|
export declare const BelongsToMany: Readonly<{
|
|
57
65
|
create(relatedModel: ModelStatic, throughTable: string, foreignKey: string, relatedKey: string): IRelationship;
|
|
58
66
|
}>;
|
|
67
|
+
/**
|
|
68
|
+
* MorphOne Relationship
|
|
69
|
+
* Polymorphic one-to-one relationship
|
|
70
|
+
* Sealed namespace object following Pattern 2
|
|
71
|
+
*
|
|
72
|
+
* @see FRAMEWORK_REFACTOR_FUNCTION_PATTERN.md for Pattern 2 details
|
|
73
|
+
*/
|
|
74
|
+
export declare const MorphOne: Readonly<{
|
|
75
|
+
create(relatedModel: ModelStatic, morphName: string, morphType?: string, morphId?: string, localKeyColumn?: string): IRelationship;
|
|
76
|
+
}>;
|
|
77
|
+
/**
|
|
78
|
+
* MorphMany Relationship
|
|
79
|
+
* Polymorphic one-to-many relationship
|
|
80
|
+
* Sealed namespace object following Pattern 2
|
|
81
|
+
*
|
|
82
|
+
* @see FRAMEWORK_REFACTOR_FUNCTION_PATTERN.md for Pattern 2 details
|
|
83
|
+
*/
|
|
84
|
+
export declare const MorphMany: Readonly<{
|
|
85
|
+
create(relatedModel: ModelStatic, morphName: string, morphType?: string, morphId?: string, localKeyColumn?: string): IRelationship;
|
|
86
|
+
}>;
|
|
87
|
+
/**
|
|
88
|
+
* MorphTo Relationship
|
|
89
|
+
* Inverse of polymorphic relationships
|
|
90
|
+
* Sealed namespace object following Pattern 2
|
|
91
|
+
*
|
|
92
|
+
* @see FRAMEWORK_REFACTOR_FUNCTION_PATTERN.md for Pattern 2 details
|
|
93
|
+
*/
|
|
94
|
+
export declare const MorphTo: Readonly<{
|
|
95
|
+
create(morphName: string, morphMap: Record<string, ModelStatic>, morphType?: string, morphId?: string): IRelationship;
|
|
96
|
+
}>;
|
|
97
|
+
/**
|
|
98
|
+
* HasOneThrough Relationship
|
|
99
|
+
* Access a distant relation through an intermediate model
|
|
100
|
+
* Example: Country -> User -> Post (Country hasOneThrough Post through User)
|
|
101
|
+
* Sealed namespace object following Pattern 2
|
|
102
|
+
*
|
|
103
|
+
* @see FRAMEWORK_REFACTOR_FUNCTION_PATTERN.md for Pattern 2 details
|
|
104
|
+
*/
|
|
105
|
+
export declare const HasOneThrough: Readonly<{
|
|
106
|
+
create(relatedModel: ModelStatic, through: ModelStatic, foreignKey?: string, throughForeignKey?: string, localKey?: string, secondLocalKey?: string): IRelationship;
|
|
107
|
+
}>;
|
|
108
|
+
/**
|
|
109
|
+
* HasManyThrough Relationship
|
|
110
|
+
* Access distant relations through an intermediate model
|
|
111
|
+
* Example: Country -> User -> Post (Country hasManyThrough Posts through Users)
|
|
112
|
+
* Sealed namespace object following Pattern 2
|
|
113
|
+
*
|
|
114
|
+
* @see FRAMEWORK_REFACTOR_FUNCTION_PATTERN.md for Pattern 2 details
|
|
115
|
+
*/
|
|
116
|
+
export declare const HasManyThrough: Readonly<{
|
|
117
|
+
create(relatedModel: ModelStatic, through: ModelStatic, foreignKey?: string, throughForeignKey?: string, localKey?: string, secondLocalKey?: string): IRelationship;
|
|
118
|
+
}>;
|
|
59
119
|
//# sourceMappingURL=Relationships.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Relationships.d.ts","sourceRoot":"","sources":["../../../src/orm/Relationships.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,MAAM,gBAAgB,
|
|
1
|
+
{"version":3,"file":"Relationships.d.ts","sourceRoot":"","sources":["../../../src/orm/Relationships.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,MAAM,gBAAgB,GACxB,QAAQ,GACR,SAAS,GACT,WAAW,GACX,eAAe,GACf,UAAU,GACV,WAAW,GACX,SAAS,GACT,eAAe,GACf,gBAAgB,CAAC;AAErB,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,EAAE,OAAO,KAAK,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,EAAE,WAAW,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACvC,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAUD;;;;;GAKG;AACH,eAAO,MAAM,MAAM;yBACI,WAAW,cAAc,MAAM,YAAY,MAAM,GAAG,aAAa;EActF,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,OAAO;yBACG,WAAW,cAAc,MAAM,YAAY,MAAM,GAAG,aAAa;EActF,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,SAAS;yBACC,WAAW,cAAc,MAAM,YAAY,MAAM,GAAG,aAAa;EActF,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,aAAa;yBAER,WAAW,gBACX,MAAM,cACR,MAAM,cACN,MAAM,GACjB,aAAa;EAoChB,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ;yBAEH,WAAW,aACd,MAAM,cACL,MAAM,YACR,MAAM,4BAEf,aAAa;EA0BhB,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,SAAS;yBAEJ,WAAW,aACd,MAAM,cACL,MAAM,YACR,MAAM,4BAEf,aAAa;EA0BhB,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,OAAO;sBAEL,MAAM,YACP,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,cACzB,MAAM,YACR,MAAM,GACf,aAAa;EAuChB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa;yBAER,WAAW,WAChB,WAAW,eACP,MAAM,sBACC,MAAM,aACf,MAAM,mBACA,MAAM,GACtB,aAAa;EAqChB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc;yBAET,WAAW,WAChB,WAAW,eACP,MAAM,sBACC,MAAM,aACf,MAAM,mBACA,MAAM,GACtB,aAAa;EAqChB,CAAC"}
|