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