@solidxai/core 0.1.10 → 0.1.11-beta.1
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/dist/controllers/datasource-introspection.controller.d.ts +234 -0
- package/dist/controllers/datasource-introspection.controller.d.ts.map +1 -0
- package/dist/controllers/datasource-introspection.controller.js +98 -0
- package/dist/controllers/datasource-introspection.controller.js.map +1 -0
- package/dist/controllers/datasource-management.controller.d.ts +18 -0
- package/dist/controllers/datasource-management.controller.d.ts.map +1 -0
- package/dist/controllers/datasource-management.controller.js +55 -0
- package/dist/controllers/datasource-management.controller.js.map +1 -0
- package/dist/dtos/create-datasource-management.dto.d.ts +25 -0
- package/dist/dtos/create-datasource-management.dto.d.ts.map +1 -0
- package/dist/dtos/create-datasource-management.dto.js +169 -0
- package/dist/dtos/create-datasource-management.dto.js.map +1 -0
- package/dist/dtos/datasource-introspection-mapping.dto.d.ts +45 -0
- package/dist/dtos/datasource-introspection-mapping.dto.d.ts.map +1 -0
- package/dist/dtos/datasource-introspection-mapping.dto.js +233 -0
- package/dist/dtos/datasource-introspection-mapping.dto.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces/datasource-introspection-provider.interface.d.ts +26 -0
- package/dist/interfaces/datasource-introspection-provider.interface.d.ts.map +1 -0
- package/dist/interfaces/datasource-introspection-provider.interface.js +3 -0
- package/dist/interfaces/datasource-introspection-provider.interface.js.map +1 -0
- package/dist/repository/scheduled-job.repository.d.ts +3 -0
- package/dist/repository/scheduled-job.repository.d.ts.map +1 -1
- package/dist/repository/scheduled-job.repository.js +60 -0
- package/dist/repository/scheduled-job.repository.js.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts +32 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.js +1011 -230
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +21 -0
- package/dist/services/action-metadata.service.d.ts +7 -0
- package/dist/services/action-metadata.service.d.ts.map +1 -1
- package/dist/services/action-metadata.service.js +76 -3
- package/dist/services/action-metadata.service.js.map +1 -1
- package/dist/services/authentication.service.js +1 -1
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/dashboard-providers/mq-dashboard-latency-trend-provider.service.d.ts.map +1 -1
- package/dist/services/dashboard-providers/mq-dashboard-latency-trend-provider.service.js +2 -2
- package/dist/services/dashboard-providers/mq-dashboard-latency-trend-provider.service.js.map +1 -1
- package/dist/services/dashboard-providers/mq-dashboard-messages-over-time-provider.service.d.ts.map +1 -1
- package/dist/services/dashboard-providers/mq-dashboard-messages-over-time-provider.service.js +2 -2
- package/dist/services/dashboard-providers/mq-dashboard-messages-over-time-provider.service.js.map +1 -1
- package/dist/services/dashboard-providers/mq-dashboard-provider-utils.d.ts +3 -0
- package/dist/services/dashboard-providers/mq-dashboard-provider-utils.d.ts.map +1 -1
- package/dist/services/dashboard-providers/mq-dashboard-provider-utils.js +71 -0
- package/dist/services/dashboard-providers/mq-dashboard-provider-utils.js.map +1 -1
- package/dist/services/dashboard-providers/mq-dashboard-queue-sla-heatmap-provider.service.d.ts.map +1 -1
- package/dist/services/dashboard-providers/mq-dashboard-queue-sla-heatmap-provider.service.js +3 -3
- package/dist/services/dashboard-providers/mq-dashboard-queue-sla-heatmap-provider.service.js.map +1 -1
- package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.d.ts +11 -0
- package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.d.ts.map +1 -0
- package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.js +181 -0
- package/dist/services/datasource-introspection/mssql-datasource-introspection-provider.service.js.map +1 -0
- package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.d.ts +11 -0
- package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.d.ts.map +1 -0
- package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.js +90 -0
- package/dist/services/datasource-introspection/mysql-datasource-introspection-provider.service.js.map +1 -0
- package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.d.ts +11 -0
- package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.d.ts.map +1 -0
- package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.js +156 -0
- package/dist/services/datasource-introspection/postgres-datasource-introspection-provider.service.js.map +1 -0
- package/dist/services/datasource-introspection.service.d.ts +288 -0
- package/dist/services/datasource-introspection.service.d.ts.map +1 -0
- package/dist/services/datasource-introspection.service.js +1278 -0
- package/dist/services/datasource-introspection.service.js.map +1 -0
- package/dist/services/datasource-management.service.d.ts +60 -0
- package/dist/services/datasource-management.service.d.ts.map +1 -0
- package/dist/services/datasource-management.service.js +461 -0
- package/dist/services/datasource-management.service.js.map +1 -0
- package/dist/services/field-metadata.service.d.ts.map +1 -1
- package/dist/services/field-metadata.service.js +19 -0
- package/dist/services/field-metadata.service.js.map +1 -1
- package/dist/services/model-metadata.service.d.ts +1 -3
- package/dist/services/model-metadata.service.d.ts.map +1 -1
- package/dist/services/model-metadata.service.js +47 -15
- package/dist/services/model-metadata.service.js.map +1 -1
- package/dist/services/role-metadata.service.d.ts +5 -0
- package/dist/services/role-metadata.service.d.ts.map +1 -1
- package/dist/services/role-metadata.service.js +85 -31
- package/dist/services/role-metadata.service.js.map +1 -1
- package/dist/services/selection-providers/mq-dashboard-message-broker-variable-options-provider.service.d.ts.map +1 -1
- package/dist/services/selection-providers/mq-dashboard-message-broker-variable-options-provider.service.js +2 -3
- package/dist/services/selection-providers/mq-dashboard-message-broker-variable-options-provider.service.js.map +1 -1
- package/dist/services/selection-providers/mq-dashboard-queue-name-variable-options-provider.service.d.ts.map +1 -1
- package/dist/services/selection-providers/mq-dashboard-queue-name-variable-options-provider.service.js +2 -3
- package/dist/services/selection-providers/mq-dashboard-queue-name-variable-options-provider.service.js.map +1 -1
- package/dist/services/setting.service.d.ts +1 -0
- package/dist/services/setting.service.d.ts.map +1 -1
- package/dist/services/setting.service.js +32 -8
- package/dist/services/setting.service.js.map +1 -1
- package/dist/services/solid-ts-morph.service.d.ts +1 -1
- package/dist/services/solid-ts-morph.service.d.ts.map +1 -1
- package/dist/services/solid-ts-morph.service.js.map +1 -1
- package/dist/services/view-metadata.service.d.ts +6 -0
- package/dist/services/view-metadata.service.d.ts.map +1 -1
- package/dist/services/view-metadata.service.js +66 -1
- package/dist/services/view-metadata.service.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +16 -0
- package/dist/solid-core.module.js.map +1 -1
- package/dist-tests/api/authenticate.spec.js +119 -0
- package/dist-tests/api/authenticate.spec.js.map +1 -0
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +97 -0
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +1 -0
- package/dist-tests/api/ping.spec.js +21 -0
- package/dist-tests/api/ping.spec.js.map +1 -0
- package/dist-tests/helpers/auth.js +41 -0
- package/dist-tests/helpers/auth.js.map +1 -0
- package/dist-tests/helpers/env.js +11 -0
- package/dist-tests/helpers/env.js.map +1 -0
- package/docs/agent-hub-grooming.md +301 -0
- package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +438 -0
- package/docs/dashboards/dashboard-curl-smoke-tests.txt +146 -0
- package/docs/dashboards/delete-legacy-dashboard-metadata.sql +172 -0
- package/docs/datasource-introspection-ddl-analysis.md +326 -0
- package/docs/datasource-introspection-implementation-plan.md +306 -0
- package/docs/grouping-enhancements.md +89 -0
- package/docs/java-spring/README.md +3 -0
- package/docs/java-spring/solid-core-module-deep-dive-report.md +1317 -0
- package/docs/module-package-import-handoff.md +691 -0
- package/docs/seed-changes.md +65 -0
- package/docs/test-data-workflow.md +200 -0
- package/docs/type-declaration-import-issue.md +24 -0
- package/package.json +1 -1
- package/src/controllers/datasource-introspection.controller.ts +58 -0
- package/src/controllers/datasource-management.controller.ts +24 -0
- package/src/dtos/create-datasource-management.dto.ts +139 -0
- package/src/dtos/datasource-introspection-mapping.dto.ts +182 -0
- package/src/index.ts +5 -0
- package/src/interfaces/datasource-introspection-provider.interface.ts +28 -0
- package/src/repository/scheduled-job.repository.ts +73 -0
- package/src/seeders/module-metadata-seeder.service.ts +1223 -262
- package/src/seeders/seed-data/solid-core-metadata.json +22 -1
- package/src/services/action-metadata.service.ts +87 -2
- package/src/services/authentication.service.ts +1 -1
- package/src/services/dashboard-providers/mq-dashboard-latency-trend-provider.service.ts +9 -4
- package/src/services/dashboard-providers/mq-dashboard-messages-over-time-provider.service.ts +9 -4
- package/src/services/dashboard-providers/mq-dashboard-provider-utils.ts +82 -0
- package/src/services/dashboard-providers/mq-dashboard-queue-sla-heatmap-provider.service.ts +10 -4
- package/src/services/datasource-introspection/mssql-datasource-introspection-provider.service.ts +185 -0
- package/src/services/datasource-introspection/mysql-datasource-introspection-provider.service.ts +95 -0
- package/src/services/datasource-introspection/postgres-datasource-introspection-provider.service.ts +160 -0
- package/src/services/datasource-introspection.service.ts +1536 -0
- package/src/services/datasource-management.service.ts +566 -0
- package/src/services/field-metadata.service.ts +21 -1
- package/src/services/model-metadata.service.ts +50 -13
- package/src/services/role-metadata.service.ts +100 -47
- package/src/services/selection-providers/mq-dashboard-message-broker-variable-options-provider.service.ts +2 -4
- package/src/services/selection-providers/mq-dashboard-queue-name-variable-options-provider.service.ts +2 -4
- package/src/services/setting.service.ts +43 -12
- package/src/services/solid-ts-morph.service.ts +2 -2
- package/src/services/view-metadata.service.ts +79 -1
- package/src/solid-core.module.ts +16 -0
- package/.claude/settings.local.json +0 -15
- package/src/services/1.js +0 -6
|
@@ -118,6 +118,14 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
118
118
|
this.dataSource = dataSource;
|
|
119
119
|
this.modelSequenceRepo = modelSequenceRepo;
|
|
120
120
|
this.logger = new common_1.Logger(ModuleMetadataSeederService_1.name);
|
|
121
|
+
this.seedTimingTag = 'SEED_TIMING';
|
|
122
|
+
this.permissionSeedBatchSize = 500;
|
|
123
|
+
this.viewComparableFields = ['name', 'displayName', 'type', 'context', 'layout', 'module', 'model'];
|
|
124
|
+
this.actionComparableFields = ['name', 'displayName', 'type', 'domain', 'context', 'customComponent', 'customIsModal', 'serverEndpoint', 'module', 'model', 'view'];
|
|
125
|
+
this.moduleLookupCache = new Map();
|
|
126
|
+
this.modelLookupCache = new Map();
|
|
127
|
+
this.viewLookupCache = new Map();
|
|
128
|
+
this.mediaStorageProviderLookupCache = new Map();
|
|
121
129
|
this.enablePruning = false;
|
|
122
130
|
}
|
|
123
131
|
async seed(conf) {
|
|
@@ -127,105 +135,110 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
127
135
|
const shouldSeedGlobalMetadata = conf?.seedGlobalMetadata !== false;
|
|
128
136
|
try {
|
|
129
137
|
this.enablePruning = Boolean(conf?.pruneMetadata);
|
|
138
|
+
this.resetLookupCaches();
|
|
130
139
|
console.log(this.enablePruning ? '▶ Pruning enabled: metadata not present in JSON will be removed.' : '▶ Pruning disabled: existing metadata will be kept.');
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
else {
|
|
136
|
-
this.logger.log(`Skipping global metadata seeding.`);
|
|
137
|
-
}
|
|
138
|
-
const seedDataFiles = this.seedDataFiles;
|
|
139
|
-
this.logger.debug(`Found seed data for modules: ${seedDataFiles.map(s => s.moduleMetadata?.name)}`);
|
|
140
|
-
currentStep = 'resolveModulesToSeed';
|
|
141
|
-
if (conf && Array.isArray(conf.modulesToSeed)) {
|
|
142
|
-
modulesToSeed = conf.modulesToSeed;
|
|
143
|
-
console.log(`▶ Selective seeding enabled. Modules to seed: ${modulesToSeed.join(', ')}`);
|
|
144
|
-
this.logger.log(`Selective seeding enabled. Modules to seed: ${modulesToSeed.join(', ')}`);
|
|
145
|
-
}
|
|
146
|
-
else {
|
|
147
|
-
console.log(`▶ No modulesToSeed provided. Seeding ALL modules.`);
|
|
148
|
-
this.logger.log(`No modulesToSeed provided. Seeding ALL modules.`);
|
|
149
|
-
}
|
|
150
|
-
const filteredSeedDataFiles = modulesToSeed ? seedDataFiles.filter((file) => modulesToSeed.includes(file.moduleMetadata?.name)) : seedDataFiles;
|
|
151
|
-
if (filteredSeedDataFiles.length === 0) {
|
|
152
|
-
this.logger.warn(`No modules matched the provided modulesToSeed list.`);
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
for (let i = 0; i < filteredSeedDataFiles.length; i++) {
|
|
156
|
-
const overallMetadata = filteredSeedDataFiles[i];
|
|
157
|
-
const moduleMetadata = overallMetadata.moduleMetadata;
|
|
158
|
-
currentModule = moduleMetadata?.name ?? 'unknown';
|
|
159
|
-
if (!moduleMetadata?.name) {
|
|
160
|
-
this.logger.warn(`Skipping seed metadata file because moduleMetadata.name is missing.`);
|
|
161
|
-
continue;
|
|
140
|
+
await this.timeOperation('seed-run', async () => {
|
|
141
|
+
if (shouldSeedGlobalMetadata) {
|
|
142
|
+
currentStep = 'seedGlobalMetadata';
|
|
143
|
+
await this.timeOperation('global-seed', () => this.seedGlobalMetadata(), { moduleName: 'global', component: 'global-metadata' });
|
|
162
144
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
145
|
+
else {
|
|
146
|
+
this.logger.log(`Skipping global metadata seeding.`);
|
|
147
|
+
}
|
|
148
|
+
const seedDataFiles = this.seedDataFiles;
|
|
149
|
+
this.logger.debug(`Found seed data for modules: ${seedDataFiles.map(s => s.moduleMetadata?.name)}`);
|
|
150
|
+
currentStep = 'resolveModulesToSeed';
|
|
151
|
+
if (conf && Array.isArray(conf.modulesToSeed)) {
|
|
152
|
+
modulesToSeed = conf.modulesToSeed;
|
|
153
|
+
console.log(`▶ Selective seeding enabled. Modules to seed: ${modulesToSeed.join(', ')}`);
|
|
154
|
+
this.logger.log(`Selective seeding enabled. Modules to seed: ${modulesToSeed.join(', ')}`);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
console.log(`▶ No modulesToSeed provided. Seeding ALL modules.`);
|
|
158
|
+
this.logger.log(`No modulesToSeed provided. Seeding ALL modules.`);
|
|
159
|
+
}
|
|
160
|
+
const filteredSeedDataFiles = modulesToSeed ? seedDataFiles.filter((file) => modulesToSeed.includes(file.moduleMetadata?.name)) : seedDataFiles;
|
|
161
|
+
if (filteredSeedDataFiles.length === 0) {
|
|
162
|
+
this.logger.warn(`No modules matched the provided modulesToSeed list.`);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
for (let i = 0; i < filteredSeedDataFiles.length; i++) {
|
|
166
|
+
const overallMetadata = filteredSeedDataFiles[i];
|
|
167
|
+
const moduleMetadata = overallMetadata.moduleMetadata;
|
|
168
|
+
currentModule = moduleMetadata?.name ?? 'unknown';
|
|
169
|
+
if (!moduleMetadata?.name) {
|
|
170
|
+
this.logger.warn(`Skipping seed metadata file because moduleMetadata.name is missing.`);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
console.log(`▶ Seeding Metadata for Module: ${moduleMetadata.name}`);
|
|
174
|
+
this.logger.log(`Seeding Metadata for Module: ${moduleMetadata.name}`);
|
|
175
|
+
await this.timeOperation('module-total', async () => {
|
|
176
|
+
currentStep = 'seedMediaStorageProviders';
|
|
177
|
+
this.logger.log(`Seeding Media Storage Providers`);
|
|
178
|
+
const mediaStorageCounts = await this.timeOperation('seed-media-storage-providers', () => this.seedMediaStorageProviders(overallMetadata.mediaStorageProviders), { moduleName: moduleMetadata.name, component: 'media-storage-providers' });
|
|
179
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Media Storage Providers', mediaStorageCounts)}`);
|
|
180
|
+
currentStep = 'seedModuleModelFields';
|
|
181
|
+
this.logger.log(`Seeding Module / Model / Fields`);
|
|
182
|
+
const moduleModelFieldCounts = await this.timeOperation('seed-module-model-fields', () => this.seedModuleModelFields(moduleMetadata), { moduleName: moduleMetadata.name, component: 'module-model-fields' });
|
|
183
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Module/Model/Fields', moduleModelFieldCounts)}`);
|
|
184
|
+
currentStep = 'seedPermissions';
|
|
185
|
+
this.logger.log(`Seeding Permissions`);
|
|
186
|
+
const permissionCounts = await this.timeOperation('seed-permissions', () => this.seedPermissions(overallMetadata), { moduleName: moduleMetadata.name, component: 'permissions' });
|
|
187
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Permissions', permissionCounts)}`);
|
|
188
|
+
currentStep = 'seedRoles';
|
|
189
|
+
this.logger.log(`Seeding Roles`);
|
|
190
|
+
const roleCounts = await this.timeOperation('seed-roles', () => this.seedRoles(overallMetadata), { moduleName: moduleMetadata.name, component: 'roles' });
|
|
191
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Roles', roleCounts)}`);
|
|
192
|
+
currentStep = 'seedUsers';
|
|
193
|
+
this.logger.log(`Seeding Users`);
|
|
194
|
+
const userCounts = await this.timeOperation('seed-users', () => this.seedUsers(overallMetadata), { moduleName: moduleMetadata.name, component: 'users' });
|
|
195
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Users', userCounts)}`);
|
|
196
|
+
currentStep = 'seedViews';
|
|
197
|
+
this.logger.log(`Seeding Views`);
|
|
198
|
+
const viewCounts = await this.timeOperation('seed-views', () => this.seedViews(overallMetadata), { moduleName: moduleMetadata.name, component: 'views' });
|
|
199
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Views', viewCounts)}`);
|
|
200
|
+
currentStep = 'seedActions';
|
|
201
|
+
this.logger.log(`Seeding Actions`);
|
|
202
|
+
const actionCounts = await this.timeOperation('seed-actions', () => this.seedActions(overallMetadata), { moduleName: moduleMetadata.name, component: 'actions' });
|
|
203
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Actions', actionCounts)}`);
|
|
204
|
+
currentStep = 'seedMenus';
|
|
205
|
+
this.logger.log(`Seeding Menus`);
|
|
206
|
+
const menuCounts = await this.timeOperation('seed-menus', () => this.seedMenus(overallMetadata), { moduleName: moduleMetadata.name, component: 'menus' });
|
|
207
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Menus', menuCounts)}`);
|
|
208
|
+
currentStep = 'seedEmailTemplates';
|
|
209
|
+
this.logger.log(`Seeding Email Templates`);
|
|
210
|
+
const emailTemplateCounts = await this.timeOperation('seed-email-templates', () => this.seedEmailTemplates(overallMetadata, moduleMetadata.name), { moduleName: moduleMetadata.name, component: 'email-templates' });
|
|
211
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Email Templates', emailTemplateCounts)}`);
|
|
212
|
+
currentStep = 'seedSmsTemplates';
|
|
213
|
+
this.logger.log(`Seeding Sms Templates`);
|
|
214
|
+
const smsTemplateCounts = await this.timeOperation('seed-sms-templates', () => this.seedSmsTemplates(overallMetadata, moduleMetadata.name), { moduleName: moduleMetadata.name, component: 'sms-templates' });
|
|
215
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Sms Templates', smsTemplateCounts)}`);
|
|
216
|
+
currentStep = 'seedSecurityRules';
|
|
217
|
+
this.logger.log(`Seeding Security Rules`);
|
|
218
|
+
const securityRuleCounts = await this.timeOperation('seed-security-rules', () => this.seedSecurityRules(overallMetadata), { moduleName: moduleMetadata.name, component: 'security-rules' });
|
|
219
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Security Rules', securityRuleCounts)}`);
|
|
220
|
+
currentStep = 'seedListOfValues';
|
|
221
|
+
this.logger.log(`Seeding List Of Values`);
|
|
222
|
+
const lovCounts = await this.timeOperation('seed-list-of-values', () => this.seedListOfValues(moduleMetadata, overallMetadata), { moduleName: moduleMetadata.name, component: 'list-of-values' });
|
|
223
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'List Of Values', lovCounts)}`);
|
|
224
|
+
currentStep = 'seedScheduledJobs';
|
|
225
|
+
this.logger.log(`Seeding Scheduled Jobs`);
|
|
226
|
+
const scheduledJobCounts = await this.timeOperation('seed-scheduled-jobs', () => this.seedScheduledJobs(moduleMetadata, overallMetadata), { moduleName: moduleMetadata.name, component: 'scheduled-jobs' });
|
|
227
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Scheduled Jobs', scheduledJobCounts)}`);
|
|
228
|
+
currentStep = 'seedSavedFilters';
|
|
229
|
+
this.logger.log(`Seeding Saved Filters`);
|
|
230
|
+
const savedFilterCounts = await this.timeOperation('seed-saved-filters', () => this.seedSavedFilters(moduleMetadata, overallMetadata), { moduleName: moduleMetadata.name, component: 'saved-filters' });
|
|
231
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Saved Filters', savedFilterCounts)}`);
|
|
232
|
+
currentStep = 'seedModelSequences';
|
|
233
|
+
this.logger.log(`Seeding Model Sequences`);
|
|
234
|
+
const modelSequenceCounts = await this.timeOperation('seed-model-sequences', () => this.seedModelSequences(overallMetadata), { moduleName: moduleMetadata.name, component: 'model-sequences' });
|
|
235
|
+
console.log(`${this.formatSeedResult(moduleMetadata.name, 'Model Sequences', modelSequenceCounts)}`);
|
|
236
|
+
}, { moduleName: moduleMetadata.name, component: 'module-seed' });
|
|
237
|
+
}
|
|
238
|
+
currentModule = 'global';
|
|
239
|
+
currentStep = 'setupDefaultRolesWithPermissions';
|
|
240
|
+
await this.timeOperation('setup-default-roles-with-permissions', () => this.setupDefaultRolesWithPermissions(), { moduleName: 'global', component: 'default-roles' });
|
|
241
|
+
}, { moduleName: 'global', component: 'seed-run' });
|
|
229
242
|
console.log(`✔ Seeding completed.`);
|
|
230
243
|
}
|
|
231
244
|
catch (error) {
|
|
@@ -238,117 +251,286 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
238
251
|
throw error;
|
|
239
252
|
}
|
|
240
253
|
}
|
|
254
|
+
buildTimingPrefix(itemTag, options) {
|
|
255
|
+
const parts = [`[${this.seedTimingTag}]`, `[ITEM:${itemTag}]`];
|
|
256
|
+
if (options?.moduleName) {
|
|
257
|
+
parts.push(`[MODULE:${options.moduleName}]`);
|
|
258
|
+
}
|
|
259
|
+
if (options?.component) {
|
|
260
|
+
parts.push(`[COMPONENT:${options.component}]`);
|
|
261
|
+
}
|
|
262
|
+
if (options?.serviceCall) {
|
|
263
|
+
parts.push(`[CALL:${options.serviceCall}]`);
|
|
264
|
+
}
|
|
265
|
+
return parts.join(' ');
|
|
266
|
+
}
|
|
267
|
+
formatDuration(durationMs) {
|
|
268
|
+
return durationMs >= 1000
|
|
269
|
+
? `${(durationMs / 1000).toFixed(2)} s (${durationMs.toFixed(2)} ms)`
|
|
270
|
+
: `${durationMs.toFixed(2)} ms`;
|
|
271
|
+
}
|
|
272
|
+
resetLookupCaches() {
|
|
273
|
+
this.moduleLookupCache.clear();
|
|
274
|
+
this.modelLookupCache.clear();
|
|
275
|
+
this.viewLookupCache.clear();
|
|
276
|
+
this.mediaStorageProviderLookupCache.clear();
|
|
277
|
+
}
|
|
278
|
+
async getModuleByUserKeyCached(moduleUserKey, options) {
|
|
279
|
+
if (!moduleUserKey) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
if (this.moduleLookupCache.has(moduleUserKey)) {
|
|
283
|
+
return this.moduleLookupCache.get(moduleUserKey) ?? null;
|
|
284
|
+
}
|
|
285
|
+
const module = await this.timeOperation('module-find-by-user-key-cache-miss', () => this.moduleMetadataService.findOneByUserKey(moduleUserKey), {
|
|
286
|
+
moduleName: options?.moduleName ?? moduleUserKey,
|
|
287
|
+
component: options?.component,
|
|
288
|
+
serviceCall: 'moduleMetadataService.findOneByUserKey',
|
|
289
|
+
details: options?.details ?? `module=${moduleUserKey}`,
|
|
290
|
+
});
|
|
291
|
+
this.moduleLookupCache.set(moduleUserKey, module ?? null);
|
|
292
|
+
return module ?? null;
|
|
293
|
+
}
|
|
294
|
+
async getModelByUserKeyCached(modelUserKey, options) {
|
|
295
|
+
if (!modelUserKey) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
if (this.modelLookupCache.has(modelUserKey)) {
|
|
299
|
+
return this.modelLookupCache.get(modelUserKey) ?? null;
|
|
300
|
+
}
|
|
301
|
+
const model = await this.timeOperation('model-find-by-user-key-cache-miss', () => this.modelMetadataService.findOneByUserKey(modelUserKey), {
|
|
302
|
+
moduleName: options?.moduleName,
|
|
303
|
+
component: options?.component,
|
|
304
|
+
serviceCall: 'modelMetadataService.findOneByUserKey',
|
|
305
|
+
details: options?.details ?? `model=${modelUserKey}`,
|
|
306
|
+
});
|
|
307
|
+
this.modelLookupCache.set(modelUserKey, model ?? null);
|
|
308
|
+
return model ?? null;
|
|
309
|
+
}
|
|
310
|
+
async getViewByUserKeyCached(viewUserKey, options) {
|
|
311
|
+
if (!viewUserKey) {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
if (this.viewLookupCache.has(viewUserKey)) {
|
|
315
|
+
return this.viewLookupCache.get(viewUserKey) ?? null;
|
|
316
|
+
}
|
|
317
|
+
const view = await this.timeOperation('view-find-by-user-key-cache-miss', () => this.solidViewService.findOneByUserKey(viewUserKey), {
|
|
318
|
+
moduleName: options?.moduleName,
|
|
319
|
+
component: options?.component,
|
|
320
|
+
serviceCall: 'solidViewService.findOneByUserKey',
|
|
321
|
+
details: options?.details ?? `view=${viewUserKey}`,
|
|
322
|
+
});
|
|
323
|
+
this.viewLookupCache.set(viewUserKey, view ?? null);
|
|
324
|
+
return view ?? null;
|
|
325
|
+
}
|
|
326
|
+
async getMediaStorageProviderByUserKeyCached(mediaStorageProviderUserKey, options) {
|
|
327
|
+
if (!mediaStorageProviderUserKey) {
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
if (this.mediaStorageProviderLookupCache.has(mediaStorageProviderUserKey)) {
|
|
331
|
+
return this.mediaStorageProviderLookupCache.get(mediaStorageProviderUserKey) ?? null;
|
|
332
|
+
}
|
|
333
|
+
const mediaStorageProvider = await this.timeOperation('media-storage-provider-find-by-user-key-cache-miss', () => this.mediaStorageProviderMetadataService.findOneByUserKey(mediaStorageProviderUserKey), {
|
|
334
|
+
moduleName: options?.moduleName,
|
|
335
|
+
component: options?.component,
|
|
336
|
+
serviceCall: 'mediaStorageProviderMetadataService.findOneByUserKey',
|
|
337
|
+
details: options?.details ?? `provider=${mediaStorageProviderUserKey}`,
|
|
338
|
+
});
|
|
339
|
+
this.mediaStorageProviderLookupCache.set(mediaStorageProviderUserKey, mediaStorageProvider ?? null);
|
|
340
|
+
return mediaStorageProvider ?? null;
|
|
341
|
+
}
|
|
342
|
+
async timeOperation(itemTag, operation, options) {
|
|
343
|
+
const prefix = this.buildTimingPrefix(itemTag, options);
|
|
344
|
+
const detailSuffix = options?.details ? ` ${options.details}` : '';
|
|
345
|
+
const start = process.hrtime.bigint();
|
|
346
|
+
try {
|
|
347
|
+
const result = await operation();
|
|
348
|
+
const durationMs = Number(process.hrtime.bigint() - start) / 1_000_000;
|
|
349
|
+
this.logger.debug(`${prefix} done in ${this.formatDuration(durationMs)}${detailSuffix}`);
|
|
350
|
+
return result;
|
|
351
|
+
}
|
|
352
|
+
catch (error) {
|
|
353
|
+
const durationMs = Number(process.hrtime.bigint() - start) / 1_000_000;
|
|
354
|
+
this.logger.debug(`${prefix} failed after ${this.formatDuration(durationMs)}${detailSuffix}`);
|
|
355
|
+
throw error;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
241
358
|
async seedScheduledJobs(moduleMetadata, overallMetadata) {
|
|
242
|
-
this.logger.debug(`[Start] Processing scheduled jobs for ${moduleMetadata.name}`);
|
|
243
359
|
const scheduledJobs = this.getSeedArray(overallMetadata?.scheduledJobs);
|
|
244
|
-
const pruned = this.enablePruning ? await this.pruneScheduledJobs(scheduledJobs, moduleMetadata.name)
|
|
360
|
+
const pruned = this.enablePruning ? await this.timeOperation('prune-scheduled-jobs', () => this.pruneScheduledJobs(scheduledJobs, moduleMetadata.name), {
|
|
361
|
+
moduleName: moduleMetadata.name,
|
|
362
|
+
component: 'scheduled-jobs',
|
|
363
|
+
serviceCall: 'pruneScheduledJobs',
|
|
364
|
+
}) : 0;
|
|
245
365
|
if (scheduledJobs.length > 0) {
|
|
246
|
-
await this.handleSeedScheduledJobs(scheduledJobs)
|
|
366
|
+
await this.timeOperation('handle-scheduled-jobs', () => this.handleSeedScheduledJobs(scheduledJobs), {
|
|
367
|
+
moduleName: moduleMetadata.name,
|
|
368
|
+
component: 'scheduled-jobs',
|
|
369
|
+
serviceCall: 'handleSeedScheduledJobs',
|
|
370
|
+
});
|
|
247
371
|
}
|
|
248
|
-
this.logger.debug(`[End] Processing scheduled jobs for ${moduleMetadata.name}`);
|
|
249
372
|
return { pruned, upserted: scheduledJobs.length };
|
|
250
373
|
}
|
|
251
374
|
async seedSavedFilters(moduleMetadata, overallMetadata) {
|
|
252
|
-
this.logger.debug(`[Start] Processing saved filters for ${moduleMetadata.name}`);
|
|
253
375
|
const savedFilters = this.getSeedArray(overallMetadata?.savedFilters);
|
|
254
|
-
const pruned = this.enablePruning ? await this.pruneSavedFilters(savedFilters, moduleMetadata.name)
|
|
376
|
+
const pruned = this.enablePruning ? await this.timeOperation('prune-saved-filters', () => this.pruneSavedFilters(savedFilters, moduleMetadata.name), {
|
|
377
|
+
moduleName: moduleMetadata.name,
|
|
378
|
+
component: 'saved-filters',
|
|
379
|
+
serviceCall: 'pruneSavedFilters',
|
|
380
|
+
}) : 0;
|
|
255
381
|
if (savedFilters.length > 0) {
|
|
256
|
-
await this.handleSeedSavedFilters(savedFilters)
|
|
382
|
+
await this.timeOperation('handle-saved-filters', () => this.handleSeedSavedFilters(savedFilters), {
|
|
383
|
+
moduleName: moduleMetadata.name,
|
|
384
|
+
component: 'saved-filters',
|
|
385
|
+
serviceCall: 'handleSeedSavedFilters',
|
|
386
|
+
});
|
|
257
387
|
}
|
|
258
|
-
this.logger.debug(`[End] Processing saved filters for ${moduleMetadata.name}`);
|
|
259
388
|
return { pruned, upserted: savedFilters.length };
|
|
260
389
|
}
|
|
261
390
|
async seedListOfValues(moduleMetadata, overallMetadata) {
|
|
262
|
-
this.logger.debug(`[Start] Processing List Of Values for ${moduleMetadata.name}`);
|
|
263
391
|
const listOfValues = this.getSeedArray(overallMetadata?.listOfValues);
|
|
264
|
-
const pruned = this.enablePruning ? await this.pruneListOfValues(listOfValues, moduleMetadata.name)
|
|
265
|
-
|
|
266
|
-
|
|
392
|
+
const pruned = this.enablePruning ? await this.timeOperation('prune-list-of-values', () => this.pruneListOfValues(listOfValues, moduleMetadata.name), {
|
|
393
|
+
moduleName: moduleMetadata.name,
|
|
394
|
+
component: 'list-of-values',
|
|
395
|
+
serviceCall: 'pruneListOfValues',
|
|
396
|
+
}) : 0;
|
|
397
|
+
await this.timeOperation('handle-list-of-values', () => this.handleSeedListOfValues(listOfValues), {
|
|
398
|
+
moduleName: moduleMetadata.name,
|
|
399
|
+
component: 'list-of-values',
|
|
400
|
+
serviceCall: 'handleSeedListOfValues',
|
|
401
|
+
});
|
|
267
402
|
return { pruned, upserted: listOfValues.length };
|
|
268
403
|
}
|
|
269
404
|
async setupDefaultRolesWithPermissions() {
|
|
270
405
|
this.logger.debug(`About to add all permissions to the Admin role`);
|
|
271
|
-
await this.roleService.addAllPermissionsToRole(create_role_metadata_dto_1.ADMIN_ROLE_NAME)
|
|
406
|
+
await this.timeOperation('role-add-all-permissions', () => this.roleService.addAllPermissionsToRole(create_role_metadata_dto_1.ADMIN_ROLE_NAME), {
|
|
407
|
+
moduleName: 'global',
|
|
408
|
+
component: 'default-roles',
|
|
409
|
+
serviceCall: 'roleService.addAllPermissionsToRole',
|
|
410
|
+
details: `role=${create_role_metadata_dto_1.ADMIN_ROLE_NAME}`,
|
|
411
|
+
});
|
|
272
412
|
}
|
|
273
413
|
async seedSecurityRules(overallMetadata) {
|
|
274
|
-
this.logger.debug(`[Start] Processing security rules`);
|
|
275
414
|
const securityRules = this.getSeedArray(overallMetadata?.securityRules);
|
|
276
|
-
const pruned = this.enablePruning ? await this.pruneSecurityRules(securityRules, overallMetadata?.moduleMetadata?.name)
|
|
277
|
-
|
|
278
|
-
|
|
415
|
+
const pruned = this.enablePruning ? await this.timeOperation('prune-security-rules', () => this.pruneSecurityRules(securityRules, overallMetadata?.moduleMetadata?.name), {
|
|
416
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
417
|
+
component: 'security-rules',
|
|
418
|
+
serviceCall: 'pruneSecurityRules',
|
|
419
|
+
}) : 0;
|
|
420
|
+
await this.timeOperation('handle-security-rules', () => this.handleSeedSecurityRules(securityRules), {
|
|
421
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
422
|
+
component: 'security-rules',
|
|
423
|
+
serviceCall: 'handleSeedSecurityRules',
|
|
424
|
+
});
|
|
279
425
|
return { pruned, upserted: securityRules.length };
|
|
280
426
|
}
|
|
281
427
|
async seedDefaultSettings() {
|
|
282
|
-
this.
|
|
283
|
-
|
|
284
|
-
|
|
428
|
+
await this.timeOperation('seed-default-settings-call', () => this.settingService.seedSystemAdminEditableAndAboveSettings(), {
|
|
429
|
+
moduleName: 'global',
|
|
430
|
+
component: 'settings',
|
|
431
|
+
serviceCall: 'settingService.seedSystemAdminEditableAndAboveSettings',
|
|
432
|
+
});
|
|
285
433
|
}
|
|
286
434
|
async seedSmsTemplates(overallMetadata, moduleName) {
|
|
287
|
-
this.logger.debug(`[Start] Processing sms templates`);
|
|
288
435
|
const smsTemplates = this.getSeedArray(overallMetadata?.smsTemplates);
|
|
289
|
-
await this.handleSeedSmsTemplates(smsTemplates, moduleName)
|
|
290
|
-
|
|
436
|
+
await this.timeOperation('handle-sms-templates', () => this.handleSeedSmsTemplates(smsTemplates, moduleName), {
|
|
437
|
+
moduleName,
|
|
438
|
+
component: 'sms-templates',
|
|
439
|
+
serviceCall: 'handleSeedSmsTemplates',
|
|
440
|
+
});
|
|
291
441
|
return { pruned: 0, upserted: smsTemplates.length };
|
|
292
442
|
}
|
|
293
443
|
async seedEmailTemplates(overallMetadata, moduleName) {
|
|
294
|
-
this.logger.debug(`[Start] Processing email templates`);
|
|
295
444
|
const emailTemplates = this.getSeedArray(overallMetadata?.emailTemplates);
|
|
296
|
-
await this.handleSeedEmailTemplates(emailTemplates, moduleName)
|
|
297
|
-
|
|
445
|
+
await this.timeOperation('handle-email-templates', () => this.handleSeedEmailTemplates(emailTemplates, moduleName), {
|
|
446
|
+
moduleName,
|
|
447
|
+
component: 'email-templates',
|
|
448
|
+
serviceCall: 'handleSeedEmailTemplates',
|
|
449
|
+
});
|
|
298
450
|
return { pruned: 0, upserted: emailTemplates.length };
|
|
299
451
|
}
|
|
300
452
|
async seedMenus(overallMetadata) {
|
|
301
|
-
this.logger.debug(`[Start] Processing menus`);
|
|
302
453
|
const menus = this.getSeedArray(overallMetadata?.menus);
|
|
303
|
-
const pruned = this.enablePruning ? await this.pruneMenus(menus, overallMetadata?.moduleMetadata?.name)
|
|
304
|
-
|
|
305
|
-
|
|
454
|
+
const pruned = this.enablePruning ? await this.timeOperation('prune-menus', () => this.pruneMenus(menus, overallMetadata?.moduleMetadata?.name), {
|
|
455
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
456
|
+
component: 'menus',
|
|
457
|
+
serviceCall: 'pruneMenus',
|
|
458
|
+
}) : 0;
|
|
459
|
+
await this.timeOperation('handle-menus', () => this.handleSeedMenus(menus), {
|
|
460
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
461
|
+
component: 'menus',
|
|
462
|
+
serviceCall: 'handleSeedMenus',
|
|
463
|
+
});
|
|
306
464
|
return { pruned, upserted: menus.length };
|
|
307
465
|
}
|
|
308
466
|
async seedActions(overallMetadata) {
|
|
309
|
-
this.logger.debug(`[Start] Processing actions`);
|
|
310
467
|
const actions = this.getSeedArray(overallMetadata?.actions);
|
|
311
|
-
const pruned = this.enablePruning ? await this.pruneActions(actions, overallMetadata?.moduleMetadata?.name)
|
|
312
|
-
|
|
313
|
-
|
|
468
|
+
const pruned = this.enablePruning ? await this.timeOperation('prune-actions', () => this.pruneActions(actions, overallMetadata?.moduleMetadata?.name), {
|
|
469
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
470
|
+
component: 'actions',
|
|
471
|
+
serviceCall: 'pruneActions',
|
|
472
|
+
}) : 0;
|
|
473
|
+
await this.timeOperation('handle-actions', () => this.handleSeedActions(actions), {
|
|
474
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
475
|
+
component: 'actions',
|
|
476
|
+
serviceCall: 'handleSeedActions',
|
|
477
|
+
});
|
|
314
478
|
return { pruned, upserted: actions.length };
|
|
315
479
|
}
|
|
316
480
|
async seedViews(overallMetadata) {
|
|
317
|
-
this.logger.debug(`[Start] Processing views`);
|
|
318
481
|
const views = this.getSeedArray(overallMetadata?.views);
|
|
319
|
-
const pruned = this.enablePruning ? await this.pruneViews(views, overallMetadata?.moduleMetadata?.name)
|
|
320
|
-
|
|
321
|
-
|
|
482
|
+
const pruned = this.enablePruning ? await this.timeOperation('prune-views', () => this.pruneViews(views, overallMetadata?.moduleMetadata?.name), {
|
|
483
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
484
|
+
component: 'views',
|
|
485
|
+
serviceCall: 'pruneViews',
|
|
486
|
+
}) : 0;
|
|
487
|
+
await this.timeOperation('handle-views', () => this.handleSeedViews(views), {
|
|
488
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
489
|
+
component: 'views',
|
|
490
|
+
serviceCall: 'handleSeedViews',
|
|
491
|
+
});
|
|
322
492
|
return { pruned, upserted: views.length };
|
|
323
493
|
}
|
|
324
494
|
async seedUsers(overallMetadata) {
|
|
325
|
-
this.logger.debug(`[Start] Processing users`);
|
|
326
495
|
const users = this.getSeedArray(overallMetadata?.users);
|
|
327
|
-
await this.handleSeedUsers(users)
|
|
328
|
-
|
|
496
|
+
await this.timeOperation('handle-users', () => this.handleSeedUsers(users), {
|
|
497
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
498
|
+
component: 'users',
|
|
499
|
+
serviceCall: 'handleSeedUsers',
|
|
500
|
+
});
|
|
329
501
|
return { pruned: 0, upserted: users.length };
|
|
330
502
|
}
|
|
331
503
|
async seedRoles(overallMetadata) {
|
|
332
|
-
this.logger.debug(`[Start] Processing roles`);
|
|
333
504
|
const roles = this.getSeedArray(overallMetadata?.roles);
|
|
334
|
-
await this.roleService.createRolesIfNotExists(roles
|
|
505
|
+
await this.timeOperation('roles-create-if-not-exists', () => this.roleService.createRolesIfNotExists(roles
|
|
335
506
|
.filter((role) => role?.name)
|
|
336
|
-
.map((role) => ({ name: role.name })))
|
|
507
|
+
.map((role) => ({ name: role.name }))), {
|
|
508
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
509
|
+
component: 'roles',
|
|
510
|
+
serviceCall: 'roleService.createRolesIfNotExists',
|
|
511
|
+
details: `roleCount=${roles.length}`,
|
|
512
|
+
});
|
|
337
513
|
for (const role of roles) {
|
|
338
514
|
if (role.permissions) {
|
|
339
|
-
await this.roleService.addPermissionsToRole(role.name, role.permissions
|
|
515
|
+
await this.timeOperation('role-add-permissions', () => this.roleService.addPermissionsToRole(role.name, role.permissions
|
|
340
516
|
.map((permission) => typeof permission === 'string' ? permission : permission?.name)
|
|
341
|
-
.filter(Boolean))
|
|
517
|
+
.filter(Boolean)), {
|
|
518
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
519
|
+
component: 'roles',
|
|
520
|
+
serviceCall: 'roleService.addPermissionsToRole',
|
|
521
|
+
details: `role=${role.name} permissionCount=${role.permissions.length}`,
|
|
522
|
+
});
|
|
342
523
|
}
|
|
343
524
|
}
|
|
344
|
-
this.logger.debug(`[End] Processing roles`);
|
|
345
525
|
return { pruned: 0, upserted: roles.length };
|
|
346
526
|
}
|
|
347
527
|
async seedPermissions(overallMetadata) {
|
|
348
|
-
this.logger.debug(`[Start] Processing permissions`);
|
|
349
528
|
const permissions = overallMetadata.permissions ?? [];
|
|
350
|
-
await this.handleSeedPermissions(permissions)
|
|
351
|
-
|
|
529
|
+
await this.timeOperation('handle-permissions', () => this.handleSeedPermissions(permissions), {
|
|
530
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
531
|
+
component: 'permissions',
|
|
532
|
+
serviceCall: 'handleSeedPermissions',
|
|
533
|
+
});
|
|
352
534
|
return { pruned: 0, upserted: permissions?.length ?? 0 };
|
|
353
535
|
}
|
|
354
536
|
get seedDataFiles() {
|
|
@@ -367,15 +549,28 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
367
549
|
}
|
|
368
550
|
async seedGlobalMetadata() {
|
|
369
551
|
this.logger.log(`Seeding Permissions`);
|
|
370
|
-
await this.seedControllerPermissions()
|
|
552
|
+
await this.timeOperation('seed-controller-permissions', () => this.seedControllerPermissions(), {
|
|
553
|
+
moduleName: 'global',
|
|
554
|
+
component: 'controller-permissions',
|
|
555
|
+
});
|
|
371
556
|
this.logger.log(`Seeding System Fields Metadata`);
|
|
372
|
-
await this.seedDefaultSystemFields()
|
|
557
|
+
await this.timeOperation('seed-default-system-fields', () => this.seedDefaultSystemFields(), {
|
|
558
|
+
moduleName: 'global',
|
|
559
|
+
component: 'system-fields',
|
|
560
|
+
});
|
|
373
561
|
this.logger.log(`Seeding Default Settings`);
|
|
374
|
-
await this.seedDefaultSettings()
|
|
562
|
+
await this.timeOperation('seed-default-settings', () => this.seedDefaultSettings(), {
|
|
563
|
+
moduleName: 'global',
|
|
564
|
+
component: 'settings',
|
|
565
|
+
});
|
|
375
566
|
this.logger.debug(`Global metadata seeding completed`);
|
|
376
567
|
}
|
|
377
568
|
async seedDefaultSystemFields() {
|
|
378
|
-
await this.systemFieldsSeederService.seed()
|
|
569
|
+
await this.timeOperation('system-fields-seed', () => this.systemFieldsSeederService.seed(), {
|
|
570
|
+
moduleName: 'global',
|
|
571
|
+
component: 'system-fields',
|
|
572
|
+
serviceCall: 'systemFieldsSeederService.seed',
|
|
573
|
+
});
|
|
379
574
|
}
|
|
380
575
|
async seedControllerPermissions() {
|
|
381
576
|
const controllers = this.solidRegistry.getControllers();
|
|
@@ -388,55 +583,112 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
388
583
|
const methodName = methods[mId];
|
|
389
584
|
const permissionName = `${controller.name}.${methodName}`;
|
|
390
585
|
permissionNames.push(permissionName);
|
|
391
|
-
await this.createPermissionIfNotExists(permissionName);
|
|
392
586
|
}
|
|
393
587
|
}
|
|
394
588
|
catch (error) {
|
|
395
589
|
this.logger.error(error);
|
|
396
590
|
}
|
|
397
591
|
}
|
|
592
|
+
await this.timeOperation('seed-controller-permissions-bulk', () => this.seedPermissionsInBatches(permissionNames, {
|
|
593
|
+
moduleName: 'global',
|
|
594
|
+
component: 'controller-permissions',
|
|
595
|
+
}), {
|
|
596
|
+
moduleName: 'global',
|
|
597
|
+
component: 'controller-permissions',
|
|
598
|
+
serviceCall: 'seedPermissionsInBatches',
|
|
599
|
+
details: `permissionCount=${permissionNames.length} batchSize=${this.permissionSeedBatchSize}`,
|
|
600
|
+
});
|
|
398
601
|
if (this.enablePruning) {
|
|
399
|
-
await this.prunePermissions(permissionNames)
|
|
602
|
+
await this.timeOperation('prune-controller-permissions', () => this.prunePermissions(permissionNames), {
|
|
603
|
+
moduleName: 'global',
|
|
604
|
+
component: 'controller-permissions',
|
|
605
|
+
serviceCall: 'prunePermissions',
|
|
606
|
+
});
|
|
400
607
|
}
|
|
401
608
|
}
|
|
402
|
-
async
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
609
|
+
async handleSeedPermissions(permissions) {
|
|
610
|
+
const permissionNames = permissions
|
|
611
|
+
.map((permission) => typeof permission === 'string' ? permission : permission?.name)
|
|
612
|
+
.filter(Boolean);
|
|
613
|
+
await this.seedPermissionsInBatches(permissionNames, {
|
|
614
|
+
component: 'permissions',
|
|
407
615
|
});
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
616
|
+
}
|
|
617
|
+
async seedPermissionsInBatches(permissionNames, options) {
|
|
618
|
+
const uniquePermissionNames = this.getUniquePermissionNames(permissionNames);
|
|
619
|
+
if (uniquePermissionNames.length === 0) {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
for (let index = 0; index < uniquePermissionNames.length; index += this.permissionSeedBatchSize) {
|
|
623
|
+
const batch = uniquePermissionNames.slice(index, index + this.permissionSeedBatchSize);
|
|
624
|
+
const batchNumber = Math.floor(index / this.permissionSeedBatchSize) + 1;
|
|
625
|
+
const existingPermissions = await this.timeOperation('permission-batch-find', () => this.permissionRepo.find({
|
|
626
|
+
where: {
|
|
627
|
+
name: (0, typeorm_1.In)(batch),
|
|
628
|
+
}
|
|
629
|
+
}), {
|
|
630
|
+
moduleName: options?.moduleName,
|
|
631
|
+
component: options?.component ?? 'permissions',
|
|
632
|
+
serviceCall: 'permissionRepo.find',
|
|
633
|
+
details: `batch=${batchNumber} batchSize=${batch.length}`,
|
|
634
|
+
});
|
|
635
|
+
const existingPermissionNames = new Set(existingPermissions.map((permission) => this.normalizePermissionName(permission.name)));
|
|
636
|
+
const missingPermissionNames = batch.filter((name) => !existingPermissionNames.has(this.normalizePermissionName(name)));
|
|
637
|
+
if (missingPermissionNames.length === 0) {
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
this.logger.log(`Creating ${missingPermissionNames.length} missing permissions in batch ${batchNumber}.`);
|
|
641
|
+
await this.timeOperation('permission-batch-save', () => this.permissionRepo.save(missingPermissionNames.map((name) => this.permissionRepo.create({ name }))), {
|
|
642
|
+
moduleName: options?.moduleName,
|
|
643
|
+
component: options?.component ?? 'permissions',
|
|
644
|
+
serviceCall: 'permissionRepo.save',
|
|
645
|
+
details: `batch=${batchNumber} createCount=${missingPermissionNames.length}`,
|
|
412
646
|
});
|
|
413
|
-
await this.permissionRepo.save(newPermission);
|
|
414
647
|
}
|
|
415
648
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
649
|
+
getUniquePermissionNames(permissionNames) {
|
|
650
|
+
const normalizedPermissionNames = new Set();
|
|
651
|
+
const uniquePermissionNames = [];
|
|
652
|
+
for (const permissionName of permissionNames) {
|
|
653
|
+
if (!permissionName) {
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
const normalizedPermissionName = this.normalizePermissionName(permissionName);
|
|
657
|
+
if (normalizedPermissionNames.has(normalizedPermissionName)) {
|
|
658
|
+
continue;
|
|
421
659
|
}
|
|
660
|
+
normalizedPermissionNames.add(normalizedPermissionName);
|
|
661
|
+
uniquePermissionNames.push(permissionName.trim());
|
|
422
662
|
}
|
|
663
|
+
return uniquePermissionNames;
|
|
664
|
+
}
|
|
665
|
+
normalizePermissionName(permissionName) {
|
|
666
|
+
return permissionName.trim().toLowerCase();
|
|
423
667
|
}
|
|
424
668
|
async seedMediaStorageProviders(mediaStorageProviders) {
|
|
425
|
-
this.logger.debug(`[Start] Processing Media Storage Provider`);
|
|
426
669
|
const providers = this.getSeedArray(mediaStorageProviders);
|
|
427
670
|
for (let i = 0; i < providers.length; i++) {
|
|
428
671
|
const mediaStorageProvider = providers[i];
|
|
429
|
-
await this.mediaStorageProviderMetadataService.upsert(mediaStorageProvider)
|
|
672
|
+
await this.timeOperation('media-storage-provider-upsert', () => this.mediaStorageProviderMetadataService.upsert(mediaStorageProvider), {
|
|
673
|
+
component: 'media-storage-providers',
|
|
674
|
+
serviceCall: 'mediaStorageProviderMetadataService.upsert',
|
|
675
|
+
details: `provider=${mediaStorageProvider?.name ?? mediaStorageProvider?.userKey ?? i}`,
|
|
676
|
+
});
|
|
430
677
|
}
|
|
431
|
-
this.logger.debug(`[End] Processing Media Storage Provider`);
|
|
432
678
|
return { pruned: 0, upserted: providers.length };
|
|
433
679
|
}
|
|
434
680
|
async seedModelSequences(overallMetadata) {
|
|
435
|
-
this.logger.debug(`[Start] Processing model sequences`);
|
|
436
681
|
const modelSequences = this.getSeedArray(overallMetadata?.modelSequences);
|
|
437
|
-
const pruned = this.enablePruning ? await this.pruneModelSequences(modelSequences, overallMetadata?.moduleMetadata?.name)
|
|
438
|
-
|
|
439
|
-
|
|
682
|
+
const pruned = this.enablePruning ? await this.timeOperation('prune-model-sequences', () => this.pruneModelSequences(modelSequences, overallMetadata?.moduleMetadata?.name), {
|
|
683
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
684
|
+
component: 'model-sequences',
|
|
685
|
+
serviceCall: 'pruneModelSequences',
|
|
686
|
+
}) : 0;
|
|
687
|
+
await this.timeOperation('handle-model-sequences', () => this.handleSeedModelSequences(modelSequences), {
|
|
688
|
+
moduleName: overallMetadata?.moduleMetadata?.name,
|
|
689
|
+
component: 'model-sequences',
|
|
690
|
+
serviceCall: 'handleSeedModelSequences',
|
|
691
|
+
});
|
|
440
692
|
return { pruned, upserted: modelSequences.length };
|
|
441
693
|
}
|
|
442
694
|
async handleSeedEmailTemplates(emailTemplates, moduleName) {
|
|
@@ -473,8 +725,18 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
473
725
|
emailTemplate.body = fs.readFileSync(fullPath, 'utf-8').toString();
|
|
474
726
|
}
|
|
475
727
|
}
|
|
476
|
-
await this.emailTemplateService.removeByName(emailTemplate.name)
|
|
477
|
-
|
|
728
|
+
await this.timeOperation('email-template-remove', () => this.emailTemplateService.removeByName(emailTemplate.name), {
|
|
729
|
+
moduleName,
|
|
730
|
+
component: 'email-templates',
|
|
731
|
+
serviceCall: 'emailTemplateService.removeByName',
|
|
732
|
+
details: `template=${emailTemplate.name}`,
|
|
733
|
+
});
|
|
734
|
+
await this.timeOperation('email-template-create', () => this.emailTemplateService.create(emailTemplate), {
|
|
735
|
+
moduleName,
|
|
736
|
+
component: 'email-templates',
|
|
737
|
+
serviceCall: 'emailTemplateService.create',
|
|
738
|
+
details: `template=${emailTemplate.name}`,
|
|
739
|
+
});
|
|
478
740
|
}
|
|
479
741
|
}
|
|
480
742
|
async handleSeedSmsTemplates(smsTemplates, moduleName) {
|
|
@@ -511,32 +773,62 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
511
773
|
smsTemplate.body = fs.readFileSync(fullPath, 'utf-8').toString();
|
|
512
774
|
}
|
|
513
775
|
}
|
|
514
|
-
await this.smsTemplateService.removeByName(smsTemplate.name)
|
|
515
|
-
|
|
776
|
+
await this.timeOperation('sms-template-remove', () => this.smsTemplateService.removeByName(smsTemplate.name), {
|
|
777
|
+
moduleName,
|
|
778
|
+
component: 'sms-templates',
|
|
779
|
+
serviceCall: 'smsTemplateService.removeByName',
|
|
780
|
+
details: `template=${smsTemplate.name}`,
|
|
781
|
+
});
|
|
782
|
+
await this.timeOperation('sms-template-create', () => this.smsTemplateService.create(smsTemplate), {
|
|
783
|
+
moduleName,
|
|
784
|
+
component: 'sms-templates',
|
|
785
|
+
serviceCall: 'smsTemplateService.create',
|
|
786
|
+
details: `template=${smsTemplate.name}`,
|
|
787
|
+
});
|
|
516
788
|
}
|
|
517
789
|
}
|
|
518
790
|
async handleSeedMenus(menus) {
|
|
519
791
|
if (!menus) {
|
|
520
792
|
return;
|
|
521
793
|
}
|
|
522
|
-
await this.dataSource.transaction(async (trx) => {
|
|
794
|
+
await this.timeOperation('menus-transaction', () => this.dataSource.transaction(async (trx) => {
|
|
523
795
|
const menuRepo = trx.getRepository(menu_item_metadata_entity_1.MenuItemMetadata);
|
|
524
796
|
const roleRepo = trx.getRepository(role_metadata_entity_1.RoleMetadata);
|
|
525
797
|
const actionRepo = trx.getRepository(action_metadata_entity_1.ActionMetadata);
|
|
526
798
|
const moduleRepo = trx.getRepository(module_metadata_entity_1.ModuleMetadata);
|
|
527
799
|
for (const m of menus) {
|
|
528
800
|
const action = m.actionUserKey
|
|
529
|
-
? await actionRepo.findOne({ where: { name: m.actionUserKey }, select: ["id"] })
|
|
801
|
+
? await this.timeOperation('menu-action-find-one', () => actionRepo.findOne({ where: { name: m.actionUserKey }, select: ["id"] }), {
|
|
802
|
+
component: 'menus',
|
|
803
|
+
serviceCall: 'actionRepo.findOne',
|
|
804
|
+
details: `action=${m.actionUserKey}`,
|
|
805
|
+
})
|
|
530
806
|
: null;
|
|
531
807
|
const module = m.moduleUserKey
|
|
532
|
-
? await moduleRepo.findOne({ where: { name: m.moduleUserKey }, select: ["id"] })
|
|
808
|
+
? await this.timeOperation('menu-module-find-one', () => moduleRepo.findOne({ where: { name: m.moduleUserKey }, select: ["id"] }), {
|
|
809
|
+
component: 'menus',
|
|
810
|
+
serviceCall: 'moduleRepo.findOne',
|
|
811
|
+
details: `module=${m.moduleUserKey}`,
|
|
812
|
+
})
|
|
533
813
|
: null;
|
|
534
814
|
const parentMenuItem = m.parentMenuItemUserKey
|
|
535
|
-
? await menuRepo.findOne({ where: { name: m.parentMenuItemUserKey }, select: ["id"] })
|
|
815
|
+
? await this.timeOperation('menu-parent-find-one', () => menuRepo.findOne({ where: { name: m.parentMenuItemUserKey }, select: ["id"] }), {
|
|
816
|
+
component: 'menus',
|
|
817
|
+
serviceCall: 'menuRepo.findOne',
|
|
818
|
+
details: `parent=${m.parentMenuItemUserKey}`,
|
|
819
|
+
})
|
|
536
820
|
: null;
|
|
537
|
-
const existing = await menuRepo.findOne({
|
|
821
|
+
const existing = await this.timeOperation('menu-existing-find-one', () => menuRepo.findOne({
|
|
538
822
|
where: { name: m.name },
|
|
539
|
-
|
|
823
|
+
relations: {
|
|
824
|
+
action: true,
|
|
825
|
+
module: true,
|
|
826
|
+
parentMenuItem: true,
|
|
827
|
+
},
|
|
828
|
+
}), {
|
|
829
|
+
component: 'menus',
|
|
830
|
+
serviceCall: 'menuRepo.findOne',
|
|
831
|
+
details: `menu=${m.name}`,
|
|
540
832
|
});
|
|
541
833
|
const base = {
|
|
542
834
|
name: m.name,
|
|
@@ -547,23 +839,51 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
547
839
|
sequenceNumber: m.sequenceNumber,
|
|
548
840
|
iconName: m.iconName,
|
|
549
841
|
};
|
|
842
|
+
const hasChanges = existing
|
|
843
|
+
? existing.displayName !== base.displayName
|
|
844
|
+
|| existing.sequenceNumber !== base.sequenceNumber
|
|
845
|
+
|| existing.iconName !== base.iconName
|
|
846
|
+
|| existing.action?.id !== base.action?.id
|
|
847
|
+
|| existing.module?.id !== base.module?.id
|
|
848
|
+
|| existing.parentMenuItem?.id !== base.parentMenuItem?.id
|
|
849
|
+
: true;
|
|
850
|
+
if (existing && !hasChanges) {
|
|
851
|
+
this.logger.debug(`Skipping menu upsert for ${m.name}; no changes detected.`);
|
|
852
|
+
continue;
|
|
853
|
+
}
|
|
550
854
|
const entity = menuRepo.create(existing ? { id: existing.id, ...base } : base);
|
|
551
|
-
await menuRepo.save(entity)
|
|
855
|
+
await this.timeOperation('menu-save', () => menuRepo.save(entity), {
|
|
856
|
+
component: 'menus',
|
|
857
|
+
serviceCall: 'menuRepo.save',
|
|
858
|
+
details: `menu=${m.name}`,
|
|
859
|
+
});
|
|
552
860
|
}
|
|
553
|
-
const seeded = await menuRepo.find({
|
|
861
|
+
const seeded = await this.timeOperation('menu-seeded-find', () => menuRepo.find({
|
|
554
862
|
where: { name: (0, typeorm_1.In)(menus.map((m) => m.name)) },
|
|
555
863
|
select: ["id", "name"],
|
|
864
|
+
}), {
|
|
865
|
+
component: 'menus',
|
|
866
|
+
serviceCall: 'menuRepo.find',
|
|
867
|
+
details: `count=${menus.length}`,
|
|
556
868
|
});
|
|
557
869
|
const idByName = new Map(seeded.map(s => [s.name, s.id]));
|
|
558
|
-
const admin = await roleRepo.findOne({ where: { name: create_role_metadata_dto_1.ADMIN_ROLE_NAME }, select: ["id", "name"] })
|
|
870
|
+
const admin = await this.timeOperation('menu-admin-role-find-one', () => roleRepo.findOne({ where: { name: create_role_metadata_dto_1.ADMIN_ROLE_NAME }, select: ["id", "name"] }), {
|
|
871
|
+
component: 'menus',
|
|
872
|
+
serviceCall: 'roleRepo.findOne',
|
|
873
|
+
details: `role=${create_role_metadata_dto_1.ADMIN_ROLE_NAME}`,
|
|
874
|
+
});
|
|
559
875
|
const allRoleNames = new Set();
|
|
560
876
|
for (const m of menus)
|
|
561
877
|
(m.roles ?? []).forEach((r) => allRoleNames.add(r));
|
|
562
878
|
if (admin)
|
|
563
879
|
allRoleNames.add(admin.name);
|
|
564
|
-
const roles = await roleRepo.find({
|
|
880
|
+
const roles = await this.timeOperation('menu-roles-find', () => roleRepo.find({
|
|
565
881
|
where: { name: (0, typeorm_1.In)([...allRoleNames]) },
|
|
566
882
|
select: ["id", "name"],
|
|
883
|
+
}), {
|
|
884
|
+
component: 'menus',
|
|
885
|
+
serviceCall: 'roleRepo.find',
|
|
886
|
+
details: `roleCount=${allRoleNames.size}`,
|
|
567
887
|
});
|
|
568
888
|
const roleByName = new Map(roles.map(r => [r.name, r]));
|
|
569
889
|
const joinRows = [];
|
|
@@ -578,57 +898,153 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
578
898
|
}
|
|
579
899
|
const menuIds = [...new Set(joinRows.map(r => r.menuId))];
|
|
580
900
|
if (menuIds.length) {
|
|
581
|
-
await trx
|
|
901
|
+
await this.timeOperation('menu-role-joins-delete', () => trx
|
|
582
902
|
.createQueryBuilder()
|
|
583
903
|
.delete()
|
|
584
904
|
.from(create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME)
|
|
585
905
|
.where(`${create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME_MENU_COL} IN (:...ids)`, { ids: menuIds })
|
|
586
|
-
.execute()
|
|
906
|
+
.execute(), {
|
|
907
|
+
component: 'menus',
|
|
908
|
+
serviceCall: 'trx.delete.menuRoleJoins',
|
|
909
|
+
details: `menuCount=${menuIds.length}`,
|
|
910
|
+
});
|
|
587
911
|
}
|
|
588
912
|
if (joinRows.length) {
|
|
589
913
|
const values = joinRows.map(r => ({
|
|
590
914
|
[create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME_MENU_COL]: r.menuId,
|
|
591
915
|
[create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME_ROLE_COL]: r.roleId,
|
|
592
916
|
}));
|
|
593
|
-
await trx
|
|
917
|
+
await this.timeOperation('menu-role-joins-insert', () => trx
|
|
594
918
|
.createQueryBuilder()
|
|
595
919
|
.insert()
|
|
596
920
|
.into(create_menu_item_metadata_dto_1.MENU_ROLE_JOIN_TABLE_NAME)
|
|
597
921
|
.values(values)
|
|
598
|
-
.execute()
|
|
922
|
+
.execute(), {
|
|
923
|
+
component: 'menus',
|
|
924
|
+
serviceCall: 'trx.insert.menuRoleJoins',
|
|
925
|
+
details: `rowCount=${values.length}`,
|
|
926
|
+
});
|
|
599
927
|
}
|
|
600
|
-
});
|
|
928
|
+
}), { component: 'menus', serviceCall: 'dataSource.transaction' });
|
|
601
929
|
}
|
|
602
930
|
async handleSeedActions(actions) {
|
|
603
931
|
if (!actions) {
|
|
604
932
|
return;
|
|
605
933
|
}
|
|
934
|
+
const actionRepo = this.dataSource.getRepository(action_metadata_entity_1.ActionMetadata);
|
|
935
|
+
await this.timeOperation('action-prime-module-cache', () => this.primeModuleLookupCache(actions.map((action) => action?.moduleUserKey)), {
|
|
936
|
+
component: 'actions',
|
|
937
|
+
serviceCall: 'primeModuleLookupCache',
|
|
938
|
+
details: `count=${actions.length}`,
|
|
939
|
+
});
|
|
940
|
+
await this.timeOperation('action-prime-model-cache', () => this.primeModelLookupCache(actions.map((action) => action?.modelUserKey)), {
|
|
941
|
+
component: 'actions',
|
|
942
|
+
serviceCall: 'primeModelLookupCache',
|
|
943
|
+
details: `count=${actions.length}`,
|
|
944
|
+
});
|
|
945
|
+
await this.timeOperation('action-prime-view-cache', () => this.primeViewLookupCache(actions.map((action) => action?.viewUserKey)), {
|
|
946
|
+
component: 'actions',
|
|
947
|
+
serviceCall: 'primeViewLookupCache',
|
|
948
|
+
details: `count=${actions.length}`,
|
|
949
|
+
});
|
|
950
|
+
const existingActionsByName = await this.timeOperation('action-preload-existing', () => this.loadExistingActionsByName(actionRepo, actions.map((action) => action?.name).filter(Boolean)), {
|
|
951
|
+
component: 'actions',
|
|
952
|
+
serviceCall: 'loadExistingActionsByName',
|
|
953
|
+
details: `count=${actions.length}`,
|
|
954
|
+
});
|
|
955
|
+
let created = 0;
|
|
956
|
+
let updated = 0;
|
|
957
|
+
let skipped = 0;
|
|
606
958
|
for (let j = 0; j < actions.length; j++) {
|
|
607
959
|
const actionData = actions[j];
|
|
608
|
-
actionData['module'] = await this.
|
|
960
|
+
actionData['module'] = await this.getModuleByUserKeyCached(actionData.moduleUserKey, {
|
|
961
|
+
moduleName: actionData.moduleUserKey,
|
|
962
|
+
component: 'actions',
|
|
963
|
+
details: `module=${actionData.moduleUserKey}`,
|
|
964
|
+
});
|
|
609
965
|
if (actionData.type === 'solid') {
|
|
610
|
-
actionData['model'] = await this.
|
|
611
|
-
|
|
966
|
+
actionData['model'] = await this.getModelByUserKeyCached(actionData.modelUserKey, {
|
|
967
|
+
moduleName: actionData.moduleUserKey,
|
|
968
|
+
component: 'actions',
|
|
969
|
+
details: `model=${actionData.modelUserKey}`,
|
|
970
|
+
});
|
|
971
|
+
actionData['view'] = await this.getViewByUserKeyCached(actionData.viewUserKey, {
|
|
972
|
+
moduleName: actionData.moduleUserKey,
|
|
973
|
+
component: 'actions',
|
|
974
|
+
details: `view=${actionData.viewUserKey}`,
|
|
975
|
+
});
|
|
612
976
|
}
|
|
613
977
|
else {
|
|
614
978
|
if (actionData.modelUserKey) {
|
|
615
|
-
actionData['model'] = await this.
|
|
979
|
+
actionData['model'] = await this.getModelByUserKeyCached(actionData.modelUserKey, {
|
|
980
|
+
moduleName: actionData.moduleUserKey,
|
|
981
|
+
component: 'actions',
|
|
982
|
+
details: `model=${actionData.modelUserKey}`,
|
|
983
|
+
});
|
|
616
984
|
}
|
|
617
985
|
}
|
|
618
|
-
await this.
|
|
986
|
+
const result = await this.upsertActionMetadataWithPreloadedExisting(actionRepo, existingActionsByName, actionData);
|
|
987
|
+
if (result.outcome === 'created') {
|
|
988
|
+
created += 1;
|
|
989
|
+
}
|
|
990
|
+
else if (result.outcome === 'updated') {
|
|
991
|
+
updated += 1;
|
|
992
|
+
}
|
|
993
|
+
else {
|
|
994
|
+
skipped += 1;
|
|
995
|
+
}
|
|
619
996
|
}
|
|
997
|
+
this.logger.debug(`Action seed summary: created=${created}, updated=${updated}, skipped=${skipped}.`);
|
|
620
998
|
}
|
|
621
999
|
async handleSeedViews(views) {
|
|
622
1000
|
if (!views) {
|
|
623
1001
|
return;
|
|
624
1002
|
}
|
|
1003
|
+
const viewRepo = this.dataSource.getRepository(view_metadata_entity_1.ViewMetadata);
|
|
1004
|
+
await this.timeOperation('view-prime-module-cache', () => this.primeModuleLookupCache(views.map((view) => view?.moduleUserKey)), {
|
|
1005
|
+
component: 'views',
|
|
1006
|
+
serviceCall: 'primeModuleLookupCache',
|
|
1007
|
+
details: `count=${views.length}`,
|
|
1008
|
+
});
|
|
1009
|
+
await this.timeOperation('view-prime-model-cache', () => this.primeModelLookupCache(views.map((view) => view?.modelUserKey)), {
|
|
1010
|
+
component: 'views',
|
|
1011
|
+
serviceCall: 'primeModelLookupCache',
|
|
1012
|
+
details: `count=${views.length}`,
|
|
1013
|
+
});
|
|
1014
|
+
const existingViewsByName = await this.timeOperation('view-preload-existing', () => this.loadExistingViewsByName(viewRepo, views.map((view) => view?.name).filter(Boolean)), {
|
|
1015
|
+
component: 'views',
|
|
1016
|
+
serviceCall: 'loadExistingViewsByName',
|
|
1017
|
+
details: `count=${views.length}`,
|
|
1018
|
+
});
|
|
1019
|
+
let created = 0;
|
|
1020
|
+
let updated = 0;
|
|
1021
|
+
let skipped = 0;
|
|
625
1022
|
for (let j = 0; j < views.length; j++) {
|
|
626
1023
|
const viewData = views[j];
|
|
627
1024
|
viewData['layout'] = JSON.stringify(viewData['layout'], null, 2);
|
|
628
|
-
viewData['module'] = await this.
|
|
629
|
-
|
|
630
|
-
|
|
1025
|
+
viewData['module'] = await this.getModuleByUserKeyCached(viewData.moduleUserKey, {
|
|
1026
|
+
moduleName: viewData.moduleUserKey,
|
|
1027
|
+
component: 'views',
|
|
1028
|
+
details: `module=${viewData.moduleUserKey}`,
|
|
1029
|
+
});
|
|
1030
|
+
viewData['model'] = await this.getModelByUserKeyCached(viewData.modelUserKey, {
|
|
1031
|
+
moduleName: viewData.moduleUserKey,
|
|
1032
|
+
component: 'views',
|
|
1033
|
+
details: `model=${viewData.modelUserKey}`,
|
|
1034
|
+
});
|
|
1035
|
+
const result = await this.upsertViewMetadataWithPreloadedExisting(viewRepo, existingViewsByName, viewData);
|
|
1036
|
+
this.viewLookupCache.set(viewData.name, result.entity ?? null);
|
|
1037
|
+
if (result.outcome === 'created') {
|
|
1038
|
+
created += 1;
|
|
1039
|
+
}
|
|
1040
|
+
else if (result.outcome === 'updated') {
|
|
1041
|
+
updated += 1;
|
|
1042
|
+
}
|
|
1043
|
+
else {
|
|
1044
|
+
skipped += 1;
|
|
1045
|
+
}
|
|
631
1046
|
}
|
|
1047
|
+
this.logger.debug(`View seed summary: created=${created}, updated=${updated}, skipped=${skipped}.`);
|
|
632
1048
|
}
|
|
633
1049
|
async handleSeedUsers(users) {
|
|
634
1050
|
if (!users) {
|
|
@@ -636,19 +1052,33 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
636
1052
|
}
|
|
637
1053
|
for (let l = 0; l < users.length; l++) {
|
|
638
1054
|
const user = users[l];
|
|
639
|
-
let exisitingUser = await this.userService.findOneByUsername(user.username)
|
|
1055
|
+
let exisitingUser = await this.timeOperation('user-find-by-username', () => this.userService.findOneByUsername(user.username), {
|
|
1056
|
+
component: 'users',
|
|
1057
|
+
serviceCall: 'userService.findOneByUsername',
|
|
1058
|
+
details: `username=${user.username}`,
|
|
1059
|
+
});
|
|
640
1060
|
if (!exisitingUser) {
|
|
641
1061
|
if (user.username === 'sa') {
|
|
642
1062
|
user.password = create_user_dto_1.DEFAULT_SA_PASSWORD;
|
|
643
1063
|
}
|
|
644
|
-
exisitingUser = await this.authenticationService.signUp(user)
|
|
1064
|
+
exisitingUser = await this.timeOperation('user-sign-up', () => this.authenticationService.signUp(user), {
|
|
1065
|
+
component: 'users',
|
|
1066
|
+
serviceCall: 'authenticationService.signUp',
|
|
1067
|
+
details: `username=${user.username}`,
|
|
1068
|
+
});
|
|
645
1069
|
this.logger.log(`Newly created user ${user.username}`);
|
|
646
1070
|
}
|
|
647
1071
|
}
|
|
648
1072
|
}
|
|
649
1073
|
async seedModuleModelFields(moduleMetadata) {
|
|
650
|
-
this.
|
|
651
|
-
const module = await this.moduleMetadataService.upsert(moduleMetadata)
|
|
1074
|
+
const fieldMetadataRepo = this.dataSource.getRepository(field_metadata_entity_1.FieldMetadata);
|
|
1075
|
+
const module = await this.timeOperation('module-upsert', () => this.moduleMetadataService.upsert(moduleMetadata), {
|
|
1076
|
+
moduleName: moduleMetadata.name,
|
|
1077
|
+
component: 'module-model-fields',
|
|
1078
|
+
serviceCall: 'moduleMetadataService.upsert',
|
|
1079
|
+
details: `module=${moduleMetadata.name}`,
|
|
1080
|
+
});
|
|
1081
|
+
this.moduleLookupCache.set(moduleMetadata.name, module ?? null);
|
|
652
1082
|
let pruned = 0;
|
|
653
1083
|
let upserted = 1;
|
|
654
1084
|
const modelsMetadata = this.getSeedArray(moduleMetadata?.models);
|
|
@@ -658,24 +1088,59 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
658
1088
|
modelMetadata['module'] = module;
|
|
659
1089
|
const { fields: fieldsMetadata, ...modelMetaDataWithoutFields } = modelMetadata;
|
|
660
1090
|
if (modelMetadata.isChild && modelMetadata.parentModelUserKey) {
|
|
661
|
-
const parentModel = await this.
|
|
1091
|
+
const parentModel = await this.getModelByUserKeyCached(modelMetadata.parentModelUserKey, {
|
|
1092
|
+
moduleName: moduleMetadata.name,
|
|
1093
|
+
component: 'module-model-fields',
|
|
1094
|
+
details: `parentModel=${modelMetadata.parentModelUserKey}`,
|
|
1095
|
+
});
|
|
662
1096
|
modelMetaDataWithoutFields['parentModel'] = parentModel;
|
|
663
1097
|
}
|
|
664
|
-
await this.modelMetadataService.upsert(modelMetaDataWithoutFields)
|
|
665
|
-
|
|
1098
|
+
const upsertedModel = await this.timeOperation('model-upsert', () => this.modelMetadataService.upsert(modelMetaDataWithoutFields), {
|
|
1099
|
+
moduleName: moduleMetadata.name,
|
|
1100
|
+
component: 'module-model-fields',
|
|
1101
|
+
serviceCall: 'modelMetadataService.upsert',
|
|
1102
|
+
details: `model=${modelMetadata.singularName}`,
|
|
1103
|
+
});
|
|
1104
|
+
this.modelLookupCache.set(modelMetadata.singularName, upsertedModel ?? null);
|
|
1105
|
+
const model = await this.timeOperation('model-find-by-singular-name', () => this.modelMetadataService.findOneBySingularName(modelMetadata.singularName), {
|
|
1106
|
+
moduleName: moduleMetadata.name,
|
|
1107
|
+
component: 'module-model-fields',
|
|
1108
|
+
serviceCall: 'modelMetadataService.findOneBySingularName',
|
|
1109
|
+
details: `model=${modelMetadata.singularName}`,
|
|
1110
|
+
});
|
|
666
1111
|
if (this.enablePruning) {
|
|
667
|
-
pruned += await this.pruneFieldsForModel(model, fieldsMetadata)
|
|
1112
|
+
pruned += await this.timeOperation('prune-fields-for-model', () => this.pruneFieldsForModel(model, fieldsMetadata), {
|
|
1113
|
+
moduleName: moduleMetadata.name,
|
|
1114
|
+
component: 'module-model-fields',
|
|
1115
|
+
serviceCall: 'pruneFieldsForModel',
|
|
1116
|
+
details: `model=${modelMetadata.singularName}`,
|
|
1117
|
+
});
|
|
668
1118
|
}
|
|
669
1119
|
let userKeyField = null;
|
|
670
1120
|
const userKeyFieldName = modelMetadata.userKeyFieldUserKey;
|
|
1121
|
+
const existingFieldsByName = await this.timeOperation('field-preload-for-model', () => this.loadExistingFieldsByName(fieldMetadataRepo, model.id), {
|
|
1122
|
+
moduleName: moduleMetadata.name,
|
|
1123
|
+
component: 'module-model-fields',
|
|
1124
|
+
serviceCall: 'loadExistingFieldsByName',
|
|
1125
|
+
details: `model=${modelMetadata.singularName}`,
|
|
1126
|
+
});
|
|
671
1127
|
upserted += fieldsMetadata?.length ?? 0;
|
|
672
1128
|
for (let k = 0; k < fieldsMetadata.length; k++) {
|
|
673
1129
|
const fieldMetadata = fieldsMetadata[k];
|
|
674
1130
|
fieldMetadata['model'] = model;
|
|
675
1131
|
if (fieldMetadata.mediaStorageProviderUserKey) {
|
|
676
|
-
fieldMetadata['mediaStorageProvider'] = await this.
|
|
1132
|
+
fieldMetadata['mediaStorageProvider'] = await this.getMediaStorageProviderByUserKeyCached(fieldMetadata.mediaStorageProviderUserKey, {
|
|
1133
|
+
moduleName: moduleMetadata.name,
|
|
1134
|
+
component: 'module-model-fields',
|
|
1135
|
+
details: `provider=${fieldMetadata.mediaStorageProviderUserKey}`,
|
|
1136
|
+
});
|
|
677
1137
|
}
|
|
678
|
-
const affectedField = await this.
|
|
1138
|
+
const affectedField = await this.timeOperation('field-upsert', () => this.upsertFieldMetadataWithPreloadedExisting(fieldMetadataRepo, existingFieldsByName, fieldMetadata), {
|
|
1139
|
+
moduleName: moduleMetadata.name,
|
|
1140
|
+
component: 'module-model-fields',
|
|
1141
|
+
serviceCall: 'upsertFieldMetadataWithPreloadedExisting',
|
|
1142
|
+
details: `field=${fieldMetadata.name} model=${modelMetadata.singularName}`,
|
|
1143
|
+
});
|
|
679
1144
|
if (fieldMetadata.name === userKeyFieldName || fieldMetadata.isUserKey) {
|
|
680
1145
|
const { model, ...fieldData } = affectedField;
|
|
681
1146
|
userKeyField = fieldData;
|
|
@@ -683,25 +1148,285 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
683
1148
|
}
|
|
684
1149
|
if (userKeyField) {
|
|
685
1150
|
modelMetaDataWithoutFields['userKeyField'] = userKeyField;
|
|
686
|
-
await this.modelMetadataService.upsert(modelMetaDataWithoutFields)
|
|
1151
|
+
await this.timeOperation('model-user-key-field-upsert', () => this.modelMetadataService.upsert(modelMetaDataWithoutFields), {
|
|
1152
|
+
moduleName: moduleMetadata.name,
|
|
1153
|
+
component: 'module-model-fields',
|
|
1154
|
+
serviceCall: 'modelMetadataService.upsert',
|
|
1155
|
+
details: `model=${modelMetadata.singularName} userKeyField=${userKeyField?.name ?? 'unknown'}`,
|
|
1156
|
+
});
|
|
687
1157
|
}
|
|
688
1158
|
}
|
|
689
1159
|
if (this.enablePruning) {
|
|
690
|
-
pruned += await this.pruneModels(modelsMetadata, moduleMetadata.name)
|
|
1160
|
+
pruned += await this.timeOperation('prune-models', () => this.pruneModels(modelsMetadata, moduleMetadata.name), {
|
|
1161
|
+
moduleName: moduleMetadata.name,
|
|
1162
|
+
component: 'module-model-fields',
|
|
1163
|
+
serviceCall: 'pruneModels',
|
|
1164
|
+
});
|
|
691
1165
|
}
|
|
692
|
-
this.logger.debug(`[End] Processing module metadata`);
|
|
693
1166
|
return { pruned, upserted };
|
|
694
1167
|
}
|
|
695
1168
|
getSeedArray(value) {
|
|
696
1169
|
return Array.isArray(value) ? value : [];
|
|
697
1170
|
}
|
|
1171
|
+
async loadExistingFieldsByName(fieldMetadataRepo, modelId) {
|
|
1172
|
+
const existingFields = await fieldMetadataRepo.find({
|
|
1173
|
+
where: {
|
|
1174
|
+
model: { id: modelId },
|
|
1175
|
+
},
|
|
1176
|
+
relations: {
|
|
1177
|
+
model: true,
|
|
1178
|
+
mediaStorageProvider: true,
|
|
1179
|
+
},
|
|
1180
|
+
});
|
|
1181
|
+
return new Map(existingFields.map((field) => [field.name, field]));
|
|
1182
|
+
}
|
|
1183
|
+
async primeModuleLookupCache(moduleUserKeys) {
|
|
1184
|
+
const missingModuleUserKeys = [...new Set(moduleUserKeys.filter((moduleUserKey) => Boolean(moduleUserKey) && !this.moduleLookupCache.has(moduleUserKey)))];
|
|
1185
|
+
if (missingModuleUserKeys.length === 0) {
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
const moduleRepo = this.dataSource.getRepository(module_metadata_entity_1.ModuleMetadata);
|
|
1189
|
+
const existingModules = await moduleRepo.find({
|
|
1190
|
+
where: {
|
|
1191
|
+
name: (0, typeorm_1.In)(missingModuleUserKeys),
|
|
1192
|
+
},
|
|
1193
|
+
});
|
|
1194
|
+
const moduleByName = new Map(existingModules.map((module) => [module.name, module]));
|
|
1195
|
+
for (const moduleUserKey of missingModuleUserKeys) {
|
|
1196
|
+
this.moduleLookupCache.set(moduleUserKey, moduleByName.get(moduleUserKey) ?? null);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
async primeModelLookupCache(modelUserKeys) {
|
|
1200
|
+
const missingModelUserKeys = [...new Set(modelUserKeys.filter((modelUserKey) => Boolean(modelUserKey) && !this.modelLookupCache.has(modelUserKey)))];
|
|
1201
|
+
if (missingModelUserKeys.length === 0) {
|
|
1202
|
+
return;
|
|
1203
|
+
}
|
|
1204
|
+
const modelRepo = this.dataSource.getRepository(model_metadata_entity_1.ModelMetadata);
|
|
1205
|
+
const existingModels = await modelRepo.find({
|
|
1206
|
+
where: {
|
|
1207
|
+
singularName: (0, typeorm_1.In)(missingModelUserKeys),
|
|
1208
|
+
},
|
|
1209
|
+
relations: {
|
|
1210
|
+
module: true,
|
|
1211
|
+
userKeyField: true,
|
|
1212
|
+
},
|
|
1213
|
+
});
|
|
1214
|
+
const modelBySingularName = new Map(existingModels.map((model) => [model.singularName, model]));
|
|
1215
|
+
for (const modelUserKey of missingModelUserKeys) {
|
|
1216
|
+
this.modelLookupCache.set(modelUserKey, modelBySingularName.get(modelUserKey) ?? null);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
async primeViewLookupCache(viewUserKeys) {
|
|
1220
|
+
const missingViewUserKeys = [...new Set(viewUserKeys.filter((viewUserKey) => Boolean(viewUserKey) && !this.viewLookupCache.has(viewUserKey)))];
|
|
1221
|
+
if (missingViewUserKeys.length === 0) {
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
const viewRepo = this.dataSource.getRepository(view_metadata_entity_1.ViewMetadata);
|
|
1225
|
+
const existingViews = await viewRepo.find({
|
|
1226
|
+
where: {
|
|
1227
|
+
name: (0, typeorm_1.In)(missingViewUserKeys),
|
|
1228
|
+
},
|
|
1229
|
+
relations: {
|
|
1230
|
+
module: true,
|
|
1231
|
+
model: true,
|
|
1232
|
+
},
|
|
1233
|
+
});
|
|
1234
|
+
const viewByName = new Map(existingViews.map((view) => [view.name, view]));
|
|
1235
|
+
for (const viewUserKey of missingViewUserKeys) {
|
|
1236
|
+
this.viewLookupCache.set(viewUserKey, viewByName.get(viewUserKey) ?? null);
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
async loadExistingViewsByName(viewRepo, viewNames) {
|
|
1240
|
+
const uniqueViewNames = [...new Set(viewNames.filter(Boolean))];
|
|
1241
|
+
if (uniqueViewNames.length === 0) {
|
|
1242
|
+
return new Map();
|
|
1243
|
+
}
|
|
1244
|
+
const existingViews = await viewRepo.find({
|
|
1245
|
+
where: {
|
|
1246
|
+
name: (0, typeorm_1.In)(uniqueViewNames),
|
|
1247
|
+
},
|
|
1248
|
+
relations: {
|
|
1249
|
+
module: true,
|
|
1250
|
+
model: true,
|
|
1251
|
+
},
|
|
1252
|
+
});
|
|
1253
|
+
return new Map(existingViews.map((view) => [view.name, view]));
|
|
1254
|
+
}
|
|
1255
|
+
async loadExistingActionsByName(actionRepo, actionNames) {
|
|
1256
|
+
const uniqueActionNames = [...new Set(actionNames.filter(Boolean))];
|
|
1257
|
+
if (uniqueActionNames.length === 0) {
|
|
1258
|
+
return new Map();
|
|
1259
|
+
}
|
|
1260
|
+
const existingActions = await actionRepo.find({
|
|
1261
|
+
where: {
|
|
1262
|
+
name: (0, typeorm_1.In)(uniqueActionNames),
|
|
1263
|
+
},
|
|
1264
|
+
relations: {
|
|
1265
|
+
module: true,
|
|
1266
|
+
model: true,
|
|
1267
|
+
view: true,
|
|
1268
|
+
},
|
|
1269
|
+
});
|
|
1270
|
+
return new Map(existingActions.map((action) => [action.name, action]));
|
|
1271
|
+
}
|
|
1272
|
+
normalizeJsonFieldValue(value) {
|
|
1273
|
+
if (typeof value === 'string') {
|
|
1274
|
+
const trimmedValue = value.trim();
|
|
1275
|
+
if ((trimmedValue.startsWith('{') && trimmedValue.endsWith('}'))
|
|
1276
|
+
|| (trimmedValue.startsWith('[') && trimmedValue.endsWith(']'))) {
|
|
1277
|
+
try {
|
|
1278
|
+
return this.normalizeJsonFieldValue(JSON.parse(trimmedValue));
|
|
1279
|
+
}
|
|
1280
|
+
catch {
|
|
1281
|
+
return value;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
return value;
|
|
1285
|
+
}
|
|
1286
|
+
if (Array.isArray(value)) {
|
|
1287
|
+
return value.map((item) => this.normalizeJsonFieldValue(item));
|
|
1288
|
+
}
|
|
1289
|
+
if (value && typeof value === 'object') {
|
|
1290
|
+
return Object.keys(value)
|
|
1291
|
+
.sort()
|
|
1292
|
+
.reduce((result, key) => {
|
|
1293
|
+
result[key] = this.normalizeJsonFieldValue(value[key]);
|
|
1294
|
+
return result;
|
|
1295
|
+
}, {});
|
|
1296
|
+
}
|
|
1297
|
+
return value;
|
|
1298
|
+
}
|
|
1299
|
+
getCanonicalJsonFieldString(value) {
|
|
1300
|
+
return JSON.stringify(this.normalizeJsonFieldValue(value) ?? null);
|
|
1301
|
+
}
|
|
1302
|
+
hasViewMetadataChanges(existingView, updateDto) {
|
|
1303
|
+
const relationFields = new Set(['module', 'model']);
|
|
1304
|
+
const jsonFields = new Set(['layout', 'context']);
|
|
1305
|
+
return this.viewComparableFields.some((key) => {
|
|
1306
|
+
const value = updateDto[key];
|
|
1307
|
+
if (typeof value === 'undefined') {
|
|
1308
|
+
return false;
|
|
1309
|
+
}
|
|
1310
|
+
if (relationFields.has(key)) {
|
|
1311
|
+
const relationValue = value;
|
|
1312
|
+
return existingView[key]?.id !== relationValue?.id;
|
|
1313
|
+
}
|
|
1314
|
+
if (jsonFields.has(key)) {
|
|
1315
|
+
return this.getCanonicalJsonFieldString(existingView[key]) !== this.getCanonicalJsonFieldString(value);
|
|
1316
|
+
}
|
|
1317
|
+
return existingView[key] !== value;
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
hasActionMetadataChanges(existingAction, updateDto) {
|
|
1321
|
+
const relationFields = new Set(['module', 'model', 'view']);
|
|
1322
|
+
const jsonFields = new Set(['domain', 'context']);
|
|
1323
|
+
return this.actionComparableFields.some((key) => {
|
|
1324
|
+
const value = updateDto[key];
|
|
1325
|
+
if (typeof value === 'undefined') {
|
|
1326
|
+
return false;
|
|
1327
|
+
}
|
|
1328
|
+
if (relationFields.has(key)) {
|
|
1329
|
+
const relationValue = value;
|
|
1330
|
+
return existingAction[key]?.id !== relationValue?.id;
|
|
1331
|
+
}
|
|
1332
|
+
if (jsonFields.has(key)) {
|
|
1333
|
+
return this.getCanonicalJsonFieldString(existingAction[key]) !== this.getCanonicalJsonFieldString(value);
|
|
1334
|
+
}
|
|
1335
|
+
return existingAction[key] !== value;
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
async upsertViewMetadataWithPreloadedExisting(viewRepo, existingViewsByName, updateDto) {
|
|
1339
|
+
const existingView = existingViewsByName.get(updateDto.name);
|
|
1340
|
+
if (existingView) {
|
|
1341
|
+
if (!this.hasViewMetadataChanges(existingView, updateDto)) {
|
|
1342
|
+
return { entity: existingView, outcome: 'skipped' };
|
|
1343
|
+
}
|
|
1344
|
+
const updatedView = { ...existingView, ...updateDto };
|
|
1345
|
+
const savedView = await this.timeOperation('view-save', () => viewRepo.save(updatedView), {
|
|
1346
|
+
component: 'views',
|
|
1347
|
+
serviceCall: 'viewRepo.save',
|
|
1348
|
+
details: `view=${updateDto.name}`,
|
|
1349
|
+
});
|
|
1350
|
+
existingViewsByName.set(updateDto.name, savedView);
|
|
1351
|
+
return { entity: savedView, outcome: 'updated' };
|
|
1352
|
+
}
|
|
1353
|
+
const view = viewRepo.create(updateDto);
|
|
1354
|
+
const savedView = await this.timeOperation('view-save', () => viewRepo.save(view), {
|
|
1355
|
+
component: 'views',
|
|
1356
|
+
serviceCall: 'viewRepo.save',
|
|
1357
|
+
details: `view=${updateDto.name}`,
|
|
1358
|
+
});
|
|
1359
|
+
existingViewsByName.set(updateDto.name, savedView);
|
|
1360
|
+
return { entity: savedView, outcome: 'created' };
|
|
1361
|
+
}
|
|
1362
|
+
async upsertActionMetadataWithPreloadedExisting(actionRepo, existingActionsByName, updateDto) {
|
|
1363
|
+
const existingAction = existingActionsByName.get(updateDto.name);
|
|
1364
|
+
if (existingAction) {
|
|
1365
|
+
if (!this.hasActionMetadataChanges(existingAction, updateDto)) {
|
|
1366
|
+
return { entity: existingAction, outcome: 'skipped' };
|
|
1367
|
+
}
|
|
1368
|
+
const updatedAction = { ...existingAction, ...updateDto };
|
|
1369
|
+
const savedAction = await this.timeOperation('action-save', () => actionRepo.save(updatedAction), {
|
|
1370
|
+
component: 'actions',
|
|
1371
|
+
serviceCall: 'actionRepo.save',
|
|
1372
|
+
details: `action=${updateDto.name}`,
|
|
1373
|
+
});
|
|
1374
|
+
existingActionsByName.set(updateDto.name, savedAction);
|
|
1375
|
+
return { entity: savedAction, outcome: 'updated' };
|
|
1376
|
+
}
|
|
1377
|
+
const action = actionRepo.create(updateDto);
|
|
1378
|
+
const savedAction = await this.timeOperation('action-save', () => actionRepo.save(action), {
|
|
1379
|
+
component: 'actions',
|
|
1380
|
+
serviceCall: 'actionRepo.save',
|
|
1381
|
+
details: `action=${updateDto.name}`,
|
|
1382
|
+
});
|
|
1383
|
+
existingActionsByName.set(updateDto.name, savedAction);
|
|
1384
|
+
return { entity: savedAction, outcome: 'created' };
|
|
1385
|
+
}
|
|
1386
|
+
async upsertFieldMetadataWithPreloadedExisting(fieldMetadataRepo, existingFieldsByName, updateDto) {
|
|
1387
|
+
const existingFieldMetadata = existingFieldsByName.get(updateDto.name);
|
|
1388
|
+
if (existingFieldMetadata) {
|
|
1389
|
+
const hasChanges = Object.entries(updateDto).some(([key, value]) => {
|
|
1390
|
+
const relationValue = value;
|
|
1391
|
+
if (key === 'model') {
|
|
1392
|
+
return existingFieldMetadata.model?.id !== relationValue?.id;
|
|
1393
|
+
}
|
|
1394
|
+
if (key === 'mediaStorageProvider') {
|
|
1395
|
+
return existingFieldMetadata.mediaStorageProvider?.id !== relationValue?.id;
|
|
1396
|
+
}
|
|
1397
|
+
const currentValue = existingFieldMetadata[key];
|
|
1398
|
+
if (Array.isArray(currentValue) || Array.isArray(value)) {
|
|
1399
|
+
return JSON.stringify(currentValue ?? null) !== JSON.stringify(value ?? null);
|
|
1400
|
+
}
|
|
1401
|
+
if (value && typeof value === 'object') {
|
|
1402
|
+
return JSON.stringify(currentValue ?? null) !== JSON.stringify(value ?? null);
|
|
1403
|
+
}
|
|
1404
|
+
return currentValue !== value;
|
|
1405
|
+
});
|
|
1406
|
+
if (!hasChanges) {
|
|
1407
|
+
return existingFieldMetadata;
|
|
1408
|
+
}
|
|
1409
|
+
const updatedFieldMetadata = { ...existingFieldMetadata, ...updateDto };
|
|
1410
|
+
const savedFieldMetadata = await fieldMetadataRepo.save(updatedFieldMetadata);
|
|
1411
|
+
existingFieldsByName.set(updateDto.name, savedFieldMetadata);
|
|
1412
|
+
return savedFieldMetadata;
|
|
1413
|
+
}
|
|
1414
|
+
const fieldMetadata = fieldMetadataRepo.create(updateDto);
|
|
1415
|
+
const savedFieldMetadata = await fieldMetadataRepo.save(fieldMetadata);
|
|
1416
|
+
existingFieldsByName.set(updateDto.name, savedFieldMetadata);
|
|
1417
|
+
return savedFieldMetadata;
|
|
1418
|
+
}
|
|
698
1419
|
async handleSeedSecurityRules(rulesDto) {
|
|
699
1420
|
if (!rulesDto || rulesDto.length === 0) {
|
|
700
1421
|
this.logger.debug(`No security rules found to seed`);
|
|
701
1422
|
return;
|
|
702
1423
|
}
|
|
703
1424
|
for (const dto of rulesDto) {
|
|
704
|
-
await this.securityRuleRepo.upsertWithDto({ ...dto, securityRuleConfig: JSON.stringify(dto.securityRuleConfig) })
|
|
1425
|
+
await this.timeOperation('security-rule-upsert', () => this.securityRuleRepo.upsertWithDto({ ...dto, securityRuleConfig: JSON.stringify(dto.securityRuleConfig) }), {
|
|
1426
|
+
component: 'security-rules',
|
|
1427
|
+
serviceCall: 'securityRuleRepo.upsertWithDto',
|
|
1428
|
+
details: `rule=${dto.name}`,
|
|
1429
|
+
});
|
|
705
1430
|
}
|
|
706
1431
|
}
|
|
707
1432
|
async handleSeedListOfValues(listOfValuesDto) {
|
|
@@ -711,8 +1436,16 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
711
1436
|
}
|
|
712
1437
|
for (let j = 0; j < listOfValuesDto.length; j++) {
|
|
713
1438
|
const listOfValueDto = listOfValuesDto[j];
|
|
714
|
-
listOfValueDto['module'] = await this.
|
|
715
|
-
|
|
1439
|
+
listOfValueDto['module'] = await this.getModuleByUserKeyCached(listOfValueDto.moduleUserKey, {
|
|
1440
|
+
moduleName: listOfValueDto.moduleUserKey,
|
|
1441
|
+
component: 'list-of-values',
|
|
1442
|
+
details: `module=${listOfValueDto.moduleUserKey}`,
|
|
1443
|
+
});
|
|
1444
|
+
await this.timeOperation('lov-upsert', () => this.listOfValuesService.upsert(listOfValuesDto[j]), {
|
|
1445
|
+
component: 'list-of-values',
|
|
1446
|
+
serviceCall: 'listOfValuesService.upsert',
|
|
1447
|
+
details: `type=${listOfValueDto.type} value=${listOfValueDto.value}`,
|
|
1448
|
+
});
|
|
716
1449
|
}
|
|
717
1450
|
}
|
|
718
1451
|
async handleSeedScheduledJobs(createScheduledJobDto) {
|
|
@@ -721,7 +1454,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
721
1454
|
return;
|
|
722
1455
|
}
|
|
723
1456
|
for (const dto of createScheduledJobDto) {
|
|
724
|
-
await this.scheduledJobRepository.upsertWithDto(dto)
|
|
1457
|
+
await this.timeOperation('scheduled-job-upsert', () => this.scheduledJobRepository.upsertWithDto(dto), {
|
|
1458
|
+
component: 'scheduled-jobs',
|
|
1459
|
+
serviceCall: 'scheduledJobRepository.upsertWithDto',
|
|
1460
|
+
details: `schedule=${dto.scheduleName}`,
|
|
1461
|
+
});
|
|
725
1462
|
}
|
|
726
1463
|
}
|
|
727
1464
|
async handleSeedSavedFilters(createSavedFilterDto) {
|
|
@@ -731,7 +1468,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
731
1468
|
}
|
|
732
1469
|
for (const dto of createSavedFilterDto) {
|
|
733
1470
|
this.validateSavedFilterQueryJsonWrapper(dto);
|
|
734
|
-
await this.savedFiltersRepo.upsertWithDto({ ...dto, filterQueryJson: JSON.stringify(dto.filterQueryJson), isSeeded: true })
|
|
1471
|
+
await this.timeOperation('saved-filter-upsert', () => this.savedFiltersRepo.upsertWithDto({ ...dto, filterQueryJson: JSON.stringify(dto.filterQueryJson), isSeeded: true }), {
|
|
1472
|
+
component: 'saved-filters',
|
|
1473
|
+
serviceCall: 'savedFiltersRepo.upsertWithDto',
|
|
1474
|
+
details: `filter=${dto.name}`,
|
|
1475
|
+
});
|
|
735
1476
|
}
|
|
736
1477
|
}
|
|
737
1478
|
validateSavedFilterQueryJsonWrapper(dto) {
|
|
@@ -755,7 +1496,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
755
1496
|
return;
|
|
756
1497
|
}
|
|
757
1498
|
for (const dto of modelSequencesDto) {
|
|
758
|
-
await this.modelSequenceRepo.upsertWithDto(dto)
|
|
1499
|
+
await this.timeOperation('model-sequence-upsert', () => this.modelSequenceRepo.upsertWithDto(dto), {
|
|
1500
|
+
component: 'model-sequences',
|
|
1501
|
+
serviceCall: 'modelSequenceRepo.upsertWithDto',
|
|
1502
|
+
details: `sequence=${dto.sequenceName}`,
|
|
1503
|
+
});
|
|
759
1504
|
}
|
|
760
1505
|
}
|
|
761
1506
|
async pruneModelSequences(modelSequencesDto, moduleName) {
|
|
@@ -764,7 +1509,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
764
1509
|
return 0;
|
|
765
1510
|
}
|
|
766
1511
|
const sequences = modelSequencesDto ?? [];
|
|
767
|
-
const module = await this.
|
|
1512
|
+
const module = await this.getModuleByUserKeyCached(moduleName, {
|
|
1513
|
+
moduleName,
|
|
1514
|
+
component: 'model-sequences',
|
|
1515
|
+
details: `module=${moduleName}`,
|
|
1516
|
+
});
|
|
768
1517
|
if (!module) {
|
|
769
1518
|
this.logger.warn(`Skipping model sequence prune: module not found for ${moduleName}.`);
|
|
770
1519
|
return 0;
|
|
@@ -798,7 +1547,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
798
1547
|
return 0;
|
|
799
1548
|
}
|
|
800
1549
|
const savedFilters = savedFiltersDto ?? [];
|
|
801
|
-
const module = await this.
|
|
1550
|
+
const module = await this.getModuleByUserKeyCached(moduleName, {
|
|
1551
|
+
moduleName,
|
|
1552
|
+
component: 'saved-filters',
|
|
1553
|
+
details: `module=${moduleName}`,
|
|
1554
|
+
});
|
|
802
1555
|
if (!module) {
|
|
803
1556
|
this.logger.warn(`Skipping saved filters prune: module not found for ${moduleName}.`);
|
|
804
1557
|
return 0;
|
|
@@ -833,7 +1586,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
833
1586
|
return 0;
|
|
834
1587
|
}
|
|
835
1588
|
const scheduledJobs = scheduledJobsDto ?? [];
|
|
836
|
-
const module = await this.
|
|
1589
|
+
const module = await this.getModuleByUserKeyCached(moduleName, {
|
|
1590
|
+
moduleName,
|
|
1591
|
+
component: 'scheduled-jobs',
|
|
1592
|
+
details: `module=${moduleName}`,
|
|
1593
|
+
});
|
|
837
1594
|
if (!module) {
|
|
838
1595
|
this.logger.warn(`Skipping scheduled jobs prune: module not found for ${moduleName}.`);
|
|
839
1596
|
return 0;
|
|
@@ -867,7 +1624,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
867
1624
|
return 0;
|
|
868
1625
|
}
|
|
869
1626
|
const securityRules = securityRulesDto ?? [];
|
|
870
|
-
const module = await this.
|
|
1627
|
+
const module = await this.getModuleByUserKeyCached(moduleName, {
|
|
1628
|
+
moduleName,
|
|
1629
|
+
component: 'security-rules',
|
|
1630
|
+
details: `module=${moduleName}`,
|
|
1631
|
+
});
|
|
871
1632
|
if (!module) {
|
|
872
1633
|
this.logger.warn(`Skipping security rules prune: module not found for ${moduleName}.`);
|
|
873
1634
|
return 0;
|
|
@@ -902,7 +1663,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
902
1663
|
return 0;
|
|
903
1664
|
}
|
|
904
1665
|
const listOfValues = listOfValuesDto ?? [];
|
|
905
|
-
const module = await this.
|
|
1666
|
+
const module = await this.getModuleByUserKeyCached(moduleName, {
|
|
1667
|
+
moduleName,
|
|
1668
|
+
component: 'list-of-values',
|
|
1669
|
+
details: `module=${moduleName}`,
|
|
1670
|
+
});
|
|
906
1671
|
if (!module) {
|
|
907
1672
|
this.logger.warn(`Skipping list of values prune: module not found for ${moduleName}.`);
|
|
908
1673
|
return 0;
|
|
@@ -944,7 +1709,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
944
1709
|
return 0;
|
|
945
1710
|
}
|
|
946
1711
|
const menus = menusDto ?? [];
|
|
947
|
-
const module = await this.
|
|
1712
|
+
const module = await this.getModuleByUserKeyCached(moduleName, {
|
|
1713
|
+
moduleName,
|
|
1714
|
+
component: 'menus',
|
|
1715
|
+
details: `module=${moduleName}`,
|
|
1716
|
+
});
|
|
948
1717
|
if (!module) {
|
|
949
1718
|
this.logger.warn(`Skipping menus prune: module not found for ${moduleName}.`);
|
|
950
1719
|
return 0;
|
|
@@ -986,7 +1755,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
986
1755
|
return 0;
|
|
987
1756
|
}
|
|
988
1757
|
const views = viewsDto ?? [];
|
|
989
|
-
const module = await this.
|
|
1758
|
+
const module = await this.getModuleByUserKeyCached(moduleName, {
|
|
1759
|
+
moduleName,
|
|
1760
|
+
component: 'views',
|
|
1761
|
+
details: `module=${moduleName}`,
|
|
1762
|
+
});
|
|
990
1763
|
if (!module) {
|
|
991
1764
|
this.logger.warn(`Skipping views prune: module not found for ${moduleName}.`);
|
|
992
1765
|
return 0;
|
|
@@ -1039,7 +1812,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
1039
1812
|
return 0;
|
|
1040
1813
|
}
|
|
1041
1814
|
const actions = actionsDto ?? [];
|
|
1042
|
-
const module = await this.
|
|
1815
|
+
const module = await this.getModuleByUserKeyCached(moduleName, {
|
|
1816
|
+
moduleName,
|
|
1817
|
+
component: 'actions',
|
|
1818
|
+
details: `module=${moduleName}`,
|
|
1819
|
+
});
|
|
1043
1820
|
if (!module) {
|
|
1044
1821
|
this.logger.warn(`Skipping actions prune: module not found for ${moduleName}.`);
|
|
1045
1822
|
return 0;
|
|
@@ -1125,7 +1902,11 @@ let ModuleMetadataSeederService = ModuleMetadataSeederService_1 = class ModuleMe
|
|
|
1125
1902
|
return 0;
|
|
1126
1903
|
}
|
|
1127
1904
|
const models = modelsMetadata ?? [];
|
|
1128
|
-
const module = await this.
|
|
1905
|
+
const module = await this.getModuleByUserKeyCached(moduleName, {
|
|
1906
|
+
moduleName,
|
|
1907
|
+
component: 'module-model-fields',
|
|
1908
|
+
details: `module=${moduleName}`,
|
|
1909
|
+
});
|
|
1129
1910
|
if (!module) {
|
|
1130
1911
|
this.logger.warn(`Skipping models prune: module not found for ${moduleName}.`);
|
|
1131
1912
|
return 0;
|