[SSE] Add backend for SSE subscriptions (#17022)
- moved a few gql types to twenty shared to re-use in server - added a new endpoint, onEventSubscription that expect a streamId to create a connection - two new endpoints to store queries in Redis - updated the existing batch channel to directly use object record type
This commit is contained in:
@@ -25,6 +25,12 @@ export type ActivateWorkspaceInput = {
|
||||
displayName?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type AddQuerySubscriptionInput = {
|
||||
eventStreamId: Scalars['String'];
|
||||
operationSignature: Scalars['JSON'];
|
||||
queryId: Scalars['String'];
|
||||
};
|
||||
|
||||
export type AdminPanelHealthServiceData = {
|
||||
__typename?: 'AdminPanelHealthServiceData';
|
||||
description: Scalars['String'];
|
||||
@@ -1311,6 +1317,18 @@ export enum EmailingDomainStatus {
|
||||
VERIFIED = 'VERIFIED'
|
||||
}
|
||||
|
||||
export type EventSubscription = {
|
||||
__typename?: 'EventSubscription';
|
||||
eventStreamId: Scalars['String'];
|
||||
eventWithQueryIdsList: Array<EventWithQueryIds>;
|
||||
};
|
||||
|
||||
export type EventWithQueryIds = {
|
||||
__typename?: 'EventWithQueryIds';
|
||||
event: ObjectRecordEvent;
|
||||
queryIds: Array<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ExecuteServerlessFunctionInput = {
|
||||
/** Id of the serverless function to execute */
|
||||
id: Scalars['UUID'];
|
||||
@@ -1799,6 +1817,7 @@ export type Mutation = {
|
||||
activateSkill: Skill;
|
||||
activateWorkflowVersion: Scalars['Boolean'];
|
||||
activateWorkspace: Workspace;
|
||||
addQueryToEventStream: Scalars['Boolean'];
|
||||
assignRoleToAgent: Scalars['Boolean'];
|
||||
assignRoleToApiKey: Scalars['Boolean'];
|
||||
authorizeApp: AuthorizeAppOutput;
|
||||
@@ -1914,6 +1933,7 @@ export type Mutation = {
|
||||
initiateOTPProvisioning: InitiateTwoFactorAuthenticationProvisioningOutput;
|
||||
initiateOTPProvisioningForAuthenticatedUser: InitiateTwoFactorAuthenticationProvisioningOutput;
|
||||
publishServerlessFunction: ServerlessFunction;
|
||||
removeQueryFromEventStream: Scalars['Boolean'];
|
||||
removeRoleFromAgent: Scalars['Boolean'];
|
||||
renewToken: AuthTokens;
|
||||
resendEmailVerificationToken: ResendEmailVerificationTokenOutput;
|
||||
@@ -2008,6 +2028,11 @@ export type MutationActivateWorkspaceArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationAddQueryToEventStreamArgs = {
|
||||
input: AddQuerySubscriptionInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationAssignRoleToAgentArgs = {
|
||||
agentId: Scalars['UUID'];
|
||||
roleId: Scalars['UUID'];
|
||||
@@ -2550,6 +2575,11 @@ export type MutationPublishServerlessFunctionArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationRemoveQueryFromEventStreamArgs = {
|
||||
input: RemoveQueryFromEventStreamInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationRemoveRoleFromAgentArgs = {
|
||||
agentId: Scalars['UUID'];
|
||||
};
|
||||
@@ -3062,6 +3092,23 @@ export type ObjectPermissionInput = {
|
||||
objectMetadataId: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type ObjectRecordEvent = {
|
||||
__typename?: 'ObjectRecordEvent';
|
||||
objectNameSingular: Scalars['String'];
|
||||
properties: ObjectRecordEventProperties;
|
||||
recordId: Scalars['String'];
|
||||
userId?: Maybe<Scalars['String']>;
|
||||
workspaceMemberId?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ObjectRecordEventProperties = {
|
||||
__typename?: 'ObjectRecordEventProperties';
|
||||
after?: Maybe<Scalars['JSON']>;
|
||||
before?: Maybe<Scalars['JSON']>;
|
||||
diff?: Maybe<Scalars['JSON']>;
|
||||
updatedFields?: Maybe<Array<Scalars['String']>>;
|
||||
};
|
||||
|
||||
export type ObjectRecordFilterInput = {
|
||||
and?: InputMaybe<Array<ObjectRecordFilterInput>>;
|
||||
createdAt?: InputMaybe<DateTimeFilter>;
|
||||
@@ -3798,6 +3845,11 @@ export enum RelationType {
|
||||
ONE_TO_MANY = 'ONE_TO_MANY'
|
||||
}
|
||||
|
||||
export type RemoveQueryFromEventStreamInput = {
|
||||
eventStreamId: Scalars['String'];
|
||||
queryId: Scalars['String'];
|
||||
};
|
||||
|
||||
export type ResendEmailVerificationTokenOutput = {
|
||||
__typename?: 'ResendEmailVerificationTokenOutput';
|
||||
success: Scalars['Boolean'];
|
||||
@@ -4136,6 +4188,7 @@ export type SubmitFormStepInput = {
|
||||
export type Subscription = {
|
||||
__typename?: 'Subscription';
|
||||
onDbEvent: OnDbEvent;
|
||||
onEventSubscription?: Maybe<EventSubscription>;
|
||||
onSubscriptionMatch?: Maybe<SubscriptionMatches>;
|
||||
serverlessFunctionLogs: ServerlessFunctionLogs;
|
||||
};
|
||||
@@ -4146,6 +4199,11 @@ export type SubscriptionOnDbEventArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type SubscriptionOnEventSubscriptionArgs = {
|
||||
eventStreamId: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type SubscriptionOnSubscriptionMatchArgs = {
|
||||
subscriptions: Array<SubscriptionInput>;
|
||||
};
|
||||
|
||||
@@ -25,6 +25,12 @@ export type ActivateWorkspaceInput = {
|
||||
displayName?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type AddQuerySubscriptionInput = {
|
||||
eventStreamId: Scalars['String'];
|
||||
operationSignature: Scalars['JSON'];
|
||||
queryId: Scalars['String'];
|
||||
};
|
||||
|
||||
export type AdminPanelHealthServiceData = {
|
||||
__typename?: 'AdminPanelHealthServiceData';
|
||||
description: Scalars['String'];
|
||||
@@ -1294,6 +1300,18 @@ export enum EmailingDomainStatus {
|
||||
VERIFIED = 'VERIFIED'
|
||||
}
|
||||
|
||||
export type EventSubscription = {
|
||||
__typename?: 'EventSubscription';
|
||||
eventStreamId: Scalars['String'];
|
||||
eventWithQueryIdsList: Array<EventWithQueryIds>;
|
||||
};
|
||||
|
||||
export type EventWithQueryIds = {
|
||||
__typename?: 'EventWithQueryIds';
|
||||
event: ObjectRecordEvent;
|
||||
queryIds: Array<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ExecuteServerlessFunctionInput = {
|
||||
/** Id of the serverless function to execute */
|
||||
id: Scalars['UUID'];
|
||||
@@ -1781,6 +1799,7 @@ export type Mutation = {
|
||||
__typename?: 'Mutation';
|
||||
activateWorkflowVersion: Scalars['Boolean'];
|
||||
activateWorkspace: Workspace;
|
||||
addQueryToEventStream: Scalars['Boolean'];
|
||||
assignRoleToAgent: Scalars['Boolean'];
|
||||
assignRoleToApiKey: Scalars['Boolean'];
|
||||
authorizeApp: AuthorizeAppOutput;
|
||||
@@ -1891,6 +1910,7 @@ export type Mutation = {
|
||||
initiateOTPProvisioning: InitiateTwoFactorAuthenticationProvisioningOutput;
|
||||
initiateOTPProvisioningForAuthenticatedUser: InitiateTwoFactorAuthenticationProvisioningOutput;
|
||||
publishServerlessFunction: ServerlessFunction;
|
||||
removeQueryFromEventStream: Scalars['Boolean'];
|
||||
removeRoleFromAgent: Scalars['Boolean'];
|
||||
renewToken: AuthTokens;
|
||||
resendEmailVerificationToken: ResendEmailVerificationTokenOutput;
|
||||
@@ -1978,6 +1998,11 @@ export type MutationActivateWorkspaceArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationAddQueryToEventStreamArgs = {
|
||||
input: AddQuerySubscriptionInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationAssignRoleToAgentArgs = {
|
||||
agentId: Scalars['UUID'];
|
||||
roleId: Scalars['UUID'];
|
||||
@@ -2495,6 +2520,11 @@ export type MutationPublishServerlessFunctionArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationRemoveQueryFromEventStreamArgs = {
|
||||
input: RemoveQueryFromEventStreamInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationRemoveRoleFromAgentArgs = {
|
||||
agentId: Scalars['UUID'];
|
||||
};
|
||||
@@ -2996,6 +3026,23 @@ export type ObjectPermissionInput = {
|
||||
objectMetadataId: Scalars['UUID'];
|
||||
};
|
||||
|
||||
export type ObjectRecordEvent = {
|
||||
__typename?: 'ObjectRecordEvent';
|
||||
objectNameSingular: Scalars['String'];
|
||||
properties: ObjectRecordEventProperties;
|
||||
recordId: Scalars['String'];
|
||||
userId?: Maybe<Scalars['String']>;
|
||||
workspaceMemberId?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ObjectRecordEventProperties = {
|
||||
__typename?: 'ObjectRecordEventProperties';
|
||||
after?: Maybe<Scalars['JSON']>;
|
||||
before?: Maybe<Scalars['JSON']>;
|
||||
diff?: Maybe<Scalars['JSON']>;
|
||||
updatedFields?: Maybe<Array<Scalars['String']>>;
|
||||
};
|
||||
|
||||
export type ObjectRecordFilterInput = {
|
||||
and?: InputMaybe<Array<ObjectRecordFilterInput>>;
|
||||
createdAt?: InputMaybe<DateTimeFilter>;
|
||||
@@ -3673,6 +3720,11 @@ export enum RelationType {
|
||||
ONE_TO_MANY = 'ONE_TO_MANY'
|
||||
}
|
||||
|
||||
export type RemoveQueryFromEventStreamInput = {
|
||||
eventStreamId: Scalars['String'];
|
||||
queryId: Scalars['String'];
|
||||
};
|
||||
|
||||
export type ResendEmailVerificationTokenOutput = {
|
||||
__typename?: 'ResendEmailVerificationTokenOutput';
|
||||
success: Scalars['Boolean'];
|
||||
@@ -4011,6 +4063,7 @@ export type SubmitFormStepInput = {
|
||||
export type Subscription = {
|
||||
__typename?: 'Subscription';
|
||||
onDbEvent: OnDbEvent;
|
||||
onEventSubscription?: Maybe<EventSubscription>;
|
||||
onSubscriptionMatch?: Maybe<SubscriptionMatches>;
|
||||
serverlessFunctionLogs: ServerlessFunctionLogs;
|
||||
};
|
||||
@@ -4021,6 +4074,11 @@ export type SubscriptionOnDbEventArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type SubscriptionOnEventSubscriptionArgs = {
|
||||
eventStreamId: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type SubscriptionOnSubscriptionMatchArgs = {
|
||||
subscriptions: Array<SubscriptionInput>;
|
||||
};
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { type RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature';
|
||||
import { type RecordGqlOperationSignature } from 'twenty-shared/types';
|
||||
|
||||
export const FIND_ONE_CALENDAR_EVENT_OPERATION_SIGNATURE: RecordGqlOperationSignature =
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ import { type Task } from '@/activities/types/Task';
|
||||
import { type TaskTarget } from '@/activities/types/TaskTarget';
|
||||
import { type CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection';
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import { type RecordGqlOperationOrderBy } from 'twenty-shared/types';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import { type TaskTarget } from '@/activities/types/TaskTarget';
|
||||
import { getActivityTargetsFilter } from '@/activities/utils/getActivityTargetsFilter';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { type CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import { type RecordGqlOperationOrderBy } from 'twenty-shared/types';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
|
||||
export const useActivityTargetsForTargetableObjects = ({
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useActivities } from '@/activities/hooks/useActivities';
|
||||
import { currentNotesQueryVariablesState } from '@/activities/notes/states/currentNotesQueryVariablesState';
|
||||
import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timeline-activities/constants/FindManyTimelineActivitiesOrderBy';
|
||||
import { type Note } from '@/activities/types/Note';
|
||||
import { type RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables';
|
||||
import { type RecordGqlOperationVariables } from 'twenty-shared/types';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { type RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables';
|
||||
import { type RecordGqlOperationVariables } from 'twenty-shared/types';
|
||||
|
||||
export const currentNotesQueryVariablesState =
|
||||
atom<RecordGqlOperationVariables | null>({
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import { type RecordGqlOperationOrderBy } from 'twenty-shared/types';
|
||||
|
||||
export const FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY: RecordGqlOperationOrderBy =
|
||||
[
|
||||
|
||||
+5
-2
@@ -3,8 +3,11 @@ import { type ReadFieldFunction } from '@apollo/client/cache/core/types/common';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
import { type RecordGqlRefEdge } from '@/object-record/cache/types/RecordGqlRefEdge';
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import { type OrderBy } from '@/types/OrderBy';
|
||||
|
||||
import {
|
||||
type OrderBy,
|
||||
type RecordGqlOperationOrderBy,
|
||||
} from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { sortAsc, sortDesc, sortNullsFirst, sortNullsLast } from '~/utils/sort';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables';
|
||||
import { type RecordGqlOperationVariables } from 'twenty-shared/types';
|
||||
|
||||
export type CachedObjectRecordQueryVariables = Omit<
|
||||
RecordGqlOperationVariables,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
|
||||
import { getOrderByFieldForObjectMetadataItem } from '@/object-metadata/utils/getObjectOrderByField';
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import { type OrderBy } from '@/types/OrderBy';
|
||||
import {
|
||||
type OrderBy,
|
||||
type RecordGqlOperationOrderBy,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
export const useGetObjectOrderByField = ({
|
||||
objectNameSingular,
|
||||
|
||||
+4
-2
@@ -1,10 +1,12 @@
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
import { generateDepthRecordGqlFieldsFromObject } from '@/object-record/graphql/record-gql-fields/utils/generateDepthRecordGqlFieldsFromObject';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { getCreateOneRecordMutationResponseField } from '@/object-record/utils/getCreateOneRecordMutationResponseField';
|
||||
import { gql } from '@apollo/client';
|
||||
import { type ObjectPermissions } from 'twenty-shared/types';
|
||||
import {
|
||||
type ObjectPermissions,
|
||||
type RecordGqlOperationGqlRecordFields,
|
||||
} from 'twenty-shared/types';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
export const generateCreateOneRecordMutation = ({
|
||||
|
||||
+4
-2
@@ -1,10 +1,12 @@
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
import { generateDepthRecordGqlFieldsFromObject } from '@/object-record/graphql/record-gql-fields/utils/generateDepthRecordGqlFieldsFromObject';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { getUpdateOneRecordMutationResponseField } from '@/object-record/utils/getUpdateOneRecordMutationResponseField';
|
||||
import { gql } from '@apollo/client';
|
||||
import { type ObjectPermissions } from 'twenty-shared/types';
|
||||
import {
|
||||
type ObjectPermissions,
|
||||
type RecordGqlOperationGqlRecordFields,
|
||||
} from 'twenty-shared/types';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
export const generateUpdateOneRecordMutation = ({
|
||||
|
||||
@@ -2,8 +2,10 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI
|
||||
|
||||
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
|
||||
import { getOrderByForFieldMetadataType } from '@/object-metadata/utils/getOrderByForFieldMetadataType';
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import { type OrderBy } from '@/types/OrderBy';
|
||||
import {
|
||||
type OrderBy,
|
||||
type RecordGqlOperationOrderBy,
|
||||
} from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const getOrderByFieldForObjectMetadataItem = (
|
||||
|
||||
+4
-2
@@ -2,13 +2,15 @@ import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataIte
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
|
||||
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import {
|
||||
type FieldEmailsValue,
|
||||
type FieldLinksValue,
|
||||
type FieldPhonesValue,
|
||||
} from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { type OrderBy } from '@/types/OrderBy';
|
||||
import {
|
||||
type OrderBy,
|
||||
type RecordGqlOperationOrderBy,
|
||||
} from 'twenty-shared/types';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const getOrderByForFieldMetadataType = (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -3,7 +3,7 @@ import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadat
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection';
|
||||
import { type RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult';
|
||||
import { type RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables';
|
||||
import { type RecordGqlOperationVariables } from 'twenty-shared/types';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { generateFindManyRecordsQuery } from '@/object-record/utils/generateFindManyRecordsQuery';
|
||||
|
||||
Vendored
+1
-1
@@ -4,7 +4,7 @@ import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { getRecordConnectionFromRecords } from '@/object-record/cache/utils/getRecordConnectionFromRecords';
|
||||
import { type RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables';
|
||||
import { type RecordGqlOperationVariables } from 'twenty-shared/types';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { generateFindManyRecordsQuery } from '@/object-record/utils/generateFindManyRecordsQuery';
|
||||
|
||||
Vendored
+1
-1
@@ -3,7 +3,7 @@ import { getConnectionTypename } from '@/object-record/cache/utils/getConnection
|
||||
import { getEmptyPageInfo } from '@/object-record/cache/utils/getEmptyPageInfo';
|
||||
import { getRecordEdgeFromRecord } from '@/object-record/cache/utils/getRecordEdgeFromRecord';
|
||||
import { type RecordGqlConnectionEdgesRequired } from '@/object-record/graphql/types/RecordGqlConnectionEdgesRequired';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
export const getRecordConnectionFromRecords = <T extends ObjectRecord>({
|
||||
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
import { type RecordGqlFieldsDeprecated } from '@/object-record/graphql/types/RecordGqlFieldsDeprecated';
|
||||
|
||||
export type RecordGqlOperationGqlRecordFields = RecordGqlFieldsDeprecated;
|
||||
+4
-2
@@ -1,5 +1,7 @@
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import { type RecordGqlOperationFilter } from 'twenty-shared/types';
|
||||
import {
|
||||
type RecordGqlOperationFilter,
|
||||
type RecordGqlOperationOrderBy,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
export type RecordGqlOperationGroupByVariables = {
|
||||
groupBy: Record<string, any>[] | Record<string, any>;
|
||||
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables';
|
||||
|
||||
export type RecordGqlOperationSignature = {
|
||||
objectNameSingular: string;
|
||||
variables: RecordGqlOperationVariables;
|
||||
fields?: RecordGqlOperationGqlRecordFields;
|
||||
};
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature';
|
||||
import { type RecordGqlOperationSignature } from 'twenty-shared/types';
|
||||
|
||||
export type RecordGqlOperationSignatureFactory<FactoryParams extends object> = (
|
||||
factoryParams: FactoryParams,
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import { type QueryCursorDirection } from '@/object-record/utils/generateFindManyRecordsQuery';
|
||||
import { type RecordGqlOperationFilter } from 'twenty-shared/types';
|
||||
|
||||
export type RecordGqlOperationVariables = {
|
||||
filter?: RecordGqlOperationFilter;
|
||||
orderBy?: RecordGqlOperationOrderBy;
|
||||
limit?: number;
|
||||
cursorFilter?: {
|
||||
cursor: string;
|
||||
cursorDirection: QueryCursorDirection;
|
||||
};
|
||||
};
|
||||
@@ -12,7 +12,7 @@ import { deleteRecordFromCache } from '@/object-record/cache/utils/deleteRecordF
|
||||
import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename';
|
||||
import { getRecordNodeFromRecord } from '@/object-record/cache/utils/getRecordNodeFromRecord';
|
||||
import { useGenerateDepthRecordGqlFieldsFromObject } from '@/object-record/graphql/record-gql-fields/hooks/useGenerateDepthRecordGqlFieldsFromObject';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types';
|
||||
import { useCreateManyRecordsMutation } from '@/object-record/hooks/useCreateManyRecordsMutation';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
import { EMPTY_MUTATION } from '@/object-record/constants/EmptyMutation';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { getCreateManyRecordsMutationResponseField } from '@/object-record/utils/getCreateManyRecordsMutationResponseField';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
@@ -13,7 +13,7 @@ import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename
|
||||
import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode';
|
||||
import { getRecordNodeFromRecord } from '@/object-record/cache/utils/getRecordNodeFromRecord';
|
||||
import { useGenerateDepthRecordGqlFieldsFromObject } from '@/object-record/graphql/record-gql-fields/hooks/useGenerateDepthRecordGqlFieldsFromObject';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types';
|
||||
import { useCreateOneRecordMutation } from '@/object-record/hooks/useCreateOneRecordMutation';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { generateCreateOneRecordMutation } from '@/object-metadata/utils/generateCreateOneRecordMutation';
|
||||
import { EMPTY_MUTATION } from '@/object-record/constants/EmptyMutation';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
|
||||
+5
-3
@@ -17,18 +17,20 @@ import { isAggregationEnabled } from '@/object-metadata/utils/isAggregationEnabl
|
||||
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection';
|
||||
import { type RecordGqlEdge } from '@/object-record/graphql/types/RecordGqlEdge';
|
||||
import { type RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables';
|
||||
import { useHandleFindManyRecordsError } from '@/object-record/hooks/useHandleFindManyRecordsError';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { type OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted';
|
||||
import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor';
|
||||
import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier';
|
||||
import {
|
||||
type RecordGqlOperationGqlRecordFields,
|
||||
type RecordGqlOperationVariables,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
import { cursorFamilyState } from '@/object-record/states/cursorFamilyState';
|
||||
import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState';
|
||||
import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export type UseFindManyRecordsParams<T> = ObjectMetadataItemIdentifier &
|
||||
RecordGqlOperationVariables & {
|
||||
|
||||
@@ -4,8 +4,6 @@ import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { type ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
|
||||
import { type RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables';
|
||||
import { useFetchMoreRecordsWithPagination } from '@/object-record/hooks/useFetchMoreRecordsWithPagination';
|
||||
import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery';
|
||||
import { useHandleFindManyRecordsCompleted } from '@/object-record/hooks/useHandleFindManyRecordsCompleted';
|
||||
@@ -14,9 +12,13 @@ import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPe
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { type OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted';
|
||||
import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier';
|
||||
import {
|
||||
type RecordGqlOperationFilter,
|
||||
type RecordGqlOperationGqlRecordFields,
|
||||
type RecordGqlOperationVariables,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
import { QUERY_DEFAULT_LIMIT_RECORDS } from 'twenty-shared/constants';
|
||||
import { type RecordGqlOperationFilter } from 'twenty-shared/types';
|
||||
|
||||
export type UseFindManyRecordsParams<T> = ObjectMetadataItemIdentifier &
|
||||
RecordGqlOperationVariables & {
|
||||
|
||||
@@ -2,12 +2,12 @@ import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { generateFindManyRecordsQuery } from '@/object-record/utils/generateFindManyRecordsQuery';
|
||||
import {
|
||||
generateFindManyRecordsQuery,
|
||||
type QueryCursorDirection,
|
||||
} from '@/object-record/utils/generateFindManyRecordsQuery';
|
||||
type RecordGqlOperationGqlRecordFields,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
export const useFindManyRecordsQuery = ({
|
||||
objectNameSingular,
|
||||
|
||||
@@ -7,7 +7,7 @@ import { type ObjectMetadataItemIdentifier } from '@/object-metadata/types/Objec
|
||||
import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode';
|
||||
import { useGenerateDepthRecordGqlFieldsFromObject } from '@/object-record/graphql/record-gql-fields/hooks/useGenerateDepthRecordGqlFieldsFromObject';
|
||||
import { type RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types';
|
||||
import { useFindOneRecordQuery } from '@/object-record/hooks/useFindOneRecordQuery';
|
||||
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useRecoilValue } from 'recoil';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { generateGroupByRecordsQuery } from '@/object-record/utils/generateGroupByRecordsQuery';
|
||||
|
||||
|
||||
+5
-3
@@ -16,18 +16,20 @@ import { isAggregationEnabled } from '@/object-metadata/utils/isAggregationEnabl
|
||||
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection';
|
||||
import { type RecordGqlEdge } from '@/object-record/graphql/types/RecordGqlEdge';
|
||||
import { type RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables';
|
||||
import { useHandleFindManyRecordsError } from '@/object-record/hooks/useHandleFindManyRecordsError';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { type OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted';
|
||||
import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor';
|
||||
import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier';
|
||||
import {
|
||||
type RecordGqlOperationGqlRecordFields,
|
||||
type RecordGqlOperationVariables,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/object-record/constants/DefaultSearchRequestLimit';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
import { cursorFamilyState } from '@/object-record/states/cursorFamilyState';
|
||||
import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export type UseFindManyRecordsParams<T> = ObjectMetadataItemIdentifier &
|
||||
RecordGqlOperationVariables & {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient
|
||||
import { type ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
|
||||
import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode';
|
||||
import { useGenerateDepthRecordGqlFieldsFromObject } from '@/object-record/graphql/record-gql-fields/hooks/useGenerateDepthRecordGqlFieldsFromObject';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types';
|
||||
import { useFindOneRecordQuery } from '@/object-record/hooks/useFindOneRecordQuery';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useCallback, useState } from 'react';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useGenerateDepthRecordGqlFieldsFromObject } from '@/object-record/graphql/record-gql-fields/hooks/useGenerateDepthRecordGqlFieldsFromObject';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types';
|
||||
import { useFindDuplicateRecordsQuery } from '@/object-record/hooks/useFindDuplicatesRecordsQuery';
|
||||
import { useFindOneRecordQuery } from '@/object-record/hooks/useFindOneRecordQuery';
|
||||
import { useMergeManyRecordsMutation } from '@/object-record/hooks/useMergeManyRecordsMutation';
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
import { EMPTY_MUTATION } from '@/object-record/constants/EmptyMutation';
|
||||
import { useGenerateDepthRecordGqlFieldsFromObject } from '@/object-record/graphql/record-gql-fields/hooks/useGenerateDepthRecordGqlFieldsFromObject';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { getMergeManyRecordsMutationResponseField } from '@/object-record/utils/getMergeManyRecordsMutationResponseField';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { generateUpdateOneRecordMutation } from '@/object-metadata/utils/generateUpdateOneRecordMutation';
|
||||
import { EMPTY_MUTATION } from '@/object-record/constants/EmptyMutation';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { type RecordGqlFields } from '@/object-record/graphql/record-gql-fields/types/RecordGqlFields';
|
||||
import { type RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature';
|
||||
import { type RecordGqlOperationSignature } from 'twenty-shared/types';
|
||||
import { useCombinedFindManyRecords } from '@/object-record/multiple-objects/hooks/useCombinedFindManyRecords';
|
||||
import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery';
|
||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { useQuery } from '@apollo/client';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection';
|
||||
import { EMPTY_QUERY } from '@/object-record/constants/EmptyQuery';
|
||||
import { type RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature';
|
||||
import { type RecordGqlOperationSignature } from 'twenty-shared/types';
|
||||
import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery';
|
||||
import { type CombinedFindManyRecordsQueryResult } from '@/object-record/multiple-objects/types/CombinedFindManyRecordsQueryResult';
|
||||
import { generateCombinedFindManyRecordsQueryVariables } from '@/object-record/multiple-objects/utils/generateCombinedFindManyRecordsQueryVariables';
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { useQuery } from '@apollo/client';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { EMPTY_QUERY } from '@/object-record/constants/EmptyQuery';
|
||||
import { type RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature';
|
||||
import { type RecordGqlOperationSignature } from 'twenty-shared/types';
|
||||
import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery';
|
||||
import { type CombinedFindManyRecordsQueryResult } from '@/object-record/multiple-objects/types/CombinedFindManyRecordsQueryResult';
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import { useRecoilValue } from 'recoil';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { getObjectPermissionsForObject } from '@/object-metadata/utils/getObjectPermissionsForObject';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
import { type RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature';
|
||||
import { type RecordGqlOperationSignature } from 'twenty-shared/types';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { getCombinedFindManyRecordsQueryFilteringPart } from '@/object-record/multiple-objects/utils/getCombinedFindManyRecordsQueryFilteringPart';
|
||||
import isEmpty from 'lodash.isempty';
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObje
|
||||
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection';
|
||||
import { EMPTY_QUERY } from '@/object-record/constants/EmptyQuery';
|
||||
import { generateDepthRecordGqlFieldsFromObject } from '@/object-record/graphql/record-gql-fields/utils/generateDepthRecordGqlFieldsFromObject';
|
||||
import { type RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature';
|
||||
import { type RecordGqlOperationSignature } from 'twenty-shared/types';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { type CombinedFindManyRecordsQueryResult } from '@/object-record/multiple-objects/types/CombinedFindManyRecordsQueryResult';
|
||||
import { generateCombinedFindManyRecordsQueryVariables } from '@/object-record/multiple-objects/utils/generateCombinedFindManyRecordsQueryVariables';
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { type RecordGqlFields } from '@/object-record/graphql/record-gql-fields/types/RecordGqlFields';
|
||||
import { type RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature';
|
||||
import { type RecordGqlOperationSignature } from 'twenty-shared/types';
|
||||
import { generateCombinedFindManyRecordsQueryVariables } from '@/object-record/multiple-objects/utils/generateCombinedFindManyRecordsQueryVariables';
|
||||
|
||||
describe('useCombinedFindManyRecordsQueryVariables', () => {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type RecordGqlOperationSignature } from '@/object-record/graphql/types/RecordGqlOperationSignature';
|
||||
import { type RecordGqlOperationSignature } from 'twenty-shared/types';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { capitalize, isDefined, isNonEmptyArray } from 'twenty-shared/utils';
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import { type RecordGqlOperationOrderBy } from 'twenty-shared/types';
|
||||
import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy';
|
||||
import { type RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||
import { type EachTestingContext } from 'twenty-shared/testing';
|
||||
|
||||
+4
-2
@@ -1,6 +1,9 @@
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import {
|
||||
type OrderBy,
|
||||
type RecordGqlOperationOrderBy,
|
||||
} from 'twenty-shared/types';
|
||||
import { mapArrayToObject } from '~/utils/array/mapArrayToObject';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
@@ -10,7 +13,6 @@ import {
|
||||
} from '@/object-metadata/utils/getOrderByForFieldMetadataType';
|
||||
import { hasObjectMetadataItemPositionField } from '@/object-metadata/utils/hasObjectMetadataItemPositionField';
|
||||
import { type RecordSort } from '@/object-record/record-sort/types/RecordSort';
|
||||
import { type OrderBy } from '@/types/OrderBy';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FieldMetadataType, ViewSortDirection } from '~/generated/graphql';
|
||||
|
||||
|
||||
+4
-2
@@ -2,9 +2,11 @@ import gql from 'graphql-tag';
|
||||
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { getGroupByQueryResultGqlFieldName } from '@/page-layout/utils/getGroupByQueryResultGqlFieldName';
|
||||
import { type ObjectPermissions } from 'twenty-shared/types';
|
||||
import {
|
||||
type ObjectPermissions,
|
||||
type RecordGqlOperationGqlRecordFields,
|
||||
} from 'twenty-shared/types';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
export const generateGroupsRecordsGroupByQuery = ({
|
||||
|
||||
+4
-2
@@ -1,7 +1,6 @@
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { hasObjectMetadataItemPositionField } from '@/object-metadata/utils/hasObjectMetadataItemPositionField';
|
||||
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection';
|
||||
import { type RecordGqlOperationOrderBy } from '@/object-record/graphql/types/RecordGqlOperationOrderBy';
|
||||
import { useGroupByRecordsQuery } from '@/object-record/hooks/useGroupByRecordsQuery';
|
||||
import { useRecordCalendarContextOrThrow } from '@/object-record/record-calendar/contexts/RecordCalendarContext';
|
||||
import { useRecordCalendarQueryDateRangeFilter } from '@/object-record/record-calendar/month/hooks/useRecordCalendarQueryDateRangeFilter';
|
||||
@@ -14,7 +13,10 @@ import { useQuery } from '@apollo/client';
|
||||
import { useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { type Temporal } from 'temporal-polyfill';
|
||||
import { ObjectRecordGroupByDateGranularity } from 'twenty-shared/types';
|
||||
import {
|
||||
ObjectRecordGroupByDateGranularity,
|
||||
type RecordGqlOperationOrderBy,
|
||||
} from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useRecordCalendarGroupByRecords = (
|
||||
|
||||
@@ -9,7 +9,7 @@ import { type SelectableItem } from '@/object-record/select/types/SelectableItem
|
||||
import { getObjectFilterFields } from '@/object-record/select/utils/getObjectFilterFields';
|
||||
import { makeAndFilterVariables } from '@/object-record/utils/makeAndFilterVariables';
|
||||
import { makeOrFilterVariables } from '@/object-record/utils/makeOrFilterVariables';
|
||||
import { type OrderBy } from '@/types/OrderBy';
|
||||
import { type OrderBy } from 'twenty-shared/types';
|
||||
|
||||
export const useRecordsForSelect = ({
|
||||
searchFilterText,
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { type WatchQueryFetchPolicy } from '@apollo/client';
|
||||
|
||||
import { type ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables';
|
||||
import { type OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted';
|
||||
import {
|
||||
type RecordGqlOperationGqlRecordFields,
|
||||
type RecordGqlOperationVariables,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
export type UseFindManyRecordsParams<T> = ObjectMetadataItemIdentifier &
|
||||
RecordGqlOperationVariables & {
|
||||
|
||||
+5
-4
@@ -2,12 +2,13 @@ import gql from 'graphql-tag';
|
||||
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type ObjectPermissions } from 'twenty-shared/types';
|
||||
import {
|
||||
type ObjectPermissions,
|
||||
type QueryCursorDirection,
|
||||
type RecordGqlOperationGqlRecordFields,
|
||||
} from 'twenty-shared/types';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
export type QueryCursorDirection = 'before' | 'after';
|
||||
|
||||
export const generateFindManyRecordsQuery = ({
|
||||
objectMetadataItem,
|
||||
objectMetadataItems,
|
||||
|
||||
+4
-2
@@ -2,8 +2,10 @@ import { gql } from '@apollo/client';
|
||||
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
import { type RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields';
|
||||
import { type ObjectPermissions } from 'twenty-shared/types';
|
||||
import {
|
||||
type ObjectPermissions,
|
||||
type RecordGqlOperationGqlRecordFields,
|
||||
} from 'twenty-shared/types';
|
||||
import { capitalize } from 'twenty-shared/utils';
|
||||
|
||||
export const generateGroupByRecordsQuery = ({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables';
|
||||
import { type RecordGqlOperationVariables } from 'twenty-shared/types';
|
||||
|
||||
export const getQueryIdentifier = ({
|
||||
objectNameSingular,
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import {
|
||||
} from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow';
|
||||
import { useObjectPermissionDerivedStates } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useObjectPermissionDerivedStates';
|
||||
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
|
||||
import { type OrderBy } from '@/types/OrderBy';
|
||||
import { type OrderBy } from 'twenty-shared/types';
|
||||
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
|
||||
import { SortableTableHeader } from '@/ui/layout/table/components/SortableTableHeader';
|
||||
import { Table } from '@/ui/layout/table/components/Table';
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ import {
|
||||
tableDataSortedBylabelInDescendingOrder,
|
||||
} from '~/testing/mock-data/tableData';
|
||||
|
||||
import { type OrderBy } from '@/types/OrderBy';
|
||||
import { type OrderBy } from 'twenty-shared/types';
|
||||
import { sortedFieldByTableFamilyState } from '@/ui/layout/table/states/sortedFieldByTableFamilyState';
|
||||
|
||||
import { useSortedArray } from '@/ui/layout/table/hooks/useSortedArray';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type OrderBy } from '@/types/OrderBy';
|
||||
import { type OrderBy } from 'twenty-shared/types';
|
||||
|
||||
export type TableSortValue = {
|
||||
fieldName: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type OrderBy } from '@/types/OrderBy';
|
||||
import { type OrderBy } from 'twenty-shared/types';
|
||||
import { assertUnreachable } from 'twenty-shared/utils';
|
||||
|
||||
export const turnOrderByIntoSort = (orderBy: OrderBy): 'asc' | 'desc' => {
|
||||
|
||||
+1
@@ -5,4 +5,5 @@ export enum CacheStorageNamespace {
|
||||
EngineWorkspace = 'engine:workspace',
|
||||
EngineLock = 'engine:lock',
|
||||
EngineHealth = 'engine:health',
|
||||
EngineSubscriptions = 'engine:subscriptions',
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
|
||||
import GraphQLJSON from 'graphql-type-json';
|
||||
import { type RecordGqlOperationSignature } from 'twenty-shared/types';
|
||||
|
||||
@InputType()
|
||||
export class AddQuerySubscriptionInput {
|
||||
@Field()
|
||||
eventStreamId: string;
|
||||
|
||||
@Field()
|
||||
queryId: string;
|
||||
|
||||
@Field(() => GraphQLJSON)
|
||||
operationSignature: RecordGqlOperationSignature;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { ObjectRecordEventDTO } from './object-record-event.dto';
|
||||
|
||||
@ObjectType('EventWithQueryIds')
|
||||
export class EventWithQueryIdsDTO {
|
||||
@Field(() => [String])
|
||||
queryIds: string[];
|
||||
|
||||
@Field(() => ObjectRecordEventDTO)
|
||||
event: ObjectRecordEventDTO;
|
||||
}
|
||||
|
||||
@ObjectType('EventSubscription')
|
||||
export class EventSubscriptionDTO {
|
||||
@Field(() => String)
|
||||
eventStreamId: string;
|
||||
|
||||
@Field(() => [EventWithQueryIdsDTO])
|
||||
eventWithQueryIdsList: EventWithQueryIdsDTO[];
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import GraphQLJSON from 'graphql-type-json';
|
||||
|
||||
@ObjectType('ObjectRecordEventProperties')
|
||||
export class ObjectRecordEventPropertiesDTO {
|
||||
@Field(() => [String], { nullable: true })
|
||||
updatedFields?: string[];
|
||||
|
||||
@Field(() => GraphQLJSON, { nullable: true })
|
||||
before?: object;
|
||||
|
||||
@Field(() => GraphQLJSON, { nullable: true })
|
||||
after?: object;
|
||||
|
||||
@Field(() => GraphQLJSON, { nullable: true })
|
||||
diff?: object;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { ObjectRecordEventPropertiesDTO } from 'src/engine/subscriptions/dtos/object-record-event-properties.dto';
|
||||
|
||||
@ObjectType('ObjectRecordEvent')
|
||||
export class ObjectRecordEventDTO {
|
||||
@Field(() => String)
|
||||
objectNameSingular: string;
|
||||
|
||||
@Field(() => String)
|
||||
recordId: string;
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
userId?: string;
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
workspaceMemberId?: string;
|
||||
|
||||
@Field(() => ObjectRecordEventPropertiesDTO)
|
||||
properties: ObjectRecordEventPropertiesDTO;
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { Field, InputType } from '@nestjs/graphql';
|
||||
|
||||
@InputType()
|
||||
export class RemoveQueryFromEventStreamInput {
|
||||
@Field()
|
||||
eventStreamId: string;
|
||||
|
||||
@Field()
|
||||
queryId: string;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
export enum SubscriptionChannel {
|
||||
WORKSPACE_EVENT_BATCH_CHANNEL = 'WORKSPACE_EVENT_BATCH_CHANNEL',
|
||||
DATABASE_EVENT_CHANNEL = 'DATABASE_EVENT_CHANNEL',
|
||||
DATABASE_BATCH_EVENTS_CHANNEL = 'DATABASE_BATCH_EVENTS_CHANNEL',
|
||||
SERVERLESS_FUNCTION_LOGS_CHANNEL = 'SERVERLESS_FUNCTION_LOGS_CHANNEL',
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { type ObjectRecordEvent } from 'twenty-shared/database-events';
|
||||
import { type RecordGqlOperationSignature } from 'twenty-shared/types';
|
||||
|
||||
import { WithLock } from 'src/engine/core-modules/cache-lock/with-lock.decorator';
|
||||
import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator';
|
||||
import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service';
|
||||
import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum';
|
||||
|
||||
export type ObjectRecordSubscriptionEvent = ObjectRecordEvent & {
|
||||
objectNameSingular: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class EventStreamService {
|
||||
constructor(
|
||||
@InjectCacheStorage(CacheStorageNamespace.EngineSubscriptions)
|
||||
private readonly cacheStorageService: CacheStorageService,
|
||||
) {}
|
||||
|
||||
private getEventStreamKey(
|
||||
workspaceId: string,
|
||||
eventStreamId: string,
|
||||
): string {
|
||||
return `eventStream:${workspaceId}:${eventStreamId}`;
|
||||
}
|
||||
|
||||
@WithLock('eventStreamId')
|
||||
async addQuery({
|
||||
workspaceId,
|
||||
eventStreamId,
|
||||
queryId,
|
||||
operationSignature,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
eventStreamId: string;
|
||||
queryId: string;
|
||||
operationSignature: RecordGqlOperationSignature;
|
||||
}): Promise<void> {
|
||||
const key = this.getEventStreamKey(workspaceId, eventStreamId);
|
||||
const existing =
|
||||
(await this.cacheStorageService.get<
|
||||
Record<string, RecordGqlOperationSignature>
|
||||
>(key)) || {};
|
||||
|
||||
existing[queryId] = operationSignature;
|
||||
|
||||
await this.cacheStorageService.set(key, existing);
|
||||
}
|
||||
|
||||
@WithLock('eventStreamId')
|
||||
async removeQuery({
|
||||
workspaceId,
|
||||
eventStreamId,
|
||||
queryId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
eventStreamId: string;
|
||||
queryId: string;
|
||||
}): Promise<void> {
|
||||
const key = this.getEventStreamKey(workspaceId, eventStreamId);
|
||||
const existing =
|
||||
await this.cacheStorageService.get<
|
||||
Record<string, RecordGqlOperationSignature>
|
||||
>(key);
|
||||
|
||||
if (existing && existing[queryId]) {
|
||||
delete existing[queryId];
|
||||
await this.cacheStorageService.set(key, existing);
|
||||
}
|
||||
}
|
||||
|
||||
async getQueries(
|
||||
workspaceId: string,
|
||||
eventStreamId: string,
|
||||
): Promise<Map<string, RecordGqlOperationSignature>> {
|
||||
const key = this.getEventStreamKey(workspaceId, eventStreamId);
|
||||
const data =
|
||||
await this.cacheStorageService.get<
|
||||
Record<string, RecordGqlOperationSignature>
|
||||
>(key);
|
||||
|
||||
return new Map(Object.entries(data || {}));
|
||||
}
|
||||
|
||||
async matchQueriesWithEvent(
|
||||
queries: Map<string, RecordGqlOperationSignature>,
|
||||
event: ObjectRecordSubscriptionEvent,
|
||||
): Promise<string[]> {
|
||||
const matchedQueryIds: string[] = [];
|
||||
|
||||
for (const [queryId, operationSignature] of queries.entries()) {
|
||||
if (this.isQueryMatchingEvent(operationSignature, event)) {
|
||||
matchedQueryIds.push(queryId);
|
||||
}
|
||||
}
|
||||
|
||||
return matchedQueryIds;
|
||||
}
|
||||
|
||||
private isQueryMatchingEvent(
|
||||
operationSignature: RecordGqlOperationSignature,
|
||||
event: ObjectRecordSubscriptionEvent,
|
||||
): boolean {
|
||||
// to be improved
|
||||
return operationSignature.objectNameSingular === event.objectNameSingular;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,20 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { CacheLockModule } from 'src/engine/core-modules/cache-lock/cache-lock.module';
|
||||
import { CacheStorageModule } from 'src/engine/core-modules/cache-storage/cache-storage.module';
|
||||
import { RedisClientModule } from 'src/engine/core-modules/redis-client/redis-client.module';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
|
||||
import { EventStreamService } from 'src/engine/subscriptions/event-stream.service';
|
||||
import { SubscriptionService } from 'src/engine/subscriptions/subscription.service';
|
||||
|
||||
@Module({
|
||||
imports: [RedisClientModule, WorkspaceManyOrAllFlatEntityMapsCacheModule],
|
||||
providers: [SubscriptionService],
|
||||
exports: [SubscriptionService],
|
||||
imports: [
|
||||
RedisClientModule,
|
||||
WorkspaceManyOrAllFlatEntityMapsCacheModule,
|
||||
CacheStorageModule,
|
||||
CacheLockModule,
|
||||
],
|
||||
providers: [SubscriptionService, EventStreamService],
|
||||
exports: [SubscriptionService, EventStreamService],
|
||||
})
|
||||
export class SubscriptionsModule {}
|
||||
|
||||
+99
-3
@@ -1,6 +1,7 @@
|
||||
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
|
||||
import { Args, Resolver, Subscription } from '@nestjs/graphql';
|
||||
import { Args, Mutation, Resolver, Subscription } from '@nestjs/graphql';
|
||||
|
||||
import { ObjectRecordEvent } from 'twenty-shared/database-events';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
|
||||
@@ -10,19 +11,28 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
|
||||
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
|
||||
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { AddQuerySubscriptionInput } from 'src/engine/subscriptions/dtos/add-query-subscription.input';
|
||||
import { EventSubscriptionDTO } from 'src/engine/subscriptions/dtos/event-subscription.dto';
|
||||
import { ObjectRecordEventDTO } from 'src/engine/subscriptions/dtos/object-record-event.dto';
|
||||
import { OnDbEventDTO } from 'src/engine/subscriptions/dtos/on-db-event.dto';
|
||||
import { OnDbEventInput } from 'src/engine/subscriptions/dtos/on-db-event.input';
|
||||
import { RemoveQueryFromEventStreamInput } from 'src/engine/subscriptions/dtos/remove-query-subscription.input';
|
||||
import { SubscriptionMatchesDTO } from 'src/engine/subscriptions/dtos/subscription-matches.dto';
|
||||
import { SubscriptionInput } from 'src/engine/subscriptions/dtos/subscription.input';
|
||||
import { SubscriptionChannel } from 'src/engine/subscriptions/enums/subscription-channel.enum';
|
||||
import { EventStreamService } from 'src/engine/subscriptions/event-stream.service';
|
||||
import { SubscriptionService } from 'src/engine/subscriptions/subscription.service';
|
||||
import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event-batch.type';
|
||||
|
||||
@Resolver()
|
||||
@UseGuards(WorkspaceAuthGuard, UserAuthGuard, NoPermissionGuard)
|
||||
@UsePipes(ResolverValidationPipe)
|
||||
@UseFilters(PreventNestToAutoLogGraphqlErrorsFilter)
|
||||
export class WorkspaceEventEmitterResolver {
|
||||
constructor(private readonly subscriptionService: SubscriptionService) {}
|
||||
constructor(
|
||||
private readonly subscriptionService: SubscriptionService,
|
||||
private readonly eventStreamService: EventStreamService,
|
||||
) {}
|
||||
|
||||
@Subscription(() => OnDbEventDTO, {
|
||||
filter: (
|
||||
@@ -104,8 +114,94 @@ export class WorkspaceEventEmitterResolver {
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
return this.subscriptionService.subscribe({
|
||||
channel: SubscriptionChannel.DATABASE_BATCH_EVENTS_CHANNEL,
|
||||
channel: SubscriptionChannel.WORKSPACE_EVENT_BATCH_CHANNEL,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Subscription(() => EventSubscriptionDTO, {
|
||||
nullable: true,
|
||||
resolve: async function (
|
||||
this: WorkspaceEventEmitterResolver,
|
||||
payload: { workspaceEventBatch: WorkspaceEventBatch<ObjectRecordEvent> },
|
||||
args: { eventStreamId: string },
|
||||
context: { req: { workspace: { id: string } } },
|
||||
): Promise<EventSubscriptionDTO> {
|
||||
const workspaceId = context.req.workspace.id;
|
||||
const { eventStreamId } = args;
|
||||
|
||||
const queries = await this.eventStreamService.getQueries(
|
||||
workspaceId,
|
||||
eventStreamId,
|
||||
);
|
||||
|
||||
const objectNameSingular =
|
||||
payload.workspaceEventBatch.objectMetadata.nameSingular;
|
||||
|
||||
const eventWithQueryIdsList: {
|
||||
queryIds: string[];
|
||||
event: ObjectRecordEventDTO;
|
||||
}[] = [];
|
||||
|
||||
for (const event of payload.workspaceEventBatch.events) {
|
||||
const eventWithObjectName = {
|
||||
objectNameSingular,
|
||||
...event,
|
||||
};
|
||||
|
||||
const matchedQueryIds =
|
||||
await this.eventStreamService.matchQueriesWithEvent(
|
||||
queries,
|
||||
eventWithObjectName,
|
||||
);
|
||||
|
||||
if (matchedQueryIds.length > 0) {
|
||||
eventWithQueryIdsList.push({
|
||||
queryIds: matchedQueryIds,
|
||||
event: eventWithObjectName,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { eventStreamId, eventWithQueryIdsList };
|
||||
},
|
||||
})
|
||||
onEventSubscription(
|
||||
@Args('eventStreamId') _: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
return this.subscriptionService.subscribe({
|
||||
channel: SubscriptionChannel.WORKSPACE_EVENT_BATCH_CHANNEL,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => Boolean)
|
||||
async addQueryToEventStream(
|
||||
@Args('input') input: AddQuerySubscriptionInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<boolean> {
|
||||
await this.eventStreamService.addQuery({
|
||||
workspaceId: workspace.id,
|
||||
eventStreamId: input.eventStreamId,
|
||||
queryId: input.queryId,
|
||||
operationSignature: input.operationSignature,
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Mutation(() => Boolean)
|
||||
async removeQueryFromEventStream(
|
||||
@Args('input') input: RemoveQueryFromEventStreamInput,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<boolean> {
|
||||
await this.eventStreamService.removeQuery({
|
||||
workspaceId: workspace.id,
|
||||
eventStreamId: input.eventStreamId,
|
||||
queryId: input.queryId,
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -43,9 +43,9 @@ export class WorkspaceEventEmitterService {
|
||||
}
|
||||
|
||||
await this.subscriptionService.publish({
|
||||
channel: SubscriptionChannel.DATABASE_BATCH_EVENTS_CHANNEL,
|
||||
channel: SubscriptionChannel.WORKSPACE_EVENT_BATCH_CHANNEL,
|
||||
workspaceId: workspaceEventBatch.workspaceId,
|
||||
payload: { onDbEvents: batchEvents },
|
||||
payload: { workspaceEventBatch: workspaceEventBatch },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export type QueryCursorDirection = 'before' | 'after';
|
||||
@@ -0,0 +1,3 @@
|
||||
import { type RecordGqlFieldsDeprecated } from './RecordGqlFieldsDeprecated';
|
||||
|
||||
export type RecordGqlOperationGqlRecordFields = RecordGqlFieldsDeprecated;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { type OrderBy } from '@/types/OrderBy';
|
||||
import { type OrderBy } from './OrderBy';
|
||||
|
||||
// Recursive type for nested orderBy values
|
||||
// Supports: OrderBy | { field: OrderBy } | { field: { subField: OrderBy } } | ...
|
||||
@@ -0,0 +1,8 @@
|
||||
import { type RecordGqlOperationGqlRecordFields } from './RecordGqlOperationGqlRecordFields';
|
||||
import { type RecordGqlOperationVariables } from './RecordGqlOperationVariables';
|
||||
|
||||
export type RecordGqlOperationSignature = {
|
||||
objectNameSingular: string;
|
||||
variables: RecordGqlOperationVariables;
|
||||
fields?: RecordGqlOperationGqlRecordFields;
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
import { type QueryCursorDirection } from './QueryCursorDirection';
|
||||
import { type RecordGqlOperationFilter } from './RecordGqlOperationFilter';
|
||||
import { type RecordGqlOperationOrderBy } from './RecordGqlOperationOrderBy';
|
||||
|
||||
export type RecordGqlOperationVariables = {
|
||||
filter?: RecordGqlOperationFilter;
|
||||
orderBy?: RecordGqlOperationOrderBy;
|
||||
limit?: number;
|
||||
cursorFilter?: {
|
||||
cursor: string;
|
||||
cursorDirection: QueryCursorDirection;
|
||||
};
|
||||
};
|
||||
@@ -137,10 +137,13 @@ export { OrderByDirection } from './ObjectRecordGroupBy';
|
||||
export { ObjectRecordGroupByDateGranularity } from './ObjectRecordGroupByDateGranularity';
|
||||
export type { ObjectsPermissions } from './ObjectsPermissions';
|
||||
export type { ObjectsPermissionsByRoleId } from './ObjectsPermissionsByRoleId';
|
||||
export type { OrderBy } from './OrderBy';
|
||||
export type { PartialFieldMetadataItem } from './PartialFieldMetadataItem';
|
||||
export type { PartialFieldMetadataItemOption } from './PartialFieldMetadataOption';
|
||||
export type { QueryCursorDirection } from './QueryCursorDirection';
|
||||
export { RecordFilterGroupLogicalOperator } from './RecordFilterGroupLogicalOperator';
|
||||
export type { RecordFilterValueDependencies } from './RecordFilterValueDependencies';
|
||||
export type { RecordGqlFieldsDeprecated } from './RecordGqlFieldsDeprecated';
|
||||
export type {
|
||||
UUIDFilterValue,
|
||||
IsFilter,
|
||||
@@ -174,6 +177,10 @@ export type {
|
||||
LeafObjectRecordFilter,
|
||||
RecordGqlOperationFilter,
|
||||
} from './RecordGqlOperationFilter';
|
||||
export type { RecordGqlOperationGqlRecordFields } from './RecordGqlOperationGqlRecordFields';
|
||||
export type { RecordGqlOperationOrderBy } from './RecordGqlOperationOrderBy';
|
||||
export type { RecordGqlOperationSignature } from './RecordGqlOperationSignature';
|
||||
export type { RecordGqlOperationVariables } from './RecordGqlOperationVariables';
|
||||
export type { RelationAndMorphRelationFieldMetadataType } from './RelationAndMorphRelationFieldMetadataType';
|
||||
export type { RelationCreationPayload } from './RelationCreationPayload';
|
||||
export { RelationOnDeleteAction } from './RelationOnDeleteAction.type';
|
||||
|
||||
Reference in New Issue
Block a user