ProtecteddbProtecteddialectReturns the SQLDialect for the current database platform, derived from the provider.
ProtectedtimestampReturns the timestamp column type name for this platform. Delegates to the database provider.
StaticEntitiesEntities that had late-phase changes requiring their base views to be regenerated after the main SQL generation pass. Each entry includes the reason for regen so downstream logic can apply reason-specific fixups.
StaticgeneratedGlobally scoped list of validators that have been generated during the metadata management process.
StaticmodifiedGlobally scoped list of entities that have been modified during the metadata management process.
StaticnewGlobally scoped list of entities that have been created during the metadata management process.
ProtectedaddAdds default permissions for a newly created entity based on config settings. Shared by both table-backed entity creation and virtual entity creation.
ProtectedaddAdds default ApplicationRole records for a newly created application based on config settings. This grants configured roles access to the new application automatically.
ProtectedaddAdds a newly created entity to the application(s) that match its schema name. If no application exists for the schema and config allows it, creates one. Shared by both table-backed entity creation and virtual entity creation.
ProtectedapplicationProtectedapplyApply Advanced Generation features - Smart Field Identification and Form Layout Generation
ProtectedapplyUpserts FieldCategoryInfo (new format) and FieldCategoryIcons (legacy format) in EntitySetting.
ProtectedapplyGenerate SQL UPDATEs for DefaultInView on the identified default view fields
ProtectedapplySets the entity icon if the entity doesn't already have one.
ProtectedapplyApplies entity importance analysis to MJApplicationEntity records. Only called for NEW entities to set DefaultForNewUser.
ProtectedapplyGenerate SQL UPDATEs for entity-level AllowUserSearchAPI.
Guardrail: even if the LLM proposes enabling AllowUserSearchAPI on an entity that looks like an audit/log/run-history table by name, refuse — those tables grow unboundedly, the LIKE fan-out across them dominates global-search latency, and they're virtually never the right target for a user-facing search box. The team can still enable search on such an entity by setting AutoUpdateAllowUserSearchAPI=0 and flipping the flag manually.
ProtectedapplyApplies category, display name, extended type, and code type to entity fields. Enforces stability rules: fields with existing categories cannot move to NEW categories. All SQL updates are batched into a single execution for performance.
ProtectedapplyApply form layout generation results to set category on entity fields. Delegates to shared methods for category assignment, icon, and category info persistence.
Database connection pool
Entity fields
Form layout result from LLM
If true, apply entityImportance; if false, skip it
ProtectedapplyGenerate SQL UPDATEs for entity-level and field-level FullTextSearch configuration
ProtectedapplyApplies LLM-generated field descriptions to entity fields that lack descriptions. All SQL updates are batched into a single execution for performance.
ProtectedapplyApplies LLM-identified foreign keys to entity fields. Sets RelatedEntityID, RelatedEntityFieldName, and IsSoftForeignKey=1. Only applies high and medium confidence FKs. All SQL updates are batched into a single execution for performance.
ProtectedapplyApplies LLM-identified primary keys to entity fields. Sets IsPrimaryKey=1 and IsSoftPrimaryKey=1 for identified fields. First clears any default PK that was set by field-sync (field #1 fallback). All SQL updates are batched into a single execution for performance.
ProtectedapplyGenerate SQL UPDATEs for IsNameField — SINGLE-WINNER semantics.
The LLM's result.nameFields is a RANKED candidate list (it may propose several
fields that "together" name the record, e.g. FirstName + LastName), but every
downstream consumer — EntityInfo.NameField, the base-view generator's FK-name
virtual columns, RelatedEntityNameFieldMap resolution — assumes exactly ONE name
field per entity. Historically this method flagged EVERY candidate and never
cleared anything, so flags accumulated across runs (57 core entities ended up with
2–4 IsNameField=1 rows) and the FK-name pick silently DRIFTED between CodeGen
runs as the first-by-sequence winner changed (observed: Conversation Details
flipping Message → Role, reshaping every view that joins to it).
Winner selection (deterministic, mirrors EntityInfo.NameField's runtime
preference and the v5.41 metadata backfill):
Name, else the first in field order (fields arrive ordered by
Sequence from the metadata query).Every NON-winner with IsNameField=1 and AutoUpdateIsNameField=1 is CLEARED, so
historical accumulation self-heals on the next analysis pass. Fields pinned with
AutoUpdateIsNameField=0 are never touched in either direction — the user owns
them, and EntityInfo.NameField's literal-Name preference arbitrates at runtime.
ProtectedapplyApplies schema-level entity name prefix/suffix rules from additionalSchemaInfo.json. The file may contain a top-level "Schemas" array with entries like:
{ "name": "CRM", "entityNamePrefix": "CRM: ", "entityNameSuffix": "" }
These are merged into the cached SchemaInfo records so that getNewEntityNameRule()
can resolve them during entity creation. Config-file rules (mj.config.cjs) still
take priority over these — this just provides a fallback from DBAutoDoc output.
ProtectedapplyGenerate SQL UPDATEs for IncludeInUserSearchAPI on the identified searchable fields.
Guardrails: even if the SmartFieldIdentificationResult flags a field as searchable, we refuse to enable IncludeInUserSearchAPI when the field is a primary key, a non-text type (LIKE forces an implicit per-row CONVERT and never seeks an index), or an unbounded text type whose parent entity is not FTX-enabled (the LIKE path cannot seek MAX/ntext/text columns; FTX is the right tool there). These are always-wrong cases — they cause the data provider to emit unindexed scans on every search.
Optionalentity: { FullTextSearchEnabled?: boolean }ProtectedapplyGenerate SQL UPDATEs for UserSearchPredicateAPI on each searchable field
ProtectedapplyApply smart field identification results to entity fields and entity-level search configuration
ProtectedapplyApplies soft PK/FK configuration from a JSON file specified in mj.config.cjs (additionalSchemaInfo property). For soft PKs: Sets BOTH IsPrimaryKey=1 AND IsSoftPrimaryKey=1 (IsPrimaryKey is source of truth, IsSoftPrimaryKey protects from schema sync). For soft FKs: Sets RelatedEntityID/RelatedEntityFieldName + IsSoftForeignKey=1 (RelatedEntityID is source of truth, IsSoftForeignKey protects from schema sync). All UPDATE statements are logged to migration files via LogSQLAndExecute() for CI/CD traceability.
ProtectedapplyApplies soft value-list configuration from Fields[] entries in additionalSchemaInfo.json. Runs AFTER manageEntityFieldValuesAndValidatorFunctions() so CHECK-constraint-derived values are already in the database. If EntityFieldValue rows already exist for a field (from CHECK constraints), the soft-enum pass skips that field — CHECK is authoritative.
ProtectedapplyApplies category assignments from VE decoration results using the shared category methods. Loads field records from DB (needs ID, Name, Category, AutoUpdateCategory, AutoUpdateDisplayName) then delegates to the shared methods.
ProtectedboolReturns a boolean literal for the platform. SQL Server: 1/0, PostgreSQL: true/false
ProtectedbuildHandles relationship management for an entire entity pair at once. Matches N FK fields to N existing relationship records using a 1:1 mapping:
ProtectedbuildBuilds a set of existing category names from entity fields. Used to enforce category stability (prevent renaming).
ProtectedbuildBuilds the DELETE for EntityFields no longer present in the freshly-introspected remote object, or '' when nothing should be removed. Field-name matching is case-insensitive. Pure/testable (no DB access) — the data-loss-sensitive computation guarded by externalObjectIsSyncable.
ProtectedbuildBuilds SQL to INSERT a new EntityRelationship record for a discovered FK field.
ProtectedbuildBuilds the provider-neutral query behind validateISARelationships: one row per DECLARED IS-A child (Entity.ParentID IS NOT NULL) carrying everything the severity rules need. LEFT JOINs throughout so an unresolvable ParentID still returns a row (that is a hard error, not a missing row).
ProtectedbuildBuilds IS-A parent chain context for an entity, computing which parent each inherited field originates from. Used to provide the LLM with inheritance awareness during form layout generation.
Returns an empty object for entities without parents, so it can be safely spread into the entity object passed to generateFormLayout().
ProtectedbuildParses a view definition SQL and resolves referenced tables to MJ entities. Returns enriched source entity context (all fields with descriptions and categories) for the LLM to use when decorating virtual entity fields.
ProtectedcheckThis method will look for situations where entity metadata exist in the entities metadata table but the underlying table has been deleted. In this case, the metadata for the entity should be removed. This method is called as part of the manageMetadata method and is not intended to be called directly.
ProtectedcheckProtectedcheckINTEGRITY CHECK — in a well-formed entity every base (non-virtual) field sequences BEFORE the
virtual/related fields, so the EntityField order matches the base view's SELECT [base].*, <joins>
column output. The positional save-capture in the data providers (e.g. SQLServerDataProvider's
@ResultTable) relies on that alignment. CodeGen assigns newly-discovered columns a temporary
maxSequence + 100000 offset that updateExistingEntityFieldsFromSchema is supposed to renumber; if
a base column is left sequenced AFTER a virtual field, the save-capture would mis-route values by
position. The providers now compensate (saves stay correct), but the metadata is still wrong — so we
scan for it after every metadata pass and log a prominent warning to drive the root cause out over time.
Public entry point for cleaning up stale EntityRelationship records. This must be called AFTER deleteUnneededEntityFields() has run, so that stale EntityField records (for dropped columns) are removed before we check which relationships are still valid. Called from sql_codegen.ts after the second manageEntityFields() pass.
database connection
schemas to exclude from FK field lookup
ProtectedcoalesceReturns ISNULL/COALESCE expression. Both platforms support COALESCE, but SQL Server also has ISNULL.
ProtectedconditionalGenerates SQL for conditional INSERT (IF NOT EXISTS pattern). Delegates to the database provider.
ProtectedcreateCreates the default constraint for a special date field. This method is called as part of the ensureSpecialDateFieldExistsAndHasCorrectDefaultValue method and is not intended to be called directly.
ProtectedcreateProtectedcreateCreates a new application using direct SQL INSERT to ensure it's captured in SQL logging. The Path field is auto-generated from Name using the same slug logic as MJApplicationEntityServer.
SQL connection pool
Pre-generated UUID for the application
Name of the application
Schema name for SchemaAutoAddNewEntities
Current user for entity operations (unused but kept for signature compatibility)
The application ID if successful, null otherwise
ProtectedcreateProtectedcreateProtectedcreateProtectedcreateOptionalentityIDs: string[]ProtectedcreateProtectedcreateProtectedcreateProtecteddecorateApplies LLM-assisted field decoration to a single virtual entity. Parses the view SQL to identify source entities, enriches the LLM prompt with their field metadata (descriptions, categories), then applies PKs, FKs, descriptions, and categories.
Whether the entity was decorated, skipped, or encountered an error.
ProtecteddecorateIterates over all virtual entities and applies LLM-assisted field decoration to identify primary keys, foreign keys, and field descriptions. Only runs if the VirtualEntityFieldDecoration advanced generation feature is enabled. Idempotent: skips entities that already have soft PK/FK annotations.
ProtecteddeleteOptionalentityIDs: string[]ProtectedderiveDerives an entity name from a view name by removing common prefixes (vw, v_) and converting to a human-friendly format.
ProtecteddetectDetect if an entity has geo-capable fields based on LLM-assigned ExtendedType values. If any field has a Geo* ExtendedType, set Entity.SupportsGeoCoding = 1. Respects the AutoUpdateSupportsGeoCoding flag — if 0, the value is locked.
ProtecteddropDrops and recreates the default constraint for a special date field. This method is called as part of the ensureSpecialDateFieldExistsAndHasCorrectDefaultValue method and is not intended to be called directly.
ProtecteddropDrops an existing default constraint from a given column within a given entity, if it exists
ProtecteddropGenerates a conditional existence check + DROP statement. Delegates to the database provider.
ProtectedensureThis 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. 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 UTC date and time. This method is called as part of the manageEntityFields method and is not intended to be called directly.
ProtectedensureThis method ensures that the __mj_DeletedAt field exists in each entity that has DeleteType=Soft. If the field does not exist, it is created.
ProtectedensureThis method handles the validation of the existence of the specified special date field and if it does exist it makes sure the default value is set correctly, if it doesn't exist it makes sure that it is created. This method is called as part of the ensureCreatedAtUpdatedAtFieldsExist method and is not intended to be called directly.
ProtectedentityProtectedentityReturns a parenthesized subquery that resolves an entity's ID by its BaseTable + SchemaName. Used in logged SQL to keep INSERT statements portable across databases (avoids hardcoding runtime UUIDs that may differ on a fresh database).
ProtectedexternalWhether an introspected remote object has columns we can safely sync. When false (object missing or zero columns), manageSingleExternalEntity skips the field sync rather than treating it as "the entity now has no fields" (which would DELETE every EntityField). Pure/testable.
ProtectedextractExtracts the top-level "Entities" array from the additionalSchemaInfo config file. Each entry identifies an entity by BaseTable + SchemaName and declares arbitrary Entity-table attributes to set (e.g., AllowMultipleSubtypes, TrackRecordChanges).
ProtectedextractExtracts value-list field configurations from the additionalSchemaInfo config file. Walks schema → tables → table.Fields[] and returns a map keyed by "schema.table".
ProtectedextractExtracts ISARelationships array from the additionalSchemaInfo config file. The config may contain a top-level "ISARelationships" key with an array of parent-child relationship definitions.
ProtectedextractExtracts organic key configurations from the additionalSchemaInfo config file. Walks all schema-keyed table arrays and collects OrganicKeys arrays with their owning schema and table name.
ProtectedextractExtracts a flat array of table configs from the config file, handling both formats:
ProtectedextractExtracts VirtualEntities array from the additionalSchemaInfo config file. The config may contain a top-level "VirtualEntities" key with an array of virtual entity definitions.
ProtectedfindFor an inherited field, walks the parent chain to find which specific parent entity originally defines this field (by matching non-virtual fields on each parent).
ProtectedgenerateThis method generates descriptions for entities in teh system where there is no existing description. This is an experimental feature and is done using AI. In order for it to be invoked, the EntityDescriptions feature must be enabled in the Advanced Generation configuration.
ProtectedgenerateGenerates a TypeScript field validator function from the text of a SQL CHECK constraint.
the data object containing the entity name, column name, and constraint definition
all of the entity fields in the system
the current user
a flag indicating whether or not to generate new code, this is set to false when we are just loading the generated code from the database.
a data structure with the function text, function name, function description, and a success flag
ProtectedgetProtectedgetReturns EntityNamingOptions derived from the entityNaming config section. These control ALL CAPS normalization and compound word splitting behavior.
ProtectedgetResolves entity name prefix/suffix rules for a given schema. The resolution order is:
If both sources define rules for the same schema, the config file wins and a console warning is emitted to alert the user of the override.
ProtectedgetThis method builds a SQL Statement that will insert a row into the EntityField table with information about a new field.
the new field
ProtectedgetCreates a SQL statement to retrieve all of the pending entity fields that need to be created in the metadata. This method looks for fields that exist in the underlying database but are NOT in the metadata.
IMPORTANT: The sequence calculation uses a dynamic offset based on the maximum existing sequence for each entity, plus 100,000, plus the column sequence. This ensures no collision with existing sequences while maintaining deterministic ordering. The spUpdateExistingEntityFieldsFromSchema stored procedure runs AFTER this method and will correct the sequences to ensure they are in the correct sequential order starting from 1. In a migration, the spUpdateExistingEntityFieldsFromSchema runs afterwards as well so this behavior ensures CodeGen works consistently.
OptionalentityIDs: string[]ProtectedgroupGroups FK fields by their entity pair key (ParentEntityID|ChildEntityID). This ensures all FK fields for the same entity pair are processed together, preventing the ping-pong bug where multi-FK pairs swap JoinFields on each run.
ProtectedhasChecks if a table has a soft primary key defined in the additionalSchemaInfo JSON file (configured in mj.config.cjs)
ProtectediifReturns an IIF/CASE expression. SQL Server: IIF(cond, t, f), PostgreSQL: CASE WHEN cond THEN t ELSE f END
ProtectedisReturns true if the field is a sensible target for IsNameField (i.e. could serve as the entity's human-readable display name). A name field must be BOUNDED TEXT ON THE BASE TABLE — so we reject primary keys, uniqueidentifiers, all non-text types, unbounded (MAX) text, and VIRTUAL fields. This stops Smart Field Identification from flagging a PK/uniqueidentifier as a name field, which would corrupt every related-entity name virtual field that joins to this entity (those resolve their SQL type from the related entity's NameField). Virtual fields are rejected because a view-only name column forces the FK-name join to target the VIEW instead of the base table — the self-referencing case is unbuildable on PostgreSQL and SQL Server (see the self-FK skip in the view generator), and a name that is itself a borrowed FK-name resolves circularly.
ProtectedisReturns true if the field is a sensible target for LIKE-based user search. Mirrors the runtime guard in GenericDatabaseProvider.isTextSearchableType / the Phase 1 hygiene migration so CodeGen stops re-introducing invalid flags.
ProtectedisHeuristic: does the entity name match the shape of an audit / log / run-history / change-tracking table? These are the entities that drive the most LIKE-scan time and almost never belong in global search.
ProtectedisThis method will load all generated code from the database - this is intended to be used when you are bypassing managing the metadata.
ProtectedloadLoads existing SchemaInfo records from the database into the cache so that entity name prefix/suffix rules are available before createNewEntities() runs. This is a read-only SELECT — it does NOT create or update any records.
Manages the creation, updating and deletion of entity field records in the metadata based on the database schema.
OptionalentityFilter: string[]Optional list of entity NAMES to scope the field-management work to. When provided,
the three SP/inline-SQL passes (delete unneeded, create new from schema, update existing from schema)
filter to those entities only. Other steps remain unscoped — they are cheap enough that scoping them
adds complexity without measurable benefit. An empty array short-circuits the entire method as a no-op,
which is the typical "no schema changes since last run" case in Pass 2.
undefined (default) preserves prior full-scan behavior.
ProtectedmanageProtectedmanageThis method creates and updates relationships in the metadata based on foreign key relationships in the database.
specify any schemas to exclude here and any relationships to/from the specified schemas will be ignored
ProtectedmanageProtectedmanageBaseline foreign-key consumption for an external entity: for each introspected single-column
relationship whose referenced remote object is ALSO an imported external entity in the same
data source, set the FK field's RelatedEntityID + RelatedEntityFieldName + IsSoftForeignKey=1.
The standard manageEntityRelationships pass then materializes these into EntityRelationship
records. Composite FKs and references to objects that aren't imported are skipped (logged) —
those are the follow-up hardening. Returns true if any FK field was updated.
ProtectedmanageManages M->M relationships between entities in the metadata based on foreign key relationships in the database. NOT IMPLEMENTED IN CURRENT VERSION IN BASE CLASS. M->M relationships ARE supported fully, but they are not AUTO generated by this method, instead an administrator must manually create these relationships in the metadata.
Primary function to manage metadata within the CodeGen system. This function will call a series of sub-functions to manage the metadata.
the ConnectionPool object to use for querying and updating the database
ProtectedmanageManages 1->M relationships between entities in the metadata based on foreign key relationships in the database.
specify any schemas to exclude here and any relationships to/from the specified schemas will be ignored
ProtectedmanageManages virtual EntityField records for IS-A parent entity fields. For each entity with ParentID set (IS-A child), creates/updates virtual field records that mirror the parent entity's base table fields (excluding PKs, timestamps, and virtual fields). Runs collision detection to prevent child table columns from shadowing parent fields.
ProtectedmanageCreates/updates virtual EntityField records for a single child entity's parent fields. Detects field name collisions between child's own base table columns and parent fields.
ProtectedmanageIntrospects the remote schema for a single external entity and syncs its EntityField rows.
Mirrors manageSingleVirtualEntity but sources the field list from the driver's
IntrospectSchema (mapped to MJ types via mapExternalNativeTypeToMJ) instead of the
local view's columns, and reuses manageSingleVirtualEntityField for create/update.
ProtectedmanageProtectedmanageProtectedmanageProtectedmarkupApplies entity name prefix/suffix rules to a given entity name. Rules are resolved from mj.config.cjs first, then from SchemaInfo database metadata as a fallback.
the database schema name
the base entity name to apply prefix/suffix to
ProtectednewProtectednextReturns a sequence value safe to use for an EntityField INSERT under the given
EntityID, defaulting to candidate when it doesn't collide. Otherwise returns
MAX(Sequence) + 1 for that entity.
Why this exists: several insert paths (virtual-entity field sync, IS-A parent field sync, schema-derived field creation) compute a deterministic sequence up-front, but a partial prior run can leave rows at that exact ordinal under the target EntityID. SS hides the collision because retried runs typically succeed before failing; PG raises UQ_EntityField_EntityID_Sequence (~4 errors per advanced-generation run). The values are temporary anyway — spUpdateExistingEntityFieldsFromSchema renumbers them on the next pass.
ProtectedparentChecks if an existing virtual parent field record needs to be updated to match the parent field.
ProtectedparseProtectedparseThis method takes the stored DEFAULT CONSTRAINT value from the database and parses it to retrieve the actual default value. This is necessary because the default value is sometimes wrapped in parentheses and sometimes wrapped in single quotes. This method removes the wrapping characters and returns the actual default value. Some common raw values that exist in SQL Server include 'getdate()', '(getdate())', 'N''SomeValue''', etc. and this method will remove those wrapping characters to get the actual underlying default value. NOTE: For future versions of MemberJunction where multiple back-end providers could be used, this method will be moved to the Provider architecture so that database-specific versions can be implemented, along with many other aspects of this current codebase.
ProtectedprimaryWhether a field's PK/Unique flags need to change. In RECONCILE mode (external entities, whose introspected PK set is authoritative across ALL fields) we sync in BOTH directions — setting the flags when a column becomes a PK AND clearing them when it stops being one (H5: otherwise a stale PK column keeps IsPrimaryKey=1 when the remote PK moves, yielding duplicate PKs). In NON-reconcile mode (virtual entities, where makePrimaryKey is a one-time first-column bootstrap, not authoritative) we only SET on acquisition and never clear — avoiding wiping a legitimately-configured PK, and avoiding a spurious UPDATE (+ __mj_UpdatedAt bump) every run when nothing changed. Pure function; unit-tested.
ProtectedprocessProcess entities in batches with parallel execution. Batch size is configurable via advancedGeneration.batchSize in mj.config.cjs (default: 5).
ProtectedprocessProcess advanced generation for a single entity
Database connection pool
Entity to process
Fields grouped by normalized EntityID (built once by the batch driver)
AdvancedGeneration instance
User context
ProtectedprocessProcesses Entity attribute configurations from the additionalSchemaInfo config. For each entry in the top-level "Entities" array, looks up the entity by BaseTable + SchemaName and applies any declared attribute updates to the Entity table. Reserved keys (BaseTable, SchemaName) are excluded from the UPDATE statement. Must run AFTER entities are created.
ProtectedprocessProcesses IS-A relationship configurations from the additionalSchemaInfo config. For each configured relationship, looks up both entities by name (or by table name within the given schema) and sets Entity.ParentID on the child entity. Must run AFTER entities are created but BEFORE manageParentEntityFields().
ProtectedprocessProcesses organic key configurations from additionalSchemaInfo. For each configured organic key:
All SQL is executed AND logged via LogSQLAndExecute for complete CI/CD traceability. Must run AFTER entities are created.
ProtectedprocessProcesses virtual entity configurations from the additionalSchemaInfo config. For each configured virtual entity, checks if it already exists and creates it if not. Uses the spCreateVirtualEntity stored procedure. Must run BEFORE manageVirtualEntities() so newly created entities get field-synced.
ProtectedqiQuotes a database identifier (column, table, etc.). SQL Server: [name], PostgreSQL: "name"
ProtectedqsProduces a schema-qualified object reference. SQL Server: [schema].[object], PostgreSQL: schema."object"
ProtectedqsqlQuotes mixed-case identifiers in a SQL string for the current platform. Delegates to the database provider's quoteSQLForExecution method.
ProtectedremoveRemoves stale One-To-Many EntityRelationship records whose RelatedEntityJoinField no longer corresponds to a valid FK field in the database. Only removes relationships where AutoUpdateFromSchema = true and Type = 'One To Many'.
ProtectedresolveResolves the AllowCaching default for a new entity in the given schema.
AllowCachingBySchema entries override the global AllowCaching default. The
${mj_core_schema} placeholder is expanded so core-schema rules apply
regardless of how the core schema is named in this deployment.
ProtectedresolveResolves a list of entity names to their UUIDs via the live Metadata cache. Names that don't resolve are dropped silently — they may be entities that have been queued for creation but aren't yet in the metadata.
Two safety properties:
new Metadata() is constructed OUTSIDE the per-name try/catch so a
metadata-load failure (e.g., refresh failed upstream) surfaces as an error
instead of being silently treated as "no entities resolved" — which would
misleadingly degrade Pass 2 to an unscoped full scan.EntityByName because that method throws
on null/empty names (_newEntityList and _modifiedEntityList can pick those
up from result-set rows whose EntityName column is null). The pre-filter on
string type + trim covers the common case; the catch is a safety net for any
other lookup failure (e.g., name shape we didn't anticipate).ProtectedresolveDesired PK/Unique flags for a virtual/external entity field. IsPrimaryKey mirrors makePrimaryKey; IsUnique is true ONLY for a SINGLE-column PK — a column of a COMPOSITE key is not unique on its own, so composite-key columns get IsUnique=false (M4). Pure function so the rule is unit-tested.
ProtectedrunExecutes a SQL query with automatic identifier quoting for the current platform.
ProtectedrunExecutes a parameterized SQL query with automatic identifier quoting for the current platform.
ProtectedsanitizeSanitizes an LLM-supplied codeType against the CK_EntityField_CodeType CHECK constraint. Uses MJEntityFieldSchema.shape.CodeType from @memberjunction/core-entities as the single source of truth — no hardcoded enum duplication. Values that fail Zod validation (e.g. 'Python', 'Markdown', 'javascript' wrong case) coerce to 'Other', preserving null/undefined. Logs any coercion so the underlying prompt drift is visible instead of silently failing the batch UPDATE at the DB.
ProtectedselectPicks the single IsNameField winner for an entity per the rules documented on
applyNameFieldUpdates: stable current winner → deterministic repair
(literal Name, then field order) → first eligible LLM candidate. Returns null
when nothing eligible exists (the entity simply has no name field — FK-name
virtual columns are skipped for it, which beats pointing them at a PK or blob).
ProtectedselectWraps a SELECT query with a row limit. SQL Server: SELECT TOP N ... , PostgreSQL: SELECT ... LIMIT N
OptionalorderBy: stringProtectedsetThis method updates the DefaultColumnWidth field in the EntityField metadata. The default logic uses a stored procedure called spSetDefaultColumnWidthWhereNeeded which is part of the MJ Core Schema. You can override this method to implement custom logic for setting default column widths. It is NOT recommended to modify the stored procedure in the MJ Core Schema because your changes will be overriden during a future upgrade.
ProtectedshouldProtectedsimpleProtectedsyncProtectedupdateThis method is responsible for generating a Display Name for each field where a display name is not already set. The approach in the base class uses a simple algorithm that looks for case changes in the field name and inserts spaces at those points. It also strips the trailing 'ID' from the field name if it exists. Override this method in a sub-class if you would like to implement a different approach for generating display names.
This method handles updating entity field related name field maps which is basically the process of finding the related entity field that is the "name" field for the related entity.
ProtectedupdateProtectedupdateOptionalentityIDs: string[]ProtectedupdateSyncs SchemaInfo records from database schemas, capturing extended properties as descriptions. Creates new SchemaInfo records for schemas that don't exist yet and updates descriptions from schema extended properties for existing records.
SQL connection pool
Array of schema names to exclude from processing
Promise
ProtectedutcReturns the current UTC timestamp expression. SQL Server: GETUTCDATE(), PostgreSQL: NOW() AT TIME ZONE 'UTC'
ProtectedvalidateValidates an LLM-suggested ExtendedType against the allowed values in EntityField. Returns the valid value (case-corrected) or null if invalid.
ProtectedvalidateFORWARD VALIDATION — verifies that every DECLARED IS-A relationship (any Entity with a non-null ParentID) actually satisfies what the IS-A runtime requires. Never mutates metadata.
Channel-agnostic BY DESIGN: it validates the END STATE of Entity.ParentID, so it covers the
additionalSchemaInfo "ISARelationships" config, an @lookup on ParentID in a metadata-sync
file, and any future channel — one check instead of one per declaration mechanism.
Reports ONLY provable-cannot-work defects (hard errors) — never inference. If a declared IS-A merely "looks off" but would still function, it passes silently: flagging it would misfire on correct declarations (see the note in the loop). The hard errors: - Child has a composite PK. The runtime routes ONE shared PK value between child and parent; it has no model for a multi-column subtype key. - Parent has a composite PK. Same reason, from the other side. - Child PK type <> parent PK type. Parent and child SHARE one PK value (Save() writes the child's PK into the parent's PK via ParentEntityFieldNames; loads match the child by the parent's PK value), so the value must be legal as BOTH PKs. Note a physical FK already guarantees matching types — this only ever fires on a soft/declared IS-A, which is exactly the case with no DB constraint to catch it. - ParentID does not resolve to an existing entity. DEFENSE-IN-DEPTH ONLY: the FK_Entity_ParentID constraint (Entity.ParentID -> Entity.ID) makes this state unstorable and vwEntities has no WHERE clause, so it is not reachable in a healthy database. It is kept because the parent JOIN must be a LEFT JOIN regardless, and without this branch an unresolved parent would silently SKIP the remaining checks (ParentPKType would be NULL) rather than fail. Covered by unit test, not live.
Timing: runs AFTER every ParentID-writing pass (config + any previously-synced @lookup) and BEFORE the 2nd-pass manageParentEntityFields() materializes IS-A virtual fields + view JOINs, so a broken declaration fails before it produces generated code.
StaticAddStaticaddAdds a list of entity names to the modified entity list if they're not already in there
StaticinvalidateDrops the cached soft PK/FK config so the next getSoftPKFKConfig call re-reads the
additionalSchemaInfo file from disk. REQUIRED for the long-lived in-process (RSU) CodeGen path:
the cache is process-static (load-once), which is correct for a one-shot mj codegen CLI run but
STALE in a long-running MJAPI where RSU rewrites additionalSchemaInfo on every ApplyAll. Without
invalidation, a connector's FIRST ApplyAll writes its soft PKs to the file but CodeGen returns the
pre-write cached config → "No primary key found" → the entity is never created → no entity map →
0 rows sync until an MJAPI restart. RunInProcess calls this at the start of every run (which always
follows RSU's WriteAdditionalSchemaInfo step), so each in-process run sees the freshly-written file.
Deterministic + event-driven (no mtime/TOCTOU race). The CLI Run() path does not call this, so its
load-once-per-process behavior is unchanged.
Returns the CodeGenDatabaseProvider for the current database platform. Lazily initialized from dbPlatform() configuration.
Lookup goes through
MJGlobal.ClassFactorykeyed by the platform string, which matches the@RegisterClass(CodeGenDatabaseProvider, '<platform>')decorators on the concrete providers ('sqlserver','postgresql'). Mismatched keys silently fall back to the abstract base class — fail loud with an explicit error so a misconfigured platform doesn't ship as a runtime breakage in dialect-specific methods.