Files v2 - FILES field update/create in common API (#17400)
## FILES Field update interface
```
mutation {
updateCompany(
id: "company-uuid"
data: {
filesfield: [
{ fileId: "new-file-uuid", label: "new-document.pdf" }
]
}
) {
id
filesfield {
fileId
label
extension
}
}
}
```
This commit is contained in:
+43
-1
@@ -22,7 +22,8 @@ import {
|
||||
TwentyORMException,
|
||||
TwentyORMExceptionCode,
|
||||
} from 'src/engine/twenty-orm/exceptions/twenty-orm.exception';
|
||||
import { RelationNestedQueries } from 'src/engine/twenty-orm/relation-nested-queries/relation-nested-queries';
|
||||
import { FilesFieldSync } from 'src/engine/twenty-orm/field-operations/files-field-sync/files-field-sync';
|
||||
import { RelationNestedQueries } from 'src/engine/twenty-orm/field-operations/relation-nested-queries/relation-nested-queries';
|
||||
import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.utils';
|
||||
import { type WorkspaceDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-delete-query-builder';
|
||||
import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder';
|
||||
@@ -46,6 +47,7 @@ export class WorkspaceInsertQueryBuilder<
|
||||
private relationNestedConfig:
|
||||
| [RelationConnectQueryConfig[], RelationDisconnectQueryFieldsByEntityIndex]
|
||||
| null;
|
||||
private filesFieldSync: FilesFieldSync;
|
||||
|
||||
constructor(
|
||||
queryBuilder: InsertQueryBuilder<T>,
|
||||
@@ -64,6 +66,7 @@ export class WorkspaceInsertQueryBuilder<
|
||||
this.relationNestedQueries = new RelationNestedQueries(
|
||||
this.internalContext,
|
||||
);
|
||||
this.filesFieldSync = new FilesFieldSync(this.internalContext);
|
||||
}
|
||||
|
||||
override clone(): this {
|
||||
@@ -158,6 +161,38 @@ export class WorkspaceInsertQueryBuilder<
|
||||
this.internalContext,
|
||||
);
|
||||
|
||||
let filesFieldFileIds = null;
|
||||
let fileIdToApplicationId = new Map<string, string>();
|
||||
|
||||
const entities = Array.isArray(this.expressionMap.valuesSet)
|
||||
? this.expressionMap.valuesSet
|
||||
: [this.expressionMap.valuesSet];
|
||||
|
||||
const filesFieldDiffByEntityIndex =
|
||||
this.filesFieldSync.computeFilesFieldDiffBeforeInsert(
|
||||
entities as QueryDeepPartialEntityWithNestedRelationFields<T>[],
|
||||
mainAliasTarget,
|
||||
);
|
||||
|
||||
if (isDefined(filesFieldDiffByEntityIndex)) {
|
||||
const result = await this.filesFieldSync.enrichFilesFields({
|
||||
entities:
|
||||
entities as QueryDeepPartialEntityWithNestedRelationFields<T>[],
|
||||
filesFieldDiffByEntityIndex,
|
||||
workspaceId: this.internalContext.workspaceId,
|
||||
target: mainAliasTarget,
|
||||
});
|
||||
|
||||
filesFieldFileIds = result.fileIds;
|
||||
fileIdToApplicationId = result.fileIdToApplicationId;
|
||||
|
||||
this.expressionMap.valuesSet = Array.isArray(
|
||||
this.expressionMap.valuesSet,
|
||||
)
|
||||
? result.entities
|
||||
: result.entities[0];
|
||||
}
|
||||
|
||||
if (isDefined(this.relationNestedConfig)) {
|
||||
const nestedRelationQueryBuilder = new WorkspaceSelectQueryBuilder(
|
||||
this as unknown as WorkspaceSelectQueryBuilder<T>,
|
||||
@@ -183,6 +218,13 @@ export class WorkspaceInsertQueryBuilder<
|
||||
this.validateRLSPredicatesForInsert();
|
||||
|
||||
const result = await super.execute();
|
||||
|
||||
if (isDefined(filesFieldFileIds)) {
|
||||
await this.filesFieldSync.updateFileEntityRecords(
|
||||
filesFieldFileIds,
|
||||
fileIdToApplicationId,
|
||||
);
|
||||
}
|
||||
const eventSelectQueryBuilder = (
|
||||
this.connection.manager as WorkspaceEntityManager
|
||||
).createQueryBuilder(
|
||||
|
||||
+86
-8
@@ -26,7 +26,8 @@ import {
|
||||
TwentyORMException,
|
||||
TwentyORMExceptionCode,
|
||||
} from 'src/engine/twenty-orm/exceptions/twenty-orm.exception';
|
||||
import { RelationNestedQueries } from 'src/engine/twenty-orm/relation-nested-queries/relation-nested-queries';
|
||||
import { FilesFieldSync } from 'src/engine/twenty-orm/field-operations/files-field-sync/files-field-sync';
|
||||
import { RelationNestedQueries } from 'src/engine/twenty-orm/field-operations/relation-nested-queries/relation-nested-queries';
|
||||
import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.utils';
|
||||
import { type WorkspaceDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-delete-query-builder';
|
||||
import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder';
|
||||
@@ -57,6 +58,7 @@ export class WorkspaceUpdateQueryBuilder<
|
||||
criteria: string;
|
||||
partialEntity: QueryDeepPartialEntity<T>;
|
||||
}[];
|
||||
private filesFieldSync: FilesFieldSync;
|
||||
|
||||
constructor(
|
||||
queryBuilder: UpdateQueryBuilder<T>,
|
||||
@@ -75,6 +77,7 @@ export class WorkspaceUpdateQueryBuilder<
|
||||
this.relationNestedQueries = new RelationNestedQueries(
|
||||
this.internalContext,
|
||||
);
|
||||
this.filesFieldSync = new FilesFieldSync(this.internalContext);
|
||||
}
|
||||
|
||||
override clone(): this {
|
||||
@@ -154,6 +157,44 @@ export class WorkspaceUpdateQueryBuilder<
|
||||
this.featureFlagMap,
|
||||
);
|
||||
|
||||
const formattedBefore = formatResult<T[]>(
|
||||
before,
|
||||
objectMetadata,
|
||||
this.internalContext.flatObjectMetadataMaps,
|
||||
this.internalContext.flatFieldMetadataMaps,
|
||||
);
|
||||
|
||||
let filesFieldDiffByEntityIndex = null;
|
||||
let filesFieldFileIds = null;
|
||||
let fileIdToApplicationId = new Map<string, string>();
|
||||
|
||||
const updatePayload = Array.isArray(this.expressionMap.valuesSet)
|
||||
? (this.expressionMap.valuesSet[0] ?? {})
|
||||
: (this.expressionMap.valuesSet ?? {});
|
||||
|
||||
filesFieldDiffByEntityIndex =
|
||||
this.filesFieldSync.computeFilesFieldDiffBeforeUpdateOne(
|
||||
updatePayload,
|
||||
mainAliasTarget,
|
||||
formattedBefore,
|
||||
);
|
||||
|
||||
if (isDefined(filesFieldDiffByEntityIndex)) {
|
||||
const entities = formattedBefore.map(() => updatePayload);
|
||||
|
||||
const result = await this.filesFieldSync.enrichFilesFields({
|
||||
entities,
|
||||
filesFieldDiffByEntityIndex,
|
||||
workspaceId: this.internalContext.workspaceId,
|
||||
target: mainAliasTarget,
|
||||
});
|
||||
|
||||
filesFieldFileIds = result.fileIds;
|
||||
fileIdToApplicationId = result.fileIdToApplicationId;
|
||||
|
||||
this.expressionMap.valuesSet = result.entities[0];
|
||||
}
|
||||
|
||||
if (isDefined(this.relationNestedConfig)) {
|
||||
const updatedValues =
|
||||
await this.relationNestedQueries.processRelationNestedQueries({
|
||||
@@ -168,13 +209,6 @@ export class WorkspaceUpdateQueryBuilder<
|
||||
updatedValues.length === 1 ? updatedValues[0] : updatedValues;
|
||||
}
|
||||
|
||||
const formattedBefore = formatResult<T[]>(
|
||||
before,
|
||||
objectMetadata,
|
||||
this.internalContext.flatObjectMetadataMaps,
|
||||
this.internalContext.flatFieldMetadataMaps,
|
||||
);
|
||||
|
||||
this.applyRowLevelPermissionPredicates();
|
||||
|
||||
const valuesSet = this.expressionMap.valuesSet ?? {};
|
||||
@@ -194,6 +228,13 @@ export class WorkspaceUpdateQueryBuilder<
|
||||
|
||||
const result = await super.execute();
|
||||
|
||||
if (isDefined(filesFieldFileIds)) {
|
||||
await this.filesFieldSync.updateFileEntityRecords(
|
||||
filesFieldFileIds,
|
||||
fileIdToApplicationId,
|
||||
);
|
||||
}
|
||||
|
||||
const after = await eventSelectQueryBuilder.getMany();
|
||||
|
||||
const formattedAfter = formatResult<T[]>(
|
||||
@@ -324,6 +365,36 @@ export class WorkspaceUpdateQueryBuilder<
|
||||
mainAliasTarget,
|
||||
);
|
||||
|
||||
let filesFieldDiffByEntityIndex = null;
|
||||
let filesFieldFileIds = null;
|
||||
let fileIdToApplicationId = null;
|
||||
|
||||
const entities = this.manyInputs.map((input) => input.partialEntity);
|
||||
|
||||
filesFieldDiffByEntityIndex =
|
||||
this.filesFieldSync.computeFilesFieldDiffBeforeUpdate(
|
||||
entities,
|
||||
mainAliasTarget,
|
||||
formattedBefore,
|
||||
);
|
||||
|
||||
if (isDefined(filesFieldDiffByEntityIndex)) {
|
||||
const result = await this.filesFieldSync.enrichFilesFields({
|
||||
entities,
|
||||
filesFieldDiffByEntityIndex,
|
||||
workspaceId: this.internalContext.workspaceId,
|
||||
target: mainAliasTarget,
|
||||
});
|
||||
|
||||
filesFieldFileIds = result.fileIds;
|
||||
fileIdToApplicationId = result.fileIdToApplicationId;
|
||||
|
||||
this.manyInputs = result.entities.map((updatedEntity, index) => ({
|
||||
criteria: this.manyInputs[index].criteria,
|
||||
partialEntity: updatedEntity,
|
||||
}));
|
||||
}
|
||||
|
||||
if (isDefined(this.relationNestedConfig)) {
|
||||
const updatedValues =
|
||||
await this.relationNestedQueries.processRelationNestedQueries({
|
||||
@@ -373,6 +444,13 @@ export class WorkspaceUpdateQueryBuilder<
|
||||
results.push(result);
|
||||
}
|
||||
|
||||
if (isDefined(filesFieldFileIds) && isDefined(fileIdToApplicationId)) {
|
||||
await this.filesFieldSync.updateFileEntityRecords(
|
||||
filesFieldFileIds,
|
||||
fileIdToApplicationId,
|
||||
);
|
||||
}
|
||||
|
||||
const afterRecords = await eventSelectQueryBuilder.getMany();
|
||||
|
||||
const formattedAfter = formatResult<T[]>(
|
||||
|
||||
Reference in New Issue
Block a user