Create query runner context from request context instead of schema builder internal context (#16858)

## Context
This PR refactors how authentication context is handled in the GraphQL
resolver layer. Previously, the auth context was baked into the schema
builder context at schema creation time. Now, the auth context is
extracted from the request at query execution time, enabling better
schema caching.

## Implementation
- Removed user-specific data from schema cache key: The schema cache key
no longer includes userId and apiKeyId, allowing the same schema to be
shared across all users in a workspace
- Cache key simplified from
${workspaceId}-${userId}-${apiKeyId}-${url}-${cacheVersion} to
${workspaceId}-${url}-${cacheVersion}
- Removed authContext from WorkspaceSchemaBuilderContext: The schema
builder context is now purely about object/field metadata, not about who
is accessing it
- Created createQueryRunnerContext utility: A new helper that combines
the schema builder context with the auth context from the actual request
- Updated all resolver factories: All 15 resolver factories now use
createQueryRunnerContext to build the full context needed by query
runners at execution time

## Benefits
- Improved cache efficiency: GraphQL schemas are now cached per
workspace rather than per user, significantly reducing memory usage and
schema regeneration
- Cleaner separation of concerns: Schema building (metadata-driven) is
now separate from query execution (auth-driven)
- Fresh auth context: Auth context is always retrieved from the current
request, ensuring it reflects the latest state
- Reduced complexity: Simplified the schema creation path by removing
unnecessary auth checks

## Next steps
- Introduce a hash in redis and expose it in the req object so the yoga
patch can access the hash and use it during its own cache key
computation. This way we will be able to invalidate the local cache in
yoga graphql schema generation without restarting pods.
This commit is contained in:
Weiko
2025-12-30 15:16:57 +01:00
committed by GitHub
parent e3ffdb0c2b
commit ab95437065
22 changed files with 264 additions and 199 deletions
@@ -14,6 +14,7 @@ import { CommonCreateManyQueryRunnerService } from 'src/engine/api/common/common
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class CreateManyResolverFactory
@@ -30,26 +31,31 @@ export class CreateManyResolverFactory
): Resolver<CreateManyResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
try {
const records = await this.commonCreateManyQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return records.map((record: ObjectRecord) =>
typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
}),
@@ -13,6 +13,7 @@ import { CommonCreateOneQueryRunnerService } from 'src/engine/api/common/common-
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class CreateOneResolverFactory
@@ -29,25 +30,30 @@ export class CreateOneResolverFactory
): Resolver<CreateOneResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
try {
const record = await this.commonCreateOneQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -14,6 +14,7 @@ import { CommonDeleteManyQueryRunnerService } from 'src/engine/api/common/common
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class DeleteManyResolverFactory
@@ -30,26 +31,31 @@ export class DeleteManyResolverFactory
): Resolver<DeleteManyResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
try {
const records = await this.commonDeleteManyQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return records.map((record: ObjectRecord) =>
typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
}),
@@ -13,6 +13,7 @@ import { CommonDeleteOneQueryRunnerService } from 'src/engine/api/common/common-
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class DeleteOneResolverFactory
@@ -29,25 +30,30 @@ export class DeleteOneResolverFactory
): Resolver<DeleteOneResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
try {
const record = await this.commonDeleteOneQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -14,6 +14,7 @@ import { CommonDestroyManyQueryRunnerService } from 'src/engine/api/common/commo
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class DestroyManyResolverFactory
@@ -30,26 +31,31 @@ export class DestroyManyResolverFactory
): Resolver<DestroyManyResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
try {
const records = await this.commonDestroyManyQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return records.map((record: ObjectRecord) =>
typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
}),
@@ -13,6 +13,7 @@ import { CommonDestroyOneQueryRunnerService } from 'src/engine/api/common/common
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class DestroyOneResolverFactory
@@ -29,25 +30,30 @@ export class DestroyOneResolverFactory
): Resolver<DestroyOneResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
try {
const record = await this.commonDestroyOneQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -14,6 +14,7 @@ import { CommonFindDuplicatesQueryRunnerService } from 'src/engine/api/common/co
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class FindDuplicatesResolverFactory
@@ -30,27 +31,32 @@ export class FindDuplicatesResolverFactory
): Resolver<FindDuplicatesResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
try {
const paginatedDuplicates =
await this.commonFindDuplicatesQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return paginatedDuplicates.map((duplicate) =>
typeORMObjectRecordsParser.createConnection({
objectRecords: duplicate.records,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: duplicate.records.length,
totalCount: duplicate.totalCount,
order: [{ id: OrderByDirection.AscNullsFirst }],
@@ -14,6 +14,7 @@ import { CommonFindManyQueryRunnerService } from 'src/engine/api/common/common-q
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class FindManyResolverFactory
@@ -30,9 +31,14 @@ export class FindManyResolverFactory
): Resolver<FindManyResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
try {
const {
records,
@@ -42,21 +48,21 @@ export class FindManyResolverFactory
selectedFieldsResult,
} = await this.commonFindManyQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.createConnection({
objectRecords: records,
objectRecordsAggregatedValues: aggregatedValues,
selectedAggregatedFields: selectedFieldsResult.aggregate,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: args.first ?? args.last ?? QUERY_MAX_RECORDS,
totalCount,
order: args.orderBy,
@@ -13,6 +13,7 @@ import { CommonFindOneQueryRunnerService } from 'src/engine/api/common/common-qu
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class FindOneResolverFactory
@@ -29,25 +30,30 @@ export class FindOneResolverFactory
): Resolver<FindOneResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
try {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
const record = await this.commonFindOneQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -14,6 +14,7 @@ import { CommonGroupByQueryRunnerService } from 'src/engine/api/common/common-qu
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class GroupByResolverFactory
@@ -30,9 +31,14 @@ export class GroupByResolverFactory
): Resolver<GroupByResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
const shouldIncludeRecords =
isDefined(selectedFields.edges?.node) &&
Object.keys(selectedFields.edges?.node).length > 0;
@@ -40,20 +46,20 @@ export class GroupByResolverFactory
try {
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
const results = await this.commonGroupByQueryRunnerService.execute(
{ ...args, selectedFields, includeRecords: shouldIncludeRecords },
internalContext,
resolverContext,
);
const formattedResults = results.map((group) => {
const formattedRecords = typeORMObjectRecordsParser.createConnection({
objectRecords: group.records ?? [],
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
objectRecordsAggregatedValues: {},
selectedAggregatedFields: {},
take: group.records?.length || 0,
@@ -13,6 +13,7 @@ import { CommonMergeManyQueryRunnerService } from 'src/engine/api/common/common-
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class MergeManyResolverFactory
@@ -29,25 +30,30 @@ export class MergeManyResolverFactory
): Resolver<MergeManyResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
try {
const record = await this.commonMergeManyQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -14,6 +14,7 @@ import { CommonRestoreManyQueryRunnerService } from 'src/engine/api/common/commo
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class RestoreManyResolverFactory
@@ -30,26 +31,31 @@ export class RestoreManyResolverFactory
): Resolver<RestoreManyResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
try {
const records = await this.commonRestoreManyQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return records.map((record: ObjectRecord) =>
typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
}),
@@ -13,6 +13,7 @@ import { CommonRestoreOneQueryRunnerService } from 'src/engine/api/common/common
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class RestoreOneResolverFactory
@@ -29,25 +30,30 @@ export class RestoreOneResolverFactory
): Resolver<RestoreOneResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
try {
const record = await this.commonRestoreOneQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -14,6 +14,7 @@ import { CommonUpdateManyQueryRunnerService } from 'src/engine/api/common/common
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class UpdateManyResolverFactory
@@ -30,26 +31,31 @@ export class UpdateManyResolverFactory
): Resolver<UpdateManyResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
try {
const records = await this.commonUpdateManyQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return records.map((record: ObjectRecord) =>
typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
}),
@@ -13,6 +13,7 @@ import { CommonUpdateOneQueryRunnerService } from 'src/engine/api/common/common-
import { ObjectRecordsToGraphqlConnectionHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/object-records-to-graphql-connection.helper';
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { createQueryRunnerContext } from 'src/engine/api/graphql/workspace-resolver-builder/utils/create-query-runner-context.util';
@Injectable()
export class UpdateOneResolverFactory
@@ -29,25 +30,30 @@ export class UpdateOneResolverFactory
): Resolver<UpdateOneResolverArgs> {
const internalContext = context;
return async (_source, args, _context, info) => {
return async (_source, args, requestContext, info) => {
const selectedFields = graphqlFields(info);
const resolverContext = createQueryRunnerContext({
workspaceSchemaBuilderContext: internalContext,
request: requestContext.req,
});
try {
const record = await this.commonUpdateOneQueryRunnerService.execute(
{ ...args, selectedFields },
internalContext,
resolverContext,
);
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
resolverContext.flatObjectMetadataMaps,
resolverContext.flatFieldMetadataMaps,
resolverContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectName: resolverContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -0,0 +1,37 @@
import { type WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
import { type CommonBaseQueryRunnerContext } from 'src/engine/api/common/types/common-base-query-runner-context.type';
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
export const createQueryRunnerContext = ({
workspaceSchemaBuilderContext,
request,
}: {
workspaceSchemaBuilderContext: WorkspaceSchemaBuilderContext;
request: AuthContext;
}): CommonBaseQueryRunnerContext => {
const {
user,
workspace,
apiKey,
workspaceMemberId,
userWorkspaceId,
userWorkspace,
authProvider,
impersonationContext,
} = request;
return {
...workspaceSchemaBuilderContext,
authContext: {
user,
workspace,
apiKey,
workspaceMemberId,
userWorkspaceId,
userWorkspace,
authProvider,
impersonationContext,
},
};
};
@@ -12,11 +12,6 @@ import { RestoreManyResolverFactory } from 'src/engine/api/graphql/workspace-res
import { RestoreOneResolverFactory } from 'src/engine/api/graphql/workspace-resolver-builder/factories/restore-one-resolver.factory';
import { UpdateManyResolverFactory } from 'src/engine/api/graphql/workspace-resolver-builder/factories/update-many-resolver.factory';
import { WorkspaceResolverBuilderService } from 'src/engine/api/graphql/workspace-resolver-builder/workspace-resolver-builder.service';
import {
AuthException,
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@@ -59,7 +54,6 @@ export class WorkspaceResolverFactory {
) {}
async create(
authContext: AuthContext,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
objectIdByNameSingular: Record<string, string>,
@@ -90,15 +84,6 @@ export class WorkspaceResolverFactory {
Mutation: {},
};
const workspaceId = authContext.workspace?.id;
if (!workspaceId) {
throw new AuthException(
'Unauthenticated',
AuthExceptionCode.UNAUTHENTICATED,
);
}
for (const flatObjectMetadata of Object.values(
flatObjectMetadataMaps.byId,
).filter(isDefined)) {
@@ -125,7 +110,6 @@ export class WorkspaceResolverFactory {
) {
// @ts-expect-error legacy noImplicitAny
resolvers.Query[resolverName] = resolverFactory.create({
authContext,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
@@ -157,7 +141,6 @@ export class WorkspaceResolverFactory {
) {
// @ts-expect-error legacy noImplicitAny
resolvers.Mutation[resolverName] = resolverFactory.create({
authContext,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,