Rework relations (#3431)

* Rework relations

* Fix tests
This commit is contained in:
Charles Bochet
2024-01-15 12:07:23 +01:00
committed by GitHub
parent 8c96acc2a3
commit 16a24c5f0c
60 changed files with 392 additions and 463 deletions

View File

@ -1,237 +0,0 @@
// import { GraphQLResolveInfo } from 'graphql';
// import { FieldMetadataTargetColumnMap } from 'src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface';
// import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity';
// import {
// PGGraphQLQueryBuilder,
// PGGraphQLQueryBuilderOptions,
// } from 'src/tenant/resolver-builder/pg-graphql/pg-graphql-query-builder';
// const testUUID = '123e4567-e89b-12d3-a456-426614174001';
// const normalizeWhitespace = (str) => str.replace(/\s+/g, '');
// // Mocking dependencies
// jest.mock('uuid', () => ({
// v4: jest.fn(() => testUUID),
// }));
// jest.mock('graphql-fields', () =>
// jest.fn(() => ({
// name: true,
// age: true,
// complexField: {
// subField1: true,
// subField2: true,
// },
// })),
// );
// describe('PGGraphQLQueryBuilder', () => {
// let queryBuilder;
// let mockOptions: PGGraphQLQueryBuilderOptions;
// beforeEach(() => {
// const fieldMetadataCollection = [
// {
// name: 'name',
// targetColumnMap: {
// value: 'column_name',
// } as FieldMetadataTargetColumnMap,
// },
// {
// name: 'age',
// targetColumnMap: {
// value: 'column_age',
// } as FieldMetadataTargetColumnMap,
// },
// {
// name: 'complexField',
// targetColumnMap: {
// subField1: 'column_subField1',
// subField2: 'column_subField2',
// } as FieldMetadataTargetColumnMap,
// },
// ] as FieldMetadata[];
// mockOptions = {
// targetTableName: 'TestTable',
// info: {} as GraphQLResolveInfo,
// fieldMetadataCollection,
// };
// queryBuilder = new PGGraphQLQueryBuilder(mockOptions);
// });
// test('findMany generates correct query with no arguments', () => {
// const query = queryBuilder.findMany();
// expect(normalizeWhitespace(query)).toBe(
// normalizeWhitespace(`
// query {
// TestTableCollection {
// name: column_name
// age: column_age
// ___complexField_subField1: column_subField1
// ___complexField_subField2: column_subField2
// }
// }
// `),
// );
// });
// test('findMany generates correct query with filter parameters', () => {
// const args = {
// filter: {
// name: { eq: 'Alice' },
// age: { gt: 20 },
// },
// };
// const query = queryBuilder.findMany(args);
// expect(normalizeWhitespace(query)).toBe(
// normalizeWhitespace(`
// query {
// TestTableCollection(filter: { column_name: { eq: "Alice" }, column_age: { gt: 20 } }) {
// name: column_name
// age: column_age
// ___complexField_subField1: column_subField1
// ___complexField_subField2: column_subField2
// }
// }
// `),
// );
// });
// test('findMany generates correct query with combined pagination parameters', () => {
// const args = {
// first: 5,
// after: 'someCursor',
// before: 'anotherCursor',
// last: 3,
// };
// const query = queryBuilder.findMany(args);
// expect(normalizeWhitespace(query)).toBe(
// normalizeWhitespace(`
// query {
// TestTableCollection(
// first: 5,
// after: "someCursor",
// before: "anotherCursor",
// last: 3
// ) {
// name: column_name
// age: column_age
// ___complexField_subField1: column_subField1
// ___complexField_subField2: column_subField2
// }
// }
// `),
// );
// });
// test('findOne generates correct query with ID filter', () => {
// const args = { filter: { id: { eq: testUUID } } };
// const query = queryBuilder.findOne(args);
// expect(normalizeWhitespace(query)).toBe(
// normalizeWhitespace(`
// query {
// TestTableCollection(filter: { id: { eq: "${testUUID}" } }) {
// edges {
// node {
// name: column_name
// age: column_age
// ___complexField_subField1: column_subField1
// ___complexField_subField2: column_subField2
// }
// }
// }
// }
// `),
// );
// });
// test('createMany generates correct mutation with complex and nested fields', () => {
// const args = {
// data: [
// {
// name: 'Alice',
// age: 30,
// complexField: {
// subField1: 'data1',
// subField2: 'data2',
// },
// },
// ],
// };
// const query = queryBuilder.createMany(args);
// expect(normalizeWhitespace(query)).toBe(
// normalizeWhitespace(`
// mutation {
// insertIntoTestTableCollection(objects: [{
// id: "${testUUID}",
// column_name: "Alice",
// column_age: 30,
// column_subField1: "data1",
// column_subField2: "data2"
// }]) {
// affectedCount
// records {
// name: column_name
// age: column_age
// ___complexField_subField1: column_subField1
// ___complexField_subField2: column_subField2
// }
// }
// }
// `),
// );
// });
// test('updateOne generates correct mutation with complex and nested fields', () => {
// const args = {
// id: '1',
// data: {
// name: 'Bob',
// age: 40,
// complexField: {
// subField1: 'newData1',
// subField2: 'newData2',
// },
// },
// };
// const query = queryBuilder.updateOne(args);
// expect(normalizeWhitespace(query)).toBe(
// normalizeWhitespace(`
// mutation {
// updateTestTableCollection(
// set: {
// column_name: "Bob",
// column_age: 40,
// column_subField1: "newData1",
// column_subField2: "newData2"
// },
// filter: { id: { eq: "1" } }
// ) {
// affectedCount
// records {
// name: column_name
// age: column_age
// ___complexField_subField1: column_subField1
// ___complexField_subField2: column_subField2
// }
// }
// }
// `),
// );
// });
// });
it('should pass', () => {
expect(true).toBe(true);
});

View File

@ -7,6 +7,7 @@ import { Record as IRecord } from 'src/workspace/workspace-query-builder/interfa
import { CreateManyResolverArgs } from 'src/workspace/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { stringifyWithoutKeyQuote } from 'src/workspace/workspace-query-builder/utils/stringify-without-key-quote.util';
import { computeObjectTargetTable } from 'src/workspace/utils/compute-object-target-table.util';
import { FieldsStringFactory } from './fields-string.factory';
import { ArgsAliasFactory } from './args-alias.factory';
@ -36,9 +37,9 @@ export class CreateManyQueryFactory {
return `
mutation {
insertInto${
options.targetTableName
}Collection(objects: ${stringifyWithoutKeyQuote(
insertInto${computeObjectTargetTable(
options.objectMetadataItem,
)}Collection(objects: ${stringifyWithoutKeyQuote(
computedArgs.data.map((datum) => ({
id: uuidv4(),
...datum,

View File

@ -4,6 +4,7 @@ import { WorkspaceQueryBuilderOptions } from 'src/workspace/workspace-query-buil
import { DeleteManyResolverArgs } from 'src/workspace/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { stringifyWithoutKeyQuote } from 'src/workspace/workspace-query-builder/utils/stringify-without-key-quote.util';
import { computeObjectTargetTable } from 'src/workspace/utils/compute-object-target-table.util';
import { FieldsStringFactory } from './fields-string.factory';
@ -23,9 +24,9 @@ export class DeleteManyQueryFactory {
return `
mutation {
deleteFrom${
options.targetTableName
}Collection(filter: ${stringifyWithoutKeyQuote(
deleteFrom${computeObjectTargetTable(
options.objectMetadataItem,
)}Collection(filter: ${stringifyWithoutKeyQuote(
args.filter,
)}, atMost: 30) {
affectedCount

View File

@ -3,6 +3,8 @@ import { Injectable, Logger } from '@nestjs/common';
import { WorkspaceQueryBuilderOptions } from 'src/workspace/workspace-query-builder/interfaces/workspace-query-builder-options.interface';
import { DeleteOneResolverArgs } from 'src/workspace/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { computeObjectTargetTable } from 'src/workspace/utils/compute-object-target-table.util';
import { FieldsStringFactory } from './fields-string.factory';
@Injectable()
@ -23,7 +25,9 @@ export class DeleteOneQueryFactory {
return `
mutation {
deleteFrom${options.targetTableName}Collection(filter: { id: { eq: "${args.id}" } }) {
deleteFrom${computeObjectTargetTable(
options.objectMetadataItem,
)}Collection(filter: { id: { eq: "${args.id}" } }) {
affectedCount
records {
${fieldsString}

View File

@ -9,6 +9,7 @@ import { FindManyResolverArgs } from 'src/workspace/workspace-resolver-builder/i
import { ArgsStringFactory } from './args-string.factory';
import { FieldsStringFactory } from './fields-string.factory';
import { computeObjectTargetTable } from 'src/workspace/utils/compute-object-target-table.util';
@Injectable()
export class FindManyQueryFactory {
@ -38,7 +39,7 @@ export class FindManyQueryFactory {
return `
query {
${options.targetTableName}Collection${
${computeObjectTargetTable(options.objectMetadataItem)}Collection${
argsString ? `(${argsString})` : ''
} {
${fieldsString}

View File

@ -4,6 +4,8 @@ import { WorkspaceQueryBuilderOptions } from 'src/workspace/workspace-query-buil
import { RecordFilter } from 'src/workspace/workspace-query-builder/interfaces/record.interface';
import { FindOneResolverArgs } from 'src/workspace/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { computeObjectTargetTable } from 'src/workspace/utils/compute-object-target-table.util';
import { ArgsStringFactory } from './args-string.factory';
import { FieldsStringFactory } from './fields-string.factory';
@ -32,7 +34,7 @@ export class FindOneQueryFactory {
return `
query {
${options.targetTableName}Collection${
${computeObjectTargetTable(options.objectMetadataItem)}Collection${
argsString ? `(${argsString})` : ''
} {
edges {

View File

@ -13,6 +13,7 @@ import {
} from 'src/workspace/utils/deduce-relation-direction.util';
import { getFieldArgumentsByKey } from 'src/workspace/workspace-query-builder/utils/get-field-arguments-by-key.util';
import { ObjectMetadataService } from 'src/metadata/object-metadata/object-metadata.service';
import { computeObjectTargetTable } from 'src/workspace/utils/compute-object-target-table.util';
import { FieldsStringFactory } from './fields-string.factory';
import { ArgsStringFactory } from './args-string.factory';
@ -109,25 +110,27 @@ export class RelationFieldAliasFactory {
);
return `
${fieldKey}: ${referencedObjectMetadata.targetTableName}Collection${
argsString ? `(${argsString})` : ''
} {
${fieldKey}: ${computeObjectTargetTable(
referencedObjectMetadata,
)}Collection${argsString ? `(${argsString})` : ''} {
${fieldsString}
}
`;
}
let relationAlias = fieldMetadata.isCustom
? `${fieldKey}: ${referencedObjectMetadata.targetTableName}`
? `${fieldKey}: _${fieldMetadata.name}`
: fieldKey;
// For one to one relations, pg_graphql use the targetTableName on the side that is not storing the foreign key
// For one to one relations, pg_graphql use the target TableName 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}`;
relationAlias = `${fieldKey}: ${computeObjectTargetTable(
referencedObjectMetadata,
)}`;
}
const fieldsString =
await this.fieldsStringFactory.createFieldsStringRecursive(

View File

@ -10,6 +10,7 @@ import { UpdateManyResolverArgs } from 'src/workspace/workspace-resolver-builder
import { stringifyWithoutKeyQuote } from 'src/workspace/workspace-query-builder/utils/stringify-without-key-quote.util';
import { FieldsStringFactory } from 'src/workspace/workspace-query-builder/factories/fields-string.factory';
import { ArgsAliasFactory } from 'src/workspace/workspace-query-builder/factories/args-alias.factory';
import { computeObjectTargetTable } from 'src/workspace/utils/compute-object-target-table.util';
@Injectable()
export class UpdateManyQueryFactory {
@ -43,7 +44,7 @@ export class UpdateManyQueryFactory {
return `
mutation {
update${options.targetTableName}Collection(
update${computeObjectTargetTable(options.objectMetadataItem)}Collection(
set: ${stringifyWithoutKeyQuote(argsData)},
filter: ${stringifyWithoutKeyQuote(args.filter)},
) {

View File

@ -5,6 +5,7 @@ import { Record as IRecord } from 'src/workspace/workspace-query-builder/interfa
import { UpdateOneResolverArgs } from 'src/workspace/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { stringifyWithoutKeyQuote } from 'src/workspace/workspace-query-builder/utils/stringify-without-key-quote.util';
import { computeObjectTargetTable } from 'src/workspace/utils/compute-object-target-table.util';
import { FieldsStringFactory } from './fields-string.factory';
import { ArgsAliasFactory } from './args-alias.factory';
@ -39,9 +40,9 @@ export class UpdateOneQueryFactory {
return `
mutation {
update${
options.targetTableName
}Collection(set: ${stringifyWithoutKeyQuote(
update${computeObjectTargetTable(
options.objectMetadataItem,
)}Collection(set: ${stringifyWithoutKeyQuote(
argsData,
)}, filter: { id: { eq: "${computedArgs.id}" } }) {
affectedCount

View File

@ -4,7 +4,7 @@ import { FieldMetadataInterface } from 'src/metadata/field-metadata/interfaces/f
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
export interface WorkspaceQueryBuilderOptions {
targetTableName: string;
objectMetadataItem: ObjectMetadataInterface;
info: GraphQLResolveInfo;
fieldMetadataCollection: FieldMetadataInterface[];
objectMetadataCollection: ObjectMetadataInterface[];