Member Junction
    Preparing search index...

    PostgreSQL data provider for MemberJunction.

    Implements the full DatabaseProviderBase interface using the pg driver. Key differences from SQL Server:

    • Uses LIMIT/OFFSET instead of TOP/OFFSET-FETCH
    • Uses $1, $2 positional parameters instead of @p0,
    • Calls functions (SELECT * FROM fn_name()) instead of EXEC sp_name
    • Boolean columns use true/false instead of 1/0
    • Identifier quoting uses "double quotes" instead of [brackets]

    Hierarchy (View Summary)

    Implements

    Index

    Constructors

    Properties

    Accessors

    Methods

    _logSqlStatement AdjustDatetimeFields applyQueryPagination assertExternalReadAllowedUnderRLS assertExternalRunViewParamsSupported auditQueryExecution autoQuoteIdentifiers backgroundValidateAndRefresh BeginTransaction BuildAggregateSQL BuildChildDiscoverySQL BuildDatasetFilterFromConfig BuildDeleteExecuteOptions BuildEntityRecordNameSQL BuildHardLinkDependencySQL BuildKeysetSeekClause BuildNonPaginatedLimitSQL BuildPaginationSQL BuildParameterPlaceholder buildPerFieldSearchPredicate BuildRecordChangePayload BuildRecordChangeSQL BuildSaveExecuteOptions BuildSiblingRecordChangeSQL BuildSoftLinkDependencySQL BuildTopClause BuildTotalRowCountSQL buildWhereClauseForCacheCheck CacheDataset cacheDeniedForViewOnlyRequest cacheQueryResults CheckCreateRLS checkPagedQueryCache checkQueryCache CheckRecordRLS CheckToSeeIfRefreshNeeded CheckUserReadPermissions ClearDatasetCache CloneAllMetadata CoerceSaveFieldValue CommitTransaction CompleteMergeLogging computeLatestUpdateDate ComputeRunViewRLSWhereClause Config ConfigWithSharedPool ConvertItemFiltersToUniqueKey CopyMetadataFromGlobalProvider CreateAuditLogRecord CreateSharedMetadataShell CreateSqlLogger CreateTransactionGroup CreateUserDescriptionOfChanges createViewUserSearchSQL Delete DiffObjects Dispose DisposeAllSqlLoggingSessions EncryptFieldValuesForSave EnqueueAfterSaveAIAction enrichQueryResults EntityByID EntityByName EntityStatusCheck escapeLikeTerm EscapeQuotesInProperties ExecuteAdhocQuery ExecuteAggregateQuery ExecuteQueryFromSpec executeQueryWithTiming ExecuteSQL ExecuteSQLBatch executeSQLForUserViewRunLogging extractMaxUpdatedAt extractMaxUpdatedAtFromRows findAndValidateQuery FindISAChildEntities FindISAChildEntity formatKeysetSeekValue FullTextSearch GenerateDeleteSQL GenerateNewID GenerateSaveSQL GetActiveSqlLoggingSessions GetAllMetadata GetAndCacheDatasetByName getBatchedQueryCacheStatus getBatchedServerCacheStatus GetCachedDataset GetCachedRecordName getColumnsForDatasetItem GetCreateUpdateSPName GetCurrentUser GetDatasetByName GetDatasetCacheKey GetDatasetStatusByName getDeletedRecordIDsSince getDialect GetEntityAIActions GetEntityDependencies GetEntityObject GetEntityRecordName GetEntityRecordNames GetFullSubTree GetLatestMetadataUpdates GetLocalDatasetTimestamp GetRecordChanges GetRecordDependencies GetRecordDuplicates GetRecordFavoriteID GetRecordFavoriteStatus getRunTimeViewFieldArray getRunTimeViewFieldString GetSaveSQL GetSqlLoggingSessionById GetTransactionExtraData getUpdatedRowsSince HandleEntityActions HandleEntityAIActions InternalExecuteQueryFromSpec InternalGetEntityRecordName InternalGetEntityRecordNames InternalRouteOperation InternalRunQueries InternalRunQuery InternalRunView InternalRunViews invalidateInflightViewsForEntity isCacheCurrent isConnectionError IsDatasetCached IsDatasetCacheUpToDate IsEntityOrAncestorOf IsExternalQuery IsNonUUIDDatabaseFunction IsServerCacheAllowedForEntity isTextSearchableType IsUUIDGenerationFunction Load LoadLocalMetadataFromStorage LocalMetadataObsolete LogRecordChange MapTransactionResultToNewValues mergeCachedAndFreshResults mergeExternalViewParams mergeQueryCachedAndFreshResults MergeRecords OnAfterDeleteExecute OnAfterSaveExecute OnBeforeDeleteExecute OnBeforeSaveExecute OnResumeRefresh OnSaveCompleted OnSuspendRefresh OnValidateBeforeSave parseClientTimestamp PostProcessEntityMetadata PostProcessRows PostProcessRunView PostProcessRunViews PostRunQueries PostRunQuery PostRunView PostRunViews PreProcessRunView PreProcessRunViews PreRunQueries PreRunQuery PreRunView PreRunViews preValidateAndRefresh processQueryParameters PropagateRecordChangesToSiblings QuoteIdentifier QuoteSchemaAndView RebuildEntityMaps Refresh RefreshIfNeeded RefreshRemoteMetadataTimestamps RemoveLocalMetadataFromStorage RenderSaveCallBinding RenderViewWhereClause resolveCategoryPath resolveExternalCacheTTLMs ResolvePlatformSQLInParams resolveQuery ResolveQueryCacheAuthorization ResolveSQL RollbackTransaction RouteOperation RunColocatedSQL runDifferentialQueryAndReturn runExternalQueryWithCache runFullQueryAndCacheResult runFullQueryAndReturn runFullQueryAndReturnForQuery RunPostRunViewHooks RunPreRunViewHooks RunQueries RunQueriesWithCacheCheck RunQuery RunReport RunView runViewCacheEligible RunViews RunViewsWithCacheCheck Save SaveLocalMetadataToStorage SearchEntities searchEntitiesSemanticPass SearchEntity SetCachedRecordName SetLocalStorageProvider SetRecordFavoriteStatus shouldAutoCache ShouldTrackRecordChanges StartMergeLogging TransformExternalSQLClause TransformSimpleObjectToEntityObject translateTSQLDateFunctions TrimString UpdateLocalMetadata UseJsonArgShape ValidateDeleteResult ValidateQueryForExecution ValidateUserProvidedSQLClause warnIfExternalQueryFieldsMissing WrapSaveCallForResult WrapSaveCallWithRecordChange arrayBufferToBase64 base64ToArrayBuffer IsNonUUIDDatabaseFunctionAllPlatforms IsUUIDGenerationFunctionAllPlatforms LogSQLStatement UnionFieldsWithPrimaryKeys

    Constructors

    Properties

    _preRunQueriesResultType: {
        allCached: boolean;
        cachedResults?: RunQueryResult[];
        cacheStatusMap?: Map<
            number,
            {
                result?: RunQueryResult;
                status: "hit"
                | "miss"
                | "disabled"
                | "expired";
            },
        >;
        telemetryEventId?: string;
        uncachedParams?: RunQueryParams[];
    }

    Result from PreRunQueries hook containing cache status for batch operations

    _preRunQueryResultType: {
        cachedResult?: RunQueryResult;
        cacheStatus: "hit" | "miss" | "disabled" | "expired";
        fingerprint?: string;
        telemetryEventId?: string;
    }

    Result from PreRunQuery hook containing cache status and optional cached result

    _preRunViewResultType: {
        cachedResult?: RunViewResult;
        cacheStatus: "hit" | "miss" | "disabled" | "expired";
        callerRequestedFields?: string[] | null;
        fingerprint?: string;
        telemetryEventId?: string;
    }

    Result from PreRunView hook containing cache status and optional cached result

    Type Declaration

    • OptionalcachedResult?: RunViewResult
    • cacheStatus: "hit" | "miss" | "disabled" | "expired"
    • OptionalcallerRequestedFields?: string[] | null

      The caller's original Fields list (lowercased), captured before PreRunView widened params.Fields to all entity fields for cache-superset storage. Non-null ONLY when that widening actually happened — PostRunView uses it to project cache-miss DB results back down to the requested shape.

    • Optionalfingerprint?: string
    • OptionaltelemetryEventId?: string
    _preRunViewsResultType: {
        allCached: boolean;
        cachedResults?: RunViewResult[];
        cacheStatusMap?: Map<
            number,
            {
                result?: RunViewResult;
                status: "hit"
                | "miss"
                | "disabled"
                | "expired";
            },
        >;
        callerFieldsMap?: Map<number, string[]>;
        fingerprintMap?: Map<number, string>;
        smartCacheCheckParams?: RunViewWithCacheCheckParams[];
        telemetryEventId?: string;
        uncachedParams?: RunViewParams[];
        useSmartCacheCheck?: boolean;
    }

    Result from PreRunViews hook containing cache status for batch operations

    Type Declaration

    • allCached: boolean
    • OptionalcachedResults?: RunViewResult[]
    • OptionalcacheStatusMap?: Map<
          number,
          { result?: RunViewResult; status: "hit"
          | "miss"
          | "disabled"
          | "expired" },
      >
    • OptionalcallerFieldsMap?: Map<number, string[]>

      Per-param-index caller Fields lists (lowercased), captured before PreRunViews widened params.Fields to all entity fields for cache-superset storage. An index is present ONLY when that widening actually happened — PostRunViews uses it to project cache-miss DB results back down to the requested shape.

    • OptionalfingerprintMap?: Map<number, string>

      Per-param-index cache fingerprints computed during PreRunViews — carried forward so PostRunViews doesn't recompute the RLS where-clause and fingerprint string for every batch item.

    • OptionalsmartCacheCheckParams?: RunViewWithCacheCheckParams[]

      When CacheLocal is enabled, contains the cache check params to send to server

    • OptionaltelemetryEventId?: string
    • OptionaluncachedParams?: RunViewParams[]
    • OptionaluseSmartCacheCheck?: boolean

      When CacheLocal is enabled, indicates we should use smart cache check

    _mjMetadataDatasetName: string
    CoalesceWindowMs: number

    When enabled, concurrent RunViews calls arriving within the same microtask (or within CoalesceWindowMs) are merged into a single mega-batch before hitting the network. This dramatically reduces the number of HTTP round-trips during startup when multiple engines independently call RunViews in parallel.

    Set to 0 to disable coalescing. Default 10ms — enough to capture all engines that fire in the same tick, without adding perceptible delay.

    DedupLingerMs: number

    How long (ms) a resolved RunViews result stays available for instant replay. Set to 0 to disable the linger window (in-flight dedup still applies). Default 5 000 ms.

    MaxLingerEntries: number

    Safety cap on the number of linger entries held simultaneously. The linger window is a latency optimization — under extreme churn (more distinct query keys than this resolving within one window) new resolutions skip lingering instead of accumulating result arrays in memory.

    MinRefreshCheckIntervalMs: number

    Minimum interval (ms) between metadata refresh checks to prevent redundant network calls when Config()/RefreshIfNeeded() fire in quick succession (e.g., multiple engines during startup). Does NOT affect forced Refresh() calls. Default: 30 000 ms.

    ServerAutoCacheMaxRows: number

    Maximum row count for auto-caching on the server side. When TrustLocalCacheCompletely is true and a RunView result has no ExtraFilter, no OrderBy, and the result count is at or below this threshold, the result is automatically stored in LocalCacheManager even without an explicit CacheLocal flag.

    This captures small reference/lookup tables that are repeatedly queried by multiple clients while avoiding caching large ad-hoc result sets. Invalidation is handled by the standard BaseEntity event-driven upsert (safe because unfiltered caches can be updated in-place).

    Set to 0 to disable auto-caching. Default 250.

    Accessors

    • get AllExplorerNavigationItems(): ExplorerNavigationItem[]

      Gets all explorer navigation items including inactive ones.

      Returns ExplorerNavigationItem[]

      Array of all ExplorerNavigationItem objects

    • get AllMetadata(): AllMetadata

      Returns the currently loaded local metadata from within the instance

      Returns AllMetadata

    • get AllowRefresh(): boolean

      Determines if a refresh is currently allowed or not. Subclasses should return FALSE if they are performing operations that should prevent refreshes. This helps avoid metadata refreshes during critical operations.

      Returns boolean

    • get Applications(): ApplicationInfo[]

      Gets all application metadata in the system.

      Returns ApplicationInfo[]

      Array of ApplicationInfo objects representing all applications

    • get AuditLogTypes(): AuditLogTypeInfo[]

      Gets all audit log types defined for tracking system activities.

      Returns AuditLogTypeInfo[]

      Array of AuditLogTypeInfo objects

    • get AuthorizationRoles(): AuthorizationRoleInfo[]

      Gets the flat collection of authorization-role assignments. Consumed lazily by AuthorizationInfo.Roles — consumers should prefer accessing roles through AuthorizationInfo.Roles rather than filtering this array directly.

      Returns AuthorizationRoleInfo[]

      Array of AuthorizationRoleInfo join-table objects

    • get Authorizations(): AuthorizationInfo[]

      Gets all authorization definitions in the system.

      Returns AuthorizationInfo[]

      Array of AuthorizationInfo objects defining permissions

    • get CurrentUser(): UserInfo

      Gets the current user's information including roles and permissions.

      Returns UserInfo

      UserInfo object for the authenticated user

    • get DatabaseConnection(): Pool

      For providers that have ProviderType==='Database', this property will return an object that represents the underlying database connection. For providers where ProviderType==='Network' this property will throw an exception. The type of object returned is provider-specific (e.g., SQL connection pool).

      Returns Pool

    • get DBDefaultFunctionPattern(): RegExp

      Regex pattern matching known database default-value functions (non-UUID) for this provider's platform. SQL Server should match GETDATE, GETUTCDATE, SYSDATETIME, etc. PostgreSQL should match NOW, CURRENT_TIMESTAMP, clock_timestamp, etc. Case-insensitive, should match the full string with optional whitespace and parens.

      Returns RegExp

    • get Dialect(): PostgreSQLDialect

      The SQLDialect instance matching this provider's PlatformKey.

      Use this whenever runtime code needs to emit dialect-specific SQL (boolean literals, identifier quoting, casts, …) — it spares callers from doing GetDialect(provider.PlatformKey) every time, and keeps dialect resolution in one place. Resolves lazily and is cached so repeated access is free.

      Example:

      const lit = provider.Dialect.BooleanLiteral(true); // '1' on SS, 'TRUE' on PG
      

      Returns PostgreSQLDialect

    • get Entities(): EntityInfo[]

      Gets all entity metadata in the system.

      Returns EntityInfo[]

      Array of EntityInfo objects representing all entities

    • get FileSystemProvider(): IFileSystemProvider | null

      Returns the filesystem provider for the current environment. Default implementation returns null (no filesystem access). Server-side providers should override this to return a NodeFileSystemProvider.

      Returns IFileSystemProvider | null

    • get InstanceConnectionString(): string

      This property is implemented by each sub-class of ProviderBase and is intended to return a unique string that identifies the instance of the provider for the connection it is making. For example: for network connections, the URL including a TCP port would be a good connection string, whereas on database connections the database host url/instance/port would be a good connection string. This is used as part of cache keys to ensure different connections don't share cached data.

      Returns string

    • get IsInTransaction(): boolean

      Whether this provider currently has an active transaction. Subclasses that track transaction state should override this. Used by callers (e.g. runMaybeSerial) to decide whether to fan out concurrent saves or run them sequentially. Defaults to false for providers that don't expose this state.

      Returns boolean

    • get LatestLocalMetadata(): MetadataInfo[]

      Gets the latest metadata timestamps from local cache. Used for comparison with remote timestamps.

      Returns MetadataInfo[]

      Array of locally cached metadata timestamps

    • get LatestRemoteMetadata(): MetadataInfo[]

      Gets the latest metadata timestamps from the remote server. Used to determine if local cache is out of date.

      Returns MetadataInfo[]

      Array of metadata timestamp information

    • get Libraries(): LibraryInfo[]

      Gets all library definitions in the system.

      Returns LibraryInfo[]

      Array of LibraryInfo objects representing code libraries

    • get LocalStoragePrefix(): string

      This property will return the prefix to use for local storage keys. This is useful if you have multiple instances of a provider running in the same environment and you want to keep their local storage keys separate. The default implementation returns an empty string, but subclasses can override this to return a unique string based on the connection or other distinct identifier.

      Returns string

    • get LocalStorageProvider(): ILocalStorageProvider

      Returns the active local storage provider, lazily creating an InMemoryLocalStorageProvider if none has been set.

      This fulfills the abstract LocalStorageProvider requirement from ProviderBase and is shared by all database providers (SQL Server, PostgreSQL, and any future platforms).

      Returns ILocalStorageProvider

    • get MJCoreSchemaName(): string

      Gets the MemberJunction core schema name (e.g. '__mj'). Subclasses should override if they have a different way to resolve this. Defaults to the value from ConfigData.

      Returns string

    • get PlatformBatchSeparator(): string

      Returns the batch separator token for the underlying database platform by delegating to the SQLDialect instance returned by getDialect(). SQL Server → 'GO', PostgreSQL → '' (no separator needed). Auto-injected as the default batchSeparator in CreateSqlLogger.

      Returns string

    • get PreRunQueriesResult(): {
          allCached: boolean;
          cachedResults?: RunQueryResult[];
          cacheStatusMap?: Map<
              number,
              {
                  result?: RunQueryResult;
                  status: "hit"
                  | "miss"
                  | "disabled"
                  | "expired";
              },
          >;
          telemetryEventId?: string;
          uncachedParams?: RunQueryParams[];
      }

      Returns {
          allCached: boolean;
          cachedResults?: RunQueryResult[];
          cacheStatusMap?: Map<
              number,
              {
                  result?: RunQueryResult;
                  status: "hit"
                  | "miss"
                  | "disabled"
                  | "expired";
              },
          >;
          telemetryEventId?: string;
          uncachedParams?: RunQueryParams[];
      }

    • get PreRunQueryResult(): {
          cachedResult?: RunQueryResult;
          cacheStatus: "hit"
          | "miss"
          | "disabled"
          | "expired";
          fingerprint?: string;
          telemetryEventId?: string;
      }

      Returns {
          cachedResult?: RunQueryResult;
          cacheStatus: "hit" | "miss" | "disabled" | "expired";
          fingerprint?: string;
          telemetryEventId?: string;
      }

    • get PreRunViewResult(): {
          cachedResult?: RunViewResult;
          cacheStatus: "hit"
          | "miss"
          | "disabled"
          | "expired";
          callerRequestedFields?: string[] | null;
          fingerprint?: string;
          telemetryEventId?: string;
      }

      Returns {
          cachedResult?: RunViewResult;
          cacheStatus: "hit" | "miss" | "disabled" | "expired";
          callerRequestedFields?: string[] | null;
          fingerprint?: string;
          telemetryEventId?: string;
      }

      • OptionalcachedResult?: RunViewResult
      • cacheStatus: "hit" | "miss" | "disabled" | "expired"
      • OptionalcallerRequestedFields?: string[] | null

        The caller's original Fields list (lowercased), captured before PreRunView widened params.Fields to all entity fields for cache-superset storage. Non-null ONLY when that widening actually happened — PostRunView uses it to project cache-miss DB results back down to the requested shape.

      • Optionalfingerprint?: string
      • OptionaltelemetryEventId?: string
    • get PreRunViewsResult(): {
          allCached: boolean;
          cachedResults?: RunViewResult[];
          cacheStatusMap?: Map<
              number,
              {
                  result?: RunViewResult;
                  status: "hit"
                  | "miss"
                  | "disabled"
                  | "expired";
              },
          >;
          callerFieldsMap?: Map<number, string[]>;
          fingerprintMap?: Map<number, string>;
          smartCacheCheckParams?: RunViewWithCacheCheckParams[];
          telemetryEventId?: string;
          uncachedParams?: RunViewParams[];
          useSmartCacheCheck?: boolean;
      }

      Returns {
          allCached: boolean;
          cachedResults?: RunViewResult[];
          cacheStatusMap?: Map<
              number,
              {
                  result?: RunViewResult;
                  status: "hit"
                  | "miss"
                  | "disabled"
                  | "expired";
              },
          >;
          callerFieldsMap?: Map<number, string[]>;
          fingerprintMap?: Map<number, string>;
          smartCacheCheckParams?: RunViewWithCacheCheckParams[];
          telemetryEventId?: string;
          uncachedParams?: RunViewParams[];
          useSmartCacheCheck?: boolean;
      }

      • allCached: boolean
      • OptionalcachedResults?: RunViewResult[]
      • OptionalcacheStatusMap?: Map<
            number,
            { result?: RunViewResult; status: "hit"
            | "miss"
            | "disabled"
            | "expired" },
        >
      • OptionalcallerFieldsMap?: Map<number, string[]>

        Per-param-index caller Fields lists (lowercased), captured before PreRunViews widened params.Fields to all entity fields for cache-superset storage. An index is present ONLY when that widening actually happened — PostRunViews uses it to project cache-miss DB results back down to the requested shape.

      • OptionalfingerprintMap?: Map<number, string>

        Per-param-index cache fingerprints computed during PreRunViews — carried forward so PostRunViews doesn't recompute the RLS where-clause and fingerprint string for every batch item.

      • OptionalsmartCacheCheckParams?: RunViewWithCacheCheckParams[]

        When CacheLocal is enabled, contains the cache check params to send to server

      • OptionaltelemetryEventId?: string
      • OptionaluncachedParams?: RunViewParams[]
      • OptionaluseSmartCacheCheck?: boolean

        When CacheLocal is enabled, indicates we should use smart cache check

    • get ProcedureParamLimit(): number

      PostgreSQL's FUNC_MAX_ARGS is 100 (compiled into the server, not configurable on managed services like RDS/Aurora/Cloud SQL). When a CRUD sproc would exceed this, CodeGen emits a JSON-arg shape instead of typed args.

      The actual value lives as the exported POSTGRESQL_PROCEDURE_PARAM_LIMIT constant at the top of this file, so runtime and codegen-time both reference one number — drift between them silently breaks CRUD calls.

      See plans/json-arg-crud-sprocs.md and GitHub issue #2552.

      Returns number

    • get Queries(): QueryInfo[]

      Returns QueryInfo[]

      Use QueryEngine.Instance.Queries from @memberjunction/core-entities. Will be removed in v6.x.

    • get QueryCategories(): QueryCategoryInfo[]

      Returns QueryCategoryInfo[]

      Use QueryEngine.Instance.Categories from @memberjunction/core-entities. Will be removed in v6.x.

    • get QueryDependencies(): QueryDependencyInfo[]

      Returns QueryDependencyInfo[]

      Use QueryEngine.Instance.Dependencies from @memberjunction/core-entities. Will be removed in v6.x.

    • get QueryEntities(): QueryEntityInfo[]

      Returns QueryEntityInfo[]

      Use QueryEngine.Instance.QueryEntities from @memberjunction/core-entities. Will be removed in v6.x.

    • get QueryFields(): QueryFieldInfo[]

      Returns QueryFieldInfo[]

      Use QueryEngine.Instance.Fields from @memberjunction/core-entities. Will be removed in v6.x.

    • get QueryParameters(): QueryParameterInfo[]

      Returns QueryParameterInfo[]

      Use QueryEngine.Instance.Parameters from @memberjunction/core-entities. Will be removed in v6.x.

    • get QueryPermissions(): QueryPermissionInfo[]

      Returns QueryPermissionInfo[]

      Use QueryEngine.Instance.Permissions from @memberjunction/core-entities. Will be removed in v6.x.

    • get QuerySQLs(): QuerySQLInfo[]

      Returns QuerySQLInfo[]

      Use QueryEngine.Instance.QuerySQLs from @memberjunction/core-entities. Will be removed in v6.x.

    • get Roles(): RoleInfo[]

      Gets all security roles defined in the system.

      Returns RoleInfo[]

      Array of RoleInfo objects representing all roles

    • get RowLevelSecurityFilters(): RowLevelSecurityFilterInfo[]

      Gets all row-level security filters defined in the system.

      Returns RowLevelSecurityFilterInfo[]

      Array of RowLevelSecurityFilterInfo objects for data access control

    • get SQLDialects(): SQLDialectInfo[]

      Returns SQLDialectInfo[]

      Use QueryEngine.Instance.SQLDialects from @memberjunction/core-entities. Will be removed in v6.x.

    • get TrustLocalCacheCompletely(): boolean

      Server-side providers trust the local cache completely because it is kept in perfect sync via BaseEntity save/delete events and cross-server Redis pub/sub. No lightweight DB validation needed on cache hits.

      Returns boolean

    • get UUIDFunctionPattern(): RegExp

      Regex pattern matching known database UUID/ID generation functions for this provider's platform. SQL Server should match NEWID, NEWSEQUENTIALID. PostgreSQL should match gen_random_uuid, uuid_generate_v4. Case-insensitive, should match the full string with optional whitespace and parens.

      Returns RegExp

    • get VisibleExplorerNavigationItems(): ExplorerNavigationItem[]

      Gets only active explorer navigation items sorted by sequence. Results are cached for performance.

      Returns ExplorerNavigationItem[]

      Array of active ExplorerNavigationItem objects

    Methods

    • Internal method to log SQL statement to all active logging sessions. This is called automatically by ExecuteSQL methods. Protected so platform-specific providers can reference it (e.g., to bind as a callback).

      Parameters

      • query: string

        The SQL query being executed

      • Optionalparameters: unknown

        Parameters for the query

      • Optionaldescription: string

        Optional description for this operation

      • OptionalignoreLogging: boolean

        If true, this statement will not be logged

      • OptionalisMutation: boolean

        Whether this is a data mutation operation

      • OptionalsimpleSQLFallback: string

        Optional simple SQL to use for loggers with logRecordChangeMetadata=false

      • OptionalcontextUser: UserInfo

        Optional user context for session filtering

      Returns Promise<void>

    • Virtual hook for platform-specific datetime field adjustments. Default implementation is a no-op (returns rows unchanged).

      SQL Server overrides this to correct datetime2/datetimeoffset/datetime timezone interpretation issues in the mssql driver. PostgreSQL does NOT need to override — PG timestamp types are timezone-aware natively.

      Parameters

      • rows: Record<string, unknown>[]

        The data rows to process

      • datetimeFields: EntityFieldInfo[]

        Entity fields with TSType === Date

      • entityInfo: EntityInfo

        The entity metadata

      Returns Promise<Record<string, unknown>[]>

      The rows with datetime fields adjusted (or unchanged for default)

    • Applies in-memory pagination to query results based on StartRow and MaxRows parameters.

      Parameters

      Returns { paginatedResult: Record<string, unknown>[]; totalRowCount: number }

    • Guards external-data-source reads against silently bypassing Row-Level Security. A remote system can't enforce MJ's RLS WHERE clauses, so if RLS would filter this user's rows we refuse the read with a clear error rather than returning unfiltered data. Users exempt from RLS (e.g. admins) get an empty clause and pass through — RLS wouldn't restrict them on an MJ-DB entity either. Called from the external RunView and Load dispatch points.

      Parameters

      Returns void

    • Rejects RunView params an external data source can't honor, rather than silently dropping them. Most important is AfterKey (keyset pagination): the external read path only supports offset paging, so a silently-dropped AfterKey would return the same page on every call — an infinite loop / duplicate processing in deep-pagination jobs. Aggregates and a non-empty UserSearchString likewise can't be evaluated remotely. Throws a clear error naming the param.

      Parameters

      Returns void

    • Creates an audit log record for query execution (fire-and-forget). Only logs if the query has AuditQueryRuns enabled or ForceAuditLog is set.

      Parameters

      Returns void

    • Quotes mixed-case identifiers in a raw SQL string for PostgreSQL. Walks the string token by token, skipping string literals, dollar-quoted blocks, already-quoted identifiers, square-bracketed identifiers, and @-prefixed parameters. Any remaining word that starts with uppercase and isn't a known SQL keyword gets wrapped in double quotes so PG preserves the case when resolving it against the schema.

      Idempotent — safe to call on already-quoted SQL (those identifiers are skipped by skipDoubleQuotedIdentifier).

      Parameters

      • sql: string

      Returns string

    • Background validation for the stale-while-revalidate fast-start pattern. Checks if local metadata is still current; if stale, fetches fresh metadata and atomically swaps it in. The app continues operating on cached data during this process — no blocking.

      Parameters

      Returns Promise<void>

    • BeginTransaction with nested-transaction support via SAVEPOINTs.

      • First call: AcquireClient + BEGIN.
      • Subsequent calls (within the same provider instance): emit a uniquely-named SAVEPOINT on the same client. PG savepoints are arbitrary-depth, so nesting from frameworks like TransactionGroups composes correctly.

      Mirrors SQLServerDataProvider's depth/savepoint-stack model so that any caller treating the provider polymorphically gets identical semantics across both backends.

      Returns Promise<void>

    • Builds and validates an aggregate SQL query from the provided aggregate expressions. Uses SQLExpressionValidator from @memberjunction/global for injection prevention. Uses QuoteIdentifier/QuoteSchemaAndView for dialect-neutral SQL generation.

      Parameters

      • aggregates: { alias?: string; expression: string }[]

        Array of aggregate expressions to validate and build

      • entityInfo: EntityInfo

        Entity metadata for field reference validation

      • schemaName: string

        Schema name for the entity

      • baseView: string

        Base view name for the entity

      • whereSQL: string

        WHERE clause to apply (without the WHERE keyword)

      Returns { aggregateSQL: string | null; validationErrors: AggregateResult[] }

      Object with aggregateSQL string and any validation errors

    • Builds the SQL to retrieve the "name" field value for a specific entity record. Uses QuoteIdentifier/QuoteSchemaAndView for dialect-neutral SQL generation.

      Parameters

      • entityName: string

        The entity name

      • compositeKey: CompositeKey

        The record's primary key

      Returns string | null

      The SQL query string, or null if the entity has no name field

    • Validates that the entity and RunViewParams are compatible with keyset (AfterKey) pagination, then returns the SQL predicate (<pk> > 'value' or <pk> < 'value') and the resolved order-by direction.

      See AfterKeyNotSupportedError for the validation rules and RunViewParams.AfterKey for the API contract.

      Parameters

      Returns { direction: "ASC" | "DESC"; pkColumnName: string; seekPredicate: string }

      AfterKeyNotSupportedError on validation failure

    • Builds a parameter placeholder for parameterized queries. Default: PG-style ($1, $2, ...). SQL Server overrides to @p0, @p1, etc.

      Parameters

      • index: number

        Zero-based parameter index

      Returns string

    • PostgreSQL per-field search predicate. The base (SQL Server) form emits N'...' string literals and ESCAPE '\' on LIKE — both invalid on PostgreSQL (N'...' is not a PG literal prefix, and the auto-quoting wraps the bare ESCAPE keyword, producing syntax error at or near "ESCAPE"). PostgreSQL's default backslash-escape behavior in LIKE makes the explicit ESCAPE clause unnecessary, so we emit plain quoted literals with no N prefix and no ESCAPE.

      Parameters

      Returns string

    • Builds the dialect-agnostic payload for a RecordChange row from the entity's old/new data and an optional restore context. Concrete providers consume the returned payload to render their dialect-specific SQL (SQL Server EXEC, PostgreSQL INSERT, etc.).

      Returns null when there's nothing to log — i.e., an Update where DiffObjects found no field-level changes. Creates and Deletes are always logged (one side of oldData/newData is null).

      The payload's recordID is whatever the caller passes in. PG's inline CTE save/delete paths can pass an empty string and resolve the actual RecordID expression in SQL (because the post-INSERT PK isn't known in JS); the standalone BuildRecordChangeSQL path passes a fully-resolved composite-key string.

      Parameters

      • newData: Record<string, unknown> | null

        Post-change data (null for deletes).

      • oldData: Record<string, unknown> | null

        Pre-change data (null for creates).

      • recordID: string

        Composite-key serialized RecordID, or empty for CTE callers.

      • entityInfo: EntityInfo

        Entity metadata (provides EntityID + field shapes for diff).

      • type: "Create" | "Update" | "Delete"

        Change type. Create and Delete skip the change-key short-circuit.

      • user: UserInfo

        Acting user (provides UserID).

      • OptionalrestoreContext: RestoreContext | null

        When non-null, populates source='Restore' plus the lineage columns; otherwise source='Internal'.

      • OptionalquoteToEscape: string

        Quote character for EscapeQuotesInProperties and DiffObjects. Defaults to single quote.

      Returns RecordChangePayload | null

    • Builds PostgreSQL INSERT INTO "RecordChange" SQL for record change logging. Uses parameterized queries with $N placeholders.

      Dialect-agnostic payload assembly (diff, JSON serialization, restore lineage derivation) is hoisted into DatabaseProviderBase.BuildRecordChangePayload, so this method only renders the parameterized INSERT.

      Parameters

      • newData: Record<string, unknown> | null
      • oldData: Record<string, unknown> | null
      • entityName: string
      • recordID: string
      • entityInfo: EntityInfo
      • type: "Create" | "Update" | "Delete"
      • user: UserInfo
      • OptionalrestoreContext: RestoreContext | null

        When non-null, the row is written with Source='Restore', RestoredFromID = SourceChangeID, and RestoreReason = Reason. When null, defaults to Source='Internal' with NULL lineage columns.

      Returns { parameters?: unknown[]; sql: string } | null

    • Builds PostgreSQL SQL for a single sibling entity in the Record Change propagation batch. Uses row_to_json to get the full record JSON, then conditionally inserts a Record Change entry.

      Parameters

      • _varName: string
      • entityInfo: EntityInfo
      • safeChangesJSON: string
      • safeChangesDesc: string
      • safePKValue: string
      • safeUserId: string

      Returns string

    • Builds a platform-specific TOP/LIMIT clause for non-paginated row limits. SQL Server: TOP N; PostgreSQL returns empty (uses LIMIT via BuildPaginationSQL). Default: returns empty string. SQL Server overrides.

      Parameters

      • _maxRows: number

      Returns string

    • Builds the SELECT COUNT(*) AS TotalRowCount FROM ... SQL used to compute the total row count for paginated views. Returns null when the view isn't row-limited (no count query needed).

      Two PG-parity details this method encapsulates — both caught real regressions:

      1. When to emit the count query. Returns non-null whenever rows are being limited — either explicit pagination or MaxRows/UserViewMaxRows. Earlier code keyed off topSQL.length > 0, which was SQL-Server-specific: PG's BuildTopClause returns empty (PG uses LIMIT appended at end via BuildNonPaginatedLimitSQL, not TOP in the SELECT). So the old condition missed every PG case where MaxRows was set without explicit StartRow — Explorer's Entity list was one such case and showed "100 of 100" (no pagination) instead of "100 of 299".

      2. Quote the alias via QuoteIdentifier. PostgreSQL folds unquoted column aliases to lowercase, so AS TotalRowCount returns a row keyed totalrowcount on PG. The caller reads countResult[0].TotalRowCount (PascalCase) and gets undefined — the count falls back to retData.length (the page size), so pagination breaks silently. SQL Server is case-insensitive so it worked unquoted there. Quoting via QuoteIdentifier produces "TotalRowCount" on PG and [TotalRowCount] on SQL Server — both preserve case.

      Parameters

      • entityInfo: EntityInfo
      • usingPagination: boolean
      • maxRowsForQuery: number

      Returns string | null

    • Builds the WHERE clause for cache status check, using same logic as InternalRunView. Handles ExtraFilter, UserSearch, and Row-Level Security. Subclasses can override to add platform-specific SQL transformations (e.g., identifier quoting).

      Parameters

      Returns Promise<string>

    • SECURITY — decide whether the shared cache must be BYPASSED for a RunView that targets a saved VIEW rather than a named entity (no EntityName), under a context user.

      The cache-hit path returns BEFORE the DB provider's read-permission gate (CheckUserReadPermissions). The primary gate keys off the entity resolved from params.EntityName, so a ViewID-/ViewName-only request (the Explorer-standard shape for a saved view) yields no entity there and the gate is disarmed — a read-denied user could be served rows a permitted user warmed for the same ViewID. The vw: fingerprint segment makes the two users' requests collide on exactly one slot, so the leak is clean.

      Returns true when the cache must be skipped for this call (fail-closed):

      • ViewEntity supplied and its entity resolves → apply the normal CanRead gate on it (allow caching for a permitted user; deny for a read-denied one).
      • ViewEntity absent/unresolvable but ViewID/ViewName present → fail closed: the view's real entity (hence the user's permission) is only known after the async MJ: User Views lookup that the cache-hit path deliberately skips, so we cannot safely consult the cache. Returns false when there is no context user, when EntityName is set (the normal gate owns that path), or when no view identifier is present at all (nothing to gate).

      Parameters

      Returns boolean

    • Caches query results if caching is enabled for the query. Currently a no-op (query caching is not active).

      Parameters

      Returns Promise<void>

    • Checks whether a new record's field values pass the Create RLS filter. Builds a synthetic single-row subquery from entity field values, then tests the RLS filter against it.

      Parameters

      Returns Promise<boolean>

    • Checks if local metadata is out of date and needs refreshing. Compares local timestamps with server timestamps.

      Parameters

      Returns Promise<boolean>

      True if refresh is needed, false otherwise

    • Checks that the given user has read permissions on the specified entity. Throws if the user lacks CanRead permission.

      Parameters

      • entityName: string

        The entity to check permissions for

      • contextUser: UserInfo

        The user whose permissions to check

      Returns void

      Error if contextUser is null, entity is not found, or user lacks read permission

    • If the specified datasetName is cached, this method will clear the cache. If itemFilters are provided, the combination of datasetName and the filters are used to determine a match in the cache

      Parameters

      Returns Promise<void>

    • CommitTransaction with savepoint-aware semantics.

      • Outermost (depth was 1): real COMMIT and release the client.
      • Nested (depth > 1): RELEASE SAVEPOINT, drop from stack, decrement depth. Releasing a savepoint discards it but does NOT commit anything yet — the work it represents is folded into the enclosing transaction and only persists when that enclosing transaction commits.

      Returns Promise<void>

    • Computes the latest update date for a dataset item from its result rows and dataset metadata. Used by both the cache-hit and cache-miss paths in GetDatasetByName.

      Parameters

      • rows: unknown[]

        The result rows (from cache or SQL)

      • dateFieldToCheck: string

        The field name to scan for latest date

      • item: Record<string, unknown>

        The dataset item metadata row (contains DatasetItemUpdatedAt, DatasetUpdatedAt)

      Returns Date

      The latest date across all rows and dataset metadata

    • Computes the per-user Row-Level-Security WHERE clause that InternalRunView will append to this query's SQL for the given user, so it can be folded into the cache fingerprint. RLS-scoped reads return a different result set than unscoped reads of the same entity+filter; without including the RLS clause in the cache key, a scoped user could be served a cached unscoped result set (a data leak).

      Returns '' when the user is exempt from RLS on this entity (the common case), which makes the resulting fingerprint byte-identical to the pre-RLS format — preserving normal cache sharing.

      Uses this (the active provider) to resolve the entity, never the global Metadata, so the correct per-provider/per-tenant metadata is consulted.

      Parameters

      Returns string

    • Adopts the global provider's metadata for this instance without reloading it from the server: shares the (immutable post-Config) metadata arrays by reference via CreateSharedMetadataShell and builds this instance's entity lookup maps.

      Returns boolean

    • Creates an audit log record in the MJ: Audit Logs entity. Uses BaseEntity with .Set() calls (no typed entity subclass imports needed - can't use those from MJCore anyway). Callers typically fire-and-forget.

      Parameters

      • user: UserInfo

        The user performing the action

      • authorizationName: string | null

        Optional authorization name to look up

      • auditLogTypeName: string

        The audit log type name (must exist in metadata)

      • status: string

        'Success' or 'Failed'

      • details: string | null

        Optional details (JSON string, description, etc.)

      • entityId: string

        The entity ID being audited

      • recordId: string | null

        Optional record ID being audited

      • auditLogDescription: string | null

        Optional description for the audit log

      • saveOptions: EntitySaveOptions | null

        Save options to pass to the entity Save() call

      Returns Promise<BaseEntity<unknown> | null>

      The saved audit log BaseEntity, or null on error

    • Builds this instance's AllMetadata as a thin shell over another provider's already-loaded metadata: every metadata array is a PER-INSTANCE shallow copy whose elements are the SHARED Info object instances, and CurrentUser remains this instance's own.

      Why sharing the instances is safe — and why this replaced the former deep clone (CloneAllMetadata) on the reuse-global fast path: the metadata graph is immutable after Config. Refreshes swap the WHOLE AllMetadata object (UpdateLocalMetadata), never mutate the Info objects in place, so the only per-instance datum inside the graph is CurrentUser — which this shell keeps independent. The deep clone cost ~1s of event-loop-blocking constructor work per provider on every server request (MemberJunction/MJ#3083); the shell is ~20 array-of-pointer copies (microseconds).

      Why the array containers are copied rather than aliased: an in-place .sort()/.push()/.splice() by request-scoped code then stays local to that provider — matching the clone era's isolation for the common accidental mutation class — instead of reordering the global graph for every other in-flight request. Only the top-level AllMetadata collections get this per-instance protection: everything below them is shared, including the nested arrays owned by Info objects (entity.Fields, entity.RelatedEntities, application.ApplicationEntities, ...) — an in-place mutation of those is process-wide. Property writes on the shared Info objects themselves are likewise visible process-wide (as they always were on the client's global provider): treat Info objects and everything they own as read-only; copy before sorting.

      Override precedence: if a subclass overrides BOTH this method and the deprecated CloneAllMetadata, the CloneAllMetadata override wins on the fast path (see CopyMetadataFromGlobalProvider) — the conservative back-compat choice, since pre-#3083 subclasses could only have customized adoption through CloneAllMetadata. Remove the CloneAllMetadata override to activate a CreateSharedMetadataShell override.

      Parameters

      Returns AllMetadata

    • Creates a new SQL logging session that will capture all SQL operations to a file. Returns a disposable session object that must be disposed to stop logging.

      Parameters

      • filePath: string

        Full path to the file where SQL statements will be logged

      • Optionaloptions: SqlLoggingOptions

        Optional configuration for the logging session

      Returns Promise<SqlLoggingSession>

      Promise - Disposable session object

      // Basic usage
      const session = await provider.CreateSqlLogger('./logs/metadata-sync.sql');
      try {
      // Perform operations that will be logged
      await provider.ExecuteSQL('INSERT INTO ...');
      } finally {
      await session.dispose(); // Stop logging
      }

      // With migration formatting
      const session = await provider.CreateSqlLogger('./migrations/changes.sql', {
      formatAsMigration: true,
      description: 'MetadataSync push operation'
      });
    • Converts a diff/changes object into a human-readable description of what changed.

      Parameters

      • changesObject: Record<string, FieldChange>

        The output of DiffObjects()

      • OptionalmaxValueLength: number

        Maximum length for displayed values before truncation

      • OptionalcutOffText: string

        Text to append when values are truncated

      Returns string

    • Builds user search SQL for the given entity and search string.

      Supports full-text search (if enabled) and field-by-field LIKE searching. For the LIKE path:

      • honors EntityField.UserSearchPredicateAPI (Exact / BeginsWith / EndsWith / Contains) so index-seekable predicates can be expressed,
      • escapes LIKE metacharacters (%, _, [, ]) in user input with ESCAPE '\',
      • skips fields that are not sensible text-search targets (non-text types, unbounded text columns when FTX is off).

      Parameters

      Returns string

    • Deletes an entity record — the full orchestration flow shared by all DB providers.

      1. Permission checks & replay handling
      2. SQL generation via GenerateDeleteSQL (abstract, provider-specific)
      3. Before-delete actions via OnBeforeDeleteExecute hook
      4. Execute via TransactionGroup or directly
      5. Validate delete result (PK match check)
      6. After-delete actions via OnAfterDeleteExecute hook

      Parameters

      Returns Promise<boolean>

    • Creates a changes object by comparing two JavaScript objects, identifying fields that have different values. Each property in the returned object represents a changed field, with the field name as the key.

      Parameters

      • oldData: Record<string, unknown>

        The original data object to compare from

      • newData: Record<string, unknown>

        The new data object to compare to

      • entityInfo: EntityInfo

        Entity metadata used to validate fields and determine comparison logic

      • quoteToEscape: string

        The quote character to escape in string values (typically "'")

      Returns Record<string, FieldChange> | null

      A Record mapping field names to FieldChange objects, or null if either input is null/undefined. Only includes fields that have actually changed and are not read-only.

    • Disposes all active SQL logging sessions. Useful for cleanup on provider shutdown.

      Returns Promise<void>

    • Encrypts field values before saving to the database.

      This method handles field-level encryption for any entity with encrypted fields. It is called by platform-specific providers (SQL Server, PostgreSQL) before building their SQL parameters, ensuring encryption is handled generically.

      For each field marked with Encrypt=true:

      • If EncryptionKeyID is null → throws an error (misconfiguration)
      • If value is null/undefined → skips (nothing to encrypt)
      • If value is already encrypted → skips (prevents double-encryption)
      • Otherwise → encrypts the value using the configured key

      Parameters

      • entity: BaseEntity

        The entity being saved

      • fieldValues: Map<EntityFieldInfo, unknown>

        Map of field info to current values — values are mutated in-place

      • OptionalcontextUser: UserInfo

        User context for encryption operations

      Returns Promise<void>

      Error if a field is marked for encryption but has no EncryptionKeyID configured

      Error if encryption fails (to prevent storing unencrypted sensitive data)

    • Optional, additive post-query enrichment step. Resolves the QueryResultEnricherBase registered under params.Enrichment.EnricherKey via the MJGlobal ClassFactory and awaits it on the result rows, returning whatever (column-appended) rows it produces.

      Fully decoupled + resilient by design:

      • Decoupled: the enricher is resolved by string key through the ClassFactory, so this provider takes no static dependency on any concrete enricher (e.g. Predictive Studio's ML-scoring enricher). When no enricher is registered under the key — i.e. the providing package isn't loaded — resolveQueryResultEnricher returns null and we no-op, returning the original rows.
      • Resilient: the whole call is wrapped in try/catch. On ANY failure (resolution, scorer error, bad config) we LogError and return the ORIGINAL un-enriched rows. A scoring problem must NEVER break the underlying query.

      The loaded QueryInfo (when resolvable from the executed query's id) is passed through so an enricher can read the query's associated entity/fields.

      Parameters

      • rows: Record<string, unknown>[]

        the assembled, paginated result rows to enrich

      • params: RunQueryParams

        the run params carrying the RunQueryEnrichment directive

      • query: MJQueryEntityExtended

        the executed query entity (used to resolve its QueryInfo metadata)

      • OptionalcontextUser: UserInfo

        the request user, threaded through for isolation/audit

      Returns Promise<Record<string, unknown>[]>

      the enriched rows on success, or the original rows on any failure / no-op

    • O(1) entity lookup by ID (UUID-normalized). Falls back to linear search if the internal Map hasn't been built yet.

      Parameters

      • entityID: string

      Returns EntityInfo | undefined

    • O(1) entity lookup by name (case-insensitive, trimmed). Falls back to linear search if the internal Map hasn't been built yet.

      Parameters

      • entityName: string

      Returns EntityInfo | undefined

    • Used to check to see if the entity in question is active or not If it is not active, it will throw an exception or log a warning depending on the status of the entity being either Deprecated or Disabled.

      Parameters

      Returns Promise<void>

    • Escape characters that have special meaning in SQL Server LIKE patterns. The backslash itself must be escaped first so its replacement isn't reprocessed. Pair with ESCAPE '\\' on the LIKE clause.

      Parameters

      • safeTerm: string

      Returns string

    • Recursively escapes the specified quote character in all string properties of an object or array. Essential for preparing data to be embedded in SQL strings.

      Parameters

      • obj: unknown

        The object, array, or primitive value to process

      • quoteToEscape: string

        The quote character to escape (typically single quote "'")

      Returns unknown

      A new object/array with all string values having quotes properly escaped

    • Executes an aggregate query and maps results back to the original expressions.

      Parameters

      • aggregateSQL: string | null

        The SQL query to execute (from BuildAggregateSQL)

      • aggregates: { alias?: string; expression: string }[]

        Original aggregate expression definitions

      • validationErrors: AggregateResult[]

        Any validation errors from BuildAggregateSQL

      • OptionalcontextUser: UserInfo

        User context for query execution

      Returns Promise<{ executionTime: number; results: AggregateResult[] }>

      Array of AggregateResult objects with execution time

    • Executes a query from a QueryExecutionSpec — the lower-layer interface-based entry point. Runs the full pipeline: composition resolution → Nunjucks template processing → SQL execution. Subclasses (GenericDatabaseProvider) provide the concrete implementation via InternalExecuteQueryFromSpec.

      Parameters

      • spec: QueryExecutionSpec

        The execution spec describing the query, parameters, and inline dependencies

      • OptionalcontextUser: UserInfo

        Optional user context for permissions (required server-side)

      Returns Promise<RunQueryResult>

      Query results including data rows and execution metadata

    • Executes the query SQL and tracks execution time.

      Parameters

      • sql: string
      • OptionalcontextUser: UserInfo

      Returns Promise<{ executionTime: number; result: Record<string, unknown>[] }>

    • Executes multiple SQL queries and returns an array of result arrays, one per query.

      The default implementation runs queries in parallel using Promise.all(ExecuteSQL(...)). Platform-specific providers can override for true multi-result-set batching:

      • SQL Server: concatenates queries and uses a single mssql request with multiple recordsets
      • PostgreSQL: could use pg pipeline or simple parallel execution

      Parameters

      • queries: string[]

        Array of SQL query strings to execute

      • Optionalparameters: unknown[][]

        Optional array of parameter arrays, one per query

      • Optionaloptions: ExecuteSQLBatchOptions

        Optional batch execution options

      • OptionalcontextUser: UserInfo

        Optional user context for logging/filtering

      Returns Promise<Record<string, unknown>[][]>

      Array of result arrays, one for each query

    • Optionally wraps a view query with user view run logging. SQL Server overrides to use spCreateUserViewRunWithDetail. Default: returns null (no view run logging).

      Parameters

      • _viewId: number
      • _entityBaseView: string
      • _whereSQL: string
      • _orderBySQL: string
      • _user: UserInfo

      Returns Promise<{ executeViewSQL: string; runID: string } | null>

    • Extracts the MAX value of a specified date field from result rows as an ISO string. Used for write-through caching of dataset item results.

      Parameters

      • rows: unknown[]

        The result rows

      • dateFieldToCheck: string

        The field name to scan

      Returns string

      ISO string of the max date, or current time if no dates found

    • Discovers ALL IS-A child entities that have records with the given primary key. Used for overlapping subtype parents (AllowMultipleSubtypes = true) where multiple children can coexist.

      Parameters

      • entityInfo: EntityInfo

        The parent entity whose children to search

      • recordPKValue: string

        The primary key value to find in child tables

      • OptionalcontextUser: UserInfo

        Optional context user for audit/permission purposes

      Returns Promise<{ ChildEntityName: string }[]>

      Array of child entity names found (empty if none)

    • Discovers which IS-A child entity, if any, has a record with the given primary key. Executes a single UNION ALL query across all child entity tables for maximum efficiency.

      Parameters

      • entityInfo: EntityInfo

        The parent entity whose children to search

      • recordPKValue: string

        The primary key value to find in child tables

      • OptionalcontextUser: UserInfo

        Optional context user for audit/permission purposes

      Returns Promise<{ ChildEntityName: string } | null>

      The child entity name if found, or null if no child record exists

    • Formats a CompositeKey value as a SQL literal for use in a keyset seek predicate.

      This bypasses parameter binding because the entire WHERE clause is built as a string elsewhere in this provider (consistent with ExtraFilter / OrderBy handling). The seek value comes from server-side application code, not raw user input — but we still type- check and escape to defend against any caller passing a tainted value.

      Strategy:

      • UUID types: validate strict UUID format, wrap in single quotes
      • Numeric types: validate finite number, output bare
      • Boolean: output 0/1 (SQL Server) or TRUE/FALSE (caller can override if needed)
      • Date/time types: validate ISO-ish string, wrap in single quotes
      • String types: escape single quotes by doubling, wrap in single quotes

      Parameters

      • value: unknown
      • sqlType: string

      Returns string

      AfterKeyNotSupportedError if the value fails type-specific validation

    • Performs a full-text search across all entities that have FullTextSearchEnabled=true. Uses the existing RunView + UserSearchString infrastructure which routes through the database-native FTS capabilities (SQL Server FREETEXT functions, PostgreSQL tsvector).

      This is the default implementation that works across all database providers. Each provider's createViewUserSearchSQL() method handles the platform-specific SQL generation.

      Parameters

      Returns Promise<FullTextSearchResult>

      /packages/MJCore/docs/FULL_TEXT_SEARCH_GUIDE.md for comprehensive documentation

    • Generates a new UUID suitable for use as a primary key or unique identifier. Uses uuidv4() from @memberjunction/global. Subclasses may override to provide platform-specific ID generation if needed.

      Returns string

      A new UUID string

    • Concrete implementation of the abstract save-SQL builder defined on DatabaseProviderBase. Iterates fields via the single IsSPParameter predicate, applies provider-specific value coercion, encrypts, then delegates parameter binding, result-capture wrapping, and record-change wrapping to abstract hooks the provider subclass implements.

      See plans/sp-save-builder-generic-layer-refactor.md (rev 4) for the design and the rev-3 lesson that motivated this shape.

      Parameters

      Returns Promise<SaveSQLResult>

    • Gets information about all active SQL logging sessions. Useful for monitoring and debugging.

      Returns {
          filePath: string;
          id: string;
          options: SqlLoggingOptions;
          startTime: Date;
          statementCount: number;
      }[]

      Array of session information objects

    • Retrieves all metadata from the server and constructs typed instances. Uses the MJ_Metadata dataset for efficient bulk loading.

      Parameters

      Returns Promise<AllMetadata>

      Complete metadata collection with all relationships

    • Executes cache status checks for multiple queries using their CacheValidationSQL. Default: parallel individual queries. SQL Server overrides for batch execution.

      Parameters

      Returns Promise<
          Map<
              number,
              {
                  errorMessage?: string;
                  maxUpdatedAt?: string;
                  rowCount?: number;
                  success: boolean;
              },
          >,
      >

    • Executes cache status checks for multiple views. Default: parallel individual queries (works on all platforms). SQL Server overrides to use ExecuteSQLBatch for multi-result-set efficiency.

      Parameters

      Returns Promise<
          Map<
              number,
              {
                  errorMessage?: string;
                  maxUpdatedAt?: string;
                  rowCount?: number;
                  success: boolean;
              },
          >,
      >

    • This routine gets the local cached version of a given datasetName/itemFilters combination, it does NOT check the server status first and does not fall back on the server if there isn't a local cache version of this dataset/itemFilters combination

      Parameters

      Returns Promise<DatasetResultType>

    • Asynchronous lookup of a cached entity record name. Returns the cached name if available, or undefined if not cached. Use this for synchronous contexts (like template rendering) where you can't await GetEntityRecordName().

      Parameters

      • entityName: string

        The name of the entity

      • compositeKey: CompositeKey

        The primary key value(s) for the record

      • OptionalloadIfNeeded: boolean

        If set to true, will load from database if not already cached

      Returns Promise<string | undefined>

      The cached display name, or undefined if not in cache

    • Validates columns for a dataset item and returns the column list string. Returns null if columns are invalid.

      Parameters

      • item: Record<string, unknown>
      • datasetName: string

      Returns string | null

    • Returns the stored procedure / function name for a Create or Update operation. Pure metadata lookup — no SQL execution needed. SQL Server uses spCreate/spUpdate naming, PostgreSQL uses the same pattern.

      Parameters

      • entity: BaseEntity

        The entity being saved

      • bNewRecord: boolean

        True for Create, false for Update

      Returns string

      The SP/function name

    • Retrieves a dataset by name, executing all item queries via ExecuteSQLBatch and aggregating results. Uses dialect-neutral quoting for all SQL construction.

      ExecuteSQLBatch gives SQL Server true multi-result-set batching automatically, while PG (and the default) use parallel individual queries.

      Parameters

      Returns Promise<DatasetResultType>

    • Creates a unique key for the given datasetName and itemFilters combination coupled with the instance connection string to ensure uniqueness when 2+ connections exist

      Parameters

      Returns string

    • Gets IDs of records deleted since a given timestamp. Uses dialect-neutral quoting. Subclasses can override for parameterized queries.

      Parameters

      • entityID: string
      • sinceTimestamp: string
      • OptionalcontextUser: UserInfo

      Returns Promise<string[]>

    • Creates a new instance of a BaseEntity subclass for the specified entity and automatically calls NewRecord() to initialize it. This method serves as the core implementation for entity instantiation in the MemberJunction framework.

      Type Parameters

      Parameters

      • entityName: string

        The name of the entity to create (must exist in metadata)

      • OptionalcontextUser: UserInfo

        Optional user context for permissions and audit tracking

      Returns Promise<T>

      Promise resolving to the newly created entity instance with NewRecord() called

      Error if entity name is not found in metadata or if instantiation fails

    • Creates a new instance of a BaseEntity subclass and loads an existing record using the provided key. This overload provides a convenient way to instantiate and load in a single operation.

      Type Parameters

      Parameters

      • entityName: string

        The name of the entity to create (must exist in metadata)

      • loadKey: CompositeKey

        CompositeKey containing the primary key value(s) for the record to load

      • OptionalcontextUser: UserInfo

        Optional user context for permissions and audit tracking

      Returns Promise<T>

      Promise resolving to the entity instance with the specified record loaded

      Error if entity name is not found, instantiation fails, or record cannot be loaded

    • Gets the display name for a single entity record with caching. Uses the entity's IsNameField or falls back to 'Name' field if available.

      Parameters

      • entityName: string

        The name of the entity

      • compositeKey: CompositeKey

        The primary key value(s) for the record

      • OptionalcontextUser: UserInfo

        Optional user context for permissions

      • OptionalforceRefresh: boolean

        If true, bypasses cache and queries database

      Returns Promise<string>

      The display name of the record or null if not found

    • Gets display names for multiple entity records in a single operation with caching. More efficient than multiple GetEntityRecordName calls.

      Parameters

      • info: EntityRecordNameInput[]

        Array of entity/key pairs to lookup

      • OptionalcontextUser: UserInfo

        Optional user context for permissions

      • OptionalforceRefresh: boolean

        If true, bypasses cache and queries database for all records

      Returns Promise<EntityRecordNameResult[]>

      Array of results with names and status for each requested record

    • Returns the timestamp of the local cached version of a given datasetName or null if there is no local cache for the specified dataset

      Parameters

      • datasetName: string

        the name of the dataset to check

      • OptionalitemFilters: DatasetItemFilterType[]

        optional filters to apply to the dataset

      Returns Promise<Date>

    • Retrieves the change history for a specific record. Uses the vwRecordChanges view which exists in both SQL Server and PostgreSQL.

      Parameters

      • entityName: string

        The entity name

      • compositeKey: CompositeKey

        The record's composite primary key

      • OptionalcontextUser: UserInfo

        Optional context user

      Returns Promise<RecordChange[]>

    • Returns a list of record-level dependencies — records in other entities linked to the specified entity/record via foreign keys (hard links) or EntityIDFieldName soft links. Uses abstract SQL builders for dialect-specific query generation.

      Parameters

      • entityName: string

        The entity name to check

      • compositeKey: CompositeKey

        The primary key(s) of the record

      • OptionalcontextUser: UserInfo

        Optional context user

      Returns Promise<RecordDependency[]>

    • Gets the favorite record ID if the record is a favorite for the given user, null otherwise.

      Parameters

      Returns Promise<string | null>

    • Checks if a record is marked as a favorite for a given user.

      Parameters

      Returns Promise<boolean>

    • Gets a specific SQL logging session by its ID. Returns the session if found, or undefined if not found.

      Parameters

      • sessionId: string

        The unique identifier of the session to retrieve

      Returns SqlLoggingSession | undefined

      The SqlLoggingSession if found, undefined otherwise

    • Gets rows updated/created since a given timestamp. Uses dialect-neutral quoting and TransformExternalSQLClause for OrderBy.

      Type Parameters

      • T = unknown

      Parameters

      Returns Promise<T[]>

    • Handles entity actions (non-AI) for save, delete, or validate operations. Uses EntityActionEngineServer to discover and run active actions.

      Parameters

      Returns Promise<ActionResult[]>

    • Handles Entity AI Actions for save or delete operations.

      For "before save" actions: blocks (awaits) until complete. For "after save" actions: fires and forgets via QueueManager.

      Subclasses that manage transactions can override to defer after-save tasks until after transaction commit (see SQLServerDataProvider).

      Parameters

      Returns Promise<void>

    • Lower-layer execution: resolves composition, processes templates, executes SQL. This is the single execution pathway used by both saved queries (via RunQuery upper layer) and transient test queries (via TestQuerySQL resolver).

      Processing order:

      1. Resolve {{query:"..."}} composition tokens → CTEs (inline deps checked first, then Metadata)
      2. Process {{ param }} Nunjucks templates (if UsesTemplate or any dependency uses templates)
      3. Apply MaxRows safety limit (wrap with TOP/LIMIT if specified)
      4. Execute the fully resolved SQL
      5. Return results with execution metadata

      Parameters

      Returns Promise<RunQueryResult>

    • Retrieves the display name for a single entity record. Uses BuildEntityRecordNameSQL for dialect-neutral SQL generation.

      Parameters

      Returns Promise<string>

    • Shared InternalRunView implementation. Handles: view resolution, permissions, field selection, WHERE clause building (view + extra filter + user search + exclude + RLS), ORDER BY, pagination, aggregates, parallel query execution, post-processing, and audit logging.

      Type Parameters

      • T = unknown

      Parameters

      Returns Promise<RunViewResult<T>>

    • Internal implementation of RunViews that subclasses must provide. This method should ONLY contain the batch data fetching logic - no pre/post processing. The base class handles all orchestration (telemetry, caching, transformation).

      Type Parameters

      • T = unknown

      Parameters

      • params: RunViewParams[]

        Array of view parameters

      • OptionalcontextUser: UserInfo

        Optional user context for permissions

      Returns Promise<RunViewResult<T>[]>

    • Drops every in-flight/lingered RunView entry whose params touch the given entity (lowercased name). Called on BaseEntity save/delete/remote-invalidate.

      Parameters

      • lowerEntityName: string

      Returns void

    • Compares client cache status with server status to determine if cache is current. Checks both row count and maxUpdatedAt timestamp.

      Parameters

      • clientStatus: { maxUpdatedAt: string; rowCount: number }
      • serverStatus: { maxUpdatedAt?: string; rowCount?: number }

      Returns boolean

    • Detects infrastructure-level connection errors (timeout, refused, pool closed) as opposed to query-level errors (bad SQL, constraint violations). Delegates to the dialect's driver-specific error classification, with a fallback for POOL_CLOSED errors thrown by our own code.

      Parameters

      • e: unknown

      Returns boolean

    • This routine checks to see if the local cache version of a given datasetName/itemFilters combination is up to date with the server or not

      Parameters

      Returns Promise<boolean>

    • Checks whether a given entity matches the target name, or is an ancestor of the target (i.e., the target is somewhere in its descendant sub-tree). Used to identify and skip the active branch during sibling propagation.

      Parameters

      Returns boolean

    • A saved query is "external" when it resolves to a Query bound to an external data source. Used by the base RunQuery CacheLocal layer to defer external-query caching to InternalRunQuery's runExternalQueryWithCache. Non-throwing — resolves from cached metadata.

      Parameters

      Returns boolean

    • Checks whether a string value looks like a known database default-value function that is NOT a UUID generator for this provider's platform.

      Parameters

      • value: string

        The string value to check

      Returns boolean

      true if the value matches a known non-UUID database function pattern

    • Checks whether server-side caching is allowed for the entity in the given RunViewParams. Returns false for entities that have TrustServerCacheCompletely = false, or for Record Changes which is always exempt (rows are created via raw SQL side-effects, not BaseEntity.Save(), so cache invalidation events never fire).

      Parameters

      Returns boolean

    • True if the field's column type is appropriate for text-pattern search. Non-text types are rejected because LIKE forces an implicit per-row CONVERT to nvarchar. Unbounded (MAX/ntext/text) columns are rejected because the LIKE path cannot seek them; FTX is the right tool for those.

      Parameters

      Returns boolean

    • Checks whether a string value looks like a database UUID generation function for this provider's platform.

      Parameters

      • value: string

        The string value to check

      Returns boolean

      true if the value matches a known UUID generation function pattern

    • Loads a single entity record by composite key, with optional relationship loading. Uses dialect-neutral quoting for all SQL construction.

      Parameters

      Returns Promise<Record<string, unknown> | null>

    • Loads metadata from local storage if available. Deserializes and reconstructs typed metadata objects.

      Returns Promise<void>

    • Checks if local metadata is obsolete compared to remote metadata. Compares timestamps and row counts to detect changes.

      Parameters

      • Optionaltype: string

        Optional specific metadata type to check

      Returns boolean

      True if local metadata is out of date

    • Logs a record change entry by diffing old/new data and executing provider-specific SQL to insert the record change. Concrete orchestration; SQL generation is delegated to BuildRecordChangeSQL.

      Parameters

      • newData: Record<string, unknown> | null

        The new record data (null for deletes)

      • oldData: Record<string, unknown> | null

        The old record data (null for creates)

      • entityName: string

        The entity name

      • recordID: string

        The record ID (CompositeKey string)

      • entityInfo: EntityInfo

        The entity metadata

      • type: "Create" | "Update" | "Delete"

        The change type

      • user: UserInfo

        The acting user

      • OptionalrestoreContext: RestoreContext | null

      Returns Promise<unknown[] | undefined>

    • Transforms a transaction result row into a list of field/value pairs.

      Parameters

      • transactionResult: Record<string, unknown>

      Returns { FieldName: string; Value: unknown }[]

    • Merges cached and fresh results for RunViews, maintaining original order.

      Parameters

      • preResult: {
            allCached: boolean;
            cachedResults?: RunViewResult[];
            cacheStatusMap?: Map<
                number,
                {
                    result?: RunViewResult;
                    status: "hit"
                    | "miss"
                    | "disabled"
                    | "expired";
                },
            >;
            callerFieldsMap?: Map<number, string[]>;
            fingerprintMap?: Map<number, string>;
            smartCacheCheckParams?: RunViewWithCacheCheckParams[];
            telemetryEventId?: string;
            uncachedParams?: RunViewParams[];
            useSmartCacheCheck?: boolean;
        }

        The pre-processing result with cache info

        • allCached: boolean
        • OptionalcachedResults?: RunViewResult[]
        • OptionalcacheStatusMap?: Map<
              number,
              { result?: RunViewResult; status: "hit"
              | "miss"
              | "disabled"
              | "expired" },
          >
        • OptionalcallerFieldsMap?: Map<number, string[]>

          Per-param-index caller Fields lists (lowercased), captured before PreRunViews widened params.Fields to all entity fields for cache-superset storage. An index is present ONLY when that widening actually happened — PostRunViews uses it to project cache-miss DB results back down to the requested shape.

        • OptionalfingerprintMap?: Map<number, string>

          Per-param-index cache fingerprints computed during PreRunViews — carried forward so PostRunViews doesn't recompute the RLS where-clause and fingerprint string for every batch item.

        • OptionalsmartCacheCheckParams?: RunViewWithCacheCheckParams[]

          When CacheLocal is enabled, contains the cache check params to send to server

        • OptionaltelemetryEventId?: string
        • OptionaluncachedParams?: RunViewParams[]
        • OptionaluseSmartCacheCheck?: boolean

          When CacheLocal is enabled, indicates we should use smart cache check

      • freshResults: RunViewResult[]

        The fresh results from InternalRunViews

      Returns RunViewResult[]

      Combined results in original order

    • Folds a saved view's stored WhereClause and OrderByClause into the RunView params before external dispatch. The external branch returns before the normal SQL path that applies them, so without this a UserView over an external entity would silently return unfiltered, unordered rows. The view's WhereClause is ANDed with any caller ExtraFilter; the view's OrderByClause is used only when the caller supplied no OrderBy. Returns params unchanged when there is no saved view.

      Parameters

      Returns Promise<RunViewParams>

    • Merges cached and fresh results for RunQueries, maintaining original order.

      Parameters

      • preResult: {
            allCached: boolean;
            cachedResults?: RunQueryResult[];
            cacheStatusMap?: Map<
                number,
                {
                    result?: RunQueryResult;
                    status: "hit"
                    | "miss"
                    | "disabled"
                    | "expired";
                },
            >;
            telemetryEventId?: string;
            uncachedParams?: RunQueryParams[];
        }

        The pre-processing result with cache info

      • freshResults: RunQueryResult[]

        The fresh results from InternalRunQueries

      Returns RunQueryResult[]

      Combined results in original order

    • Called after a save/delete SQL operation completes (success or failure) to resume refresh.

      Returns void

    • Called after a direct (non-transaction) save succeeds, before the result is returned to the caller and loaded into the entity via finalizeSave().

      Post-Save Patch Mechanism

      This hook can optionally return a Record<string, unknown> containing field values that should be patched onto the SP result row before it is loaded into the entity. This solves a timing problem: the SP result is captured before OnSaveCompleted runs, so any data created by post-save hooks (e.g., geocoding writing to a JOINed table) would be stale in the returned entity without this patch.

      1. The SP executes and returns result[0] with the current view data
      2. OnSaveCompleted runs post-save logic (geocoding, ISA propagation, etc.)
      3. If this method returns a non-null Record, those key/value pairs are merged onto result[0] via Object.assign(), overwriting stale values
      4. The patched result is then returned to BaseEntity.finalizeSave() which calls SetMany() to load the corrected data into the entity

      After geocoding updates RecordGeoCode, the new lat/lng are returned as patches for the __mj_Latitude and __mj_Longitude virtual fields that come from the RecordGeoCode JOIN in the entity's base view. Without this patch, those fields would contain the pre-geocoding values until the next query.

      • Return null if no patches are needed (default behavior)
      • Only include fields that were actually changed by your post-save logic
      • Always call await super.OnSaveCompleted(...) and merge its patches with yours
      • Patches are shallow-merged via Object.assign — last writer wins for each key

      Parameters

      Returns Promise<Record<string, unknown> | null>

      Patch fields to apply to the SP result, or null if no patches needed

    • Called before starting a save/delete SQL operation to pause background metadata refresh. SQL Server overrides to set _bAllowRefresh = false.

      Returns void

    • Parses a timestamp string sent by the client.

      Accepts both ISO 8601 strings (the canonical form) and all-digit strings representing milliseconds since epoch. The numeric form has been observed in the wild from clients whose cache layer round-tripped a Date through a lossy serializer — new Date('1778004618383') returns Invalid Date, but new Date(Number('1778004618383')) is a valid timestamp. Returning null on unparseable input lets callers degrade to a stale-cache fallback instead of throwing RangeError: Invalid time value on a downstream .toISOString().

      Parameters

      • raw: string | null | undefined

      Returns Date | null

    • Post-processes rows: first applies platform-specific datetime adjustments via the virtual AdjustDatetimeFields hook, then handles field-level decryption for encrypted fields.

      Subclasses should NOT override this method. Instead, override AdjustDatetimeFields for platform-specific datetime corrections.

      Parameters

      Returns Promise<Record<string, unknown>[]>

    • Base class utilty method that should be called after each sub-class handles its internal RunViews() process before returning results This handles the optional conversion of simple objects to entity objects for each requested view depending on if the params requests a result_type === 'entity_object'

      Parameters

      Returns Promise<void>

    • Post-processing hook for RunQueries (batch). Handles telemetry end.

      Parameters

      • results: RunQueryResult[]

        Array of query results

      • params: RunQueryParams[]

        Array of query parameters

      • preResult: {
            allCached: boolean;
            cachedResults?: RunQueryResult[];
            cacheStatusMap?: Map<
                number,
                {
                    result?: RunQueryResult;
                    status: "hit"
                    | "miss"
                    | "disabled"
                    | "expired";
                },
            >;
            telemetryEventId?: string;
            uncachedParams?: RunQueryParams[];
        }

        The pre-processing result

      • OptionalcontextUser: UserInfo

        Optional user context

      Returns Promise<void>

    • Post-processing hook for RunQuery. Handles cache storage and telemetry end.

      Parameters

      • result: RunQueryResult

        The query result

      • params: RunQueryParams

        The query parameters

      • preResult: {
            cachedResult?: RunQueryResult;
            cacheStatus: "hit" | "miss" | "disabled" | "expired";
            fingerprint?: string;
            telemetryEventId?: string;
        }

        The pre-processing result

      • OptionalcontextUser: UserInfo

        Optional user context

      Returns Promise<void>

    • Post-processing hook for RunView. Handles result transformation, cache storage, and telemetry end.

      Parameters

      • result: RunViewResult

        The view result

      • params: RunViewParams

        The view parameters

      • preResult: {
            cachedResult?: RunViewResult;
            cacheStatus: "hit" | "miss" | "disabled" | "expired";
            callerRequestedFields?: string[] | null;
            fingerprint?: string;
            telemetryEventId?: string;
        }

        The pre-processing result

        • OptionalcachedResult?: RunViewResult
        • cacheStatus: "hit" | "miss" | "disabled" | "expired"
        • OptionalcallerRequestedFields?: string[] | null

          The caller's original Fields list (lowercased), captured before PreRunView widened params.Fields to all entity fields for cache-superset storage. Non-null ONLY when that widening actually happened — PostRunView uses it to project cache-miss DB results back down to the requested shape.

        • Optionalfingerprint?: string
        • OptionaltelemetryEventId?: string
      • OptionalcontextUser: UserInfo

        Optional user context

      Returns Promise<void>

    • Post-processing hook for RunViews (batch). Handles result transformation, cache storage, and telemetry end.

      Parameters

      • results: RunViewResult[]

        Array of view results

      • params: RunViewParams[]

        Array of view parameters

      • preResult: {
            allCached: boolean;
            cachedResults?: RunViewResult[];
            cacheStatusMap?: Map<
                number,
                {
                    result?: RunViewResult;
                    status: "hit"
                    | "miss"
                    | "disabled"
                    | "expired";
                },
            >;
            callerFieldsMap?: Map<number, string[]>;
            fingerprintMap?: Map<number, string>;
            smartCacheCheckParams?: RunViewWithCacheCheckParams[];
            telemetryEventId?: string;
            uncachedParams?: RunViewParams[];
            useSmartCacheCheck?: boolean;
        }

        The pre-processing result

        • allCached: boolean
        • OptionalcachedResults?: RunViewResult[]
        • OptionalcacheStatusMap?: Map<
              number,
              { result?: RunViewResult; status: "hit"
              | "miss"
              | "disabled"
              | "expired" },
          >
        • OptionalcallerFieldsMap?: Map<number, string[]>

          Per-param-index caller Fields lists (lowercased), captured before PreRunViews widened params.Fields to all entity fields for cache-superset storage. An index is present ONLY when that widening actually happened — PostRunViews uses it to project cache-miss DB results back down to the requested shape.

        • OptionalfingerprintMap?: Map<number, string>

          Per-param-index cache fingerprints computed during PreRunViews — carried forward so PostRunViews doesn't recompute the RLS where-clause and fingerprint string for every batch item.

        • OptionalsmartCacheCheckParams?: RunViewWithCacheCheckParams[]

          When CacheLocal is enabled, contains the cache check params to send to server

        • OptionaltelemetryEventId?: string
        • OptionaluncachedParams?: RunViewParams[]
        • OptionaluseSmartCacheCheck?: boolean

          When CacheLocal is enabled, indicates we should use smart cache check

      • OptionalcontextUser: UserInfo

        Optional user context

      Returns Promise<void>

    • Base class implementation for handling pre-processing of RunViews() each sub-class should call this within their RunViews() method implementation

      Parameters

      Returns Promise<void>

    • Pre-processing hook for RunQueries (batch). Handles telemetry for batch query operations.

      Parameters

      Returns Promise<
          {
              allCached: boolean;
              cachedResults?: RunQueryResult[];
              cacheStatusMap?: Map<
                  number,
                  {
                      result?: RunQueryResult;
                      status: "hit"
                      | "miss"
                      | "disabled"
                      | "expired";
                  },
              >;
              telemetryEventId?: string;
              uncachedParams?: RunQueryParams[];
          },
      >

      Pre-processing result

    • Pre-processing hook for RunQuery. Handles telemetry and cache lookup.

      Parameters

      Returns Promise<
          {
              cachedResult?: RunQueryResult;
              cacheStatus: "hit"
              | "miss"
              | "disabled"
              | "expired";
              fingerprint?: string;
              telemetryEventId?: string;
          },
      >

      Pre-processing result with cache status and optional cached result

    • Pre-processing hook for RunView. Handles telemetry, validation, entity status check, and cache lookup.

      Parameters

      Returns Promise<
          {
              cachedResult?: RunViewResult;
              cacheStatus: "hit"
              | "miss"
              | "disabled"
              | "expired";
              callerRequestedFields?: string[] | null;
              fingerprint?: string;
              telemetryEventId?: string;
          },
      >

      Pre-processing result with cache status and optional cached result

    • Pre-processing hook for RunViews (batch). Handles telemetry, validation, and cache lookup for multiple views.

      Parameters

      Returns Promise<
          {
              allCached: boolean;
              cachedResults?: RunViewResult[];
              cacheStatusMap?: Map<
                  number,
                  {
                      result?: RunViewResult;
                      status: "hit"
                      | "miss"
                      | "disabled"
                      | "expired";
                  },
              >;
              callerFieldsMap?: Map<number, string[]>;
              fingerprintMap?: Map<number, string>;
              smartCacheCheckParams?: RunViewWithCacheCheckParams[];
              telemetryEventId?: string;
              uncachedParams?: RunViewParams[];
              useSmartCacheCheck?: boolean;
          },
      >

      Pre-processing result with cache status for each view

    • Synchronous pre-validation of cached metadata before engine startup.

      On a warm load we serve the metadata graph from IndexedDB so the app can boot without pulling MBs of metadata from the server. Before engines run, this method makes one batched timestamp round-trip to confirm the snapshot is still current:

      • Cached metadata is current → engines proceed against the cached snapshot. Their RunViews calls go through the normal smart-cache-check path which batches per-view fingerprints to the server — efficient and authoritative.
      • Cached metadata is stale → refresh framework metadata in place before engines start, then proceed normally.

      Cost on the warm-current path is one batched timestamp fetch (~50–200 ms depending on RTT). On the warm-stale path we additionally pay the full metadata fetch but avoid serving stale data to the UI in the first place.

      Caller contract: invoke this before StartupManager.Startup().

      Parameters

      Returns Promise<void>

    • Processes query parameters: resolves {{query:"..."}} composition tokens, then applies Nunjucks template substitution for {{param}} tokens.

      Delegates to RenderPipeline.Run for the composition → template pipeline. Paging is handled separately by the caller (InternalRunQuery).

      Parameters

      Returns {
          appliedParameters: Record<string, string>;
          finalSQL: string;
          renderResult: RenderResult;
      }

    • Propagates record change entries to sibling branches of an IS-A hierarchy. Called after saving an entity with AllowMultipleSubtypes (overlapping subtypes). Collects SQL from BuildSiblingRecordChangeSQL for each sibling and executes as a batch.

      Parameters

      • parentInfo: EntityInfo

        The parent entity info

      • changeData: { changesDescription: string; changesJSON: string }

        The changes JSON and description

      • pkValue: string

        The primary key value

      • userId: string

        The acting user ID

      • activeChildEntityName: string | undefined

        The child entity that initiated the save (to skip)

      • OptionalextraExecOptions: Record<string, unknown>

        Optional provider-specific execution options (e.g. connectionSource for SQL Server transactions)

      Returns Promise<void>

    • Rebuilds the O(1) entity lookup Maps from the current AllEntities array. Called automatically from UpdateLocalMetadata().

      Returns void

    • Refreshes all metadata from the server. Respects the AllowRefresh flag from subclasses.

      Parameters

      Returns Promise<boolean>

      True if refresh was initiated or allowed

    • Refreshes metadata only if needed based on timestamp comparison. Combines check and refresh into a single operation.

      Parameters

      Returns Promise<boolean>

      True if refresh was successful or not needed

    • Refreshes the remote metadata timestamps from the server. Updates the internal cache of remote timestamps.

      Parameters

      Returns Promise<boolean>

      True if timestamps were successfully refreshed

    • Removes all cached metadata from local storage. Clears both timestamps and metadata collections.

      Returns Promise<void>

    • Renders the PostgreSQL binding for a save call. Picks between two shapes:

      • pg-json-arg (wide entities ≥ ProcedureParamLimit typed args): a single $1::jsonb payload keyed by field name. Binary fields serialize as base64; key-presence semantics on the SP side interpret missing keys as "leave unchanged" and explicit nulls as "clear" — no _Clear companions needed.
      • pg-positional (default): typed $N placeholders, named p_<lowercase-field-name> to match the CodeGen-emitted SP signature. _Clear companion args emitted for nullable columns set explicitly to NULL.

      Parameters

      Returns SaveCallBinding

    • Renders the WHERE clause for a saved view, replacing template variables like {%UserView "viewId"%} with subquery SQL. Handles nested/recursive templates with circular reference detection.

      Uses QuoteIdentifier/QuoteSchemaAndView for dialect-neutral SQL generation.

      Parameters

      Returns Promise<string>

    • Resolves a category path string to a QueryCategoryInfo ID.

      Parameters

      • categoryPath: string

      Returns string | null

    • Resolves the cache TTL (in ms) for a RunView's entity, or undefined for MJ-DB entities (which use event-based cache invalidation, not TTL). External-data-source entities MUST be time-bounded — their remote data changes never emit BaseEntity events — so this returns the data source's DefaultCacheTTLSeconds (via the external router) in ms, or 0 to signal "do not cache" (TTL disabled on the source, or no router available to resolve one).

      Parameters

      Returns Promise<number | undefined>

    • Resolves any PlatformSQL values in RunViewParams to plain strings for the active platform. Mutates the params object in place so downstream InternalRunView implementations always receive plain string values for ExtraFilter and OrderBy.

      Parameters

      Returns void

    • B45 override of the RunQuery cache-serve seam — enforce the SAME authorization on a cache HIT that the miss path enforces. Resolution uses resolveQuery() (QueryEngine as the single source of truth, with CategoryPath disambiguation of same-named queries — the B46 pairing), and authorization is the FULL MJQueryEntityExtended.UserCanRun (roles + entity CanRead + recursive composition) — exactly the check ValidateQueryForExecution applies before a real execution. The base's roles-only check would let a user read cached rows of a query whose underlying entities they cannot read.

      Non-throwing by contract: any resolution error degrades to resolvable: false, which the gate treats as "fall through to authorized execution" — one extra query run, never an unauthorized serve and never a crashed cache path.

      Parameters

      Returns QueryCacheAuthorization

    • Resolves a PlatformSQL value to the appropriate SQL string for this provider's platform. If the value is a plain string, it is returned as-is (backward compatible). If the value is a PlatformSQL object, the platform-specific variant is used if available, otherwise the default variant is used.

      Parameters

      Returns string

    • RollbackTransaction with savepoint-aware semantics.

      • Outermost (depth was 1): real ROLLBACK and release the client.
      • Nested (depth > 1): ROLLBACK TO SAVEPOINT (which keeps the savepoint itself active but discards work done after it), then RELEASE SAVEPOINT to drop it. Combining the two matches what callers usually mean by "undo this nested operation entirely".

      Returns Promise<void>

    • Routes a typed Remote Operation by key to its implementation (see IRemoteOperationProvider).

      This is the public power-tool transport seam. Prefer the typed BaseRemotableOperation.Execute() entry point in application code — RouteOperation is the stringly-typed escape hatch for dynamic dispatch / generic tooling, not for building significant systems. Server providers override InternalRouteOperation to execute the operation in-process; the client (GraphQL) provider overrides it to marshal over the wire. Only registered, active (and, when AI-authored, approved) operations are routable, and every call is authorized on the server side.

      Type Parameters

      • TInput = unknown
      • TOutput = unknown

      Parameters

      • operationKey: string

        Stable registry key of the operation (e.g. RecordProcess.RunNow).

      • input: TInput

        The operation's typed input payload.

      • Optionaloptions: RemoteOpInvokeOptions

        Optional invocation options (mode, progress callback, user, provider, fingerprint).

      Returns Promise<RemoteOpResult<TOutput>>

      The operation result; never throws for logical failures — check Success/ErrorMessage.

    • Execute a parameterized statement for a colocated vector provider against this connection. Uses the active transaction client when one is open (so vector writes commit/rollback with the entity write), otherwise the shared pool. Placeholders use PG's native $1..$n. Deliberately bypasses ExecuteSQL's PascalCase auto-quoting — the vector provider emits its own correctly-quoted SQL.

      Type Parameters

      • T = Record<string, unknown>

      Parameters

      • sql: string
      • Optionalparams: readonly unknown[]

      Returns Promise<T[]>

    • Runs a differential query and returns only changes since the client's cached state. Includes updated/created rows and deleted record IDs. Falls back to full query if hidden deletes are detected.

      Type Parameters

      • T = unknown

      Parameters

      • params: RunViewParams
      • entityInfo: EntityInfo
      • clientMaxUpdatedAt: string
      • clientRowCount: number
      • serverStatus: { maxUpdatedAt?: string; rowCount?: number }
      • whereSQL: string
      • viewIndex: number
      • OptionalcontextUser: UserInfo
      • OptionalcallerFields: string[] | null

      Returns Promise<RunViewWithCacheCheckResult<T>>

    • Runs a full query and returns results with cache metadata.

      Type Parameters

      • T = unknown

      Parameters

      • params: RunQueryParams
      • queryIndex: number
      • status: "stale" | "no_validation"
      • OptionalcontextUser: UserInfo
      • OptionalqueryId: string
      • OptionalvalidationStamp: { maxUpdatedAt?: string; rowCount?: number }

      Returns Promise<RunQueryWithCacheCheckResult<T>>

    • Runs all registered PostRunView hooks against a single result, returning the (possibly mutated) result.

      Protected (not private) for the same reason as RunPreRunViewHooks above: a subclass pipeline that returns view rows WITHOUT passing through PostRunView/PostRunViews — e.g. the RunViewsWithCacheCheck smart-cache path — MUST apply these hooks to the rows it returns. PostRunView is the OUTPUT half of the enforcement seam (data masking / audit); a path that skips it returns rows the hooked paths would have masked.

      Parameters

      Returns Promise<RunViewResult>

    • Runs all registered PreRunView hooks against a single RunViewParams, returning the (possibly mutated) params.

      Protected (not private) on purpose: any subclass pipeline that executes view queries WITHOUT passing through PreRunView/PreRunViews — e.g. the RunViewsWithCacheCheck smart-cache path in GenericDatabaseProvider — MUST apply these hooks itself. Hooks are an enforcement seam (tenant scoping middleware injects filters here); a query path that skips them silently returns rows the hooked paths would have filtered out.

      Parameters

      Returns Promise<RunViewParams>

    • Runs multiple queries based on the provided parameters. This method orchestrates the full execution flow for batch query operations.

      Parameters

      • params: RunQueryParams[]

        Array of query parameters

      • OptionalcontextUser: UserInfo

        Optional user context for permissions (required server-side)

      Returns Promise<RunQueryResult[]>

      Array of query results

    • Runs a report by looking up its SQL definition from vwReports and executing it. Both SQL Server and PostgreSQL share this logic — the only dialect difference is identifier quoting, handled by QuoteIdentifier/QuoteSchemaAndView.

      Parameters

      • params: RunReportParams

        Report parameters including ReportID

      • OptionalcontextUser: UserInfo

        Optional context user for permission/audit purposes

      Returns Promise<RunReportResult>

      Reports are no longer supported and will eventually be removed. Interactive Components and Artifacts are replacements

    • Runs a view based on the provided parameters. This method orchestrates the full execution flow: pre-processing, cache check, internal execution, post-processing, and cache storage.

      Type Parameters

      • T = any

      Parameters

      • params: RunViewParams

        The view parameters

      • OptionalcontextUser: UserInfo

        Optional user context for permissions (required server-side)

      Returns Promise<RunViewResult<T>>

      The view results

    • Single source of truth for whether a RunView call participates in the local cache (both READ and WRITE). Pre/Post hooks for the singular and batch paths must all use this predicate — historically each site recomputed it inline and they drifted (PostRunViews wrote BypassCache results into the cache, poisoning the Fields-agnostic superset slot with narrow rows).

      Ineligible:

      • BypassCache — caller explicitly wants true DB state, no cache interaction
      • AfterKey — keyset pages are single-use AND the fingerprint doesn't include the seek key, so caching a page would poison the entity+filter slot
      • ResultType 'count_only' — returns no rows; caching its empty Results under a fingerprint that excludes ResultType would poison row queries
      • entities where server caching is disallowed

      Parameters

      Returns boolean

    • Runs multiple views based on the provided parameters. Wraps the execution pipeline with request deduplication and a linger window so that concurrent (and near-sequential) identical calls share a single server round-trip. Every caller receives a shallow-copied Results array to protect against cross-caller mutations (push/sort/splice).

      Type Parameters

      • T = any

      Parameters

      • params: RunViewParams[]

        Array of view parameters

      • OptionalcontextUser: UserInfo

        Optional user context for permissions (required server-side)

      Returns Promise<RunViewResult<T>[]>

      Array of view results (shallow-copied Results per caller)

    • Saves an entity record — the full orchestration flow shared by all DB providers.

      1. Permission & dirty-state checks
      2. Validation via OnValidateBeforeSave hook
      3. Before-save actions via OnBeforeSaveExecute hook
      4. SQL generation via GenerateSaveSQL (abstract, provider-specific)
      5. Execute via TransactionGroup or directly
      6. After-save actions via OnAfterSaveExecute hook
      7. Post-save cleanup via OnSaveCompleted hook (ISA propagation, etc.)

      Parameters

      Returns Promise<{}>

    • Saves current metadata to local storage for caching. Serializes both timestamps and full metadata collections.

      Returns Promise<void>

    • Batch form of SearchEntity. Fans the input list out to N independent SearchEntity calls via Promise.all; result arrays come back aligned by input order (result[i] holds the matches for params[i]).

      On the server side, the per-entity passes are independent — running them concurrently is a real wall-clock win when the caller wants results from multiple entities. On the client side, GraphQLDataProvider overrides this method to pack the whole batch into a single GraphQL round-trip instead of issuing N parallel HTTP requests.

      See IMetadataProvider.SearchEntities for the contract.

      Parameters

      Returns Promise<EntitySearchResult[][]>

    • Server-side semantic ranking pass for ProviderBase.SearchEntity (and, by extension, the batched ProviderBase.SearchEntities).

      The query embedding MUST be generated with the same model that produced the indexed vectors — otherwise cosine scores compare apples to oranges and rankings are garbage. We look up the EntityDocument's AIModelID via AIEngine.Models to recover the driver class / APIName and call EmbedText(model, text) directly. If the EntityDocument does not specify a model (or the model isn't loaded) we fall back to EmbedTextLocal (highest-power local model) only as a last resort.

      Vector ranking runs against the in-process SimpleVectorServiceProvider, which rehydrates the vector pool for entityDocumentId from MJ: Entity Record Documents.VectorJSON rows.

      Failures (no embedding model available, vector index miss) degrade to an empty result set so hybrid mode can still surface lexical matches.

      Parameters

      • entityDocumentId: string
      • searchText: string
      • overFetch: number
      • embeddingAIModelId: string | null
      • contextUser: UserInfo | undefined

      Returns Promise<ScoredCandidate[]>

    • Ranked search over one entity's records. See IMetadataProvider.SearchEntity for the contract and how this differs from EntityByName / FullTextSearch.

      Implementation overview (concrete on ProviderBase, used as-is by every server-side provider; GraphQLDataProvider overrides to proxy via GQL):

      1. Resolve the EntityDocument (by params.options.entityDocumentId override or by looking up the active Search-category doc for the entity).
      2. In parallel: run the lexical pass (RunView with LIKE filters on the name field + any IncludeInUserSearchAPI fields) and the semantic pass (searchEntitiesSemanticPass, the protected template method each concrete server provider implements).
      3. Fuse via canonical ComputeRRF() with optional per-list weights.
      4. Permission-filter via a second RunView constrained to the matched record IDs — that pipeline already enforces row-level read perms on this entity, so any rows the user can't read drop out.
      5. Slice to topK, apply minScore cutoff, return.

      Parameters

      Returns Promise<EntitySearchResult[]>

    • Stores a record name in the cache for later synchronous retrieval via GetCachedRecordName(). Called automatically by BaseEntity after Load(), LoadFromData(), and Save() operations.

      Parameters

      • entityName: string

        The name of the entity

      • compositeKey: CompositeKey

        The primary key value(s) for the record

      • recordName: string

        The display name to cache

      Returns void

    • Replaces the active local storage provider at runtime.

      Use this to swap from the default in-memory provider to a Redis-backed provider (or any other ILocalStorageProvider) after reading application configuration.

      Parameters

      Returns void

      import { RedisLocalStorageProvider } from '@memberjunction/redis-provider';

      // During server startup, after config is loaded:
      const redis = new RedisLocalStorageProvider({
      url: process.env.REDIS_URL,
      defaultTTLSeconds: 300
      });
      (Metadata.Provider as GenericDatabaseProvider).SetLocalStorageProvider(redis);
    • Creates or deletes a user favorite record for the specified entity record. Uses GetEntityObject and BaseEntity CRUD methods (no entity-specific type imports needed).

      Parameters

      Returns Promise<void>

    • Dialect-agnostic predicate: should we write a RecordChange entry for this entity? Excludes the Record Changes entity itself to prevent recursion. Provider implementations should call this before invoking BuildRecordChangePayload or constructing dialect SQL.

      Parameters

      Returns boolean

    • Transforms user-provided SQL clauses (ExtraFilter, OrderBy) to quote mixed-case identifiers and convert [bracket] notation for PostgreSQL. Also coerces SQL Server bit literals (= 1 / = 0) on boolean fields to PG boolean literals (= TRUE / = FALSE), since hand-written filters across the codebase (engines, dashboards, agents) use SQL Server's bit-as-integer convention. Without this, PG rejects the comparison with operator does not exist: boolean = integer.

      Parameters

      Returns string

    • Translates the SQL Server date/time functions that show up in hand-written ExtraFilter / OrderBy clauses across the codebase into their PostgreSQL equivalents. PG has no GETUTCDATE/GETDATE/DATEADD and there is no shim function, so an untranslated clause errors with function getutcdate() does not exist. This is the framework backstop — app-layer call sites should prefer dialect-neutral literals, but any clause that still carries these forms is rewritten here. Covers the forms actually used in MJ filters:

      • GETUTCDATE() -> (NOW() AT TIME ZONE 'UTC')
      • SYSDATETIMEOFFSET() -> NOW()
      • GETDATE() -> CURRENT_TIMESTAMP
      • DATEADD(unit, n, expr) -> (expr + (n) * INTERVAL '1 <pg-unit>')

      Public so it can be unit-tested directly (same convention as autoQuoteIdentifiers).

      Parameters

      • sql: string

      Returns string

    • Truncates a string value to a maximum length, appending trailing characters if truncated.

      Parameters

      • value: unknown
      • maxLength: number
      • trailingChars: string

      Returns unknown

    • Returns true when CRUD sproc generation and call-construction for the given entity + sproc verb should use a single JSON-arg shape (instead of typed args + _Clear companions).

      Convenience wrapper around the pure useJsonArgShape helper, applying this provider's ProcedureParamLimit. CodeGen and runtime call-sites can invoke this via the provider instance to keep sproc emit and sproc invocation in lockstep.

      Parameters

      Returns boolean

    • PostgreSQL spDelete sprocs return a single-column result that confirms the delete. Two shapes coexist in the wild:

      • Legacy (baseline migration V202602170015): RETURNS TABLE("_result_id" UUID) — uses _result_id because PL/pgSQL flagged the natural RETURNS TABLE("ID") against WHERE "ID" = p_id as ambiguous before #variable_conflict use_column was adopted in the codegen template. Most existing PG installs still have these.
      • Current codegen output: RETURNS TABLE("<PKName>" UUID) (matches framework contract directly) — emitted only after a fresh codegen pass replaces the baseline sproc.

      The base ValidateDeleteResult only knows the second shape, so deletes against legacy sprocs return false despite the row actually being deleted. This override accepts either shape: a single non-null UUID column whose value matches the expected primary key counts as success.

      Parameters

      Returns boolean

    • Validates that a query can be executed by the given user. Checks both permissions and approval status. Permission failures throw an error. Non-approved status emits a console warning but allows execution to proceed, enabling query testing before formal approval.

      Parameters

      • query: MJQueryEntityExtended

        The resolved MJQueryEntityExtended to validate

      • OptionalcontextUser: UserInfo

        The user attempting to execute the query

      Returns void

      Error if the user does not have permission to run the query

    • Validates a user-provided SQL clause (WHERE, ORDER BY, etc.) to prevent SQL injection. Checks for forbidden keywords (INSERT, UPDATE, DELETE, EXEC, DROP, UNION, etc.) and dangerous patterns (comments, semicolons, xp_ prefix). String literals are stripped before validation to avoid false positives.

      Parameters

      • clause: string

        The SQL clause to validate

      Returns boolean

      true if the clause is safe, false if it contains forbidden patterns

    • Converts an ArrayBuffer to a base64-encoded string. Used for compressed metadata storage/retrieval.

      Parameters

      • buffer: ArrayBuffer

      Returns string

    • Converts a base64-encoded string to an ArrayBuffer. Used for compressed metadata storage/retrieval.

      Parameters

      • base64: string

      Returns ArrayBuffer

    • Static convenience: checks all platforms' default-value functions. Prefer the instance method when you have a provider reference.

      Parameters

      • value: string

      Returns boolean

    • Static convenience: checks all platforms' UUID generation functions. Prefer the instance method when you have a provider reference.

      Parameters

      • value: string

      Returns boolean

    • Static method to log SQL statements from external sources like transaction groups. Gets the current provider instance from Metadata.Provider and delegates to the instance _logSqlStatement method.

      Parameters

      • query: string

        The SQL query being executed

      • Optionalparameters: unknown

        Parameters for the query

      • Optionaldescription: string

        Optional description for this operation

      • OptionalisMutation: boolean

        Whether this is a data mutation operation

      • OptionalsimpleSQLFallback: string

        Optional simple SQL to use for loggers with logRecordChangeMetadata=false

      • OptionalcontextUser: UserInfo

        Optional user context for session filtering

      Returns Promise<void>

    • Returns the caller's requested fields (lowercased) unioned with the entity's primary key field names. Platform contract: when Fields is explicitly specified, results ALWAYS include the primary key(s) — the direct SQL path has always done this, differential smart-cache merges require it, and entity linking in UIs depends on it. Applying the same union at every projection site keeps result shapes identical across cached, non-cached, and smart-cache paths.

      Parameters

      Returns string[]