Fix typeorm internal query builder missing twenty internal context (#17719)

## Context
Fix TypeError: Cannot read properties of undefined (reading
'coreDataSource') when updating records with RLS predicates enabled

## Implementation
Use lazy initialization for FilesFieldSync and RelationNestedQueries in
workspace query builder

## Technical details
When Row-Level Security (RLS) predicates are applied during an update
operation, TypeORM internally creates sub-query builders to evaluate
Brackets in WHERE clauses. TypeORM's createQueryBuilder() method calls
new this.constructor(connection, queryRunner) with only 2 arguments, but
WorkspaceUpdateQueryBuilder expects 6 arguments including
internalContext.
This caused FilesFieldSync to be instantiated with undefined context,
resulting in the error when accessing internalContext.coreDataSource.

Converting filesFieldSync and relationNestedQueries from eager
initialization in the constructor to lazy getters. This way:
TypeORM internal sub-query builders work fine (they never access these
dependencies)
Real query builders create dependencies on-demand when execute() runs

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Weiko <Weiko@users.noreply.github.com>
This commit is contained in:
Weiko
2026-02-04 17:57:42 +01:00
committed by GitHub
parent 8674cf973e
commit 64700a00b0
2 changed files with 26 additions and 12 deletions
@@ -43,11 +43,22 @@ export class WorkspaceInsertQueryBuilder<
private internalContext: WorkspaceInternalContext;
private authContext: AuthContext;
private featureFlagMap: FeatureFlagMap;
private relationNestedQueries: RelationNestedQueries;
private relationNestedConfig:
| [RelationConnectQueryConfig[], RelationDisconnectQueryFieldsByEntityIndex]
| null;
private filesFieldSync: FilesFieldSync;
private _relationNestedQueries?: RelationNestedQueries;
private _filesFieldSync?: FilesFieldSync;
private get relationNestedQueries(): RelationNestedQueries {
return (this._relationNestedQueries ??= new RelationNestedQueries(
this.internalContext,
));
}
private get filesFieldSync(): FilesFieldSync {
return (this._filesFieldSync ??= new FilesFieldSync(this.internalContext));
}
constructor(
queryBuilder: InsertQueryBuilder<T>,
@@ -63,10 +74,6 @@ export class WorkspaceInsertQueryBuilder<
this.shouldBypassPermissionChecks = shouldBypassPermissionChecks;
this.authContext = authContext;
this.featureFlagMap = featureFlagMap;
this.relationNestedQueries = new RelationNestedQueries(
this.internalContext,
);
this.filesFieldSync = new FilesFieldSync(this.internalContext);
}
override clone(): this {
@@ -50,7 +50,6 @@ export class WorkspaceUpdateQueryBuilder<
private internalContext: WorkspaceInternalContext;
private authContext: AuthContext;
private featureFlagMap: FeatureFlagMap;
private relationNestedQueries: RelationNestedQueries;
private relationNestedConfig:
| [RelationConnectQueryConfig[], RelationDisconnectQueryFieldsByEntityIndex]
| null;
@@ -58,7 +57,19 @@ export class WorkspaceUpdateQueryBuilder<
criteria: string;
partialEntity: QueryDeepPartialEntity<T>;
}[];
private filesFieldSync: FilesFieldSync;
private _relationNestedQueries?: RelationNestedQueries;
private _filesFieldSync?: FilesFieldSync;
private get relationNestedQueries(): RelationNestedQueries {
return (this._relationNestedQueries ??= new RelationNestedQueries(
this.internalContext,
));
}
private get filesFieldSync(): FilesFieldSync {
return (this._filesFieldSync ??= new FilesFieldSync(this.internalContext));
}
constructor(
queryBuilder: UpdateQueryBuilder<T>,
@@ -74,10 +85,6 @@ export class WorkspaceUpdateQueryBuilder<
this.shouldBypassPermissionChecks = shouldBypassPermissionChecks;
this.authContext = authContext;
this.featureFlagMap = featureFlagMap;
this.relationNestedQueries = new RelationNestedQueries(
this.internalContext,
);
this.filesFieldSync = new FilesFieldSync(this.internalContext);
}
override clone(): this {