Member Junction
    Preparing search index...

    Interface DatabaseProviderBaseAbstract

    This class is a generic server-side provider class to abstract database operations on any database system and therefore be usable by server-side components that need to do database operations but do not want close coupling with a specific database provider like

    @memberjunction/sqlserver-dataprovider

    It contains DB-agnostic business logic (record change tracking, favorites, ISA hierarchy, record dependencies, diffing, etc.) that is shared across all database providers. Subclasses implement abstract methods for DB-specific SQL dialect generation.

    interface DatabaseProviderBase {
        _preRunQueriesResultType: {
            allCached: boolean;
            cachedResults?: RunQueryResult[];
            cacheStatusMap?: Map<
                number,
                {
                    result?: RunQueryResult;
                    status: "expired"
                    | "disabled"
                    | "hit"
                    | "miss";
                },
            >;
            telemetryEventId?: string;
            uncachedParams?: RunQueryParams[];
        };
        _preRunQueryResultType: {
            cachedResult?: RunQueryResult;
            cacheStatus: "expired"
            | "disabled"
            | "hit"
            | "miss";
            fingerprint?: string;
            telemetryEventId?: string;
        };
        _preRunViewResultType: {
            cachedResult?: RunViewResult;
            cacheStatus: "expired"
            | "disabled"
            | "hit"
            | "miss";
            callerRequestedFields?: string[];
            fingerprint?: string;
            telemetryEventId?: string;
        };
        _preRunViewsResultType: {
            allCached: boolean;
            cachedResults?: RunViewResult[];
            cacheStatusMap?: Map<
                number,
                {
                    result?: RunViewResult;
                    status: "expired"
                    | "disabled"
                    | "hit"
                    | "miss";
                },
            >;
            callerFieldsMap?: Map<number, string[]>;
            fingerprintMap?: Map<number, string>;
            smartCacheCheckParams?: RunViewWithCacheCheckParams[];
            telemetryEventId?: string;
            uncachedParams?: RunViewParams[];
            useSmartCacheCheck?: boolean;
        };
        get AllExplorerNavigationItems(): ExplorerNavigationItem[];
        get AllMetadata(): AllMetadata;
        get AllowRefresh(): boolean;
        get Applications(): ApplicationInfo[];
        get AuditLogTypes(): AuditLogTypeInfo[];
        get AuthorizationRoles(): AuthorizationRoleInfo[];
        get Authorizations(): AuthorizationInfo[];
        get ConfigData(): ProviderConfigDataBase;
        get CurrentTransactionDepth(): number;
        get CurrentUser(): UserInfo;
        get DatabaseConnection(): any;
        get DBDefaultFunctionPattern(): RegExp;
        get Dialect(): SQLDialect;
        get Entities(): EntityInfo[];
        get FileSystemProvider(): IFileSystemProvider;
        get InstanceConnectionString(): string;
        get IsInTransaction(): boolean;
        get LatestLocalMetadata(): MetadataInfo[];
        get LatestRemoteMetadata(): MetadataInfo[];
        get Libraries(): LibraryInfo[];
        get LocalStoragePrefix(): string;
        get LocalStorageProvider(): ILocalStorageProvider;
        get Metadata(): IMetadataProvider;
        get MetadataMemberRefreshDelayMs(): number;
        get MetadataMemberRefreshRearmsOnNewEvents(): boolean;
        get MJCoreSchemaName(): string;
        get PlatformKey(): DatabasePlatform;
        get PreRunQueriesResult(): {
            allCached: boolean;
            cachedResults?: RunQueryResult[];
            cacheStatusMap?: Map<
                number,
                {
                    result?: RunQueryResult;
                    status: "expired"
                    | "disabled"
                    | "hit"
                    | "miss";
                },
            >;
            telemetryEventId?: string;
            uncachedParams?: RunQueryParams[];
        };
        get PreRunQueryResult(): {
            cachedResult?: RunQueryResult;
            cacheStatus: "expired"
            | "disabled"
            | "hit"
            | "miss";
            fingerprint?: string;
            telemetryEventId?: string;
        };
        get PreRunViewResult(): {
            cachedResult?: RunViewResult;
            cacheStatus: "expired"
            | "disabled"
            | "hit"
            | "miss";
            callerRequestedFields?: string[];
            fingerprint?: string;
            telemetryEventId?: string;
        };
        get PreRunViewsResult(): {
            allCached: boolean;
            cachedResults?: RunViewResult[];
            cacheStatusMap?: Map<
                number,
                {
                    result?: RunViewResult;
                    status: "expired"
                    | "disabled"
                    | "hit"
                    | "miss";
                },
            >;
            callerFieldsMap?: Map<number, string[]>;
            fingerprintMap?: Map<number, string>;
            smartCacheCheckParams?: RunViewWithCacheCheckParams[];
            telemetryEventId?: string;
            uncachedParams?: RunViewParams[];
            useSmartCacheCheck?: boolean;
        };
        get ProviderType(): ProviderType;
        get Queries(): QueryInfo[];
        get QueryCategories(): QueryCategoryInfo[];
        get QueryDependencies(): QueryDependencyInfo[];
        get QueryEntities(): QueryEntityInfo[];
        get QueryFields(): QueryFieldInfo[];
        get QueryParameters(): QueryParameterInfo[];
        get QueryPermissions(): QueryPermissionInfo[];
        get QuerySQLs(): QuerySQLInfo[];
        get Roles(): RoleInfo[];
        get RowLevelSecurityFilters(): RowLevelSecurityFilterInfo[];
        get SQLDialects(): SQLDialectInfo[];
        get SupportsEntityTransactions(): boolean;
        get transactionDepth(): number;
        get TransactionDepth(): number;
        get TrustLocalCacheCompletely(): boolean;
        get UUIDFunctionPattern(): RegExp;
        get VisibleExplorerNavigationItems(): ExplorerNavigationItem[];
        ApplyFieldSecurityProjection<T>(
            rows: T[],
            params: RunViewParams,
            contextUser?: UserInfo,
        ): T[];
        ApplyPostRunViewHooksToCacheHit(
            params: RunViewParams,
            result: RunViewResult,
            contextUser?: UserInfo,
        ): Promise<void>;
        ApplyRecordChangeFieldSecurityProjection<T>(
            rows: T[],
            params: RunViewParams,
            contextUser?: UserInfo,
        ): T[];
        AssertPredicatesRespectFieldSecurity(
            params: RunViewParams,
            contextUser?: UserInfo,
        ): void;
        backgroundValidateAndRefresh(
            providerToUse?: IMetadataProvider,
        ): Promise<void>;
        BeginEntityTransaction(): Promise<EntityTransactionScope>;
        BeginTransaction(): Promise<void>;
        BuildAggregateSQL(
            aggregates: { alias?: string; expression: string }[],
            entityInfo: EntityInfo,
            schemaName: string,
            baseView: string,
            whereSQL: string,
        ): { aggregateSQL: string; validationErrors: AggregateResult[] };
        BuildChildDiscoverySQL(
            childEntities: EntityInfo[],
            recordPKValue: string,
        ): string;
        BuildDatasetFilterFromConfig(): DatasetItemFilterType[];
        BuildDeleteExecuteOptions(
            entity: BaseEntity,
            sqlDetails: DeleteSQLResult,
        ): ExecuteSQLOptions;
        BuildEntityRecordNameSQL(
            entityName: string,
            compositeKey: CompositeKey,
        ): string;
        BuildHardLinkDependencySQL(
            entityDependencies: EntityDependency[],
            compositeKey: CompositeKey,
        ): string;
        BuildParameterPlaceholder(index: number): string;
        BuildRecordChangePayload(
            newData: Record<string, unknown>,
            oldData: Record<string, unknown>,
            recordID: string,
            entityInfo: EntityInfo,
            type: "Create" | "Update" | "Delete",
            user: UserInfo,
            restoreContext?: RestoreContext,
            quoteToEscape?: string,
        ): RecordChangePayload;
        BuildRecordChangeSQL(
            newData: Record<string, unknown>,
            oldData: Record<string, unknown>,
            entityName: string,
            recordID: string,
            entityInfo: EntityInfo,
            type: "Create" | "Update" | "Delete",
            user: UserInfo,
            restoreContext?: RestoreContext,
        ): { parameters?: unknown[]; sql: string };
        BuildSaveExecuteOptions(
            entity: BaseEntity,
            sqlDetails: SaveSQLResult,
        ): ExecuteSQLOptions;
        BuildSiblingRecordChangeSQL(
            varName: string,
            entityInfo: EntityInfo,
            safeChangesJSON: string,
            safeChangesDesc: string,
            safePKValue: string,
            safeUserId: string,
        ): string;
        BuildSoftLinkDependencySQL(
            entityName: string,
            compositeKey: CompositeKey,
        ): string;
        CacheDataset(
            datasetName: string,
            itemFilters: DatasetItemFilterType[],
            dataset: DatasetResultType,
        ): Promise<void>;
        cacheDeniedForViewOnlyRequest(
            params: RunViewParams,
            contextUser?: UserInfo,
        ): boolean;
        CancelPendingMetadataMemberRefresh(): void;
        CheckCreateRLS(entity: BaseEntity, user: UserInfo): Promise<boolean>;
        CheckRecordRLS(
            entity: BaseEntity,
            user: UserInfo,
            type: EntityPermissionType,
        ): Promise<boolean>;
        CheckToSeeIfRefreshNeeded(
            providerToUse?: IMetadataProvider,
            bypassMinCheckInterval?: boolean,
        ): Promise<boolean>;
        CheckUpdateRLSPostImage(
            entity: BaseEntity,
            user: UserInfo,
        ): Promise<boolean>;
        CheckUserReadPermissions(entityName: string, contextUser: UserInfo): void;
        ClearDatasetCache(
            datasetName: string,
            itemFilters?: DatasetItemFilterType[],
        ): Promise<void>;
        CloneAllMetadata(toClone: AllMetadata): AllMetadata;
        CommitTransaction(): Promise<void>;
        CompleteMergeLogging(
            recordMergeLog: BaseEntity,
            result: RecordMergeResult,
            contextUser?: UserInfo,
        ): Promise<void>;
        ComputeClientFLSAllowedKey(params: RunViewParams): string;
        ComputeRunViewFetchFields(entity: EntityInfo): string[];
        ComputeRunViewFLSFingerprintKey(params: RunViewParams): string;
        ComputeRunViewRLSWhereClause(
            params: RunViewParams,
            contextUser?: UserInfo,
        ): string;
        Config(
            data: ProviderConfigDataBase,
            providerToUse?: IMetadataProvider,
        ): Promise<boolean>;
        ConvertItemFiltersToUniqueKey(itemFilters: DatasetItemFilterType[]): string;
        CopyMetadataFromGlobalProvider(): boolean;
        CreateAuditLogRecord(
            user: UserInfo,
            authorizationName: string,
            auditLogTypeName: string,
            status: string,
            details: string,
            entityId: string,
            recordId: string,
            auditLogDescription: string,
            saveOptions: EntitySaveOptions,
        ): Promise<BaseEntity<unknown>>;
        CreateIndependentInstance(): Promise<DatabaseProviderBase>;
        CreateSharedMetadataShell(shared: AllMetadata): AllMetadata;
        CreateTransactionGroup(): Promise<TransactionGroupBase>;
        CreateUserDescriptionOfChanges(
            changesObject: Record<string, FieldChange>,
            maxValueLength?: number,
            cutOffText?: string,
        ): string;
        Delete(
            entity: BaseEntity,
            options: EntityDeleteOptions,
            user: UserInfo,
        ): Promise<boolean>;
        DiffObjects(
            oldData: Record<string, unknown>,
            newData: Record<string, unknown>,
            entityInfo: EntityInfo,
            quoteToEscape: string,
        ): Record<string, FieldChange>;
        EntityByID(entityID: string): EntityInfo;
        EntityByName(entityName: string): EntityInfo;
        EntityStatusCheck(
            params: RunViewParams,
            callerName: string,
            contextUser?: UserInfo,
        ): Promise<void>;
        EscapeQuotesInProperties(obj: unknown, quoteToEscape: string): unknown;
        eventTargetsThisProviderBackend(entityEvent: BaseEntityEvent): boolean;
        ExecuteAggregateQuery(
            aggregateSQL: string,
            aggregates: { alias?: string; expression: string }[],
            validationErrors: AggregateResult[],
            contextUser?: UserInfo,
        ): Promise<{ executionTime: number; results: AggregateResult[] }>;
        ExecuteQueryFromSpec(
            spec: QueryExecutionSpec,
            contextUser?: UserInfo,
        ): Promise<RunQueryResult>;
        ExecuteSQL<T>(
            query: string,
            parameters?: unknown[],
            options?: ExecuteSQLOptions,
            contextUser?: UserInfo,
        ): Promise<T[]>;
        extractMaxUpdatedAt(results: unknown[]): string;
        FindISAChildEntities(
            entityInfo: EntityInfo,
            recordPKValue: string,
            contextUser?: UserInfo,
        ): Promise<{ ChildEntityName: string }[]>;
        FindISAChildEntity(
            entityInfo: EntityInfo,
            recordPKValue: string,
            contextUser?: UserInfo,
        ): Promise<{ ChildEntityName: string }>;
        FullTextSearch(
            params: FullTextSearchParams,
            contextUser?: UserInfo,
        ): Promise<FullTextSearchResult>;
        GenerateDeleteSQL(
            entity: BaseEntity,
            user: UserInfo,
            options?: EntityDeleteOptions,
        ): DeleteSQLResult;
        GenerateNewID(): string;
        GenerateSaveSQL(
            entity: BaseEntity,
            isNew: boolean,
            user: UserInfo,
            options?: EntitySaveOptions,
        ): Promise<SaveSQLResult>;
        GetAllMetadata(
            providerToUse?: IMetadataProvider,
            forceRefresh?: boolean,
        ): Promise<AllMetadata>;
        GetAndCacheDatasetByName(
            datasetName: string,
            itemFilters?: DatasetItemFilterType[],
            contextUser?: UserInfo,
            providerToUse?: IMetadataProvider,
        ): Promise<DatasetResultType>;
        GetCachedDataset(
            datasetName: string,
            itemFilters?: DatasetItemFilterType[],
        ): Promise<DatasetResultType>;
        GetCachedRecordName(
            entityName: string,
            compositeKey: CompositeKey,
            loadIfNeeded?: boolean,
        ): Promise<string>;
        GetCreateUpdateSPName(entity: BaseEntity, bNewRecord: boolean): string;
        GetCurrentUser(): Promise<UserInfo>;
        GetDatasetByName(
            datasetName: string,
            itemFilters?: DatasetItemFilterType[],
            contextUser?: UserInfo,
            providerToUse?: IMetadataProvider,
            forceRefresh?: boolean,
        ): Promise<DatasetResultType>;
        GetDatasetCacheKey(
            datasetName: string,
            itemFilters?: DatasetItemFilterType[],
        ): string;
        GetDatasetStatusByName(
            datasetName: string,
            itemFilters?: DatasetItemFilterType[],
            contextUser?: UserInfo,
            providerToUse?: IMetadataProvider,
        ): Promise<DatasetStatusResultType>;
        GetEntityAIActions(
            _entityInfo: EntityInfo,
            _before: boolean,
        ): {
            AIActionID: string;
            AIModelID: string;
            EntityID: string;
            ID: string;
            TriggerEvent: string;
        }[];
        GetEntityDependencies(entityName: string): Promise<EntityDependency[]>;
        GetEntityObject<T extends BaseEntity<unknown>>(
            entityName: string,
            contextUser?: UserInfo,
        ): Promise<T>;
        GetEntityObject<T extends BaseEntity<unknown>>(
            entityName: string,
            loadKey: CompositeKey,
            contextUser?: UserInfo,
        ): Promise<T>;
        GetEntityRecordName(
            entityName: string,
            compositeKey: CompositeKey,
            contextUser?: UserInfo,
            forceRefresh?: boolean,
        ): Promise<string>;
        GetEntityRecordNames(
            info: EntityRecordNameInput[],
            contextUser?: UserInfo,
            forceRefresh?: boolean,
        ): Promise<EntityRecordNameResult[]>;
        GetFullSubTree(entityInfo: EntityInfo): EntityInfo[];
        GetLatestMetadataUpdates(
            providerToUse?: IMetadataProvider,
        ): Promise<MetadataInfo[]>;
        GetLocalDatasetTimestamp(
            datasetName: string,
            itemFilters?: DatasetItemFilterType[],
        ): Promise<Date>;
        GetRecordChanges(
            entityName: string,
            compositeKey: CompositeKey,
            contextUser?: UserInfo,
        ): Promise<RecordChange[]>;
        GetRecordDependencies(
            entityName: string,
            compositeKey: CompositeKey,
            contextUser?: UserInfo,
        ): Promise<RecordDependency[]>;
        GetRecordDuplicates(
            params: PotentialDuplicateRequest,
            contextUser?: UserInfo,
        ): Promise<PotentialDuplicateResponse>;
        GetRecordFavoriteID(
            userId: string,
            entityName: string,
            compositeKey: CompositeKey,
            contextUser?: UserInfo,
        ): Promise<string>;
        GetRecordFavoriteStatus(
            userId: string,
            entityName: string,
            compositeKey: CompositeKey,
            contextUser?: UserInfo,
        ): Promise<boolean>;
        GetTransactionExtraData(_entity: BaseEntity): Record<string, unknown>;
        HandleEntityActions(
            _entity: BaseEntity,
            _baseType: "delete" | "validate" | "save",
            _before: boolean,
            _user: UserInfo,
            _originatingEntityActionIDs?: string[],
        ): Promise<{ Message?: string; Success: boolean }[]>;
        HandleEntityAIActions(
            _entity: BaseEntity,
            _baseType: "delete" | "save",
            _before: boolean,
            _user: UserInfo,
        ): Promise<void>;
        handleMetadataMemberEntityEvent(
            lowerEntityName: string,
            entityEvent: BaseEntityEvent,
        ): void;
        InternalExecuteQueryFromSpec(
            spec: QueryExecutionSpec,
            contextUser?: UserInfo,
        ): Promise<RunQueryResult>;
        InternalGetEntityRecordName(
            entityName: string,
            compositeKey: CompositeKey,
            contextUser?: UserInfo,
        ): Promise<string>;
        InternalGetEntityRecordNames(
            info: EntityRecordNameInput[],
            contextUser?: UserInfo,
        ): Promise<EntityRecordNameResult[]>;
        InternalRouteOperation<TInput = unknown, TOutput = unknown>(
            operationKey: string,
            input: TInput,
            options: RemoteOpInvokeOptions,
        ): Promise<RemoteOpResult<TOutput>>;
        InternalRunQueries(
            params: RunQueryParams[],
            contextUser?: UserInfo,
        ): Promise<RunQueryResult[]>;
        InternalRunQuery(
            params: RunQueryParams,
            contextUser?: UserInfo,
        ): Promise<RunQueryResult>;
        InternalRunView<T = any>(
            params: RunViewParams,
            contextUser?: UserInfo,
        ): Promise<RunViewResult<T>>;
        InternalRunViews<T = any>(
            params: RunViewParams[],
            contextUser?: UserInfo,
        ): Promise<RunViewResult<T>[]>;
        invalidateInflightViewsForEntity(lowerEntityName: string): void;
        IsDatasetCached(
            datasetName: string,
            itemFilters?: DatasetItemFilterType[],
        ): Promise<boolean>;
        IsDatasetCacheUpToDate(
            datasetName: string,
            itemFilters?: DatasetItemFilterType[],
        ): Promise<boolean>;
        IsEntityOrAncestorOf(entityInfo: EntityInfo, targetName: string): boolean;
        IsExternalQuery(_params: RunQueryParams): boolean;
        isMaterializedWrapperEntity(param: RunViewParams): boolean;
        IsNonUUIDDatabaseFunction(value: string): boolean;
        IsServerCacheAllowedForEntity(params: RunViewParams): boolean;
        IsUUIDGenerationFunction(value: string): boolean;
        LoadLocalMetadataFromStorage(): Promise<void>;
        LocalMetadataObsolete(type?: string): boolean;
        LogRecordChange(
            newData: Record<string, unknown>,
            oldData: Record<string, unknown>,
            entityName: string,
            recordID: string,
            entityInfo: EntityInfo,
            type: "Create" | "Update" | "Delete",
            user: UserInfo,
            restoreContext?: RestoreContext,
        ): Promise<unknown[]>;
        MapTransactionResultToNewValues(
            transactionResult: Record<string, unknown>,
        ): { FieldName: string; Value: unknown }[];
        mergeCachedAndFreshResults(
            preResult: {
                allCached: boolean;
                cachedResults?: RunViewResult[];
                cacheStatusMap?: Map<
                    number,
                    {
                        result?: RunViewResult;
                        status: "expired"
                        | "disabled"
                        | "hit"
                        | "miss";
                    },
                >;
                callerFieldsMap?: Map<number, string[]>;
                fingerprintMap?: Map<number, string>;
                smartCacheCheckParams?: RunViewWithCacheCheckParams[];
                telemetryEventId?: string;
                uncachedParams?: RunViewParams[];
                useSmartCacheCheck?: boolean;
            },
            freshResults: RunViewResult[],
        ): RunViewResult[];
        mergeQueryCachedAndFreshResults(
            preResult: {
                allCached: boolean;
                cachedResults?: RunQueryResult[];
                cacheStatusMap?: Map<
                    number,
                    {
                        result?: RunQueryResult;
                        status: "expired"
                        | "disabled"
                        | "hit"
                        | "miss";
                    },
                >;
                telemetryEventId?: string;
                uncachedParams?: RunQueryParams[];
            },
            freshResults: RunQueryResult[],
        ): RunQueryResult[];
        MergeRecords(
            request: RecordMergeRequest,
            contextUser?: UserInfo,
            _options?: EntityMergeOptions,
        ): Promise<RecordMergeResult>;
        NormalizeSimpleRowTypes(param: RunViewParams, result: RunViewResult): void;
        OnAfterDeleteExecute(
            _entity: BaseEntity,
            _user: UserInfo,
            _options: EntityDeleteOptions,
        ): void;
        OnAfterSaveExecute(
            _entity: BaseEntity,
            _user: UserInfo,
            _options: EntitySaveOptions,
            _context: SaveContext,
        ): void;
        OnBeforeDeleteExecute(
            _entity: BaseEntity,
            _user: UserInfo,
            _options: EntityDeleteOptions,
        ): Promise<void>;
        OnBeforeSaveExecute(
            _entity: BaseEntity,
            _user: UserInfo,
            _options: EntitySaveOptions,
            _context: SaveContext,
        ): Promise<void>;
        OnResumeRefresh(): void;
        OnSaveCompleted(
            entity: BaseEntity,
            saveSQLResult: SaveSQLResult,
            user: UserInfo,
            options: EntitySaveOptions,
            _context: SaveContext,
        ): Promise<Record<string, unknown>>;
        OnSuspendRefresh(): void;
        OnValidateBeforeSave(
            _entity: BaseEntity,
            _user: UserInfo,
            _context: SaveContext,
        ): Promise<string>;
        PostProcessEntityMetadata(
            entities: EntityMetadataRow[],
            fields: EntityFieldMetadataRow[],
            fieldValues: EntityFieldValueMetadataRow[],
            permissions: EntityChildMetadataRow[],
            relationships: EntityChildMetadataRow[],
            settings: EntityChildMetadataRow[],
            organicKeys?: OrganicKeyMetadataRow[],
            organicKeyRelatedEntities?: OrganicKeyRelatedEntityMetadataRow[],
            fieldPermissions?: EntityFieldPermissionMetadataRow[],
        ): EntityInfo[];
        PostProcessRows(
            rows: Record<string, unknown>[],
            _entityInfo: EntityInfo,
            _user: UserInfo,
        ): Promise<Record<string, unknown>[]>;
        PostProcessRunView(
            result: RunViewResult,
            params: RunViewParams,
            contextUser?: UserInfo,
        ): Promise<void>;
        PostProcessRunViews(
            results: RunViewResult[],
            params: RunViewParams[],
            contextUser?: UserInfo,
        ): Promise<void>;
        PostRunQueries(
            results: RunQueryResult[],
            params: RunQueryParams[],
            preResult: {
                allCached: boolean;
                cachedResults?: RunQueryResult[];
                cacheStatusMap?: Map<
                    number,
                    {
                        result?: RunQueryResult;
                        status: "expired"
                        | "disabled"
                        | "hit"
                        | "miss";
                    },
                >;
                telemetryEventId?: string;
                uncachedParams?: RunQueryParams[];
            },
            contextUser?: UserInfo,
        ): Promise<void>;
        PostRunQuery(
            result: RunQueryResult,
            params: RunQueryParams,
            preResult: {
                cachedResult?: RunQueryResult;
                cacheStatus: "expired" | "disabled" | "hit" | "miss";
                fingerprint?: string;
                telemetryEventId?: string;
            },
            contextUser?: UserInfo,
        ): Promise<void>;
        PostRunView(
            result: RunViewResult,
            params: RunViewParams,
            preResult: {
                cachedResult?: RunViewResult;
                cacheStatus: "expired" | "disabled" | "hit" | "miss";
                callerRequestedFields?: string[];
                fingerprint?: string;
                telemetryEventId?: string;
            },
            contextUser?: UserInfo,
        ): Promise<void>;
        PostRunViews(
            results: RunViewResult[],
            params: RunViewParams[],
            preResult: {
                allCached: boolean;
                cachedResults?: RunViewResult[];
                cacheStatusMap?: Map<
                    number,
                    {
                        result?: RunViewResult;
                        status: "expired"
                        | "disabled"
                        | "hit"
                        | "miss";
                    },
                >;
                callerFieldsMap?: Map<number, string[]>;
                fingerprintMap?: Map<number, string>;
                smartCacheCheckParams?: RunViewWithCacheCheckParams[];
                telemetryEventId?: string;
                uncachedParams?: RunViewParams[];
                useSmartCacheCheck?: boolean;
            },
            contextUser?: UserInfo,
        ): Promise<void>;
        PreProcessRunView<T = any>(
            params: RunViewParams,
            contextUser?: UserInfo,
        ): Promise<void>;
        PreProcessRunViews(
            params: RunViewParams[],
            contextUser?: UserInfo,
        ): Promise<void>;
        PreRunQueries(
            params: RunQueryParams[],
            contextUser?: UserInfo,
        ): Promise<
            {
                allCached: boolean;
                cachedResults?: RunQueryResult[];
                cacheStatusMap?: Map<
                    number,
                    {
                        result?: RunQueryResult;
                        status: "expired"
                        | "disabled"
                        | "hit"
                        | "miss";
                    },
                >;
                telemetryEventId?: string;
                uncachedParams?: RunQueryParams[];
            },
        >;
        PreRunQuery(
            params: RunQueryParams,
            contextUser?: UserInfo,
        ): Promise<
            {
                cachedResult?: RunQueryResult;
                cacheStatus: "expired"
                | "disabled"
                | "hit"
                | "miss";
                fingerprint?: string;
                telemetryEventId?: string;
            },
        >;
        PreRunView(
            params: RunViewParams,
            contextUser?: UserInfo,
        ): Promise<
            {
                cachedResult?: RunViewResult;
                cacheStatus: "expired"
                | "disabled"
                | "hit"
                | "miss";
                callerRequestedFields?: string[];
                fingerprint?: string;
                telemetryEventId?: string;
            },
        >;
        PreRunViews(
            params: RunViewParams[],
            contextUser?: UserInfo,
        ): Promise<
            {
                allCached: boolean;
                cachedResults?: RunViewResult[];
                cacheStatusMap?: Map<
                    number,
                    {
                        result?: RunViewResult;
                        status: "expired"
                        | "disabled"
                        | "hit"
                        | "miss";
                    },
                >;
                callerFieldsMap?: Map<number, string[]>;
                fingerprintMap?: Map<number, string>;
                smartCacheCheckParams?: RunViewWithCacheCheckParams[];
                telemetryEventId?: string;
                uncachedParams?: RunViewParams[];
                useSmartCacheCheck?: boolean;
            },
        >;
        preValidateAndRefresh(providerToUse?: IMetadataProvider): Promise<void>;
        PropagateRecordChangesToSiblings(
            parentInfo: EntityInfo,
            changeData: { changesDescription: string; changesJSON: string },
            pkValue: string,
            userId: string,
            activeChildEntityName: string,
            extraExecOptions?: Record<string, unknown>,
        ): Promise<void>;
        QuoteIdentifier(name: string): string;
        QuoteSchemaAndView(schemaName: string, objectName: string): string;
        RebuildEntityMaps(): void;
        Refresh(providerToUse?: IMetadataProvider): Promise<boolean>;
        RefreshAfterMetadataMemberChange(): Promise<boolean>;
        RefreshCurrentUser(): Promise<UserInfo>;
        RefreshIfNeeded(
            providerToUse?: IMetadataProvider,
            bypassMinCheckInterval?: boolean,
        ): Promise<boolean>;
        RefreshRemoteMetadataTimestamps(
            providerToUse?: IMetadataProvider,
        ): Promise<boolean>;
        registerMetadataDatasetMembership(dataset: DatasetResultType): void;
        ReleaseIndependentInstance(): Promise<void>;
        RemoveLocalMetadataFromStorage(): Promise<void>;
        ResetTransactionState(): Promise<void>;
        ResolveMergeLinkValue(
            dependency: RecordDependency,
            survivingRecordKey: CompositeKey,
        ): unknown;
        ResolvePlatformSQLInParams(params: RunViewParams): void;
        ResolveQueryCacheAuthorization(
            params: RunQueryParams,
            user?: UserInfo,
        ): QueryCacheAuthorization;
        ResolveRunViewEntitySync(params: RunViewParams): EntityInfo;
        ResolveSQL(value: string | PlatformSQL): string;
        RollbackTransaction(): Promise<void>;
        RouteOperation<TInput = unknown, TOutput = unknown>(
            operationKey: string,
            input: TInput,
            options?: RemoteOpInvokeOptions,
        ): Promise<RemoteOpResult<TOutput>>;
        RunPostRunViewHooks(
            params: RunViewParams,
            result: RunViewResult,
            contextUser?: UserInfo,
        ): Promise<RunViewResult>;
        RunPreRunViewHooks(
            params: RunViewParams,
            contextUser?: UserInfo,
        ): Promise<RunViewParams>;
        RunQueries(
            params: RunQueryParams[],
            contextUser?: UserInfo,
        ): Promise<RunQueryResult[]>;
        RunQuery(
            params: RunQueryParams,
            contextUser?: UserInfo,
        ): Promise<RunQueryResult>;
        RunView<T = any>(
            params: RunViewParams,
            contextUser?: UserInfo,
        ): Promise<RunViewResult<T>>;
        runViewCacheEligible(param: RunViewParams): boolean;
        runViewCacheEligibleForWrite(param: RunViewParams): boolean;
        RunViews<T = any>(
            params: RunViewParams[],
            contextUser?: UserInfo,
        ): Promise<RunViewResult<T>[]>;
        Save(
            entity: BaseEntity,
            user: UserInfo,
            options: EntitySaveOptions,
        ): Promise<{}>;
        SaveLocalMetadataToStorage(): Promise<void>;
        scheduleMetadataMemberRefresh(): void;
        SearchEntities(
            params: SearchEntityParams[],
        ): Promise<EntitySearchResult[][]>;
        searchEntitiesSemanticPass(
            entityDocumentId: string,
            searchText: string,
            overFetch: number,
            embeddingAIModelId: string,
            contextUser: UserInfo,
        ): Promise<ScoredCandidate[]>;
        SearchEntity(params: SearchEntityParams): Promise<EntitySearchResult[]>;
        SetCachedRecordName(
            entityName: string,
            compositeKey: CompositeKey,
            recordName: string,
        ): void;
        SetRecordFavoriteStatus(
            userId: string,
            entityName: string,
            compositeKey: CompositeKey,
            isFavorite: boolean,
            contextUser: UserInfo,
        ): Promise<void>;
        shouldAutoCache(
            params: RunViewParams,
            result: RunViewResult,
            contextUser?: UserInfo,
        ): boolean;
        ShouldTrackRecordChanges(entityInfo: EntityInfo): boolean;
        StartMergeLogging(
            request: RecordMergeRequest,
            result: RecordMergeResult,
            contextUser?: UserInfo,
        ): Promise<BaseEntity<unknown>>;
        TransformSimpleObjectToEntityObject(
            param: RunViewParams,
            result: RunViewResult,
            contextUser?: UserInfo,
        ): Promise<void>;
        TrimString(
            value: unknown,
            maxLength: number,
            trailingChars: string,
        ): unknown;
        UpdateLocalMetadata(res: AllMetadata): void;
        ValidateDeleteResult(
            entity: BaseEntity,
            rawResult: Record<string, unknown>[],
            entityResult: BaseEntityResult,
        ): boolean;
        ValidateUserProvidedSQLClause(clause: string): boolean;
    }

    Hierarchy (View Summary)

    Index

    Properties

    Accessors

    Methods

    ApplyFieldSecurityProjection ApplyPostRunViewHooksToCacheHit ApplyRecordChangeFieldSecurityProjection AssertPredicatesRespectFieldSecurity backgroundValidateAndRefresh BeginEntityTransaction BeginTransaction BuildAggregateSQL BuildChildDiscoverySQL BuildDatasetFilterFromConfig BuildDeleteExecuteOptions BuildEntityRecordNameSQL BuildHardLinkDependencySQL BuildParameterPlaceholder BuildRecordChangePayload BuildRecordChangeSQL BuildSaveExecuteOptions BuildSiblingRecordChangeSQL BuildSoftLinkDependencySQL CacheDataset cacheDeniedForViewOnlyRequest CancelPendingMetadataMemberRefresh CheckCreateRLS CheckRecordRLS CheckToSeeIfRefreshNeeded CheckUpdateRLSPostImage CheckUserReadPermissions ClearDatasetCache CloneAllMetadata CommitTransaction CompleteMergeLogging ComputeClientFLSAllowedKey ComputeRunViewFetchFields ComputeRunViewFLSFingerprintKey ComputeRunViewRLSWhereClause Config ConvertItemFiltersToUniqueKey CopyMetadataFromGlobalProvider CreateAuditLogRecord CreateIndependentInstance CreateSharedMetadataShell CreateTransactionGroup CreateUserDescriptionOfChanges Delete DiffObjects EntityByID EntityByName EntityStatusCheck EscapeQuotesInProperties eventTargetsThisProviderBackend ExecuteAggregateQuery ExecuteQueryFromSpec ExecuteSQL extractMaxUpdatedAt FindISAChildEntities FindISAChildEntity FullTextSearch GenerateDeleteSQL GenerateNewID GenerateSaveSQL GetAllMetadata GetAndCacheDatasetByName GetCachedDataset GetCachedRecordName GetCreateUpdateSPName GetCurrentUser GetDatasetByName GetDatasetCacheKey GetDatasetStatusByName GetEntityAIActions GetEntityDependencies GetEntityObject GetEntityRecordName GetEntityRecordNames GetFullSubTree GetLatestMetadataUpdates GetLocalDatasetTimestamp GetRecordChanges GetRecordDependencies GetRecordDuplicates GetRecordFavoriteID GetRecordFavoriteStatus GetTransactionExtraData HandleEntityActions HandleEntityAIActions handleMetadataMemberEntityEvent InternalExecuteQueryFromSpec InternalGetEntityRecordName InternalGetEntityRecordNames InternalRouteOperation InternalRunQueries InternalRunQuery InternalRunView InternalRunViews invalidateInflightViewsForEntity IsDatasetCached IsDatasetCacheUpToDate IsEntityOrAncestorOf IsExternalQuery isMaterializedWrapperEntity IsNonUUIDDatabaseFunction IsServerCacheAllowedForEntity IsUUIDGenerationFunction LoadLocalMetadataFromStorage LocalMetadataObsolete LogRecordChange MapTransactionResultToNewValues mergeCachedAndFreshResults mergeQueryCachedAndFreshResults MergeRecords NormalizeSimpleRowTypes OnAfterDeleteExecute OnAfterSaveExecute OnBeforeDeleteExecute OnBeforeSaveExecute OnResumeRefresh OnSaveCompleted OnSuspendRefresh OnValidateBeforeSave PostProcessEntityMetadata PostProcessRows PostProcessRunView PostProcessRunViews PostRunQueries PostRunQuery PostRunView PostRunViews PreProcessRunView PreProcessRunViews PreRunQueries PreRunQuery PreRunView PreRunViews preValidateAndRefresh PropagateRecordChangesToSiblings QuoteIdentifier QuoteSchemaAndView RebuildEntityMaps Refresh RefreshAfterMetadataMemberChange RefreshCurrentUser RefreshIfNeeded RefreshRemoteMetadataTimestamps registerMetadataDatasetMembership ReleaseIndependentInstance RemoveLocalMetadataFromStorage ResetTransactionState ResolveMergeLinkValue ResolvePlatformSQLInParams ResolveQueryCacheAuthorization ResolveRunViewEntitySync ResolveSQL RollbackTransaction RouteOperation RunPostRunViewHooks RunPreRunViewHooks RunQueries RunQuery RunView runViewCacheEligible runViewCacheEligibleForWrite RunViews Save SaveLocalMetadataToStorage scheduleMetadataMemberRefresh SearchEntities searchEntitiesSemanticPass SearchEntity SetCachedRecordName SetRecordFavoriteStatus shouldAutoCache ShouldTrackRecordChanges StartMergeLogging TransformSimpleObjectToEntityObject TrimString UpdateLocalMetadata ValidateDeleteResult ValidateUserProvidedSQLClause

    Properties

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

    Result from PreRunQueries hook containing cache status for batch operations

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

    Result from PreRunQuery hook containing cache status and optional cached result

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

    Result from PreRunView hook containing cache status and optional cached result

    Type Declaration

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

      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: "expired"
                | "disabled"
                | "hit"
                | "miss";
            },
        >;
        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: "expired"
          | "disabled"
          | "hit"
          | "miss" },
      >
    • 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

    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 ConfigData(): ProviderConfigDataBase

      Gets the configuration data that was provided to the provider.

      Returns ProviderConfigDataBase

      The provider configuration including schema filters

    • get CurrentTransactionDepth(): number

      The provider's current transaction nesting depth, for subclasses that track one.

      Distinct from IsInTransaction, which some providers deliberately leave false so that RunMaybeSerial keeps fanning out — SQL Server most notably. This accessor exists so the entity-transaction machinery can still see real nesting on those providers: it feeds EntityTransactionScope.IsNested and the out-of-order settle detection in BeginEntityTransaction. Defaults to 0 for providers that do not track depth.

      Returns number

    • get CurrentUser(): UserInfo

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

      Returns UserInfo

      UserInfo object for the authenticated user

    • get DatabaseConnection(): any

      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 any

    • 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(): SQLDialect

      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 SQLDialect

    • get Entities(): EntityInfo[]

      Gets all entity metadata in the system.

      Returns EntityInfo[]

      Array of EntityInfo objects representing all entities

    • get FileSystemProvider(): IFileSystemProvider

      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

    • 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

      Gets the local storage provider implementation. Must be implemented by subclasses to provide environment-specific storage.

      Returns ILocalStorageProvider

      Local storage provider instance

    • get Metadata(): IMetadataProvider

      Gets the metadata provider instance. Must be implemented by subclasses to provide access to metadata.

      Returns IMetadataProvider

      The metadata provider instance

    • get MetadataMemberRefreshDelayMs(): number

      How long a member-entity write waits before this provider's refresh runs. The base value is the short debounce window — right for the server, where the writer is the refresher and the delay only exists to coalesce a burst and let the enclosing transaction commit. Transport providers override this with a much longer, RANDOMIZED window: every browser receives every write broadcast, so the delay is what turns "N clients each re-pull the metadata graph within the same half-second of any member write" into "each client pays at most one staleness check per window, at a moment no other client shares".

      Returns number

    • get MetadataMemberRefreshRearmsOnNewEvents(): boolean

      Whether a member-entity write arriving while the refresh timer is already armed RESTARTS the timer (debounce) or joins the pending window (coalesce/throttle).

      The base is a true debounce (true): the server's refresh must run AFTER the last write of the unit of work, so every event pushes the timer out — a burst costs one refresh, run once the burst ends. Transport providers return false: with a long window, re-arming would let steady org-wide write activity postpone the refresh indefinitely (starvation); joining the armed window guarantees at most one refresh per window regardless of write rate, which is the whole point of the window.

      Returns boolean

    • 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 PlatformKey(): DatabasePlatform

      Returns the database platform key for this provider. Override in subclasses. Defaults to 'sqlserver' for backward compatibility. Inherited from ProviderBase; redeclared here for DatabaseProviderBase consumers.

      Returns DatabasePlatform

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

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

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

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

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

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

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

        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: "expired"
                  | "disabled"
                  | "hit"
                  | "miss";
              },
          >;
          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: "expired"
                  | "disabled"
                  | "hit"
                  | "miss";
              },
          >;
          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: "expired"
            | "disabled"
            | "hit"
            | "miss" },
        >
      • 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 ProviderType(): ProviderType

      Returns the provider type for the instance. Identifies whether this is a Database or Network provider.

      Returns ProviderType

    • 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 SupportsEntityTransactions(): boolean

      Database providers execute multi-record units of work atomically, in-process.

      Returns boolean

      ProviderBase.SupportsEntityTransactions for why the base default is false.

    • get transactionDepth(): number

      Returns number

      Use TransactionDepth.

    • get TransactionDepth(): number

      Public nesting depth. 0 = no ambient TX. Join-TX callers (accounting CreateJournalEntries) must read this, not IsInTransaction (SQL Server leaves that false). Deprecated camelCase transactionDepth alias ships for one release.

      Returns number

    • 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

    • Strips fields the user cannot read from plain-object result rows.

      This is the primary read-time control for list results, and it runs on BOTH cache hits and cache misses — the property the rest of the cache design is arranged around. Because it reads live metadata, a permission change takes effect on the next metadata refresh with no result-cache invalidation: the cached full-width superset stays valid and only the projection changes.

      It composes with two per-request, never-cached narrowings that avoid pulling columns a restricted service account has no business holding: the simple-path SELECT-list intersection, and Load()'s allowed-column SELECT.

      NEVER applied to entity_object results. Those become BaseEntity instances whose fields round-trip through GenerateSaveSQL, which iterates ALL IsSPParameter fields reading field.Value — not just dirty ones. A stripped field would therefore be written back as a real NULL on the user's next save: silent data loss. Entity objects keep their values in server memory exactly as encrypted fields do; the trust boundary is the API output, which the GraphQL layer enforces separately.

      Type Parameters

      • T

      Parameters

      Returns T[]

    • Applies the PostRunView hook chain to a result that was served from cache, mutating result in place so the caller's reference reflects the chain's output.

      PostRunView is the OUTPUT half of the enforcement seam (data masking / audit). Hooks receive contextUser, so masking is PER-USER, while the cache slot is shared across users — there is no correct way to apply masking once at write time on behalf of a reader who has not arrived yet. A hit that skips the chain therefore returns rows the miss path would have masked.

      This previously appeared to work by accident: PostRunView writes the cache BEFORE running the hooks, so a hook that masked rows in place was writing through into the cached objects — which both made later hits look masked and baked one user's masking decision into a shared slot. Freeze-on-write removes that write-through, which is what makes running the chain here necessary rather than merely tidier.

      Cache-hit results are FRESH wrapper objects built per hit by PreRunView/PreRunViews — only .Results points at shared cache state. A hook that returns a replacement (the required pattern now that rows are frozen) is copied onto that per-hit wrapper, so it can never write back into the cache.

      GetDataHooks is a memoized store read (~30ns), but await-ing the async chain costs a microtask (~750ns) — comparable to the entire cache lookup this rides on. The overwhelmingly common case is zero registered hooks, so check first and skip the await.

      Parameters

      Returns Promise<void>

    • Strips or narrows the MJ: Record Changes payload columns a user may not read, using the denied set of the entity each row is ABOUT rather than of Record Changes itself.

      A sibling of ApplyFieldSecurityProjection rather than part of it, because that method short-circuits on EnableFieldLevelSecurity for the entity named in the RunView params — which here is MJ: Record Changes, whose flag is off in every default deployment. Everything about the per-row denied set, the payload treatment, and the fail-closed decision lives in RecordChangeFieldSecurityProjector; this is only the RunView wiring.

      Runs at all four RunView projection points, matching the main projection: both cache-hit paths and both cache-miss paths. The cache-hit path is not optional — it is the exact path the original cross-user leak runs through, an unrestricted user warming a full-width slot that a restricted user then hits.

      NEVER applied to entity_object results, for the reason the main projection is exempt plus one specific to this one. The main reason transfers directly: an entity object's fields round-trip through GenerateSaveSQL, which reads EVERY IsSPParameter field's value rather than only dirty ones, so a withheld ChangesDescription would be written back as a real NULL and a narrowed ChangesJSON as the narrowed payload — destroying audit history instead of merely hiding it. Record Changes rows genuinely are saved through the entity layer (replay writes Status/ErrorLog, users write Comments), so this is not hypothetical. The additional reason is that the exemption cannot become a hole: the GraphQL RunView resolver coerces entity_object to simple on the wire, so an entity_object Record Changes result is by construction server-internal — and server-internal code holding full values in memory is the documented trust boundary (FLS guide §3.4), exactly as for encrypted fields.

      Type Parameters

      • T

      Parameters

      Returns T[]

    • Rejects a RunView whose ExtraFilter, OrderBy, or Aggregates expressions reference a field the user cannot read.

      Output projection alone is security theater. A user denied Salary can send ExtraFilter: "Salary > 200000" or OrderBy: "Salary DESC" and reconstruct the values from which rows come back and in what order — the column never appears in a result, so every output-stripping point reports "secure." Aggregates are the same channel in a purer form: Aggregates: [{expression: 'MIN(Salary)'}] under a narrow filter returns a denied field's exact values directly. Predicate validation is a first-class enforcement point, not a belt-and-braces afterthought. Together these cover every caller-authored expression surface (UserSearchString is handled by excluding denied fields from the searched set, not by rejection — see below).

      Lives at the provider layer rather than in the GraphQL resolver (where the plan first placed it) because every RunView funnels through here — the batch path, server-internal agents and actions running under a restricted contextUser, and the resolver alike. One gate, no path left uncovered.

      The error deliberately does not say whether the field is missing or merely forbidden — see ProviderBase.FieldSecurityDenialMessage.

      Parameters

      Returns void

    • 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>

    • Begins a transaction scope, or joins one already in flight on this provider.

      This is the single transaction primitive for all multi-record entity work — IS-A parent chains, composite save graphs and hand-written application cascades. It delegates to the provider's existing depth-counted BeginTransaction / CommitTransaction / RollbackTransaction, which already implement the join semantics: the outermost call issues a physical BEGIN, nested calls create savepoints, and only the outermost commit commits for real.

      Routing IS-A through here is what closed the torn-write bug described in EntityTransactionScope — the previous BeginISATransaction() opened a second physical transaction on the same pool, blind to any transaction the caller had already started.

      The returned scope is settle-once: the first Commit() or Rollback() wins and later calls are no-ops, so try { ...; Commit() } catch { Rollback() } is safe even when the work already unwound its own scope.

      Returns Promise<EntityTransactionScope>

      A scope bound to this provider's ambient transaction.

    • Begins a transaction for the current database connection.

      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; validationErrors: AggregateResult[] }

      Object with aggregateSQL string and any validation errors

    • Builds a UNION ALL query that checks each child entity's base table for a record with the given primary key. Used by FindISAChildEntity/FindISAChildEntities.

      Parameters

      • childEntities: EntityInfo[]

        The child entities to search

      • recordPKValue: string

        The primary key value to find

      Returns string

    • 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

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

    • Builds SQL for hard-link (foreign key) dependency queries. Returns a UNION ALL query across all dependent entities.

      Parameters

      • entityDependencies: EntityDependency[]

        The entity-level dependency metadata

      • compositeKey: CompositeKey

        The primary key of the record being checked

      Returns string

    • 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

    • 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>

        Post-change data (null for deletes).

      • oldData: Record<string, unknown>

        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

        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

    • Builds the SQL (and optional parameters) for inserting a record change entry. Each provider generates its own dialect: SQL Server uses EXEC spCreateRecordChange_Internal, PostgreSQL uses INSERT INTO "RecordChange" with parameterized values.

      Returns null if there are no changes to log.

      Implementations should delegate the dialect-agnostic assembly work to BuildRecordChangePayload and only handle SQL string rendering locally — that's how the duplication between SQL Server and PostgreSQL stays minimal.

      Parameters

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

        When non-null, the resulting RecordChange row is written with Source='Restore', RestoredFromID = SourceChangeID, and RestoreReason = Reason. Read by callers from BaseEntity.RestoreContext immediately before generating SQL.

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

    • Builds the SQL for a single sibling entity's record change entry in the propagation batch. SQL Server uses FOR JSON PATH + spCreateRecordChange_Internal. PostgreSQL uses json_build_object + INSERT INTO "RecordChange".

      Parameters

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

      Returns string

    • Builds SQL for soft-link dependency queries (entities using EntityIDFieldName pattern). Returns a UNION ALL query across all soft-linked entities.

      Parameters

      • entityName: string

        The entity name being checked for dependencies

      • compositeKey: CompositeKey

        The primary key of the record

      Returns string

    • Stores a dataset in the local cache. If itemFilters are provided, the combination of datasetName and the filters are used to build a key and determine a match in the cache

      Parameters

      Returns Promise<void>

    • 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

    • Cancels any pending debounced metadata refresh. Call during teardown (logout, provider disposal) so a timer armed just before teardown doesn't fire a refresh against a connection that no longer has a valid session.

      Returns void

    • Checks whether a new record's field values pass the Create RLS filter. Subclasses must implement the actual RLS check logic.

      Parameters

      Returns Promise<boolean>

    • Checks whether an existing record passes RLS for a given permission type (Update or Delete). Subclasses must implement the actual RLS check logic.

      Parameters

      Returns Promise<boolean>

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

      Parameters

      • OptionalproviderToUse: IMetadataProvider
      • OptionalbypassMinCheckInterval: boolean

        When true, skips the MinRefreshCheckIntervalMs throttle. Event-driven callers pass true: they hold positive evidence that a metadata member entity was just written, and the throttle otherwise answers "fresh" for any check arriving within the window of the previous one — which would silently drop the second of two permission changes made less than the window apart.

      Returns Promise<boolean>

      True if refresh is needed, false otherwise

    • Checks whether an UPDATE's pending (post-image) field values still pass the Update RLS filter. The pre-image check (CheckRecordRLS) validates the row as stored; this validates the row as it WILL be after the update, so a caller cannot move a row they legitimately own outside their own row scope (a privilege escalation the pre-image check cannot see). Runs after the before-save hooks so it validates the final values. Subclasses must implement; return true when no Update filter applies.

      Parameters

      Returns Promise<boolean>

    • 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>

    • Commits the current transaction.

      Returns Promise<void>

    • Finalizes merge logging by updating the log record with completion status and creating deletion detail records. Uses BaseEntity with .Set() calls (no typed entity subclass imports).

      Parameters

      Returns Promise<void>

    • The CLIENT's field-security cache key: a canonical list of the fields this user MAY read.

      Keyed on the ALLOWED set rather than the denied set for two reasons. Once metadata ships to browsers filtered to what a user may see (#3485), a denied field will not appear in the client's field list at all — so a denied-set key would be empty and would silently stop segmenting. The allowed list also resolves the f:* ambiguity in the client's projection segment, where "full width" means different columns for different users.

      Returns '' when the entity has field security off or the user is denied nothing, so unrestricted users keep byte-identical fingerprints and shared slots.

      Only takes effect once the client's metadata refreshes. A client on stale metadata computes a stale key; the backstop is that the server strips denied columns from every fresh fetch regardless.

      Parameters

      Returns string

    • The fetch-widening field list for a cache-eligible request: always every entity field. One slot per (entity, filter, order) serves every caller regardless of the field subset they asked for, and field security narrows per request at read time via ApplyFieldSecurityProjection.

      Parameters

      Returns string[]

    • The field-security segment for a LocalCacheManager RunView fingerprint — the one place the client/server asymmetry is decided, so the two tiers cannot drift.

      SERVER → no segment. Its slots are full-width and shared by every user; per-request narrowing happens at read time in ApplyFieldSecurityProjection, which runs on every hit and every miss. A segment here would fragment one shared slot into one per permission class and protect nothing the projection does not already handle.

      CLIENT → the allowed-list key. Its slots are stored exactly as the server returned them (already narrowed on the wire) and are not projected on read, so slot identity has to carry the field set. Without it, a user whose access is tightened keeps being served their persisted IndexedDB slot: the currency check compares maxUpdatedAt and rowCount only, neither of which notices a column, so the server answers "current" and the browser keeps showing a column that was just taken away.

      Empty/undefined for unrestricted users on both tiers, so their fingerprints stay byte-identical and keep sharing slots.

      Parameters

      Returns string

    • 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

    • Configures the provider with the specified configuration data. Handles metadata refresh if needed and initializes the provider.

      Parameters

      Returns Promise<boolean>

      True if configuration was successful

    • 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

        Optional authorization name to look up

      • auditLogTypeName: string

        The audit log type name (must exist in metadata)

      • status: string

        'Success' or 'Failed'

      • details: string

        Optional details (JSON string, description, etc.)

      • entityId: string

        The entity ID being audited

      • recordId: string

        Optional record ID being audited

      • auditLogDescription: string

        Optional description for the audit log

      • saveOptions: EntitySaveOptions

        Save options to pass to the entity Save() call

      Returns Promise<BaseEntity<unknown>>

      The saved audit log BaseEntity, or null on error

    • Independent instance that shares the connection pool and metadata cache but has its own transaction stack. Same pattern MJAPI uses for per-request providers. Used by mj sync push so --parallel-batch-size (default 10) does not interleave EntityTransactionScopes on one provider.

      Not SQL Server-specific: each concrete provider implements this against its own pool. ReleaseIndependentInstance must NOT close the pool.

      Returns Promise<DatabaseProviderBase>

    • 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 transaction group for managing database transactions. Must be implemented by subclasses to provide transaction support.

      Returns Promise<TransactionGroupBase>

      A new transaction group instance

    • 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

    • 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>

      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.

    • 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

    • 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

    • 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>

    • 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

    • Whether the write described by entityEvent happened against the backend THIS provider's metadata comes from. In a multi-provider process (a client connected to several MJ servers, a server connected to several databases) a write on one backend must not refresh another's metadata. Deliberately fails OPEN — when the event does not identify its provider, or a connection string is unavailable, the answer is "yes": a spurious refresh is a bounded cost, a suppressed one is a stale-permissions window.

      Parameters

      Returns boolean

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

      Parameters

      • aggregateSQL: string

        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 a SQL query with optional parameters and options.

      Type Parameters

      • T

        The type of the result set

      Parameters

      Returns Promise<T[]>

      A promise that resolves to an array of results of type T

    • Parameters

      • results: unknown[]

      Returns string

    • 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 }>

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

    • 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

    • options carries per-save behavior the SQL builder must honor (e.g. SkipRecordChanges). Optional for back-compat with provider subclasses compiled against the 3-arg shape.

      Parameters

      Returns Promise<SaveSQLResult>

    • 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

    • 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>

      The cached display name, or undefined if not in cache

    • 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

    • Gets the current user information from the provider. Must be implemented by subclasses to return user-specific data.

      Returns Promise<UserInfo>

      Current user information including roles and permissions

    • Retrieves a dataset by name. When forceRefresh is true, bypasses any in-memory or local cache and fetches directly from the database. When false (default), server-side providers may serve from LocalCacheManager if TrustLocalCacheCompletely is true.

      Parameters

      • datasetName: string
      • OptionalitemFilters: DatasetItemFilterType[]
      • OptionalcontextUser: UserInfo
      • OptionalproviderToUse: IMetadataProvider
      • OptionalforceRefresh: boolean

        When true, bypasses all caching and fetches fresh data from the database

      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

    • Returns AI actions configured for the given entity and timing. Override in subclasses that have access to AIEngine. Default: returns empty array.

      Parameters

      Returns {
          AIActionID: string;
          AIModelID: string;
          EntityID: string;
          ID: string;
          TriggerEvent: string;
      }[]

    • Returns a list of entity dependencies, basically metadata that tells you the links to this entity from all other entities.

      Parameters

      • entityName: string

      Returns Promise<EntityDependency[]>

    • 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

    • Recursively enumerates an entity's entire sub-tree from metadata. No DB queries — uses EntityInfo.ChildEntities which is populated from metadata.

      Parameters

      Returns EntityInfo[]

    • 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>

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

      Parameters

      Returns Promise<boolean>

    • Returns provider-specific extra data to attach to a TransactionItem. SQL Server overrides to include { dataSource: this._pool }.

      Parameters

      Returns Record<string, unknown>

    • Handles entity actions (non-AI) for save, delete, or validate operations. Override in subclasses that have access to EntityActionEngineServer. Default: no-op, returns empty array.

      Parameters

      • _entity: BaseEntity
      • _baseType: "delete" | "validate" | "save"
      • _before: boolean
      • _user: UserInfo
      • Optional_originatingEntityActionIDs: string[]

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

      Array of action results (empty by default)

    • Handles AI-specific entity actions for save or delete operations. Override in subclasses that have access to AIEngine. Default: no-op.

      Parameters

      Returns Promise<void>

    • Static fan-out callback: a BaseEntity save/delete (or a remote-invalidate from another server) touched lowerEntityName. If that entity is one of the entities this provider's metadata is BUILT FROM, the metadata this provider is serving — and, on the server, the metadata every per-request provider adopts from it — is now stale, so schedule a debounced refresh. Permission metadata is the load-bearing case: field-level security is enforced FROM metadata at every enforcement point, so a rule an administrator just tightened is simply not enforced until this re-read happens.

      Parameters

      Returns void

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

      Parameters

      Returns Promise<string>

    • Server in-process transport for Remote Operations: resolves the registered operation by key and runs it via ExecuteServer. Inherited by both SQL Server and PostgreSQL providers. The client (GraphQL) provider overrides this to marshal over the wire instead.

      Type Parameters

      • TInput = unknown
      • TOutput = unknown

      Parameters

      Returns Promise<RemoteOpResult<TOutput>>

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

      Parameters

      • params: RunQueryParams[]

        Array of query parameters

      • OptionalcontextUser: UserInfo

        Optional user context for permissions

      Returns Promise<RunQueryResult[]>

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

      Parameters

      • params: RunQueryParams

        The query parameters

      • OptionalcontextUser: UserInfo

        Optional user context for permissions

      Returns Promise<RunQueryResult>

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

      Type Parameters

      • T = any

      Parameters

      • params: RunViewParams

        The view parameters

      • OptionalcontextUser: UserInfo

        Optional user context for permissions

      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 = any

      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

    • Determines if a given datasetName/itemFilters combination is cached locally or not

      Parameters

      Returns Promise<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

    • Whether a saved query is bound to an external data source. The base returns false; providers that support external data sources override this (consulting query metadata) so the outer RunQuery CacheLocal layer can defer to InternalRunQuery's own external TTL caching. Synchronous + non-throwing: resolves from cached metadata only.

      Parameters

      Returns boolean

    • True when the entity is a CodeGen materialized-query wrapper (materialized_vw*) whose snapshot is refreshed out-of-band — the same one IsServerCacheAllowedForEntity excludes from the server cache.

      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

    • 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 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>

        The new record data (null for deletes)

      • oldData: Record<string, unknown>

        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

      Returns Promise<unknown[]>

    • 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: "expired"
                    | "disabled"
                    | "hit"
                    | "miss";
                },
            >;
            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: "expired"
              | "disabled"
              | "hit"
              | "miss" },
          >
        • 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

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

      Parameters

      • preResult: {
            allCached: boolean;
            cachedResults?: RunQueryResult[];
            cacheStatusMap?: Map<
                number,
                {
                    result?: RunQueryResult;
                    status: "expired"
                    | "disabled"
                    | "hit"
                    | "miss";
                },
            >;
            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

    • Normalizes non-entity ('simple') result rows so Date and numeric columns hold real Dates and numbers on EVERY tier, matching what the generated entity types declare.

      Before this existed, the value a simple read returned for a DATETIME column depended on where the code happened to run: a fresh server-side query yields real Date objects (the driver parses them and AdjustDatetimeFields timezone-adjusts them), a server-side Redis cache hit yields ISO strings (JSON.parse with no reviver), and a browser client over GraphQL yields ISO strings (rows are JSON.stringify'd on the wire). Same call, three shapes. MJ's contract is a unified programming interface on both sides of the wire, so the one representation the platform's own generated types declare — Date — is enforced here, at the one choke point every provider's RunView pipeline flows through.

      It makes date and number VALUES match the generated types; it does not make a caller's T honest in general. A Status column typed as a closed union still holds whatever string the database held, and plain rows never have entity methods. If you need the type to be fully true, use ResultType: 'entity_object'.

      The field-key lists are computed once per view from EntityInfo, not per cell. Rows already in the right shape — the common server-side case, where the driver returned Dates — are detected and the ORIGINAL array is kept untouched: same array identity, same row objects, zero copying. A row is shallow-copied only when a cell actually converts, and that copy is load-bearing: on a cache hit the rows handed back can be the cache's OWN objects (the in-memory server store holds them by reference), so converting in place would write Dates into the cache entry itself and corrupt it for serialization and for later readers.

      Per-cell rules:

      • Date instances pass through untouched, so the pass is idempotent on every path.
      • NULL/undefined cells are left alone rather than becoming epoch-1970 dates.
      • An unparseable value is left as-is rather than written as Invalid Date, which renders as that literal string and destroys the evidence of what the database actually held.
      • An integer string outside Number.MAX_SAFE_INTEGER stays a string: the PostgreSQL provider deliberately returns unsafe-range BIGINTs as strings to avoid precision loss, and Number('9007199254740993') "succeeds" while silently corrupting the value.

      View-based runs (ViewID/ViewName with neither EntityName nor a loaded ViewEntity) skip normalization: resolving the entity would take an async User Views read this late in the pipeline. Pass EntityName alongside the view identifier to get normalized rows.

      Parameters

      Returns void

    • Called after a successful save (both direct and transaction-callback paths). Intentionally synchronous (fire-and-forget) — SQL Server overrides to dispatch after-save entity actions and AI actions without awaiting.

      Parameters

      Returns void

    • Called before the delete SQL is executed. SQL Server overrides to fire before-delete entity actions and AI actions.

      Parameters

      Returns Promise<void>

    • 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>>

      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

    • Called during Save before any SQL is executed to run validation-type entity actions. Return a non-empty string to abort the save with that message; return null to proceed. SQL Server overrides this to delegate to HandleEntityActions('validate', ...).

      Parameters

      Returns Promise<string>

    • Post-processes rows returned by a save/load SQL operation. SQL Server overrides to handle datetimeoffset conversion and field decryption. Default: returns rows unchanged.

      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: "expired"
                    | "disabled"
                    | "hit"
                    | "miss";
                },
            >;
            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: "expired" | "disabled" | "hit" | "miss";
            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: "expired" | "disabled" | "hit" | "miss";
            callerRequestedFields?: string[];
            fingerprint?: string;
            telemetryEventId?: string;
        }

        The pre-processing result

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

          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: "expired"
                    | "disabled"
                    | "hit"
                    | "miss";
                },
            >;
            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: "expired"
              | "disabled"
              | "hit"
              | "miss" },
          >
        • 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>

    • Type Parameters

      • T = any

      Parameters

      Returns Promise<void>

      Use PreRunView instead. This method is kept for backward compatibility.

    • 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: "expired"
                      | "disabled"
                      | "hit"
                      | "miss";
                  },
              >;
              telemetryEventId?: string;
              uncachedParams?: RunQueryParams[];
          },
      >

      Pre-processing result

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

      Parameters

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

      Pre-processing result with cache status and optional cached result

    • Parameters

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

    • 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: "expired"
                      | "disabled"
                      | "hit"
                      | "miss";
                  },
              >;
              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>

    • 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

        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>

    • Quotes a database identifier (table, column, view name) using the provider's dialect convention. SQL Server uses [brackets], PostgreSQL uses "double quotes".

      Parameters

      • name: string

        The identifier to quote

      Returns string

    • Quotes a schema-qualified object name (e.g. schema.viewName) using the provider's dialect convention. SQL Server uses [schema].[view], PostgreSQL uses "schema"."view".

      Parameters

      • schemaName: string

        The schema name

      • objectName: string

        The object name (table, view, etc.)

      Returns string

    • 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

    • How this provider refreshes after a metadata member entity changed. The base behavior is a hard Refresh — correct for database providers, where the process that PERFORMED the write is the one refreshing, so re-checking staleness first is wasted work and the re-read must bypass every cache layer. Transport providers (GraphQL) override this with a staleness check so a browser doesn't re-pull the full metadata graph for a change the server-side timestamp comparison can disconfirm.

      Returns Promise<boolean>

    • Refreshes the CurrentUser from the server and updates local metadata in place. Useful on warm boot or when user roles/permissions change dynamically without entity schema changes.

      Returns Promise<UserInfo>

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

      Parameters

      • OptionalproviderToUse: IMetadataProvider
      • OptionalbypassMinCheckInterval: boolean

        Passed through to CheckToSeeIfRefreshNeeded; event-driven callers set true so the throttle cannot eat a check they have positive evidence for.

      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

    • Records which entities compose this provider's metadata, from the loaded MJ_Metadata dataset result, and registers this instance with the static event fan-out so writes to any of them schedule a debounced metadata refresh. Called from GetAllMetadata on every successful load, so the set tracks the dataset definition as it changes.

      Parameters

      Returns void

    • Drop this instance's transaction handle. Must not close the shared pool.

      Returns Promise<void>

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

      Returns Promise<void>

    • Drop a dead physical handle and reset depth. No-op on providers that do not track nested transactions. Use after a server-side abort when RollbackTransaction itself rejects.

      Returns Promise<void>

    • The value to write into a dependent record's link column so it points at the surviving record of a merge.

      The two kinds of link store their target differently, and writing the wrong one is silent: a hard foreign key holds the bare primary key value, while a polymorphic RecordID column holds the canonical ID|<guid> encoding produced by CompositeKey.ToRecordID. Writing a bare value into a RecordID column leaves a pointer that resolves to nothing and re-introduces the second encoding this work exists to eliminate - so it would corrupt exactly the rows the merge was supposed to preserve.

      Separated from MergeRecords so the choice is directly testable, since nothing about the resulting row makes the mistake visible after the fact.

      Parameters

      Returns unknown

    • 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

    • The RunQuery cache-serve seam (B45/B46) — resolves a RunQuery request against this provider's query metadata and answers, in ONE computation performed BEFORE fingerprinting:

      • categoryPath: the RESOLVED query's canonical full category path. This becomes a distinguishing fingerprint segment (B46) so two same-named queries in different categories can never collide onto one cache slot. When the request is unresolvable the caller falls back to the CALLER-STATED params.CategoryPath (still distinguishing, just not canonicalized).
      • resolvable: whether metadata could resolve the request at all. Runtime-created queries are typically NOT resolvable from the base metadata cache (it does not refresh in-process) — the gate then applies the warmer tie-break instead.
      • authorized: whether user may run the resolved query. Meaningful only when resolvable is true.

      The BASE implementation resolves from the metadata Queries cache and enforces the ROLES-ONLY QueryInfo.UserCanRun — the strongest check available at this layer. Providers with richer query metadata MUST override this to enforce the SAME authorization their miss path enforces (GenericDatabaseProvider overrides with MJQueryEntityExtended.UserCanRun, which adds entity CanRead + recursive composition checks — the exact check ValidateQueryForExecution applies on a cache miss). The invariant this seam exists to hold: a cache HIT must never be easier to read than a cache MISS (B45 was precisely that asymmetry — the TTL gate checked roles only while the miss path also checked entity read permissions).

      Parameters

      Returns QueryCacheAuthorization

    • The entity a RunView targets, resolved with NO I/O — for gates that run on the result path, where an async RunView.GetEntityNameFromRunViewParams (which issues a User Views query for a bare ViewID) would be a query per result set.

      Covers the two shapes every caller in this repository uses: an explicit EntityName, and a loaded ViewEntity. A request carrying only ViewID/ViewName with neither is not resolvable here and returns undefined — the same shape RunView's own row normalization already declines to handle for the same reason, and the same one cacheDeniedForViewOnlyRequest exists to fail closed for on the cache path.

      Parameters

      Returns EntityInfo

    • 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

    • Rolls back the current transaction.

      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.

    • 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 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
      • DataSource: 'Materialized' — the snapshot is rebuilt OUT-OF-BAND by the scheduled refresh (direct SQL, no BaseEntity save), so the entity's normal event-driven cache invalidation never fires for it; a cached materialized result would be served indefinitely stale after a refresh. Bypass caching entirely for materialized reads. (The ds:materialized fingerprint segment still keeps the short-lived dedup/linger layer from cross-serving Live vs Materialized in-flight reads.)
      • entities where server caching is disallowed

      Parameters

      Returns boolean

    • Write-side eligibility for the smart-cache-check (stamped) path. On the trusting SERVER this is exactly runViewCacheEligible — the server cache is kept fresh by BaseEntity events, so a server-cache-disallowed entity must never be slotted. On a CLIENT the slot is instead written with a maxUpdatedAt stamp and DB-revalidated per request, so the server Trust/event gate does NOT apply: a server-cache-disallowed entity (Trust=0 'MJ: Audit Logs', Record Changes, other caching-disabled) is still safely client-cacheable when stamped — folding runViewCacheEligible's server gate onto this path regressed that (integration check client-cache.C12). Materialized reads stay excluded on both (the out-of-band snapshot swap the stamp can't observe).

      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>

    • Schedules this provider's metadata refresh after a write to a metadata member entity. Delay and re-arm semantics come from MetadataMemberRefreshDelayMs and MetadataMemberRefreshRearmsOnNewEvents — debounce on the server, long jittered coalescing window on clients. The refresh targets THIS instance — the provider that loaded the dataset owns the metadata built from it; short-lived per-request providers never load the dataset (they adopt the global's metadata as a shared shell), so on the server only the process-global provider ever gets here.

      Returns 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[][]>

    • Run the semantic ranking pass for SearchEntity. Each concrete ProviderBase subclass supplies its own implementation: server-side providers (GenericDatabaseProvider) embed the query text and query an in-process vector pool directly; client-side providers (GraphQLDataProvider) override SearchEntity / SearchEntities outright to proxy via GraphQL and never reach this method.

      Parameters

      • entityDocumentId: string
      • searchText: string
      • overFetch: number
      • embeddingAIModelId: string
      • contextUser: UserInfo

      Returns Promise<ScoredCandidate[]>

      Ranked array of ScoredCandidate whose ID is the parent entity's record ID and Metadata.entityRecordDocumentId carries the EntityRecordDocument PK.

    • 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

    • 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

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

      Parameters

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

      Returns unknown

    • Updates the local metadata cache with new data.

      Parameters

      Returns void

    • Validates the result of a delete SQL execution by checking that the returned primary keys match the entity being deleted. SQL Server overrides to handle the multi-result-set case (CASCADE deletes).

      Parameters

      Returns boolean

    • 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