@memberjunction/codegen-lib 3.2.0 → 3.4.0

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.
@@ -42,6 +42,13 @@ export declare class ManageMetadataBase {
42
42
  * Globally scoped list of validators that have been generated during the metadata management process.
43
43
  */
44
44
  static get generatedValidators(): ValidatorResult[];
45
+ private static _softPKFKConfigCache;
46
+ private static _softPKFKConfigPath;
47
+ /**
48
+ * Loads and caches the soft PK/FK configuration from the additionalSchemaInfo file.
49
+ * The file is only loaded once per session to avoid repeated I/O.
50
+ */
51
+ private static getSoftPKFKConfig;
45
52
  /**
46
53
  * Primary function to manage metadata within the CodeGen system. This function will call a series of sub-functions to manage the metadata.
47
54
  * @param pool - the ConnectionPool object to use for querying and updating the database
@@ -105,6 +112,13 @@ export declare class ManageMetadataBase {
105
112
  * This method ensures that the __mj_DeletedAt field exists in each entity that has DeleteType=Soft. If the field does not exist, it is created.
106
113
  */
107
114
  protected ensureDeletedAtFieldsExist(pool: sql.ConnectionPool, excludeSchemas: string[]): Promise<boolean>;
115
+ /**
116
+ * Applies soft PK/FK configuration from a JSON file specified in mj.config.cjs (additionalSchemaInfo property).
117
+ * For soft PKs: Sets BOTH IsPrimaryKey=1 AND IsSoftPrimaryKey=1 (IsPrimaryKey is source of truth, IsSoftPrimaryKey protects from schema sync).
118
+ * For soft FKs: Sets RelatedEntityID/RelatedEntityFieldName + IsSoftForeignKey=1 (RelatedEntityID is source of truth, IsSoftForeignKey protects from schema sync).
119
+ * All UPDATE statements are logged to migration files via LogSQLAndExecute() for CI/CD traceability.
120
+ */
121
+ protected applySoftPKFKConfig(pool: sql.ConnectionPool): Promise<boolean>;
108
122
  /**
109
123
  * This method ensures that the __mj_CreatedAt and __mj_UpdatedAt fields exist in each entity that has TrackRecordChanges set to true. If the fields do not exist, they are created.
110
124
  * If the fields exist but have incorrect default values, the default values are updated. The default value that is to be used for these special fields is GETUTCDATE() which is the
@@ -242,6 +256,10 @@ export declare class ManageMetadataBase {
242
256
  shouldCreate: boolean;
243
257
  validationMessage: string;
244
258
  }>;
259
+ /**
260
+ * Checks if a table has a soft primary key defined in the additionalSchemaInfo JSON file (configured in mj.config.cjs)
261
+ */
262
+ protected hasSoftPrimaryKeyInConfig(schemaName: string, tableName: string): boolean;
245
263
  protected createNewEntityName(newEntity: any, currentUser: UserInfo): Promise<string>;
246
264
  protected createNewEntityDisplayName(newEntity: any, newName: string): string | null;
247
265
  protected newEntityNameWithAdvancedGeneration(ag: AdvancedGeneration, newEntity: any, currentUser: UserInfo): Promise<string>;
@@ -261,16 +279,14 @@ export declare class ManageMetadataBase {
261
279
  protected createNewEntity(pool: sql.ConnectionPool, newEntity: any, md: Metadata, currentUser: UserInfo): Promise<void>;
262
280
  protected isSchemaNew(pool: sql.ConnectionPool, schemaName: string): Promise<boolean>;
263
281
  /**
264
- * Creates a new application using the entity framework.
265
- * This ensures the server-side entity extension is used, which handles:
266
- * - Auto-generation of Path from Name (via ApplicationEntityServerEntity)
267
- * - Any other server-side business logic
282
+ * Creates a new application using direct SQL INSERT to ensure it's captured in SQL logging.
283
+ * The Path field is auto-generated from Name using the same slug logic as ApplicationEntityServerEntity.
268
284
  *
269
- * @param pool SQL connection pool (unused but kept for signature compatibility)
285
+ * @param pool SQL connection pool
270
286
  * @param appID Pre-generated UUID for the application
271
287
  * @param appName Name of the application
272
288
  * @param schemaName Schema name for SchemaAutoAddNewEntities
273
- * @param currentUser Current user for entity operations
289
+ * @param currentUser Current user for entity operations (unused but kept for signature compatibility)
274
290
  * @returns The application ID if successful, null otherwise
275
291
  */
276
292
  protected createNewApplication(pool: sql.ConnectionPool, appID: string, appName: string, schemaName: string, currentUser: UserInfo): Promise<string | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"manage-metadata.d.ts","sourceRoot":"","sources":["../../src/Database/manage-metadata.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"manage-metadata.d.ts","sourceRoot":"","sources":["../../src/Database/manage-metadata.ts"],"names":[],"mappings":"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"}
@@ -87,6 +87,38 @@ class ManageMetadataBase {
87
87
  static get generatedValidators() {
88
88
  return this._generatedValidators;
89
89
  }
90
+ static _softPKFKConfigCache = null;
91
+ static _softPKFKConfigPath = '';
92
+ /**
93
+ * Loads and caches the soft PK/FK configuration from the additionalSchemaInfo file.
94
+ * The file is only loaded once per session to avoid repeated I/O.
95
+ */
96
+ static getSoftPKFKConfig() {
97
+ // Return cached config if path hasn't changed
98
+ const configPath = config_1.configInfo.additionalSchemaInfo
99
+ ? path_1.default.join(config_1.currentWorkingDirectory, config_1.configInfo.additionalSchemaInfo)
100
+ : '';
101
+ if (this._softPKFKConfigCache !== null && this._softPKFKConfigPath === configPath) {
102
+ return this._softPKFKConfigCache;
103
+ }
104
+ // Cache miss or path changed - reload from disk
105
+ if (!configPath || !fs.existsSync(configPath)) {
106
+ this._softPKFKConfigCache = null;
107
+ this._softPKFKConfigPath = configPath;
108
+ return null;
109
+ }
110
+ try {
111
+ const configContent = fs.readFileSync(configPath, 'utf-8');
112
+ this._softPKFKConfigCache = JSON.parse(configContent);
113
+ this._softPKFKConfigPath = configPath;
114
+ return this._softPKFKConfigCache;
115
+ }
116
+ catch (e) {
117
+ this._softPKFKConfigCache = null;
118
+ this._softPKFKConfigPath = configPath;
119
+ return null;
120
+ }
121
+ }
90
122
  /**
91
123
  * Primary function to manage metadata within the CodeGen system. This function will call a series of sub-functions to manage the metadata.
92
124
  * @param pool - the ConnectionPool object to use for querying and updating the database
@@ -526,6 +558,12 @@ class ManageMetadataBase {
526
558
  bSuccess = false;
527
559
  }
528
560
  (0, status_logging_1.logStatus)(` Updated existing entity fields from schema in ${(new Date().getTime() - step3StartTime.getTime()) / 1000} seconds`);
561
+ // Apply soft PK/FK configuration if config file exists
562
+ const stepConfigStartTime = new Date();
563
+ if (!await this.applySoftPKFKConfig(pool)) {
564
+ (0, status_logging_1.logError)('Error applying soft PK/FK configuration');
565
+ }
566
+ (0, status_logging_1.logStatus)(` Applied soft PK/FK configuration in ${(new Date().getTime() - stepConfigStartTime.getTime()) / 1000} seconds`);
529
567
  const step4StartTime = new Date();
530
568
  if (!await this.setDefaultColumnWidthWhereNeeded(pool, excludeSchemas)) {
531
569
  (0, status_logging_1.logError)('Error setting default column width where needed');
@@ -600,6 +638,87 @@ class ManageMetadataBase {
600
638
  return false;
601
639
  }
602
640
  }
641
+ /**
642
+ * Applies soft PK/FK configuration from a JSON file specified in mj.config.cjs (additionalSchemaInfo property).
643
+ * For soft PKs: Sets BOTH IsPrimaryKey=1 AND IsSoftPrimaryKey=1 (IsPrimaryKey is source of truth, IsSoftPrimaryKey protects from schema sync).
644
+ * For soft FKs: Sets RelatedEntityID/RelatedEntityFieldName + IsSoftForeignKey=1 (RelatedEntityID is source of truth, IsSoftForeignKey protects from schema sync).
645
+ * All UPDATE statements are logged to migration files via LogSQLAndExecute() for CI/CD traceability.
646
+ */
647
+ async applySoftPKFKConfig(pool) {
648
+ // Check if additionalSchemaInfo is configured in mj.config.cjs
649
+ if (!config_1.configInfo.additionalSchemaInfo) {
650
+ // No additional schema info configured - this is fine, it's optional
651
+ return true;
652
+ }
653
+ const configPath = path_1.default.join(config_1.currentWorkingDirectory, config_1.configInfo.additionalSchemaInfo);
654
+ if (!fs.existsSync(configPath)) {
655
+ (0, status_logging_1.logStatus)(` ⚠️ additionalSchemaInfo configured but file not found: ${configPath}`);
656
+ return true;
657
+ }
658
+ try {
659
+ (0, status_logging_1.logStatus)(` Found ${config_1.configInfo.additionalSchemaInfo}, applying soft PK/FK configuration...`);
660
+ const config = ManageMetadataBase.getSoftPKFKConfig();
661
+ let totalPKs = 0;
662
+ let totalFKs = 0;
663
+ const schema = (0, config_1.mj_core_schema)();
664
+ for (const table of config.tables || []) {
665
+ // Look up entity ID (SELECT query - no need to log to migration file)
666
+ const entityLookupSQL = `SELECT ID FROM [${schema}].[Entity] WHERE SchemaName = '${table.schemaName}' AND BaseTable = '${table.tableName}'`;
667
+ const entityResult = await pool.request().query(entityLookupSQL);
668
+ if (entityResult.recordset.length === 0) {
669
+ (0, status_logging_1.logStatus)(` ⚠️ Entity not found for ${table.schemaName}.${table.tableName} - skipping`);
670
+ continue;
671
+ }
672
+ const entityId = entityResult.recordset[0].ID;
673
+ // Process primary keys - set BOTH IsPrimaryKey = 1 AND IsSoftPrimaryKey = 1
674
+ // IsPrimaryKey is the source of truth, IsSoftPrimaryKey protects it from schema sync
675
+ if (table.primaryKeys && table.primaryKeys.length > 0) {
676
+ for (const pk of table.primaryKeys) {
677
+ const sSQL = `UPDATE [${schema}].[EntityField]
678
+ SET ${core_1.EntityInfo.UpdatedAtFieldName}=GETUTCDATE(),
679
+ [IsPrimaryKey] = 1,
680
+ [IsSoftPrimaryKey] = 1
681
+ WHERE [EntityID] = '${entityId}' AND [Name] = '${pk.fieldName}'`;
682
+ const result = await this.LogSQLAndExecute(pool, sSQL, `Set soft PK for ${table.schemaName}.${table.tableName}.${pk.fieldName}`);
683
+ if (result !== null) {
684
+ (0, status_logging_1.logStatus)(` ✓ Set IsPrimaryKey=1, IsSoftPrimaryKey=1 for ${table.tableName}.${pk.fieldName}`);
685
+ totalPKs++;
686
+ }
687
+ }
688
+ }
689
+ // Process foreign keys - set RelatedEntityID, RelatedEntityFieldName, and IsSoftForeignKey = 1
690
+ if (table.foreignKeys && table.foreignKeys.length > 0) {
691
+ for (const fk of table.foreignKeys) {
692
+ // Look up related entity ID (SELECT query - no need to log to migration file)
693
+ const relatedLookupSQL = `SELECT ID FROM [${schema}].[Entity] WHERE SchemaName = '${fk.relatedSchema}' AND BaseTable = '${fk.relatedTable}'`;
694
+ const relatedEntityResult = await pool.request().query(relatedLookupSQL);
695
+ if (relatedEntityResult.recordset.length === 0) {
696
+ (0, status_logging_1.logStatus)(` ⚠️ Related entity not found for ${fk.relatedSchema}.${fk.relatedTable} - skipping FK ${fk.fieldName}`);
697
+ continue;
698
+ }
699
+ const relatedEntityId = relatedEntityResult.recordset[0].ID;
700
+ const sSQL = `UPDATE [${schema}].[EntityField]
701
+ SET ${core_1.EntityInfo.UpdatedAtFieldName}=GETUTCDATE(),
702
+ [RelatedEntityID] = '${relatedEntityId}',
703
+ [RelatedEntityFieldName] = '${fk.relatedField}',
704
+ [IsSoftForeignKey] = 1
705
+ WHERE [EntityID] = '${entityId}' AND [Name] = '${fk.fieldName}'`;
706
+ const result = await this.LogSQLAndExecute(pool, sSQL, `Set soft FK for ${table.schemaName}.${table.tableName}.${fk.fieldName} → ${fk.relatedTable}.${fk.relatedField}`);
707
+ if (result !== null) {
708
+ (0, status_logging_1.logStatus)(` ✓ Set soft FK for ${table.tableName}.${fk.fieldName} → ${fk.relatedTable}.${fk.relatedField}`);
709
+ totalFKs++;
710
+ }
711
+ }
712
+ }
713
+ }
714
+ (0, status_logging_1.logStatus)(` Applied ${totalPKs} soft PK(s) and ${totalFKs} soft FK(s) from configuration`);
715
+ return true;
716
+ }
717
+ catch (e) {
718
+ (0, status_logging_1.logError)(`Error applying soft PK/FK configuration: ${e}`);
719
+ return false;
720
+ }
721
+ }
603
722
  /**
604
723
  * This method ensures that the __mj_CreatedAt and __mj_UpdatedAt fields exist in each entity that has TrackRecordChanges set to true. If the fields do not exist, they are created.
605
724
  * If the fields exist but have incorrect default values, the default values are updated. The default value that is to be used for these special fields is GETUTCDATE() which is the
@@ -1561,6 +1680,11 @@ NumberedRows AS (
1561
1680
  const resultResult = await ds.request().query(query);
1562
1681
  const result = resultResult.recordset;
1563
1682
  if (result.length === 0) {
1683
+ // No database PK constraint found - check if there's a soft PK defined in config
1684
+ if (this.hasSoftPrimaryKeyInConfig(newEntity.SchemaName, newEntity.TableName)) {
1685
+ (0, status_logging_1.logStatus)(` ✓ No database PK for ${newEntity.SchemaName}.${newEntity.TableName}, but soft PK found in config - allowing entity creation`);
1686
+ return { shouldCreate: true, validationMessage: '' };
1687
+ }
1564
1688
  return { shouldCreate: false, validationMessage: "No primary key found" };
1565
1689
  }
1566
1690
  return { shouldCreate: true, validationMessage: '' };
@@ -1571,6 +1695,38 @@ NumberedRows AS (
1571
1695
  return { shouldCreate: false, validationMessage: errorMsg };
1572
1696
  }
1573
1697
  }
1698
+ /**
1699
+ * Checks if a table has a soft primary key defined in the additionalSchemaInfo JSON file (configured in mj.config.cjs)
1700
+ */
1701
+ hasSoftPrimaryKeyInConfig(schemaName, tableName) {
1702
+ // Check if additionalSchemaInfo is configured
1703
+ if (!config_1.configInfo.additionalSchemaInfo) {
1704
+ return false;
1705
+ }
1706
+ const configPath = path_1.default.join(config_1.currentWorkingDirectory, config_1.configInfo.additionalSchemaInfo);
1707
+ if (!fs.existsSync(configPath)) {
1708
+ (0, status_logging_1.logStatus)(` [Soft PK Check] Config file not found at: ${configPath}`);
1709
+ return false;
1710
+ }
1711
+ try {
1712
+ const config = ManageMetadataBase.getSoftPKFKConfig();
1713
+ if (!config || !config.tables) {
1714
+ (0, status_logging_1.logStatus)(` [Soft PK Check] Config file found but no tables array`);
1715
+ return false;
1716
+ }
1717
+ const tableConfig = config.tables.find((t) => t.schemaName?.toLowerCase() === schemaName?.toLowerCase() &&
1718
+ t.tableName?.toLowerCase() === tableName?.toLowerCase());
1719
+ const found = Boolean(tableConfig?.primaryKeys && tableConfig.primaryKeys.length > 0);
1720
+ if (!found) {
1721
+ (0, status_logging_1.logStatus)(` [Soft PK Check] No config found for ${schemaName}.${tableName} (config has ${config.tables.length} tables)`);
1722
+ }
1723
+ return found;
1724
+ }
1725
+ catch (e) {
1726
+ (0, status_logging_1.logStatus)(` [Soft PK Check] Error reading config: ${e}`);
1727
+ return false;
1728
+ }
1729
+ }
1574
1730
  async createNewEntityName(newEntity, currentUser) {
1575
1731
  const ag = new advanced_generation_1.AdvancedGeneration();
1576
1732
  if (ag.featureEnabled('EntityNames')) {
@@ -1747,39 +1903,33 @@ NumberedRows AS (
1747
1903
  return result && result.length > 0 ? result[0].Count === 0 : true;
1748
1904
  }
1749
1905
  /**
1750
- * Creates a new application using the entity framework.
1751
- * This ensures the server-side entity extension is used, which handles:
1752
- * - Auto-generation of Path from Name (via ApplicationEntityServerEntity)
1753
- * - Any other server-side business logic
1906
+ * Creates a new application using direct SQL INSERT to ensure it's captured in SQL logging.
1907
+ * The Path field is auto-generated from Name using the same slug logic as ApplicationEntityServerEntity.
1754
1908
  *
1755
- * @param pool SQL connection pool (unused but kept for signature compatibility)
1909
+ * @param pool SQL connection pool
1756
1910
  * @param appID Pre-generated UUID for the application
1757
1911
  * @param appName Name of the application
1758
1912
  * @param schemaName Schema name for SchemaAutoAddNewEntities
1759
- * @param currentUser Current user for entity operations
1913
+ * @param currentUser Current user for entity operations (unused but kept for signature compatibility)
1760
1914
  * @returns The application ID if successful, null otherwise
1761
1915
  */
1762
1916
  async createNewApplication(pool, appID, appName, schemaName, currentUser) {
1763
1917
  try {
1764
- const md = new core_1.Metadata();
1765
- const app = await md.GetEntityObject('Applications', currentUser);
1766
- app.NewRecord();
1767
- app.ID = appID;
1768
- app.Name = appName;
1769
- app.Description = 'Generated for schema';
1770
- app.SchemaAutoAddNewEntities = schemaName;
1771
- // Path and AutoUpdatePath will be handled by the server-side entity extension
1772
- // which auto-generates Path from Name when AutoUpdatePath is true (default)
1773
- const saved = await app.Save();
1774
- if (saved) {
1775
- (0, core_1.LogStatus)(`Created new application ${appName} with Path: ${app.Path}`);
1776
- return appID;
1777
- }
1778
- else {
1779
- const errorMsg = app.LatestResult ? JSON.stringify(app.LatestResult) : 'Unknown error';
1780
- (0, core_1.LogError)(`Failed to save new application ${appName}: ${errorMsg}`);
1781
- return null;
1782
- }
1918
+ // Generate Path from Name using slug conversion:
1919
+ // 1. Convert to lowercase
1920
+ // 2. Replace spaces with hyphens
1921
+ // 3. Remove special characters (keep only alphanumeric and hyphens)
1922
+ const path = appName
1923
+ .toLowerCase()
1924
+ .replace(/\s+/g, '-') // spaces to hyphens
1925
+ .replace(/[^a-z0-9-]/g, '') // remove special chars
1926
+ .replace(/-+/g, '-') // collapse multiple hyphens
1927
+ .replace(/^-|-$/g, ''); // trim hyphens from start/end
1928
+ const sSQL = `INSERT INTO [${(0, config_1.mj_core_schema)()}].Application (ID, Name, Description, SchemaAutoAddNewEntities, Path, AutoUpdatePath)
1929
+ VALUES ('${appID}', '${appName}', 'Generated for schema', '${schemaName}', '${path}', 1)`;
1930
+ await this.LogSQLAndExecute(pool, sSQL, `SQL generated to create new application ${appName}`);
1931
+ (0, core_1.LogStatus)(`Created new application ${appName} with Path: ${path}`);
1932
+ return appID;
1783
1933
  }
1784
1934
  catch (e) {
1785
1935
  (0, core_1.LogError)(`Failed to create new application ${appName} for schema ${schemaName}`, null, e);