Gql direct execution - Improvements (#18972)
#### Direct Execution __typename & null backfill ##### __typename filling The direct execution path now correctly derives __typename at every level of the GraphQL response: Connection types — CompanyConnection, CompanyEdge, Company, PageInfo GroupBy types — TaskGroupByConnection (was incorrectly producing TaskConnection) Composite fields — Links, FullName, Currency, etc. handled by a dedicated formatter (was inheriting the parent object's typename) Previously, __typename was derived from the object's universal identifier (a UUID), producing broken values like 20202020B3744779A56180086Cb2E17FConnection. ##### Null backfill Selected fields missing from the resolver result are backfilled with null, matching the standard Yoga schema behavior. ##### Integration test A new test runs the same findMany query (with __typename at all structural levels) through both paths — standard Yoga schema and direct execution — and asserts identical output via toStrictEqual.
This commit is contained in:
+6
@@ -1,9 +1,15 @@
|
||||
import { DataArgProcessorService } from 'src/engine/api/common/common-args-processors/data-arg-processor/data-arg-processor.service';
|
||||
import { FilterArgProcessorService } from 'src/engine/api/common/common-args-processors/filter-arg-processor/filter-arg-processor.service';
|
||||
import { GroupByArgProcessorService } from 'src/engine/api/common/common-args-processors/group-by-arg-processor/group-by-arg-processor.service';
|
||||
import { OrderByArgProcessorService } from 'src/engine/api/common/common-args-processors/order-by-arg-processor/order-by-arg-processor.service';
|
||||
import { OrderByWithGroupByArgProcessorService } from 'src/engine/api/common/common-args-processors/order-by-with-group-by-arg-processor/order-by-with-group-by-arg-processor.service';
|
||||
import { QueryRunnerArgsFactory } from 'src/engine/api/common/common-args-processors/query-runner-args.factory';
|
||||
|
||||
export const CommonArgsProcessors = [
|
||||
DataArgProcessorService,
|
||||
FilterArgProcessorService,
|
||||
GroupByArgProcessorService,
|
||||
OrderByArgProcessorService,
|
||||
OrderByWithGroupByArgProcessorService,
|
||||
QueryRunnerArgsFactory,
|
||||
]; // TODO: Refacto-common Remove QueryRunnerArgsFactory
|
||||
|
||||
+2
-1
@@ -1,9 +1,10 @@
|
||||
import { isString } from '@sniptt/guards';
|
||||
import { isNullEquivalentArrayFieldValue } from 'src/engine/api/common/common-args-processors/data-arg-processor/utils/is-null-equivalent-array-field-value.util';
|
||||
|
||||
export const transformArrayField = (
|
||||
value: string | string[] | null,
|
||||
): string[] | null => {
|
||||
if (typeof value === 'string') return [value];
|
||||
if (isString(value)) return [value];
|
||||
|
||||
return isNullEquivalentArrayFieldValue(value) ? null : value;
|
||||
};
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import {
|
||||
ObjectRecordGroupByForAtomicField,
|
||||
ObjectRecordGroupByForCompositeField,
|
||||
ObjectRecordGroupByForDateField,
|
||||
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
||||
|
||||
@Injectable()
|
||||
export class GroupByArgProcessorService {
|
||||
process({
|
||||
groupBy,
|
||||
}: {
|
||||
groupBy:
|
||||
| ObjectRecordGroupByForAtomicField
|
||||
| ObjectRecordGroupByForCompositeField
|
||||
| ObjectRecordGroupByForDateField
|
||||
| Array<
|
||||
| ObjectRecordGroupByForAtomicField
|
||||
| ObjectRecordGroupByForCompositeField
|
||||
| ObjectRecordGroupByForDateField
|
||||
>;
|
||||
}): Array<
|
||||
| ObjectRecordGroupByForAtomicField
|
||||
| ObjectRecordGroupByForCompositeField
|
||||
| ObjectRecordGroupByForDateField
|
||||
> {
|
||||
if (Array.isArray(groupBy)) {
|
||||
return groupBy;
|
||||
}
|
||||
|
||||
return [groupBy];
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ObjectRecordOrderBy } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
||||
import {
|
||||
ObjectRecordOrderByForCompositeField,
|
||||
ObjectRecordOrderByForScalarField,
|
||||
} from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@Injectable()
|
||||
export class OrderByArgProcessorService {
|
||||
process({
|
||||
orderBy,
|
||||
}: {
|
||||
orderBy:
|
||||
| undefined
|
||||
| ObjectRecordOrderByForScalarField
|
||||
| ObjectRecordOrderByForCompositeField
|
||||
| ObjectRecordOrderBy;
|
||||
}): ObjectRecordOrderBy | undefined {
|
||||
if (Array.isArray(orderBy) || !isDefined(orderBy)) {
|
||||
return orderBy;
|
||||
}
|
||||
|
||||
return [orderBy];
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import {
|
||||
OrderByWithGroupBy,
|
||||
type AggregateOrderByWithGroupByField,
|
||||
type ObjectRecordOrderByForCompositeField,
|
||||
type ObjectRecordOrderByForRelationField,
|
||||
type ObjectRecordOrderByForScalarField,
|
||||
type ObjectRecordOrderByWithGroupByDateField,
|
||||
} from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@Injectable()
|
||||
export class OrderByWithGroupByArgProcessorService {
|
||||
process({
|
||||
orderBy,
|
||||
}: {
|
||||
orderBy:
|
||||
| undefined
|
||||
| ObjectRecordOrderByForScalarField
|
||||
| ObjectRecordOrderByForCompositeField
|
||||
| ObjectRecordOrderByWithGroupByDateField
|
||||
| ObjectRecordOrderByForRelationField
|
||||
| AggregateOrderByWithGroupByField
|
||||
| OrderByWithGroupBy;
|
||||
}): OrderByWithGroupBy | undefined {
|
||||
if (Array.isArray(orderBy) || !isDefined(orderBy)) {
|
||||
return orderBy;
|
||||
}
|
||||
|
||||
return [orderBy];
|
||||
}
|
||||
}
|
||||
+9
@@ -6,6 +6,9 @@ import { QueryResultFieldValue } from 'src/engine/api/graphql/workspace-query-ru
|
||||
|
||||
import { DataArgProcessorService } from 'src/engine/api/common/common-args-processors/data-arg-processor/data-arg-processor.service';
|
||||
import { FilterArgProcessorService } from 'src/engine/api/common/common-args-processors/filter-arg-processor/filter-arg-processor.service';
|
||||
import { GroupByArgProcessorService } from 'src/engine/api/common/common-args-processors/group-by-arg-processor/group-by-arg-processor.service';
|
||||
import { OrderByArgProcessorService } from 'src/engine/api/common/common-args-processors/order-by-arg-processor/order-by-arg-processor.service';
|
||||
import { OrderByWithGroupByArgProcessorService } from 'src/engine/api/common/common-args-processors/order-by-with-group-by-arg-processor/order-by-with-group-by-arg-processor.service';
|
||||
import { QueryRunnerArgsFactory } from 'src/engine/api/common/common-args-processors/query-runner-args.factory';
|
||||
import { ProcessNestedRelationsHelper } from 'src/engine/api/common/common-nested-relations-processor/process-nested-relations.helper';
|
||||
import {
|
||||
@@ -64,6 +67,12 @@ export abstract class CommonBaseQueryRunnerService<
|
||||
@Inject()
|
||||
protected readonly filterArgProcessor: FilterArgProcessorService;
|
||||
@Inject()
|
||||
protected readonly groupByArgProcessor: GroupByArgProcessorService;
|
||||
@Inject()
|
||||
protected readonly orderByArgProcessor: OrderByArgProcessorService;
|
||||
@Inject()
|
||||
protected readonly orderByWithGroupByArgProcessor: OrderByWithGroupByArgProcessorService;
|
||||
@Inject()
|
||||
protected readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager;
|
||||
@Inject()
|
||||
protected readonly processNestedRelationsHelper: ProcessNestedRelationsHelper;
|
||||
|
||||
+4
-1
@@ -13,7 +13,6 @@ import {
|
||||
ObjectRecordOrderBy,
|
||||
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
||||
|
||||
import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
|
||||
import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service';
|
||||
import {
|
||||
CommonQueryRunnerException,
|
||||
@@ -39,6 +38,7 @@ import {
|
||||
countRelationFieldsInOrderBy,
|
||||
hasRelationFieldInOrderBy,
|
||||
} from 'src/engine/api/utils/validate-and-get-order-by.utils';
|
||||
import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
|
||||
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
|
||||
@@ -235,6 +235,9 @@ export class CommonFindManyQueryRunnerService extends CommonBaseQueryRunnerServi
|
||||
|
||||
return {
|
||||
...args,
|
||||
orderBy: this.orderByArgProcessor.process({
|
||||
orderBy: args.orderBy,
|
||||
}),
|
||||
filter: this.filterArgProcessor.process({
|
||||
filter: args.filter,
|
||||
flatObjectMetadata,
|
||||
|
||||
+9
@@ -405,6 +405,15 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
|
||||
|
||||
return {
|
||||
...args,
|
||||
groupBy: this.groupByArgProcessor.process({
|
||||
groupBy: args.groupBy,
|
||||
}),
|
||||
orderBy: this.orderByWithGroupByArgProcessor.process({
|
||||
orderBy: args.orderBy,
|
||||
}),
|
||||
orderByForRecords: this.orderByArgProcessor.process({
|
||||
orderBy: args.orderByForRecords,
|
||||
}),
|
||||
filter: this.filterArgProcessor.process({
|
||||
filter: args.filter,
|
||||
flatObjectMetadata,
|
||||
|
||||
Reference in New Issue
Block a user