Member Junction
    Preparing search index...

    This class is responsible for generating database level objects like views, stored procedures, permissions, etc. You can sub-class this class to create your own SQL generation logic or implement support for other databases. The base class implements support for SQL Server. In future versions of MJ, we will break out an abstract base class that has the skeleton of the logic and then the SQL Server version will be a sub-class of that abstract base class and other databases will be sub-classes of the abstract base class as well.

    Index

    Constructors

    Properties

    Accessors

    Methods

    analyzeCascadeDeleteDependencies applyLatePhaseFixups applyPermissions buildCascadeDeleteDependencies buildCustomBaseViewRefreshSQL buildPrimaryKeyComponents buildUpdateCursorParameters checkBaseViewChangedInDB checkBaseViewColumnsChangedPG createCombinedEntitySQLFiles createEntityFieldsInsertString createEntityFieldsParamString createEntityFieldsUpdateString deleteGeneratedEntityFiles detectRecursiveForeignKeys emitCustomBaseViewRefreshes executeEntityInPhases extractViewSelectBody formatDefaultValue generateAllEntitiesSQLFileHeader generateAllRootIDFunctions generateAndExecuteEntitySQLToSeparateFiles generateAndExecuteSingleEntitySQLToSeparateFiles generateBaseView generateBaseViewJoins generateBaseViewPieces generateBaseViewRelatedFieldsString generateCascadeCursorOperation generateCascadeDeletes generateDefaultAlias generateEntityFullTextSearchSQL generateEntitySQL generateFullTextSearchFunctionPermissions generateIndexesForForeignKeys generateNativeGeoFields generateParentEntityFieldSelects generateParentEntityJoins generateRecordGeoCodeFields generateRecursiveCTEJoins generateRootFieldSelects generateRootIDFunction generateRootIDJoins generateSingleCascadeOperation generateSingleEntitySQLFileHeader generateSingleEntitySQLToSeparateFiles generateSPCreate generateSPDelete generateSPPermissions generateSPUpdate generateUpdatedAtTrigger generateViewPermissions getEntitiesRequiringCascadeDeleteRegeneration getEntityPermissionFileNames getEntityPrimaryKeyIndexName getIsNameFieldForSingleEntity getModifiedCustomBaseViewEntities getModifiedEntitiesWithUpdateAPI getSPName hasAliasCollision hasNativeGeoFields isFieldInCompositeUniqueConstraint logSQLForNewOrModifiedEntity manageSQLScriptsAndExecution markEntitiesForCascadeDeleteRegeneration orderEntitiesByDependencies runCustomSQLScripts stripID validateFieldExists writeFileIfChanged

    Constructors

    Properties

    _dbProvider: CodeGenDatabaseProvider = ...

    The database-specific code generation provider, resolved from MJGlobal.ClassFactory against the configured dbPlatform. Each provider (SQLServerCodeGenProvider, PostgreSQLCodeGenProvider, …) registers itself with @RegisterClass(CodeGenDatabaseProvider, '<platform>') — the canonical DatabasePlatform value as its key — so this single line picks up the right one without dialect-specific branching. Subclasses can override via @RegisterClass(... priority) to plug in customized codegen behavior, same hook every other MJ class uses.

    _sqlUtilityObject: SQLUtilityBase = ...
    cascadeDeleteDependencies: Map<string, Set<string>> = ...

    Tracks cascade delete dependencies between entities. Key: Entity ID whose update/delete SP is called by other entities' delete SPs Value: Set of Entity IDs that have CascadeDeletes=true and call this entity's update/delete SP

    entitiesNeedingDeleteSPRegeneration: Set<string> = ...

    Tracks entities that need their delete stored procedures regenerated due to cascade dependencies

    entitiesQualifiedForForcedRegeneration: string[] = []

    Array of entity names that qualify for forced regeneration based on the whereClause filter

    filterEntitiesQualifiedForRegeneration: boolean = false

    Flag indicating whether to filter entities for forced regeneration based on entityWhereClause

    orderedEntitiesForDeleteSPRegeneration: string[] = []

    Ordered list of entity IDs for delete SP regeneration (dependency order)

    Accessors

    Methods

    • Builds a complete map of cascade delete dependencies by analyzing all entities. This method populates the cascadeDeleteDependencies map without generating SQL.

      Parameters

      Returns Promise<void>

    • Parameters

      Returns {
          fetchInto: string;
          selectFields: string;
          spParams: string;
          varDeclarations: string;
      }

    • Parameters

      Returns {
          allParams: string;
          declarations: string;
          fetchInto: string;
          selectFields: string;
      }

    • Fetches the current base view definition from SQL Server and compares it against newly generated SQL. If the view body has changed (e.g., a virtual field was added to a joined table), the entity is logged and executed. Unlike adding to modifiedEntityList (which would cause all SPs, permissions, indexes, etc. to be logged too), this only logs the base view SQL itself.

      Comparison extracts the SELECT body from both the DB definition (CREATE VIEW ... AS ) and the generated SQL, normalizing whitespace for a fair comparison.

      Parameters

      Returns Promise<boolean>

      true if the base view changed, false otherwise

    • PostgreSQL base-view change detection by COLUMN SET rather than text.

      pg_get_viewdef() re-qualifies columns and normalizes whitespace/casing, so the SELECT-body text comparison used on SQL Server never byte-matches on PG and false-flags nearly every view. The base view exposes exactly the entity's fields, so comparing the view's live column set (information_schema.columns) against the entity's expected field set is deterministic, immune to that reformatting, and still catches the cases that matter:

      • a stale view missing a field that metadata now declares (the v5.46 OpenApp outage: a migration added the column + EntityField but never re-baked the view), and
      • a missing view entirely (empty column set → force-recreate; the documented self-heal for a view that a prior run dropped but failed to recreate). A pure Sequence renumber does not change the column set, so it correctly does NOT flag.

      NOT caught (by design — a tradeoff vs. SQL Server's text comparison): a view-BODY change that leaves the exposed column NAMES identical — e.g. a RelatedEntityNameFieldMap re-pointed to a different source column under the same output alias, or a codegen view-template change that rewrites the SELECT without renaming columns. Those alter the SELECT text but not the column set, so they must be forced through the metadata-driven modifiedEntityList (or an explicit EntitiesRequiringViewRegen entry), not this column-set check.

      Parameters

      Returns Promise<boolean>

      true if the view's column set differs from the entity's fields (or the view is missing)

    • Emits sp_refreshview statements into the migration log file for modified custom base view entities (BaseViewGenerated === false). This ensures that when the migration runs on other environments, custom base views affected by schema changes get refreshed automatically. Only entities in the modified or new entity lists are included.

      Returns void

    • Extracts the SELECT body from a CREATE VIEW statement, normalizing whitespace for comparison. Handles both DB-stored definitions (CREATE VIEW ... AS SELECT ...) and generated SQL (which includes DROP VIEW, comment headers, GO, and permissions after the view body).

      Parameters

      • viewSQL: string

      Returns string

    • Formats a default value for use in SQL, handling special cases like SQL functions

      Parameters

      • defaultValue: string

        The default value from the database metadata

      • needsQuotes: boolean

        Whether the field type typically needs quotes

      Returns string

      Properly formatted default value for SQL

    • This function will handle the process of creating all of the generated objects like base view, stored procedures, etc. for all entities in the entities array. It will generate the SQL for each entity and then execute it.

      Parameters

      • options: {
            batchSize?: number;
            directory: string;
            enableSQLLoggingForNewOrModifiedEntities?: boolean;
            entities: EntityInfo[];
            onlyPermissions: boolean;
            pool: CodeGenConnection;
            skipExecution: boolean;
            willRegenerate?: Set<string>;
            writeFiles: boolean;
        }
        • OptionalbatchSize?: number
        • directory: string
        • OptionalenableSQLLoggingForNewOrModifiedEntities?: boolean
        • entities: EntityInfo[]
        • onlyPermissions: boolean
        • pool: CodeGenConnection
        • skipExecution: boolean
        • OptionalwillRegenerate?: Set<string>

          Optional UNION of will-regenerate keys across ALL batches in the same codegen run. When provided, takes precedence over the per-batch set.

        • writeFiles: boolean

      Returns Promise<{ Files: string[]; Success: boolean }>

    • Parameters

      • options: {
            directory: string;
            enableSQLLoggingForNewOrModifiedEntities?: boolean;
            entity: EntityInfo;
            onlyPermissions: boolean;
            pool: CodeGenConnection;
            skipExecution: boolean;
            willRegenerate?: Set<string>;
            writeFiles: boolean;
        }
        • directory: string
        • OptionalenableSQLLoggingForNewOrModifiedEntities?: boolean
        • entity: EntityInfo
        • onlyPermissions: boolean
        • pool: CodeGenConnection
        • skipExecution: boolean
        • OptionalwillRegenerate?: Set<string>

          Names of other entities regenerating in this run — passed to the PG phased executor's willRegenerate so stale captured dependents that will be rebuilt anyway aren't restored.

        • writeFiles: boolean

      Returns Promise<{ Files: string[]; Success: boolean }>

    • Same as generateBaseView, but returns the view DDL and the GRANT/permissions DDL as separate strings rather than concatenating. Used by phased per-entity execution paths (e.g. PG's phased executor) where the view must run under 42P16 fallback recovery but the permissions must run afterwards in a later phase — concatenating them would prevent the executor from detecting where a failure actually occurred.

      Parameters

      Returns Promise<{ viewPermSQL: string; viewSQL: string }>

    • Generate SELECT aliases for native lat/lng fields → __mj_Latitude / __mj_Longitude. Virtual fields are excluded — see hasNativeGeoFields for the rationale.

      Parameters

      • entityFields: EntityFieldInfo[]
      • classNameFirstChar: string
      • qi: (name: string) => string

      Returns string

    • Generates SELECT field expressions for IS-A parent entity columns. Walks the ParentID chain upward, joining to each parent's base table, and includes non-PK, non-timestamp, non-virtual fields from each parent table. Returns a string starting with ',\n' if there are parent fields, or '' if none.

      Parameters

      Returns string

    • Generates INNER JOIN clauses for IS-A parent entity base tables. Chains joins from child -> parent -> grandparent using PK-to-PK conditions. Each parent is joined via its base table (not view) to avoid view dependency ordering issues.

      Parameters

      Returns string

    • Generate SELECT aliases from the RecordGeoCode LEFT JOIN → __mj_Latitude / __mj_Longitude.

      Parameters

      • qi: (name: string) => string

      Returns string

    • Parameters

      • options: {
            directory: string;
            enableSQLLoggingForNewOrModifiedEntities?: boolean;
            entity: EntityInfo;
            onlyPermissions: boolean;
            pool: CodeGenConnection;
            skipExecution: boolean;
            writeFiles: boolean;
        }

      Returns Promise<{ files: string[]; permissionsSQL: string; sql: string }>

    • Identifies entities that need their delete stored procedures regenerated due to cascade dependencies on entities that had schema changes.

      Parameters

      Returns Promise<Set<string>>

    • Parameters

      • entityName: string

      Returns { nameField: string; nameFieldIsComputed: boolean; nameFieldIsVirtual: boolean }

    • Gets entities that had schema changes from the ManageMetadataBase tracking. Returns a map of entity names to their IDs for entities that had update-affecting changes.

      Parameters

      Returns Promise<Map<string, string>>

    • Check if an entity has native latitude/longitude fields marked with GeoLatitude/GeoLongitude ExtendedType. If both exist, the view should alias them directly instead of joining to RecordGeoCode.

      MUST exclude virtual fields. The view-introspection pass creates virtual EntityField rows for the __mj_Latitude/__mj_Longitude SELECT aliases the JOIN path emits, then auto-assigns ExtendedType=GeoLatitude/Longitude by name-pattern. Without this filter the next view regen flips to the native path and tries to SELECT e.__mj_Longitude from the base table — the column doesn't exist on the table, only on the view itself, so view creation fails with "Invalid column name '__mj_Longitude'". This recurs on any geo-eligible entity whose RecordGeoCode-based view ran once.

      Parameters

      Returns boolean

    • Checks if a field is part of a composite (multi-column) unique constraint. Returns true if the field participates in a unique index with 2+ columns. This is used to determine if a nullable FK should use DELETE instead of UPDATE during cascade operations, since setting to NULL could violate uniqueness.

      Parameters

      Returns Promise<boolean>

    • Parameters

      • entity: EntityInfo
      • sql: string
      • description: string
      • logSql: boolean = false
      • forceLog: boolean = false

      Returns void

    • Orders entities by their cascade delete dependencies using topological sort. Ensures that if Entity A's delete SP calls Entity B's update/delete SP, then Entity B is regenerated before Entity A.

      Parameters

      • entities: EntityInfo[]

        All entities for name lookup

      • entityIdsToOrder: Set<string>

        Set of entity IDs that need ordering

      Returns string[]

      Array of entity IDs in dependency order

    • Writes a generated SQL file to disk only if the content has changed from the existing file. Returns true if the file was written (content changed or file is new), false if unchanged. This avoids false timestamp updates and unnecessary I/O.

      Parameters

      • filePath: string
      • newContent: string

      Returns boolean