fix: relations issues (#2497)

* fix: relations issues

one-to-one relation not working
alias should not be used on the foreignKey side

* fix: naming
This commit is contained in:
Jérémy M
2023-11-14 12:07:17 +01:00
committed by GitHub
parent 448f256a35
commit 65af954671
4 changed files with 50 additions and 7 deletions

View File

@ -7,6 +7,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import camelCase from 'lodash.camelcase';
import { ObjectMetadataService } from 'src/metadata/object-metadata/object-metadata.service'; import { ObjectMetadataService } from 'src/metadata/object-metadata/object-metadata.service';
import { FieldMetadataService } from 'src/metadata/field-metadata/field-metadata.service'; import { FieldMetadataService } from 'src/metadata/field-metadata/field-metadata.service';
@ -43,6 +44,19 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
); );
} }
/**
* Relation types
*
* MANY TO MANY:
* FROM Ǝ-E TO (NOT YET SUPPORTED)
*
* ONE TO MANY:
* FROM --E TO (host the id in the TO table)
*
* ONE TO ONE:
* FROM --- TO (host the id in the TO table)
*/
const objectMetadataEntries = const objectMetadataEntries =
await this.objectMetadataService.findManyWithinWorkspace( await this.objectMetadataService.findManyWithinWorkspace(
[record.fromObjectMetadataId, record.toObjectMetadataId], [record.fromObjectMetadataId, record.toObjectMetadataId],
@ -63,6 +77,8 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
); );
} }
const foreignKeyColumnName = `${camelCase(record.toName)}Id`;
const createdFields = await this.fieldMetadataService.createMany([ const createdFields = await this.fieldMetadataService.createMany([
// FROM // FROM
{ {
@ -84,7 +100,9 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
description: undefined, description: undefined,
icon: record.toIcon, icon: record.toIcon,
isCustom: true, isCustom: true,
targetColumnMap: {}, targetColumnMap: {
value: foreignKeyColumnName,
},
isActive: true, isActive: true,
type: FieldMetadataType.RELATION, type: FieldMetadataType.RELATION,
objectMetadataId: record.toObjectMetadataId, objectMetadataId: record.toObjectMetadataId,
@ -103,10 +121,6 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
toFieldMetadataId: createdFieldMap[record.toObjectMetadataId].id, toFieldMetadataId: createdFieldMap[record.toObjectMetadataId].id,
}); });
const foreignKeyColumnName = `${
objectMetadataMap[record.fromObjectMetadataId].targetTableName
}Id`;
await this.tenantMigrationService.createCustomMigration( await this.tenantMigrationService.createCustomMigration(
record.workspaceId, record.workspaceId,
[ [
@ -133,6 +147,7 @@ export class RelationMetadataService extends TypeOrmQueryService<RelationMetadat
referencedTableName: referencedTableName:
objectMetadataMap[record.fromObjectMetadataId].targetTableName, objectMetadataMap[record.fromObjectMetadataId].targetTableName,
referencedTableColumnName: 'id', referencedTableColumnName: 'id',
isUnique: record.relationType === RelationMetadataType.ONE_TO_ONE,
}, },
], ],
}, },

View File

@ -21,6 +21,7 @@ export type TenantMigrationColumnRelation = {
columnName: string; columnName: string;
referencedTableName: string; referencedTableName: string;
referencedTableColumnName: string; referencedTableColumnName: string;
isUnique?: boolean;
}; };
export type TenantMigrationColumnAction = { export type TenantMigrationColumnAction = {

View File

@ -1,6 +1,12 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { QueryRunner, Table, TableColumn, TableForeignKey } from 'typeorm'; import {
QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableUnique,
} from 'typeorm';
import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service';
import { TenantDataSourceService } from 'src/tenant-datasource/tenant-datasource.service'; import { TenantDataSourceService } from 'src/tenant-datasource/tenant-datasource.service';
@ -217,5 +223,16 @@ export class TenantMigrationRunnerService {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}), }),
); );
// Create unique constraint if for one to one relation
if (migrationColumn.isUnique) {
await queryRunner.createUniqueConstraint(
`${schemaName}.${tableName}`,
new TableUnique({
name: `UNIQUE_${tableName}_${migrationColumn.columnName}`,
columnNames: [migrationColumn.columnName],
}),
);
}
} }
} }

View File

@ -95,10 +95,20 @@ export class CompositeFieldAliasFactory {
} }
`; `;
} }
let relationAlias = fieldKey;
// For one to one relations, pg_graphql use the targetTableName on the side that is not storing the foreign key
// so we need to alias it to the field key
if (
relationMetadata.relationType === RelationMetadataType.ONE_TO_ONE &&
relationDirection === RelationDirection.FROM
) {
relationAlias = `${fieldKey}: ${referencedObjectMetadata.targetTableName}`;
}
// Otherwise it means it's a relation destination is of kind ONE // Otherwise it means it's a relation destination is of kind ONE
return ` return `
${fieldKey} { ${relationAlias} {
${this.fieldsStringFactory.createFieldsStringRecursive( ${this.fieldsStringFactory.createFieldsStringRecursive(
info, info,
fieldValue, fieldValue,