This PR fixes a few bugs on TwentyORM:
- fix many to one relations that were not properly queries
- fix many to one relations that were not properly parsed
- compute datasource (or use from cache) at run-time and do not use
injected one that could be outdated

We still need to refactor it to simplify, I feel the API are too complex
and we have too many cache layers. Also the relation computation part is
very complex and bug prone
This commit is contained in:
Charles Bochet
2024-07-22 15:07:35 +02:00
committed by GitHub
parent 284e75791c
commit d212aedf81
7 changed files with 92 additions and 88 deletions

View File

@ -16,19 +16,20 @@ import {
SaveOptions,
UpdateResult,
} from 'typeorm';
import { PickKeysByType } from 'typeorm/common/PickKeysByType';
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
import { UpsertOptions } from 'typeorm/repository/UpsertOptions';
import { PickKeysByType } from 'typeorm/common/PickKeysByType';
import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface';
import { WorkspaceEntitiesStorage } from 'src/engine/twenty-orm/storage/workspace-entities.storage';
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
import { compositeTypeDefintions } from 'src/engine/metadata-modules/field-metadata/composite-types';
import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
import { isPlainObject } from 'src/utils/is-plain-object';
import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util';
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { WorkspaceEntitiesStorage } from 'src/engine/twenty-orm/storage/workspace-entities.storage';
import { computeRelationType } from 'src/engine/twenty-orm/utils/compute-relation-type.util';
import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util';
import { isPlainObject } from 'src/utils/is-plain-object';
export class WorkspaceRepository<
Entity extends ObjectLiteral,
@ -607,10 +608,13 @@ export class WorkspaceRepository<
* PRIVATE METHODS
*/
private async getObjectMetadataFromTarget() {
const objectMetadataName = WorkspaceEntitiesStorage.getObjectMetadataName(
this.internalContext.workspaceId,
this.target as EntitySchema,
);
const objectMetadataName =
typeof this.target === 'string'
? this.target
: WorkspaceEntitiesStorage.getObjectMetadataName(
this.internalContext.workspaceId,
this.target as EntitySchema,
);
if (!objectMetadataName) {
throw new Error('Object metadata name is missing');
@ -751,20 +755,30 @@ export class WorkspaceRepository<
]);
}),
);
const relationMetadataMap = new Map(
objectMetadata.fields
.filter(({ type }) => isRelationFieldMetadataType(type))
.map((fieldMetadata) => [
fieldMetadata.name,
fieldMetadata.fromRelationMetadata ??
fieldMetadata.toRelationMetadata,
{
relationMetadata:
fieldMetadata.fromRelationMetadata ??
fieldMetadata.toRelationMetadata,
relationType: computeRelationType(
fieldMetadata,
fieldMetadata.fromRelationMetadata ??
fieldMetadata.toRelationMetadata,
),
},
]),
);
const newData: object = {};
for (const [key, value] of Object.entries(data)) {
const compositePropertyArgs = compositeFieldMetadataMap.get(key);
const relationMetadata = relationMetadataMap.get(key);
const { relationMetadata, relationType } =
relationMetadataMap.get(key) ?? {};
if (!compositePropertyArgs && !relationMetadata) {
if (isPlainObject(value)) {
@ -776,22 +790,38 @@ export class WorkspaceRepository<
}
if (relationMetadata) {
const inverseSideObjectName =
relationMetadata.toObjectMetadata.nameSingular;
const objectMetadata =
const toObjectMetadata =
await this.internalContext.workspaceCacheStorage.getObjectMetadata(
this.internalContext.workspaceId,
relationMetadata.workspaceId,
(objectMetadata) =>
objectMetadata.nameSingular === inverseSideObjectName,
objectMetadata.id === relationMetadata.toObjectMetadataId,
);
if (!objectMetadata) {
const fromObjectMetadata =
await this.internalContext.workspaceCacheStorage.getObjectMetadata(
relationMetadata.workspaceId,
(objectMetadata) =>
objectMetadata.id === relationMetadata.fromObjectMetadataId,
);
if (!toObjectMetadata) {
throw new Error(
`Object metadata for object metadata "${inverseSideObjectName}" is missing`,
`Object metadata for object metadataId "${relationMetadata.toObjectMetadataId}" is missing`,
);
}
newData[key] = await this.formatResult(value, objectMetadata);
if (!fromObjectMetadata) {
throw new Error(
`Object metadata for object metadataId "${relationMetadata.fromObjectMetadataId}" is missing`,
);
}
newData[key] = await this.formatResult(
value,
relationType === 'one-to-many'
? toObjectMetadata
: fromObjectMetadata,
);
continue;
}