Add crud actions (#8500)
Adding update / delete / find actions
Update and delete are not really different than creation.
Find uses the same logique as for graphql filters.
Expected formats are:
Filter
```
{
"and": [
{
"name": {
"eq": "salut"
}
},
{
"employees": {
"eq": "0"
}
}
]
}
```
Order
`[ { "name": 'AscNullsFirst' } ]`
This commit is contained in:
@ -54,7 +54,7 @@ export class GraphqlQueryParser {
|
|||||||
|
|
||||||
public applyDeletedAtToBuilder(
|
public applyDeletedAtToBuilder(
|
||||||
queryBuilder: SelectQueryBuilder<any>,
|
queryBuilder: SelectQueryBuilder<any>,
|
||||||
recordFilter: ObjectRecordFilter,
|
recordFilter: Partial<ObjectRecordFilter>,
|
||||||
): SelectQueryBuilder<any> {
|
): SelectQueryBuilder<any> {
|
||||||
if (this.checkForDeletedAtFilter(recordFilter)) {
|
if (this.checkForDeletedAtFilter(recordFilter)) {
|
||||||
queryBuilder.withDeleted();
|
queryBuilder.withDeleted();
|
||||||
|
|||||||
@ -10,10 +10,12 @@ import { checkStringIsDatabaseEventAction } from 'src/engine/api/graphql/graphql
|
|||||||
import { INDEX_FILE_NAME } from 'src/engine/core-modules/serverless/drivers/constants/index-file-name';
|
import { INDEX_FILE_NAME } from 'src/engine/core-modules/serverless/drivers/constants/index-file-name';
|
||||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||||
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
|
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
|
||||||
|
import { generateFakeValue } from 'src/engine/utils/generate-fake-value';
|
||||||
import { CodeIntrospectionService } from 'src/modules/code-introspection/code-introspection.service';
|
import { CodeIntrospectionService } from 'src/modules/code-introspection/code-introspection.service';
|
||||||
import { generateFakeObjectRecord } from 'src/modules/workflow/workflow-builder/utils/generate-fake-object-record';
|
import { generateFakeObjectRecord } from 'src/modules/workflow/workflow-builder/utils/generate-fake-object-record';
|
||||||
import { generateFakeObjectRecordEvent } from 'src/modules/workflow/workflow-builder/utils/generate-fake-object-record-event';
|
import { generateFakeObjectRecordEvent } from 'src/modules/workflow/workflow-builder/utils/generate-fake-object-record-event';
|
||||||
import { WorkflowSendEmailStepOutputSchema } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action';
|
import { WorkflowSendEmailStepOutputSchema } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action';
|
||||||
|
import { WorkflowRecordCRUDType } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type';
|
||||||
import {
|
import {
|
||||||
WorkflowAction,
|
WorkflowAction,
|
||||||
WorkflowActionType,
|
WorkflowActionType,
|
||||||
@ -44,7 +46,7 @@ export class WorkflowBuilderWorkspaceService {
|
|||||||
|
|
||||||
switch (stepType) {
|
switch (stepType) {
|
||||||
case WorkflowTriggerType.DATABASE_EVENT: {
|
case WorkflowTriggerType.DATABASE_EVENT: {
|
||||||
return await this.computeDatabaseEventTriggerOutputSchema({
|
return this.computeDatabaseEventTriggerOutputSchema({
|
||||||
eventName: step.settings.eventName,
|
eventName: step.settings.eventName,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataRepository: this.objectMetadataRepository,
|
objectMetadataRepository: this.objectMetadataRepository,
|
||||||
@ -57,7 +59,7 @@ export class WorkflowBuilderWorkspaceService {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.computeRecordOutputSchema({
|
return this.computeRecordOutputSchema({
|
||||||
objectType,
|
objectType,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataRepository: this.objectMetadataRepository,
|
objectMetadataRepository: this.objectMetadataRepository,
|
||||||
@ -70,7 +72,7 @@ export class WorkflowBuilderWorkspaceService {
|
|||||||
const { serverlessFunctionId, serverlessFunctionVersion } =
|
const { serverlessFunctionId, serverlessFunctionVersion } =
|
||||||
step.settings.input;
|
step.settings.input;
|
||||||
|
|
||||||
return await this.computeCodeActionOutputSchema({
|
return this.computeCodeActionOutputSchema({
|
||||||
serverlessFunctionId,
|
serverlessFunctionId,
|
||||||
serverlessFunctionVersion,
|
serverlessFunctionVersion,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
@ -79,8 +81,9 @@ export class WorkflowBuilderWorkspaceService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
case WorkflowActionType.RECORD_CRUD:
|
case WorkflowActionType.RECORD_CRUD:
|
||||||
return await this.computeRecordOutputSchema({
|
return this.computeRecordCrudOutputSchema({
|
||||||
objectType: step.settings.input.objectName,
|
objectType: step.settings.input.objectName,
|
||||||
|
operationType: step.settings.input.type,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataRepository: this.objectMetadataRepository,
|
objectMetadataRepository: this.objectMetadataRepository,
|
||||||
});
|
});
|
||||||
@ -122,6 +125,34 @@ export class WorkflowBuilderWorkspaceService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async computeRecordCrudOutputSchema<Entity>({
|
||||||
|
objectType,
|
||||||
|
operationType,
|
||||||
|
workspaceId,
|
||||||
|
objectMetadataRepository,
|
||||||
|
}: {
|
||||||
|
objectType: string;
|
||||||
|
operationType: string;
|
||||||
|
workspaceId: string;
|
||||||
|
objectMetadataRepository: Repository<ObjectMetadataEntity>;
|
||||||
|
}) {
|
||||||
|
const recordOutputSchema = await this.computeRecordOutputSchema<Entity>({
|
||||||
|
objectType,
|
||||||
|
workspaceId,
|
||||||
|
objectMetadataRepository,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (operationType === WorkflowRecordCRUDType.READ) {
|
||||||
|
return {
|
||||||
|
first: recordOutputSchema,
|
||||||
|
last: recordOutputSchema,
|
||||||
|
totalCount: generateFakeValue('number'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return recordOutputSchema;
|
||||||
|
}
|
||||||
|
|
||||||
private async computeRecordOutputSchema<Entity>({
|
private async computeRecordOutputSchema<Entity>({
|
||||||
objectType,
|
objectType,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
import { CustomException } from 'src/utils/custom-exception';
|
||||||
|
|
||||||
|
export class RecordCRUDActionException extends CustomException {
|
||||||
|
code: RecordCRUDActionExceptionCode;
|
||||||
|
constructor(message: string, code: RecordCRUDActionExceptionCode) {
|
||||||
|
super(message, code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum RecordCRUDActionExceptionCode {
|
||||||
|
INVALID_REQUEST = 'INVALID_REQUEST',
|
||||||
|
RECORD_NOT_FOUND = 'RECORD_NOT_FOUND',
|
||||||
|
}
|
||||||
@ -1,9 +1,12 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
||||||
|
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
|
||||||
import { RecordCRUDWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud.workflow-action';
|
import { RecordCRUDWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud.workflow-action';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [RecordCRUDWorkflowAction],
|
imports: [WorkspaceCacheStorageModule],
|
||||||
|
providers: [RecordCRUDWorkflowAction, ScopedWorkspaceContextFactory],
|
||||||
exports: [RecordCRUDWorkflowAction],
|
exports: [RecordCRUDWorkflowAction],
|
||||||
})
|
})
|
||||||
export class RecordCRUDActionModule {}
|
export class RecordCRUDActionModule {}
|
||||||
|
|||||||
@ -1,18 +1,45 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { Entity } from '@microsoft/microsoft-graph-types';
|
||||||
|
import { ObjectLiteral } from 'typeorm';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ObjectRecordFilter,
|
||||||
|
ObjectRecordOrderBy,
|
||||||
|
OrderByDirection,
|
||||||
|
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
||||||
import { WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface';
|
import { WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface';
|
||||||
|
|
||||||
|
import { QUERY_MAX_RECORDS } from 'src/engine/api/graphql/graphql-query-runner/constants/query-max-records.constant';
|
||||||
|
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
|
||||||
|
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
||||||
|
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
|
||||||
|
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
||||||
|
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||||
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||||
|
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||||
|
import { WorkspaceCacheStorageService } from 'src/engine/workspace-cache-storage/workspace-cache-storage.service';
|
||||||
|
import {
|
||||||
|
RecordCRUDActionException,
|
||||||
|
RecordCRUDActionExceptionCode,
|
||||||
|
} from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/exceptions/record-crud-action.exception';
|
||||||
import {
|
import {
|
||||||
WorkflowCreateRecordActionInput,
|
WorkflowCreateRecordActionInput,
|
||||||
|
WorkflowDeleteRecordActionInput,
|
||||||
|
WorkflowReadRecordActionInput,
|
||||||
WorkflowRecordCRUDActionInput,
|
WorkflowRecordCRUDActionInput,
|
||||||
WorkflowRecordCRUDType,
|
WorkflowRecordCRUDType,
|
||||||
|
WorkflowUpdateRecordActionInput,
|
||||||
} from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type';
|
} from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type';
|
||||||
import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-result.type';
|
import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-result.type';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RecordCRUDWorkflowAction implements WorkflowAction {
|
export class RecordCRUDWorkflowAction implements WorkflowAction {
|
||||||
constructor(private readonly twentyORMManager: TwentyORMManager) {}
|
constructor(
|
||||||
|
private readonly twentyORMManager: TwentyORMManager,
|
||||||
|
private readonly workspaceCacheStorageService: WorkspaceCacheStorageService,
|
||||||
|
private readonly scopedWorkspaceContextFactory: ScopedWorkspaceContextFactory,
|
||||||
|
) {}
|
||||||
|
|
||||||
async execute(
|
async execute(
|
||||||
workflowActionInput: WorkflowRecordCRUDActionInput,
|
workflowActionInput: WorkflowRecordCRUDActionInput,
|
||||||
@ -20,9 +47,16 @@ export class RecordCRUDWorkflowAction implements WorkflowAction {
|
|||||||
switch (workflowActionInput.type) {
|
switch (workflowActionInput.type) {
|
||||||
case WorkflowRecordCRUDType.CREATE:
|
case WorkflowRecordCRUDType.CREATE:
|
||||||
return this.createRecord(workflowActionInput);
|
return this.createRecord(workflowActionInput);
|
||||||
|
case WorkflowRecordCRUDType.DELETE:
|
||||||
|
return this.deleteRecord(workflowActionInput);
|
||||||
|
case WorkflowRecordCRUDType.UPDATE:
|
||||||
|
return this.updateRecord(workflowActionInput);
|
||||||
|
case WorkflowRecordCRUDType.READ:
|
||||||
|
return this.findRecords(workflowActionInput);
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new RecordCRUDActionException(
|
||||||
`Unknown record operation type: ${workflowActionInput.type}`,
|
`Unknown record operation type`,
|
||||||
|
RecordCRUDActionExceptionCode.INVALID_REQUEST,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,8 +72,213 @@ export class RecordCRUDWorkflowAction implements WorkflowAction {
|
|||||||
workflowActionInput.objectRecord,
|
workflowActionInput.objectRecord,
|
||||||
);
|
);
|
||||||
|
|
||||||
const createdObjectRecord = await repository.save(objectRecord);
|
await repository.save(objectRecord);
|
||||||
|
|
||||||
return { result: createdObjectRecord };
|
return {
|
||||||
|
result: objectRecord,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async updateRecord(
|
||||||
|
workflowActionInput: WorkflowUpdateRecordActionInput,
|
||||||
|
): Promise<WorkflowActionResult> {
|
||||||
|
const repository = await this.twentyORMManager.getRepository(
|
||||||
|
workflowActionInput.objectName,
|
||||||
|
);
|
||||||
|
|
||||||
|
const objectRecord = await repository.findOne({
|
||||||
|
where: {
|
||||||
|
id: workflowActionInput.objectRecordId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!objectRecord) {
|
||||||
|
throw new RecordCRUDActionException(
|
||||||
|
`Failed to update: Record ${workflowActionInput.objectName} with id ${workflowActionInput.objectRecordId} not found`,
|
||||||
|
RecordCRUDActionExceptionCode.RECORD_NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await repository.update(workflowActionInput.objectRecordId, {
|
||||||
|
...workflowActionInput.objectRecord,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
result: {
|
||||||
|
...objectRecord,
|
||||||
|
...workflowActionInput.objectRecord,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async deleteRecord(
|
||||||
|
workflowActionInput: WorkflowDeleteRecordActionInput,
|
||||||
|
): Promise<WorkflowActionResult> {
|
||||||
|
const repository = await this.twentyORMManager.getRepository(
|
||||||
|
workflowActionInput.objectName,
|
||||||
|
);
|
||||||
|
|
||||||
|
const objectRecord = await repository.findOne({
|
||||||
|
where: {
|
||||||
|
id: workflowActionInput.objectRecordId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!objectRecord) {
|
||||||
|
throw new RecordCRUDActionException(
|
||||||
|
`Failed to delete: Record ${workflowActionInput.objectName} with id ${workflowActionInput.objectRecordId} not found`,
|
||||||
|
RecordCRUDActionExceptionCode.RECORD_NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await repository.update(workflowActionInput.objectRecordId, {
|
||||||
|
deletedAt: new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
result: objectRecord,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async findRecords(
|
||||||
|
workflowActionInput: WorkflowReadRecordActionInput,
|
||||||
|
): Promise<WorkflowActionResult> {
|
||||||
|
const repository = await this.twentyORMManager.getRepository(
|
||||||
|
workflowActionInput.objectName,
|
||||||
|
);
|
||||||
|
const workspaceId = this.scopedWorkspaceContextFactory.create().workspaceId;
|
||||||
|
|
||||||
|
if (!workspaceId) {
|
||||||
|
throw new RecordCRUDActionException(
|
||||||
|
'Failed to read: Workspace ID is required',
|
||||||
|
RecordCRUDActionExceptionCode.INVALID_REQUEST,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentCacheVersion =
|
||||||
|
await this.workspaceCacheStorageService.getMetadataVersion(workspaceId);
|
||||||
|
|
||||||
|
if (currentCacheVersion === undefined) {
|
||||||
|
throw new RecordCRUDActionException(
|
||||||
|
'Failed to read: Metadata cache version not found',
|
||||||
|
RecordCRUDActionExceptionCode.INVALID_REQUEST,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const objectMetadataMaps =
|
||||||
|
await this.workspaceCacheStorageService.getObjectMetadataMaps(
|
||||||
|
workspaceId,
|
||||||
|
currentCacheVersion,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!objectMetadataMaps) {
|
||||||
|
throw new RecordCRUDActionException(
|
||||||
|
'Failed to read: Object metadata collection not found',
|
||||||
|
RecordCRUDActionExceptionCode.INVALID_REQUEST,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const objectMetadataItemWithFieldsMaps =
|
||||||
|
objectMetadataMaps.byNameSingular[workflowActionInput.objectName];
|
||||||
|
|
||||||
|
if (!objectMetadataItemWithFieldsMaps) {
|
||||||
|
throw new RecordCRUDActionException(
|
||||||
|
`Failed to read: Object ${workflowActionInput.objectName} not found`,
|
||||||
|
RecordCRUDActionExceptionCode.INVALID_REQUEST,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const graphqlQueryParser = new GraphqlQueryParser(
|
||||||
|
objectMetadataItemWithFieldsMaps.fieldsByName,
|
||||||
|
objectMetadataMaps,
|
||||||
|
);
|
||||||
|
|
||||||
|
const objectRecords = await this.getObjectRecords(
|
||||||
|
workflowActionInput,
|
||||||
|
objectMetadataItemWithFieldsMaps,
|
||||||
|
objectMetadataMaps,
|
||||||
|
repository,
|
||||||
|
graphqlQueryParser,
|
||||||
|
);
|
||||||
|
|
||||||
|
const totalCount = await this.getTotalCount(
|
||||||
|
workflowActionInput,
|
||||||
|
repository,
|
||||||
|
graphqlQueryParser,
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
result: {
|
||||||
|
first: objectRecords[0],
|
||||||
|
last: objectRecords[objectRecords.length - 1],
|
||||||
|
totalCount,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getObjectRecords<T extends ObjectLiteral>(
|
||||||
|
workflowActionInput: WorkflowReadRecordActionInput,
|
||||||
|
objectMetadataItemWithFieldsMaps: ObjectMetadataItemWithFieldMaps,
|
||||||
|
objectMetadataMaps: ObjectMetadataMaps,
|
||||||
|
repository: WorkspaceRepository<T>,
|
||||||
|
graphqlQueryParser: GraphqlQueryParser,
|
||||||
|
) {
|
||||||
|
const queryBuilder = repository.createQueryBuilder(
|
||||||
|
workflowActionInput.objectName,
|
||||||
|
);
|
||||||
|
|
||||||
|
const withFilterQueryBuilder = graphqlQueryParser.applyFilterToBuilder(
|
||||||
|
queryBuilder,
|
||||||
|
workflowActionInput.objectName,
|
||||||
|
workflowActionInput.filter ?? ({} as ObjectRecordFilter),
|
||||||
|
);
|
||||||
|
|
||||||
|
const orderByWithIdCondition = [
|
||||||
|
...(workflowActionInput.orderBy ?? []),
|
||||||
|
{ id: OrderByDirection.AscNullsFirst },
|
||||||
|
] as ObjectRecordOrderBy;
|
||||||
|
|
||||||
|
const withOrderByQueryBuilder = graphqlQueryParser.applyOrderToBuilder(
|
||||||
|
withFilterQueryBuilder,
|
||||||
|
orderByWithIdCondition,
|
||||||
|
workflowActionInput.objectName,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
const nonFormattedObjectRecords = await withOrderByQueryBuilder
|
||||||
|
.take(workflowActionInput.limit ?? QUERY_MAX_RECORDS)
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
return formatResult(
|
||||||
|
nonFormattedObjectRecords,
|
||||||
|
objectMetadataItemWithFieldsMaps,
|
||||||
|
objectMetadataMaps,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getTotalCount(
|
||||||
|
workflowActionInput: WorkflowReadRecordActionInput,
|
||||||
|
repository: WorkspaceRepository<Entity>,
|
||||||
|
graphqlQueryParser: GraphqlQueryParser,
|
||||||
|
) {
|
||||||
|
const countQueryBuilder = repository.createQueryBuilder(
|
||||||
|
workflowActionInput.objectName,
|
||||||
|
);
|
||||||
|
|
||||||
|
const withFilterCountQueryBuilder = graphqlQueryParser.applyFilterToBuilder(
|
||||||
|
countQueryBuilder,
|
||||||
|
workflowActionInput.objectName,
|
||||||
|
workflowActionInput.filter ?? ({} as ObjectRecordFilter),
|
||||||
|
);
|
||||||
|
|
||||||
|
const withDeletedCountQueryBuilder =
|
||||||
|
graphqlQueryParser.applyDeletedAtToBuilder(
|
||||||
|
withFilterCountQueryBuilder,
|
||||||
|
workflowActionInput.filter
|
||||||
|
? workflowActionInput.filter
|
||||||
|
: ({} as ObjectRecordFilter),
|
||||||
|
);
|
||||||
|
|
||||||
|
return withDeletedCountQueryBuilder.getCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,15 @@
|
|||||||
|
import {
|
||||||
|
ObjectRecordFilter,
|
||||||
|
ObjectRecordOrderBy,
|
||||||
|
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
|
||||||
|
|
||||||
type ObjectRecord = Record<string, any>;
|
type ObjectRecord = Record<string, any>;
|
||||||
|
|
||||||
export enum WorkflowRecordCRUDType {
|
export enum WorkflowRecordCRUDType {
|
||||||
CREATE = 'create',
|
CREATE = 'create',
|
||||||
UPDATE = 'update',
|
UPDATE = 'update',
|
||||||
DELETE = 'delete',
|
DELETE = 'delete',
|
||||||
|
READ = 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WorkflowCreateRecordActionInput = {
|
export type WorkflowCreateRecordActionInput = {
|
||||||
@ -25,7 +31,16 @@ export type WorkflowDeleteRecordActionInput = {
|
|||||||
objectRecordId: string;
|
objectRecordId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type WorkflowReadRecordActionInput = {
|
||||||
|
type: WorkflowRecordCRUDType.READ;
|
||||||
|
objectName: string;
|
||||||
|
filter?: Partial<ObjectRecordFilter>;
|
||||||
|
orderBy?: Partial<ObjectRecordOrderBy>;
|
||||||
|
limit?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type WorkflowRecordCRUDActionInput =
|
export type WorkflowRecordCRUDActionInput =
|
||||||
| WorkflowCreateRecordActionInput
|
| WorkflowCreateRecordActionInput
|
||||||
| WorkflowUpdateRecordActionInput
|
| WorkflowUpdateRecordActionInput
|
||||||
| WorkflowDeleteRecordActionInput;
|
| WorkflowDeleteRecordActionInput
|
||||||
|
| WorkflowReadRecordActionInput;
|
||||||
|
|||||||
Reference in New Issue
Block a user